Refactored MeetingsView

This commit is contained in:
Benoit Martins 2025-06-17 23:00:17 +02:00
parent 0d149c7b54
commit 8aa5b32787
10 changed files with 198 additions and 193 deletions

View file

@ -40,14 +40,11 @@ struct ContentView: View {
@State private var contactsListViewModel: ContactsListViewModel? @State private var contactsListViewModel: ContactsListViewModel?
@State private var historyListViewModel: HistoryListViewModel? @State private var historyListViewModel: HistoryListViewModel?
@State private var conversationsListViewModel: ConversationsListViewModel? @State private var conversationsListViewModel: ConversationsListViewModel?
@State private var meetingsListViewModel: MeetingsListViewModel?
//@ObservedObject var meetingWaitingRoomViewModel: MeetingWaitingRoomViewModel //@ObservedObject var meetingWaitingRoomViewModel: MeetingWaitingRoomViewModel
//@ObservedObject var meetingsListViewModel: MeetingsListViewModel
//@ObservedObject var meetingViewModel: MeetingViewModel
//@Binding var index: Int //@Binding var index: Int
@State private var orientation = UIDevice.current.orientation @State private var orientation = UIDevice.current.orientation
@State var sideMenuIsOpen: Bool = false @State var sideMenuIsOpen: Bool = false
@ -513,9 +510,9 @@ struct ContentView: View {
historyListVM.resetFilterCallLogs() historyListVM.resetFilterCallLogs()
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 { } else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
conversationsListVM.resetFilterConversations() conversationsListVM.resetFilterConversations()
} else if sharedMainViewModel.indexView == 3 { } else if let meetingsListVM = meetingsListViewModel, sharedMainViewModel.indexView == 3 {
//meetingsListViewModel.currentFilter = "" meetingsListVM.currentFilter = ""
//meetingsListViewModel.computeMeetingsList() meetingsListVM.computeMeetingsList()
} }
} label: { } label: {
Image("caret-left") Image("caret-left")
@ -567,9 +564,9 @@ struct ContentView: View {
} else { } else {
conversationsListVM.filterConversations(filter: text) conversationsListVM.filterConversations(filter: text)
} }
} else if sharedMainViewModel.indexView == 3 { } else if let meetingsListVM = meetingsListViewModel, sharedMainViewModel.indexView == 3 {
//meetingsListViewModel.currentFilter = text meetingsListVM.currentFilter = text
//meetingsListViewModel.computeMeetingsList() meetingsListVM.computeMeetingsList()
} }
} }
} else { } else {
@ -602,9 +599,9 @@ struct ContentView: View {
historyListVM.filterCallLogs(filter: text) historyListVM.filterCallLogs(filter: text)
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 { } else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 {
conversationsListVM.filterConversations(filter: text) conversationsListVM.filterConversations(filter: text)
} else if sharedMainViewModel.indexView == 3 { } else if let meetingsListVM = meetingsListViewModel, sharedMainViewModel.indexView == 3 {
//meetingsListViewModel.currentFilter = text meetingsListVM.currentFilter = text
//meetingsListViewModel.computeMeetingsList() meetingsListVM.computeMeetingsList()
} }
} }
} }
@ -726,31 +723,38 @@ struct ContentView: View {
} }
} }
} else if sharedMainViewModel.indexView == 3 { } else if sharedMainViewModel.indexView == 3 {
//TODO a changer if let meetingsListVM = meetingsListViewModel {
NavigationView { MeetingsView(
ZStack(alignment: .bottomTrailing) { isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment,
} isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup,
} text: $text
.navigationViewStyle(.stack) )
/* .environmentObject(meetingsListVM)
MeetingsView( .roundedCorner(25, corners: [.topRight, .topLeft])
meetingsListViewModel: meetingsListViewModel, .shadow(
meetingViewModel: meetingViewModel, color: (orientation == .landscapeLeft
isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, || orientation == .landscapeRight
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup, || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
text: $text ? .white.opacity(0.0)
) : .black.opacity(0.2),
.roundedCorner(25, corners: [.topRight, .topLeft]) radius: 25
.shadow( )
color: (orientation == .landscapeLeft } else {
|| orientation == .landscapeRight NavigationView {
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) VStack {
? .white.opacity(0.0) Spacer()
: .black.opacity(0.2),
radius: 25 ProgressView()
) .controlSize(.large)
*/
} Spacer()
}
.onAppear {
meetingsListViewModel = MeetingsListViewModel()
}
}
}
}
} }
} }
} }
@ -976,7 +980,7 @@ struct ContentView: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(Color.gray100) .background(Color.gray100)
.ignoresSafeArea(.keyboard) .ignoresSafeArea(.keyboard)
} else if let conversationsListVM = conversationsListViewModel, sharedMainViewModel.indexView == 2 { } else if let conversationsListVM = conversationsListViewModel, let displayedConversation = sharedMainViewModel.displayedConversation, sharedMainViewModel.indexView == 2 {
ConversationFragment( ConversationFragment(
isShowConversationFragment: $isShowConversationFragment, isShowConversationFragment: $isShowConversationFragment,
isShowStartCallGroupPopup: $isShowStartCallGroupPopup, isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
@ -989,13 +993,12 @@ struct ContentView: View {
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(Color.gray100) .background(Color.gray100)
.ignoresSafeArea(.keyboard) .ignoresSafeArea(.keyboard)
} else if sharedMainViewModel.indexView == 3 { } else if let meetingsListVM = meetingsListViewModel, let displayedMeeting = sharedMainViewModel.displayedMeeting, sharedMainViewModel.indexView == 3 {
/* MeetingFragment(isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup)
MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup) .environmentObject(meetingsListVM)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(Color.gray100) .background(Color.gray100)
.ignoresSafeArea(.keyboard) .ignoresSafeArea(.keyboard)
*/
} }
} }
@ -1235,19 +1238,14 @@ struct ContentView: View {
} }
} }
/* if let meetingsListVM = meetingsListViewModel, isShowScheduleMeetingFragment {
if isShowScheduleMeetingFragment {
ScheduleMeetingFragment( ScheduleMeetingFragment(
meetingViewModel: meetingViewModel,
meetingsListViewModel: meetingsListViewModel,
isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment
) )
.environmentObject(meetingsListVM)
.zIndex(3) .zIndex(3)
.transition(.move(edge: .bottom)) .transition(.move(edge: .bottom))
.onAppear {
}
} }
*/
if isShowAccountProfileFragment { if isShowAccountProfileFragment {
AccountProfileFragment( AccountProfileFragment(
@ -1276,25 +1274,23 @@ struct ContentView: View {
.zIndex(3) .zIndex(3)
.transition(.move(edge: .trailing)) .transition(.move(edge: .trailing))
} }
*/
if isShowSendCancelMeetingNotificationPopup { if let meetingsListVM = meetingsListViewModel, isShowSendCancelMeetingNotificationPopup {
PopupView(isShowPopup: $isShowSendCancelMeetingNotificationPopup, PopupView(isShowPopup: $isShowSendCancelMeetingNotificationPopup,
title: Text("meeting_schedule_cancel_dialog_title"), title: Text("meeting_schedule_cancel_dialog_title"),
content: Text("meeting_schedule_cancel_dialog_message"), content: Text("meeting_schedule_cancel_dialog_message"),
titleFirstButton: Text("dialog_cancel"), titleFirstButton: Text("dialog_cancel"),
actionFirstButton: { actionFirstButton: {
sharedMainViewModel.displayedMeeting = nil sharedMainViewModel.displayedMeeting = nil
meetingsListViewModel.deleteSelectedMeeting() meetingsListVM.deleteSelectedMeeting()
self.isShowSendCancelMeetingNotificationPopup.toggle( self.isShowSendCancelMeetingNotificationPopup.toggle(
) }, ) },
titleSecondButton: Text("dialog_ok"), titleSecondButton: Text("dialog_ok"),
actionSecondButton: { actionSecondButton: {
sharedMainViewModel.displayedMeeting = nil sharedMainViewModel.displayedMeeting = nil
if let meetingToDelete = self.meetingsListViewModel.selectedMeetingToDelete { meetingsListVM.cancelMeetingWithNotifications()
self.meetingViewModel.cancelMeetingWithNotifications(meeting: meetingToDelete) self.isShowSendCancelMeetingNotificationPopup.toggle()
meetingsListViewModel.deleteSelectedMeeting()
self.isShowSendCancelMeetingNotificationPopup.toggle()
}
}) })
.background(.black.opacity(0.65)) .background(.black.opacity(0.65))
.zIndex(3) .zIndex(3)
@ -1302,7 +1298,6 @@ struct ContentView: View {
self.isShowSendCancelMeetingNotificationPopup.toggle() self.isShowSendCancelMeetingNotificationPopup.toggle()
} }
} }
*/
if isShowStartCallGroupPopup { if isShowStartCallGroupPopup {
PopupView( PopupView(
@ -1455,7 +1450,6 @@ class NavigationManager: ObservableObject {
//meetingViewModel: MeetingViewModel(), //meetingViewModel: MeetingViewModel(),
//conversationForwardMessageViewModel: ConversationForwardMessageViewModel(), //conversationForwardMessageViewModel: ConversationForwardMessageViewModel(),
//accountProfileViewModel: AccountProfileViewModel(), //accountProfileViewModel: AccountProfileViewModel(),
//index: .constant(0)
) )
} }
// swiftlint:enable type_body_length // swiftlint:enable type_body_length

View file

@ -189,9 +189,10 @@ struct AddParticipantsFragment: View {
.padding(.trailing, 5) .padding(.trailing, 5)
} }
if index < contactsManager.avatarListModel.count if index < contactsManager.avatarListModel.count,
&& contactsManager.avatarListModel[index].friend!.photo != nil let friend = contactsManager.avatarListModel[index].friend,
&& !contactsManager.avatarListModel[index].friend!.photo!.isEmpty { let photo = friend.photo,
!photo.isEmpty {
Avatar(contactAvatarModel: contactsManager.avatarListModel[index], avatarSize: 50) Avatar(contactAvatarModel: contactsManager.avatarListModel[index], avatarSize: 50)
} else { } else {
Image("profil-picture-default") Image("profil-picture-default")
@ -199,7 +200,8 @@ struct AddParticipantsFragment: View {
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
.clipShape(Circle()) .clipShape(Circle())
} }
Text((contactsManager.lastSearch[index].friend?.name)!)
Text((contactsManager.lastSearch[index].friend?.name ?? "")!)
.default_text_style(styleSize: 16) .default_text_style(styleSize: 16)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.foregroundStyle(Color.orangeMain500) .foregroundStyle(Color.orangeMain500)

View file

@ -28,8 +28,9 @@ struct MeetingFragment: View {
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@State private var orientation = UIDevice.current.orientation @State private var orientation = UIDevice.current.orientation
@ObservedObject var meetingViewModel: MeetingViewModel @EnvironmentObject var meetingsListViewModel: MeetingsListViewModel
@ObservedObject var meetingsListViewModel: MeetingsListViewModel
@StateObject private var meetingViewModel = MeetingViewModel()
@State private var showDatePicker = false @State private var showDatePicker = false
@State private var showTimePicker = false @State private var showTimePicker = false
@ -63,21 +64,15 @@ struct MeetingFragment: View {
} }
var body: some View { var body: some View {
let displayedMeetingUpdated = NotificationCenter.default
.publisher(for: NSNotification.Name("DisplayedMeetingUpdated"))
NavigationView { NavigationView {
ZStack(alignment: .bottomTrailing) { ZStack(alignment: .bottomTrailing) {
VStack(spacing: 0) { VStack(spacing: 0) {
if #available(iOS 16.0, *) { Rectangle()
Rectangle() .foregroundColor(Color.orangeMain500)
.foregroundColor(Color.orangeMain500) .edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.top) .frame(height: 1)
.frame(height: 0)
} else if idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
Rectangle()
.foregroundColor(Color.orangeMain500)
.edgesIgnoringSafeArea(.top)
.frame(height: 1)
}
HStack { HStack {
Image("caret-left") Image("caret-left")
@ -316,16 +311,10 @@ struct MeetingFragment: View {
}) })
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
.onReceive(displayedMeetingUpdated) { _ in
if let displayedMeeting = SharedMainViewModel.shared.displayedMeeting {
meetingViewModel.loadExistingMeeting(meeting: displayedMeeting)
}
}
} }
} }
#Preview {
let model = MeetingViewModel()
model.subject = "Meeting subject"
model.conferenceUri = "linphone.com/lalalal.fr"
model.description = ""
return MeetingFragment(meetingViewModel: model
, meetingsListViewModel: MeetingsListViewModel()
, isShowScheduleMeetingFragment: .constant(true)
, isShowSendCancelMeetingNotificationPopup: .constant(false))
}

View file

@ -21,9 +21,8 @@ import SwiftUI
import linphonesw import linphonesw
struct MeetingsFragment: View { struct MeetingsFragment: View {
@ObservedObject var meetingsListViewModel: MeetingsListViewModel @EnvironmentObject var meetingsListViewModel: MeetingsListViewModel
@ObservedObject var meetingViewModel: MeetingViewModel
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@ -86,7 +85,7 @@ struct MeetingsFragment: View {
.onTapGesture { .onTapGesture {
withAnimation { withAnimation {
if let meetingModel = model.model, meetingModel.confInfo.state != ConferenceInfo.State.Cancelled { if let meetingModel = model.model, meetingModel.confInfo.state != ConferenceInfo.State.Cancelled {
meetingViewModel.loadExistingMeeting(meeting: meetingModel) SharedMainViewModel.shared.displayedMeeting = meetingModel
} }
} }
} }
@ -191,7 +190,5 @@ struct MeetingsFragment: View {
} }
#Preview { #Preview {
MeetingsFragment(meetingsListViewModel: MeetingsListViewModel(), MeetingsFragment(showingSheet: .constant(false), text: .constant(""))
meetingViewModel: MeetingViewModel(),
showingSheet: .constant(false), text: .constant(""))
} }

View file

@ -28,7 +28,8 @@ struct MeetingsListBottomSheet: View {
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@State private var orientation = UIDevice.current.orientation @State private var orientation = UIDevice.current.orientation
@ObservedObject var meetingsListViewModel: MeetingsListViewModel @EnvironmentObject var meetingsListViewModel: MeetingsListViewModel
@Binding var showingSheet: Bool @Binding var showingSheet: Bool
@Binding var isShowSendCancelMeetingNotificationPopup: Bool @Binding var isShowSendCancelMeetingNotificationPopup: Bool

View file

@ -27,8 +27,9 @@ struct ScheduleMeetingFragment: View {
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@State private var orientation = UIDevice.current.orientation @State private var orientation = UIDevice.current.orientation
@ObservedObject var meetingViewModel: MeetingViewModel @EnvironmentObject var meetingsListViewModel: MeetingsListViewModel
@ObservedObject var meetingsListViewModel: MeetingsListViewModel
@StateObject private var meetingViewModel = MeetingViewModel()
@State private var delayedColor = Color.white @State private var delayedColor = Color.white
@State private var showDatePicker = false @State private var showDatePicker = false
@ -75,10 +76,6 @@ struct ScheduleMeetingFragment: View {
.padding(.leading, -10) .padding(.leading, -10)
.onTapGesture { .onTapGesture {
withAnimation { withAnimation {
if let meeting = SharedMainViewModel.shared.displayedMeeting {
// reload meeting to cancel change from edit
meetingViewModel.loadExistingMeeting(meeting: meeting)
}
isShowScheduleMeetingFragment.toggle() isShowScheduleMeetingFragment.toggle()
} }
} }
@ -506,9 +503,7 @@ struct ScheduleMeetingFragment: View {
} }
#Preview { #Preview {
ScheduleMeetingFragment(meetingViewModel: MeetingViewModel() ScheduleMeetingFragment(isShowScheduleMeetingFragment: .constant(true))
, meetingsListViewModel: MeetingsListViewModel()
, isShowScheduleMeetingFragment: .constant(true))
} }
// swiftlint:enable type_body_length // swiftlint:enable type_body_length

View file

@ -21,9 +21,8 @@ import SwiftUI
struct MeetingsView: View { struct MeetingsView: View {
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@ObservedObject var meetingsListViewModel: MeetingsListViewModel @EnvironmentObject var meetingsListViewModel: MeetingsListViewModel
@ObservedObject var meetingViewModel: MeetingViewModel
@Binding var isShowScheduleMeetingFragment: Bool @Binding var isShowScheduleMeetingFragment: Bool
@Binding var isShowSendCancelMeetingNotificationPopup: Bool @Binding var isShowSendCancelMeetingNotificationPopup: Bool
@ -36,29 +35,28 @@ struct MeetingsView: View {
ZStack(alignment: .bottomTrailing) { ZStack(alignment: .bottomTrailing) {
if #available(iOS 16.0, *), idiom != .pad { if #available(iOS 16.0, *), idiom != .pad {
MeetingsFragment(meetingsListViewModel: meetingsListViewModel, meetingViewModel: meetingViewModel, showingSheet: $showingSheet, text: $text) MeetingsFragment(showingSheet: $showingSheet, text: $text)
.sheet(isPresented: $showingSheet) { .sheet(isPresented: $showingSheet) {
MeetingsListBottomSheet( MeetingsListBottomSheet(
meetingsListViewModel: meetingsListViewModel,
showingSheet: $showingSheet, showingSheet: $showingSheet,
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup
) )
.environmentObject(meetingsListViewModel)
.presentationDetents([.fraction(0.1)]) .presentationDetents([.fraction(0.1)])
} }
} else { } else {
MeetingsFragment(meetingsListViewModel: meetingsListViewModel, meetingViewModel: meetingViewModel, showingSheet: $showingSheet, text: $text) MeetingsFragment(showingSheet: $showingSheet, text: $text)
.halfSheet(showSheet: $showingSheet) { .halfSheet(showSheet: $showingSheet) {
MeetingsListBottomSheet( MeetingsListBottomSheet(
meetingsListViewModel: meetingsListViewModel,
showingSheet: $showingSheet, showingSheet: $showingSheet,
isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup
) )
.environmentObject(meetingsListViewModel)
} onDismiss: {} } onDismiss: {}
} }
Button { Button {
withAnimation { withAnimation {
meetingViewModel.resetViewModelData()
isShowScheduleMeetingFragment.toggle() isShowScheduleMeetingFragment.toggle()
} }
} label: { } label: {
@ -80,8 +78,6 @@ struct MeetingsView: View {
#Preview { #Preview {
MeetingsView( MeetingsView(
meetingsListViewModel: MeetingsListViewModel(),
meetingViewModel: MeetingViewModel(),
isShowScheduleMeetingFragment: .constant(false), isShowScheduleMeetingFragment: .constant(false),
isShowSendCancelMeetingNotificationPopup: .constant(false), isShowSendCancelMeetingNotificationPopup: .constant(false),
text: .constant("") text: .constant("")

View file

@ -47,7 +47,6 @@ class MeetingViewModel: ObservableObject {
var conferenceScheduler: ConferenceScheduler? var conferenceScheduler: ConferenceScheduler?
private var mSchedulerDelegate: ConferenceSchedulerDelegate? private var mSchedulerDelegate: ConferenceSchedulerDelegate?
var conferenceInfoToEdit: ConferenceInfo?
@Published var myself: SelectedAddressModel? @Published var myself: SelectedAddressModel?
@Published var fromDate: Date @Published var fromDate: Date
@Published var toDate: Date @Published var toDate: Date
@ -71,6 +70,10 @@ class MeetingViewModel: ObservableObject {
selectedTimezoneIdx = knownTimezones.firstIndex(where: {$0 == selectedTimezone.identifier}) ?? 0 selectedTimezoneIdx = knownTimezones.firstIndex(where: {$0 == selectedTimezone.identifier}) ?? 0
computeDateLabels() computeDateLabels()
computeTimeLabels() computeTimeLabels()
if let displayedMeeting = SharedMainViewModel.shared.displayedMeeting {
self.loadExistingMeeting(meeting: displayedMeeting)
}
} }
func resetViewModelData() { func resetViewModelData() {
@ -185,17 +188,18 @@ class MeetingViewModel: ObservableObject {
} }
} else if state == ConferenceScheduler.State.Ready { } else if state == ConferenceScheduler.State.Ready {
let conferenceAddress = self.conferenceScheduler?.info?.uri let conferenceAddress = self.conferenceScheduler?.info?.uri
if let confInfoToEdit = self.conferenceInfoToEdit { Log.info("\(MeetingViewModel.TAG) Conference info created, address will be \(conferenceAddress?.asStringUriOnly() ?? "'nil'")")
Log.info("\(MeetingViewModel.TAG) Conference info \(confInfoToEdit.uri?.asStringUriOnly() ?? "'nil'") has been updated") DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_meeting_info_created_toast"
ToastViewModel.shared.displayToast = true
}
if SharedMainViewModel.shared.displayedMeeting != nil {
DispatchQueue.main.async { DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_meeting_info_updated_toast" NotificationCenter.default.post(
ToastViewModel.shared.displayToast = true name: NSNotification.Name("DisplayedMeetingUpdated"),
} object: nil
} else { )
Log.info("\(MeetingViewModel.TAG) Conference info created, address will be \(conferenceAddress?.asStringUriOnly() ?? "'nil'")")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_meeting_info_created_toast"
ToastViewModel.shared.displayToast = true
} }
} }
@ -210,9 +214,6 @@ class MeetingViewModel: ObservableObject {
} }
} }
} else if state == ConferenceScheduler.State.Updating { } else if state == ConferenceScheduler.State.Updating {
DispatchQueue.main.async {
ToastViewModel.shared.displayToast = true
}
self.sendIcsInvitation(core: core) self.sendIcsInvitation(core: core)
} }
}, onInvitationsSent: { (_: ConferenceScheduler, failedInvitations: [Address]) in }, onInvitationsSent: { (_: ConferenceScheduler, failedInvitations: [Address]) in
@ -295,73 +296,54 @@ class MeetingViewModel: ObservableObject {
} }
} }
func update() {
self.operationInProgress = true
CoreContext.shared.doOnCoreQueue { core in
Log.info("\(MeetingViewModel.TAG) Updating \(self.isBroadcastSelected ? "broadcast" : "meeting")")
if let conferenceInfo = self.conferenceInfoToEdit {
self.fillConferenceInfo(confInfo: conferenceInfo)
self.resetConferenceSchedulerAndListeners(core: core)
// Will trigger the conference update automatically
self.conferenceScheduler?.info = conferenceInfo
} else {
Log.error("No conference info to edit found!")
return
}
}
}
// Warning: must be called from core queue. Removed the dispatchQueue.main.async in order to have the animation properly trigger. // Warning: must be called from core queue. Removed the dispatchQueue.main.async in order to have the animation properly trigger.
func loadExistingMeeting(meeting: MeetingModel) { func loadExistingMeeting(meeting: MeetingModel) {
self.resetViewModelData() self.resetViewModelData()
self.subject = meeting.confInfo.subject ?? "" self.subject = meeting.confInfo.subject ?? ""
self.description = meeting.confInfo.description ?? "" self.description = meeting.confInfo.description ?? ""
self.fromDate = meeting.meetingDate self.fromDate = meeting.meetingDate
self.toDate = meeting.endDate self.toDate = meeting.endDate
self.participants = [] self.participants = []
CoreContext.shared.doOnCoreQueue { core in CoreContext.shared.doOnCoreQueue { core in
let organizer = meeting.confInfo.organizer let organizer = meeting.confInfo.organizer
var organizerFound = false var organizerFound = false
if let myAddr = core.defaultAccount?.contactAddress { if let myAddr = core.defaultAccount?.contactAddress {
let isOrganizer = (organizer != nil) ? myAddr.weakEqual(address2: organizer!) : false let isOrganizer = (organizer != nil) ? myAddr.weakEqual(address2: organizer!) : false
organizerFound = organizerFound || isOrganizer
ContactAvatarModel.getAvatarModelFromAddress(address: myAddr) { avatarResult in
DispatchQueue.main.async {
self.myself = SelectedAddressModel(addr: myAddr, avModel: avatarResult, isOrg: isOrganizer)
}
}
}
for pInfo in meeting.confInfo.participantInfos {
if let addr = pInfo.address {
let isOrganizer = (organizer != nil) ? addr.weakEqual(address2: organizer!) : false
organizerFound = organizerFound || isOrganizer organizerFound = organizerFound || isOrganizer
ContactAvatarModel.getAvatarModelFromAddress(address: myAddr) { avatarResult in ContactAvatarModel.getAvatarModelFromAddress(address: addr) { avatarResult in
DispatchQueue.main.async { DispatchQueue.main.async {
self.myself = SelectedAddressModel(addr: myAddr, avModel: avatarResult, isOrg: isOrganizer) self.participants.append(SelectedAddressModel(addr: addr, avModel: avatarResult, isOrg: isOrganizer))
}
}
}
for pInfo in meeting.confInfo.participantInfos {
if let addr = pInfo.address {
let isOrganizer = (organizer != nil) ? addr.weakEqual(address2: organizer!) : false
organizerFound = organizerFound || isOrganizer
ContactAvatarModel.getAvatarModelFromAddress(address: addr) { avatarResult in
DispatchQueue.main.async {
self.participants.append(SelectedAddressModel(addr: addr, avModel: avatarResult, isOrg: isOrganizer))
}
}
}
}
// if didn't find organizer, add him
if !organizerFound, let org = organizer {
ContactAvatarModel.getAvatarModelFromAddress(address: org) { avatarResult in
DispatchQueue.main.async {
self.participants.append(SelectedAddressModel(addr: org, avModel: avatarResult, isOrg: true))
} }
} }
} }
} }
self.conferenceUri = meeting.confInfo.uri?.asStringUriOnly() ?? "" // if didn't find organizer, add him
self.computeDateLabels() if !organizerFound, let org = organizer {
self.computeTimeLabels() ContactAvatarModel.getAvatarModelFromAddress(address: org) { avatarResult in
SharedMainViewModel.shared.displayedMeeting = meeting DispatchQueue.main.async {
self.participants.append(SelectedAddressModel(addr: org, avModel: avatarResult, isOrg: true))
}
}
}
}
self.conferenceUri = meeting.confInfo.uri?.asStringUriOnly() ?? ""
self.computeDateLabels()
self.computeTimeLabels()
} }
func cancelMeetingWithNotifications(meeting: MeetingModel) { func cancelMeetingWithNotifications(meeting: MeetingModel) {

View file

@ -141,8 +141,61 @@ class MeetingsListViewModel: ObservableObject {
// Only remaining meeting is the fake TodayMeeting, remove it too // Only remaining meeting is the fake TodayMeeting, remove it too
meetingsList.removeAll() meetingsList.removeAll()
} }
ToastViewModel.shared.toastMessage = "Success_toast_meeting_deleted"
ToastViewModel.shared.displayToast = true DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_toast_meeting_deleted"
ToastViewModel.shared.displayToast = true
}
}
}
func cancelMeetingWithNotifications() {
CoreContext.shared.doOnCoreQueue { core in
if let meeting = self.selectedMeetingToDelete {
let conferenceScheduler = try? core.createConferenceScheduler()
//self.mSchedulerDelegate = ConferenceSchedulerDelegateStub(onStateChanged: { (_: ConferenceScheduler, state: ConferenceScheduler.State) in
let mSchedulerDelegate = ConferenceSchedulerDelegateStub(onStateChanged: { (_: ConferenceScheduler, state: ConferenceScheduler.State) in
Log.info("\(MeetingViewModel.TAG) Conference state changed \(state)")
if state == ConferenceScheduler.State.Ready {
self.sendIcsInvitation(core: core, conferenceScheduler: conferenceScheduler)
self.deleteSelectedMeeting()
}
}, onInvitationsSent: { (_: ConferenceScheduler, failedInvitations: [Address]) in
if failedInvitations.isEmpty {
Log.info("\(MeetingViewModel.TAG) All invitations have been sent")
} else {
var failInvList = ""
for failInv in failedInvitations {
if !failInvList.isEmpty {
failInvList += ", "
}
failInvList.append(failInv.asStringUriOnly())
}
Log.warn("\(MeetingViewModel.TAG) \(failedInvitations.count) invitations couldn't have been sent to: \(failInvList)")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "meeting_failed_to_send_part_of_invites_toast"
ToastViewModel.shared.displayToast = true
}
}
})
conferenceScheduler?.addDelegate(delegate: mSchedulerDelegate)
conferenceScheduler?.cancelConference(conferenceInfo: meeting.confInfo)
}
}
}
private func sendIcsInvitation(core: Core, conferenceScheduler: ConferenceScheduler?) {
if let chatRoomParams = try? core.createDefaultChatRoomParams() {
chatRoomParams.groupEnabled = false
chatRoomParams.backend = ChatRoom.Backend.FlexisipChat
chatRoomParams.encryptionEnabled = true
chatRoomParams.subject = "Meeting ics"
conferenceScheduler?.sendInvitations(chatRoomParams: chatRoomParams)
} else {
Log.error("\(MeetingViewModel.TAG) Failed to create default chatroom parameters. This should not happen")
} }
} }
} }

