Add participant list fragment to the call view

This commit is contained in:
Benoit Martins 2024-04-23 16:11:48 +02:00
parent 582c1b1d66
commit 0a2d4a1682
11 changed files with 463 additions and 86 deletions

View file

@ -43,6 +43,7 @@
D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; };
D71707202AC5989C0037746F /* TextExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071F2AC5989C0037746F /* TextExtension.swift */; };
D7173EBE2B7A5C0A00BCC481 /* LinphoneUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7173EBD2B7A5C0A00BCC481 /* LinphoneUtils.swift */; };
D717630D2BD7BD0E00464097 /* ParticipantsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717630C2BD7BD0E00464097 /* ParticipantsListFragment.swift */; };
D71968922B86369D00DF4459 /* ChatBubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71968912B86369D00DF4459 /* ChatBubbleView.swift */; };
D719ABB72ABC67BF00B41C10 /* LinphoneApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABB62ABC67BF00B41C10 /* LinphoneApp.swift */; };
D719ABB92ABC67BF00B41C10 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABB82ABC67BF00B41C10 /* ContentView.swift */; };
@ -191,6 +192,7 @@
D717071D2AC5922E0037746F /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = "<group>"; };
D717071F2AC5989C0037746F /* TextExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextExtension.swift; sourceTree = "<group>"; };
D7173EBD2B7A5C0A00BCC481 /* LinphoneUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinphoneUtils.swift; sourceTree = "<group>"; };
D717630C2BD7BD0E00464097 /* ParticipantsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantsListFragment.swift; sourceTree = "<group>"; };
D71968912B86369D00DF4459 /* ChatBubbleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatBubbleView.swift; sourceTree = "<group>"; };
D719ABB32ABC67BF00B41C10 /* Linphone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Linphone.app; sourceTree = BUILT_PRODUCTS_DIR; };
D719ABB62ABC67BF00B41C10 /* LinphoneApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinphoneApp.swift; sourceTree = "<group>"; };
@ -582,6 +584,7 @@
children = (
D75759312B56D40900E7AC10 /* ZRTPPopup.swift */,
D7F4D9CA2B5FD27200CDCD76 /* CallsListFragment.swift */,
D717630C2BD7BD0E00464097 /* ParticipantsListFragment.swift */,
);
path = Fragments;
sourceTree = "<group>";
@ -954,6 +957,7 @@
D7A03FBD2ACC2DB60081A588 /* ContactsView.swift in Sources */,
66E50A492BD12B2300AD61CA /* MeetingsView.swift in Sources */,
D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */,
D717630D2BD7BD0E00464097 /* ParticipantsListFragment.swift in Sources */,
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */,

View file