View file

@ -10,7 +10,6 @@
660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; }; 660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; };
6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */; }; 6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */; };
6613A0B02BAEB7F4008923A4 /* MeetingsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */; };
6613A0B42BAEBE3F008923A4 /* MeetingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */; }; 6613A0B42BAEBE3F008923A4 /* MeetingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */; };
66162A202BDFC2F900DCE913 /* AddParticipantsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */; }; 66162A202BDFC2F900DCE913 /* AddParticipantsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */; };
66246C6A2C622AE900973E97 /* TimeZoneExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66246C692C622AE900973E97 /* TimeZoneExtension.swift */; }; 66246C6A2C622AE900973E97 /* TimeZoneExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66246C692C622AE900973E97 /* TimeZoneExtension.swift */; };
@ -226,7 +225,6 @@
660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = msgNotificationService.entitlements; sourceTree = "<group>"; }; 660AAF842B8392E0004C0FA6 /* msgNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = msgNotificationService.entitlements; sourceTree = "<group>"; };
660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; 660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingFragment.swift; sourceTree = "<group>"; }; 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingFragment.swift; sourceTree = "<group>"; };
6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingsListFragment.swift; sourceTree = "<group>"; };
6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingViewModel.swift; sourceTree = "<group>"; }; 6613A0B32BAEBE3F008923A4 /* MeetingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeetingViewModel.swift; sourceTree = "<group>"; };
66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsViewModel.swift; sourceTree = "<group>"; }; 66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsViewModel.swift; sourceTree = "<group>"; };
66246C692C622AE900973E97 /* TimeZoneExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneExtension.swift; sourceTree = "<group>"; }; 66246C692C622AE900973E97 /* TimeZoneExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneExtension.swift; sourceTree = "<group>"; };
@ -491,7 +489,6 @@
children = ( children = (
66E50A4A2BD12B7800AD61CA /* MeetingsFragment.swift */, 66E50A4A2BD12B7800AD61CA /* MeetingsFragment.swift */,
6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */, 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */,
6613A0AF2BAEB7F4008923A4 /* MeetingsListFragment.swift */,
66F08C882C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift */, 66F08C882C2AFEF700D9AE2F /* MeetingsListBottomSheet.swift */,
6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */, 6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */,
66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */, 66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */,
@ -1242,7 +1239,6 @@
66E56BC92BA4A6D7006CE56F /* MeetingsListViewModel.swift in Sources */, 66E56BC92BA4A6D7006CE56F /* MeetingsListViewModel.swift in Sources */,
D726E4392B16440C0083C415 /* ContactAvatarModel.swift in Sources */, D726E4392B16440C0083C415 /* ContactAvatarModel.swift in Sources */,
C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */, C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */,
6613A0B02BAEB7F4008923A4 /* MeetingsListFragment.swift in Sources */,
D76005F62B0798B00054B79A /* IntExtension.swift in Sources */, D76005F62B0798B00054B79A /* IntExtension.swift in Sources */,
D79F2D0A2C47F4BF0038FA07 /* TouchFeedback.swift in Sources */, D79F2D0A2C47F4BF0038FA07 /* TouchFeedback.swift in Sources */,
D78E06282BE3811D00CE3783 /* CallStatsModel.swift in Sources */, D78E06282BE3811D00CE3783 /* CallStatsModel.swift in Sources */,