@ -51,6 +51,16 @@
},
"%lld" : {
},
"%lld %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "%1$lld %2$@"
}
}
}
},
"%lld Book (Example)" : {
"extractionState" : "manual",
@ -167,6 +177,9 @@
},
"Add to favourites" : {
},
"Administrateur" : {
},
"All calls will be removed from the history." : {
@ -355,6 +368,9 @@
},
"Error Name" : {
},
"Etes-vous sûr de vouloir supprimer %@ ?" : {
},
"Favourites" : {
@ -509,6 +525,12 @@
},
"No meeting for the moment..." : {
},
"No participant for the moment..." : {
},
"Non" : {
},
"Not account yet?" : {
@ -524,6 +546,9 @@
},
"Other actions" : {
},
"Oui" : {
},
"Partage d'écran" : {
@ -683,6 +708,9 @@
},
"Supprimer la conversation" : {
},
"Supprimer un participant" : {
},
"TCP" : {

View file

@ -50,7 +50,8 @@ struct CallView: View {
@State var displayVideo = false
@Binding var fullscreenVideo: Bool
@Binding var isShowCallsListFragment: Bool
@State var isShowCallsListFragment: Bool = false
@State var isShowParticipantsListFragment: Bool = false
@Binding var isShowStartCallFragment: Bool
var body: some View {
@ -107,8 +108,14 @@ struct CallView: View {
if isShowCallsListFragment {
CallsListFragment(callViewModel: callViewModel, isShowCallsListFragment: $isShowCallsListFragment)
.zIndex(4)
.transition(.move(edge: .bottom))
.zIndex(4)
.transition(.move(edge: .bottom))
}
if isShowParticipantsListFragment {
ParticipantsListFragment(callViewModel: callViewModel, isShowParticipantsListFragment: $isShowParticipantsListFragment)
.zIndex(4)
.transition(.move(edge: .bottom))
}
if callViewModel.zrtpPopupDisplayed == true {
@ -1218,6 +1225,9 @@ struct CallView: View {
VStack {
Button {
withAnimation {
isShowParticipantsListFragment.toggle()
}
} label: {
HStack {
Image("users")
@ -1458,58 +1468,110 @@ struct CallView: View {
.frame(height: geo.size.height * 0.15)
} else {
HStack {
VStack {
Button {
withAnimation {
callViewModel.isTransferInsteadCall = true
MagicSearchSingleton.shared.searchForSuggestions()
isShowStartCallFragment.toggle()
if callViewModel.isOneOneCall {
VStack {
Button {
withAnimation {
callViewModel.isTransferInsteadCall = true
MagicSearchSingleton.shared.searchForSuggestions()
isShowStartCallFragment.toggle()
}
} label: {
HStack {
Image("phone-transfer")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
}
}
} label: {
HStack {
Image("phone-transfer")
.renderingMode(.template)
.resizable()
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
Text(callViewModel.calls.count < 2 ? "Transfer" : "Attended transfer")
.foregroundStyle(.white)
.default_text_style(styleSize: 15)
}
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
VStack {
Button {
withAnimation {
MagicSearchSingleton.shared.searchForSuggestions()
isShowStartCallFragment.toggle()
}
} label: {
HStack {
Image("phone-plus")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
}
}
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
Text("New call")
.foregroundStyle(.white)
.default_text_style(styleSize: 15)
}
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
} else {
VStack {
VStack {
Button {
} label: {
HStack {
Image("screencast")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.gray500)
.frame(width: 32, height: 32)
}
}
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(.white)
.cornerRadius(40)
.disabled(true)
Text("Partage d'écran")
.foregroundStyle(.white)
.frame(width: 32, height: 32)
.default_text_style(styleSize: 15)
}
}
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
Text(callViewModel.calls.count < 2 ? "Transfer" : "Attended transfer")
.foregroundStyle(.white)
.default_text_style(styleSize: 15)
}
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
VStack {
Button {
withAnimation {
MagicSearchSingleton.shared.searchForSuggestions()
isShowStartCallFragment.toggle()
}
} label: {
HStack {
Image("phone-plus")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
VStack {
Button {
withAnimation {
isShowParticipantsListFragment.toggle()
}
} label: {
HStack {
Image("users")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
}
}
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
Text("Participants")
.foregroundStyle(.white)
.default_text_style(styleSize: 15)
}
.buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
Text("New call")
.foregroundStyle(.white)
.default_text_style(styleSize: 15)
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
}
.frame(width: geo.size.width * 0.125, height: geo.size.width * 0.125)
VStack {
ZStack {
@ -1823,7 +1885,7 @@ struct PressedButtonStyle: ButtonStyle {
}
#Preview {
CallView(callViewModel: CallViewModel(), fullscreenVideo: .constant(false), isShowCallsListFragment: .constant(false), isShowStartCallFragment: .constant(false))
CallView(callViewModel: CallViewModel(), fullscreenVideo: .constant(false), isShowStartCallFragment: .constant(false))
}
// swiftlint:enable type_body_length
// swiftlint:enable line_length

View file

@ -1,18 +1,239 @@
//
// ParticipantsListFragment.swift
// Linphone
//
// Created by Benoît Martins on 23/04/2024.
//
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import SwiftUI
struct ParticipantsListFragment: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
@ObservedObject private var coreContext = CoreContext.shared
@ObservedObject private var contactsManager = ContactsManager.shared
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@ObservedObject var callViewModel: CallViewModel
@State private var delayedColor = Color.white
@Binding var isShowParticipantsListFragment: Bool
@State private var isShowPopup = false
@State private var indexToRemove = -1
var body: some View {
ZStack {
VStack(spacing: 1) {
Rectangle()
.foregroundColor(delayedColor)
.edgesIgnoringSafeArea(.top)
.frame(height: 0)
.task(delayColor)
HStack {
Image("caret-left")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeMain500)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
.padding(.top, 2)
.padding(.leading, -10)
.onTapGesture {
delayColorDismiss()
withAnimation {
isShowParticipantsListFragment.toggle()
}
}
Text("\(callViewModel.participantList.count + 1) \(callViewModel.participantList.isEmpty ? "Participant" : "Participants")")
.multilineTextAlignment(.leading)
.default_text_style_orange_800(styleSize: 16)
Spacer()
}
.frame(maxWidth: .infinity)
.frame(height: 50)
.padding(.horizontal)
.padding(.bottom, 4)
.background(.white)
participantsList
}
.background(.white)
if self.isShowPopup {
let contentPopup = Text("Etes-vous sûr de vouloir supprimer \(callViewModel.participantList[indexToRemove].name) ?")
PopupView(isShowPopup: $isShowPopup,
title: Text("Supprimer un participant"),
content: contentPopup,
titleFirstButton: Text("Non"),
actionFirstButton: {self.isShowPopup.toggle()},
titleSecondButton: Text("Oui"),
actionSecondButton: {
callViewModel.removeParticipant(index: indexToRemove)
self.isShowPopup.toggle()
indexToRemove = -1
})
.background(.black.opacity(0.65))
.onTapGesture {
self.isShowPopup.toggle()
indexToRemove = -1
}
}
}
.navigationBarHidden(true)
}
@Sendable private func delayColor() async {
try? await Task.sleep(nanoseconds: 250_000_000)
delayedColor = Color.orangeMain500
}
func delayColorDismiss() {
Task {
try? await Task.sleep(nanoseconds: 80_000_000)
delayedColor = .white
}
}
var participantsList: some View {
VStack {
List {
HStack {
HStack {
if callViewModel.myParticipantModel != nil {
Avatar(contactAvatarModel: callViewModel.myParticipantModel!.avatarModel, avatarSize: 50, hidePresence: true)
Text(callViewModel.myParticipantModel!.name)
.default_text_style(styleSize: 16)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
Spacer()
if callViewModel.myParticipantModel!.isAdmin {
Text("Administrateur")
.foregroundStyle(Color.grayMain2c300)
.default_text_style(styleSize: 12)
.frame(maxWidth: .infinity, alignment: .trailing)
.lineLimit(1)
}
if callViewModel.myParticipantModel!.isAdmin {
Toggle("", isOn: .constant(true))
.tint(Color.greenSuccess700)
.labelsHidden()
.padding(.horizontal, 4)
HStack(alignment: .center, spacing: 10) {
Image("x")
.renderingMode(.template)
.foregroundStyle(Color.grayMain2c400)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(width: 30, height: 30, alignment: .center)
.hidden()
}
}
}
}
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.listRowSeparator(.hidden)
.background(.white)
ForEach(0..<callViewModel.participantList.count, id: \.self) { index in
HStack {
HStack {
if index < callViewModel.participantList.count {
Avatar(contactAvatarModel: callViewModel.participantList[index].avatarModel, avatarSize: 50, hidePresence: true)
Text(callViewModel.participantList[index].name)
.default_text_style(styleSize: 16)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
Spacer()
if callViewModel.participantList[index].isAdmin {
Text("Administrateur")
.foregroundStyle(Color.grayMain2c300)
.default_text_style(styleSize: 12)
.frame(maxWidth: .infinity, alignment: .trailing)
.lineLimit(1)
}
if callViewModel.myParticipantModel!.isAdmin {
Toggle("", isOn: $callViewModel.participantList[index].isAdmin)
.tint(Color.greenSuccess500)
.labelsHidden()
.padding(.horizontal, 10)
.onTapGesture {
callViewModel.toggleAdminParticipant(index: index)
}
Button {
indexToRemove = index
isShowPopup.toggle()
} label: {
Image("x")
.renderingMode(.template)
.foregroundStyle(Color.grayMain2c400)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(width: 30, height: 30, alignment: .center)
.background(Color.grayMain2c100)
.cornerRadius(50)
}
}
}
}
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.listRowSeparator(.hidden)
.background(.white)
}
}
.listStyle(.plain)
.overlay(
VStack {
if callViewModel.myParticipantModel == nil && callViewModel.calls.isEmpty {
Spacer()
Image("illus-belledonne")
.resizable()
.scaledToFit()
.clipped()
.padding(.all)
Text("No participant for the moment...")
.default_text_style_800(styleSize: 16)
Spacer()
Spacer()
}
}
.padding(.all)
)
}
.navigationTitle("")
.navigationBarHidden(true)
}
}
#Preview {
ParticipantsListFragment()
ParticipantsListFragment(callViewModel: CallViewModel(), isShowParticipantsListFragment: .constant(true))
}

View file

@ -31,8 +31,9 @@ class ParticipantModel: ObservableObject {
@Published var isJoining: Bool
@Published var onPause: Bool
@Published var isMuted: Bool
@Published var isAdmin: Bool
init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false) {
init(address: Address, isJoining: Bool = false, onPause: Bool = false, isMuted: Bool = false, isAdmin: Bool = false) {
self.address = address
self.sipUri = address.asStringUriOnly()
@ -48,5 +49,6 @@ class ParticipantModel: ObservableObject {
self.isJoining = isJoining
self.onPause = onPause
self.isMuted = isMuted
self.isAdmin = isAdmin
}
}

View file

@ -215,9 +215,9 @@ class CallViewModel: ObservableObject {
var myParticipantModelTmp: ParticipantModel? = nil
if conf.me?.address != nil {
myParticipantModelTmp = ParticipantModel(address: conf.me!.address!, isJoining: false, onPause: false, isMuted: false)
myParticipantModelTmp = ParticipantModel(address: conf.me!.address!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin)
} else if self.currentCall?.callLog?.localAddress != nil {
myParticipantModelTmp = ParticipantModel(address: self.currentCall!.callLog!.localAddress!, isJoining: false, onPause: false, isMuted: false)
myParticipantModelTmp = ParticipantModel(address: self.currentCall!.callLog!.localAddress!, isJoining: false, onPause: false, isMuted: false, isAdmin: conf.me!.isAdmin)
}
var activeSpeakerParticipantTmp: ParticipantModel? = nil
@ -262,12 +262,14 @@ class CallViewModel: ObservableObject {
conf.participantDeviceList.forEach({ participantDevice in
if participantDevice.address != nil && !conf.isMe(uri: participantDevice.address!.clone()!) {
if !conf.isMe(uri: participantDevice.address!.clone()!) {
let isAdmin = conf.participantList.first(where: {$0.address!.equal(address2: participantDevice.address!.clone()!)})?.isAdmin
participantListTmp.append(
ParticipantModel(
address: participantDevice.address!,
isJoining: participantDevice.state == .Joining || participantDevice.state == .Alerting,
onPause: participantDevice.state == .OnHold,
isMuted: participantDevice.isMuted
isMuted: participantDevice.isMuted,
isAdmin: isAdmin ?? false
)
)
}
@ -336,12 +338,14 @@ class CallViewModel: ObservableObject {
cbValue.conference.participantDeviceList.forEach({ participantDevice in
if participantDevice.address != nil && !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
if !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
let isAdmin = cbValue.conference.participantList.first(where: {$0.address!.equal(address2: participantDevice.address!.clone()!)})?.isAdmin
participantListTmp.append(
ParticipantModel(
address: participantDevice.address!,
isJoining: participantDevice.state == .Joining || participantDevice.state == .Alerting,
onPause: participantDevice.state == .OnHold,
isMuted: participantDevice.isMuted
isMuted: participantDevice.isMuted,
isAdmin: isAdmin ?? false
)
)
}
@ -368,12 +372,14 @@ class CallViewModel: ObservableObject {
cbValue.conference.participantDeviceList.forEach({ participantDevice in
if participantDevice.address != nil && !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
if !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
let isAdmin = cbValue.conference.participantList.first(where: {$0.address!.equal(address2: participantDevice.address!.clone()!)})?.isAdmin
participantListTmp.append(
ParticipantModel(
address: participantDevice.address!,
isJoining: participantDevice.state == .Joining || participantDevice.state == .Alerting,
onPause: participantDevice.state == .OnHold,
isMuted: participantDevice.isMuted
isMuted: participantDevice.isMuted,
isAdmin: isAdmin ?? false
)
)
}
@ -394,12 +400,14 @@ class CallViewModel: ObservableObject {
cbValue.conference.participantDeviceList.forEach({ participantDevice in
if participantDevice.address != nil && !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
if !cbValue.conference.isMe(uri: participantDevice.address!.clone()!) {
let isAdmin = cbValue.conference.participantList.first(where: {$0.address!.equal(address2: participantDevice.address!.clone()!)})?.isAdmin
participantListTmp.append(
ParticipantModel(
address: participantDevice.address!,
isJoining: participantDevice.state == .Joining || participantDevice.state == .Alerting,
onPause: participantDevice.state == .OnHold,
isMuted: participantDevice.isMuted
isMuted: participantDevice.isMuted,
isAdmin: isAdmin ?? false
)
)
}
@ -467,6 +475,25 @@ class CallViewModel: ObservableObject {
}
}
)
self.mConferenceSuscriptions.insert(
self.currentCall?.conference?.publisher?.onParticipantAdminStatusChanged?.postOnMainQueue {(cbValue: (conference: Conference, participant: Participant)) in
let isAdmin = cbValue.participant.isAdmin
if self.myParticipantModel != nil && self.myParticipantModel!.address.clone()!.equal(address2: cbValue.participant.address!) {
DispatchQueue.main.async {
self.myParticipantModel!.isAdmin = isAdmin
}
} else {
self.participantList.forEach({ participantDevice in
if participantDevice.address.clone()!.equal(address2: cbValue.participant.address!) {
DispatchQueue.main.async {
participantDevice.isAdmin = isAdmin
}
}
})
}
}
)
}
}
@ -830,5 +857,29 @@ class CallViewModel: ObservableObject {
}
}
}
func toggleAdminParticipant(index: Int) {
coreContext.doOnCoreQueue { core in
self.currentCall?.conference?.participantList.forEach({ participant in
if participant.address != nil && self.participantList[index].address.clone() != nil && participant.address!.equal(address2: self.participantList[index].address.clone()!) {
self.currentCall?.conference?.setParticipantAdminStatus(participant: participant, isAdmin: !participant.isAdmin)
}
})
}
}
func removeParticipant(index: Int) {
coreContext.doOnCoreQueue { core in
self.currentCall?.conference?.participantList.forEach({ participant in
if participant.address != nil && self.participantList[index].address.clone() != nil && participant.address!.equal(address2: self.participantList[index].address.clone()!) {
do {
try self.currentCall?.conference?.removeParticipant(participant: participant)
} catch {
}
}
})
}
}
}
// swiftlint:enable type_body_length

View file

@ -78,6 +78,10 @@ struct ContactsListFragment: View {
.foregroundStyle(Color.orangeMain500)
}
}
.frame(height: 50)
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 20))
.listRowSeparator(.hidden)
.background(.white)
.onTapGesture {
withAnimation {
@ -91,8 +95,6 @@ struct ContactsListFragment: View {
contactViewModel.selectedFriend = contactsManager.lastSearch[index].friend
showingSheet.toggle()
}
.buttonStyle(.borderless)
.listRowSeparator(.hidden)
}
}
}

View file

@ -62,7 +62,6 @@ struct ContentView: View {
@State var isShowDismissPopup = false
@State var fullscreenVideo = false
@State var isShowCallsListFragment = false
@State var isShowScheduleMeetingFragment = false
@ -913,8 +912,8 @@ struct ContentView: View {
}
if telecomManager.callDisplayed && ((telecomManager.callInProgress && telecomManager.outgoingCallStarted) || telecomManager.callConnected) && !telecomManager.meetingWaitingRoomDisplayed {
CallView(callViewModel: callViewModel, fullscreenVideo: $fullscreenVideo, isShowCallsListFragment: $isShowCallsListFragment, isShowStartCallFragment: $isShowStartCallFragment)
.zIndex(3)
CallView(callViewModel: callViewModel, fullscreenVideo: $fullscreenVideo, isShowStartCallFragment: $isShowStartCallFragment)
.zIndex(5)
.transition(.scale.combined(with: .move(edge: .top)))
.onAppear {
callViewModel.resetCallView()

View file

@ -128,6 +128,7 @@ struct ConversationsListFragment: View {
}
.padding(.trailing, 10)
}
.frame(height: 50)
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 20))
.listRowSeparator(.hidden)

View file

@ -57,7 +57,7 @@ struct HistoryListFragment: View {
} else {
Image("profil-picture-default")
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
}
} else {
@ -69,7 +69,7 @@ struct HistoryListFragment: View {
? historyListViewModel.callLogs[index].toAddress!.displayName!.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
} else if historyListViewModel.callLogs[index].toAddress!.username != nil {
@ -79,7 +79,7 @@ struct HistoryListFragment: View {
? historyListViewModel.callLogs[index].toAddress!.username!.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
} else {
VStack {
@ -89,7 +89,7 @@ struct HistoryListFragment: View {
.frame(width: 28, height: 28)
.foregroundStyle(Color.grayMain2c600)
}
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.background(Color.grayMain2c200)
.clipShape(Circle())
}
@ -101,7 +101,7 @@ struct HistoryListFragment: View {
? historyListViewModel.callLogs[index].fromAddress!.displayName!.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
} else if historyListViewModel.callLogs[index].fromAddress!.username != nil {
Image(uiImage: contactsManager.textToImage(
@ -110,7 +110,7 @@ struct HistoryListFragment: View {
? historyListViewModel.callLogs[index].fromAddress!.username!.components(separatedBy: " ")[1]
: ""))
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
} else {
VStack {
@ -120,14 +120,14 @@ struct HistoryListFragment: View {
.frame(width: 28, height: 28)
.foregroundStyle(Color.grayMain2c600)
}
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.background(Color.grayMain2c200)
.clipShape(Circle())
}
} else {
Image("profil-picture-default")
.resizable()
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.clipShape(Circle())
}
}
@ -139,7 +139,7 @@ struct HistoryListFragment: View {
.frame(width: 28, height: 28)
.foregroundStyle(Color.grayMain2c600)
}
.frame(width: 45, height: 45)
.frame(width: 50, height: 50)
.background(Color.grayMain2c200)
.clipShape(Circle())
}
@ -215,8 +215,9 @@ struct HistoryListFragment: View {
}
}
}
.frame(height: 50)
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 20))
.listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 20))
.listRowSeparator(.hidden)
.background(.white)
.onTapGesture {

View file

@ -23,11 +23,16 @@ struct MeetingsFragment: View {
ForEach(0..<meetingsListViewModel.meetingsList.count, id: \.self) { index in
HStack {
HStack {
Image("users-three-square")
.renderingMode(.template)
.resizable()
.frame(width: 28, height: 28)
.foregroundStyle(Color.grayMain2c600)
VStack {
Image("users-three-square")
.renderingMode(.template)
.resizable()
.frame(width: 28, height: 28)
.foregroundStyle(Color.grayMain2c600)
}
.frame(width: 50, height: 50)
.background(Color.grayMain2c200)
.clipShape(Circle())
VStack(spacing: 0) {
Text(meetingsListViewModel.meetingsList[index].model?.subject ?? "")
@ -38,8 +43,9 @@ struct MeetingsFragment: View {
}
.frame(height: 40)
}
.frame(height: 50)
.buttonStyle(.borderless)
.listRowInsets(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 20))
.listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 20))
.listRowSeparator(.hidden)
.background(.white)
.onTapGesture {