diff --git a/Linphone/Assets.xcassets/video-conference.imageset/Contents.json b/Linphone/Assets.xcassets/video-conference.imageset/Contents.json
new file mode 100644
index 000000000..6ec75ca93
--- /dev/null
+++ b/Linphone/Assets.xcassets/video-conference.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "video-conference.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/video-conference.imageset/video-conference.svg b/Linphone/Assets.xcassets/video-conference.imageset/video-conference.svg
new file mode 100644
index 000000000..5f7f30001
--- /dev/null
+++ b/Linphone/Assets.xcassets/video-conference.imageset/video-conference.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift
index 5e76f7dcc..38802c523 100644
--- a/Linphone/UI/Main/ContentView.swift
+++ b/Linphone/UI/Main/ContentView.swift
@@ -241,7 +241,7 @@ struct ContentView: View {
conversationViewModel.displayedConversation = nil
}, label: {
VStack {
- Image("meetings")
+ Image("video-conference")
.renderingMode(.template)
.resizable()
.foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600)
@@ -669,7 +669,7 @@ struct ContentView: View {
conversationViewModel.displayedConversation = nil
}, label: {
VStack {
- Image("meetings")
+ Image("video-conference")
.renderingMode(.template)
.resizable()
.foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600)
@@ -698,7 +698,9 @@ struct ContentView: View {
}
}
- if contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil {
+ if contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil ||
+ scheduleMeetingViewModel.displayedMeeting != nil
+ {
HStack(spacing: 0) {
Spacer()
.frame(maxWidth:
@@ -739,7 +741,13 @@ struct ContentView: View {
.frame(maxWidth: .infinity)
.background(Color.gray100)
.ignoresSafeArea(.keyboard)
+ } else if self.index == 3 {
+ MeetingFragment(scheduleMeetingViewModel: scheduleMeetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment)
+ .frame(maxWidth: .infinity)
+ .background(Color.gray100)
+ .ignoresSafeArea(.keyboard)
}
+
}
.onAppear {
if !(orientation == .landscapeLeft
diff --git a/Linphone/UI/Main/Meetings/Fragments/MeetingFragment.swift b/Linphone/UI/Main/Meetings/Fragments/MeetingFragment.swift
index cce87d668..e1d58118b 100644
--- a/Linphone/UI/Main/Meetings/Fragments/MeetingFragment.swift
+++ b/Linphone/UI/Main/Meetings/Fragments/MeetingFragment.swift
@@ -17,19 +17,254 @@
* along with this program. If not, see .
*/
+// swiftlint:disable line_length
import SwiftUI
+import linphonesw
struct MeetingFragment: View {
- @ObservedObject var meetingViewModel: MeetingViewModel
+ @Environment(\.dismiss) var dismiss
+
+ private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
+ @State private var orientation = UIDevice.current.orientation
+
+ @ObservedObject var scheduleMeetingViewModel: ScheduleMeetingViewModel
+ @ObservedObject var meetingsListViewModel: MeetingsListViewModel
+
+ @State private var showDatePicker = false
+ @State private var showTimePicker = false
+
+ @State var selectedDate = Date.now
+ @State var setFromDate: Bool = true
+ @State var selectedHours: Int = 0
+ @State var selectedMinutes: Int = 0
+
+ @State var addParticipantsViewModel = AddParticipantsViewModel()
+ @Binding var isShowScheduleMeetingFragment: Bool
+
+ @ViewBuilder
+ func getParticipantLine(participant: SelectedAddressModel) -> some View {
+ HStack(spacing: 0) {
+ Avatar(contactAvatarModel: participant.avatarModel, avatarSize: 50)
+ .padding(.leading, 10)
+
+ Text(participant.avatarModel.name)
+ .default_text_style(styleSize: 14)
+ .padding(.leading, 10)
+ .padding(.trailing, 40)
+
+ Text("Organizer")
+ .font(Font.custom("NotoSans-Light", size: 12))
+ .foregroundStyle(Color.grayMain2c600)
+ .opacity(participant.isOrganizer ? 1 : 0)
+ }.padding(.bottom, 5)
+ }
var body: some View {
- ZStack {
- Text("TODO")
+ NavigationView {
+ ZStack(alignment: .bottomTrailing) {
+ VStack(spacing: 0) {
+ if #available(iOS 16.0, *) {
+ Rectangle()
+ .foregroundColor(Color.orangeMain500)
+ .edgesIgnoringSafeArea(.top)
+ .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 {
+ Image("caret-left")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.orangeMain500)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ .padding(.leading, -10)
+ .onTapGesture {
+ withAnimation {
+ scheduleMeetingViewModel.displayedMeeting = nil
+ }
+ }
+ Spacer()
+ if scheduleMeetingViewModel.myself != nil && scheduleMeetingViewModel.myself!.isOrganizer {
+ Image("pencil-simple")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.orangeMain500)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.trailing, 5)
+ .onTapGesture {
+ withAnimation {
+ isShowScheduleMeetingFragment.toggle()
+ }
+ }
+ }
+ Image("dots-three-vertical")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.orangeMain500)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .onTapGesture {
+ }
+ }
+ .frame(maxWidth: .infinity)
+ .frame(height: 50)
+ .padding(.horizontal)
+ .padding(.bottom, 5)
+ .background(.white)
+
+ ScrollView(.vertical) {
+ HStack(alignment: .center, spacing: 10) {
+ Image("video-conference")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+ Text(scheduleMeetingViewModel.subject)
+ .fontWeight(.bold)
+ .default_text_style(styleSize: 20)
+ .frame(height: 29, alignment: .leading)
+ Spacer()
+ }.padding(.bottom, 5)
+
+ Rectangle()
+ .foregroundStyle(.clear)
+ .frame(height: 1)
+ .background(Color.gray200)
+
+ HStack(alignment: .center, spacing: 10) {
+ Image("video-camera")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+ Text(scheduleMeetingViewModel.conferenceUri)
+ .underline()
+ .default_text_style(styleSize: 14)
+ Spacer()
+
+ Image("share-network")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 25, height: 25)
+ .padding(.trailing, 15)
+ }
+
+ HStack(alignment: .center, spacing: 10) {
+ Image("clock")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+ Text(scheduleMeetingViewModel.getFullDateString())
+ .default_text_style(styleSize: 14)
+ Spacer()
+ }
+
+ HStack(alignment: .center, spacing: 10) {
+ Image("earth")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c800)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+ Text("TODO : timezone")
+ .default_text_style(styleSize: 14)
+ Spacer()
+ }
+
+ Rectangle()
+ .foregroundStyle(.clear)
+ .frame(height: 1)
+ .background(Color.gray200)
+
+ HStack(alignment: .top, spacing: 10) {
+ Image("note")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c600)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+
+ Text(scheduleMeetingViewModel.description)
+ .default_text_style(styleSize: 14)
+ Spacer()
+ }.padding(.top, 10)
+ .padding(.bottom, 10)
+
+ Rectangle()
+ .foregroundStyle(.clear)
+ .frame(height: 1)
+ .background(Color.gray200)
+
+ HStack(alignment: .top, spacing: 10) {
+ Image("users")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c600)
+ .frame(width: 24, height: 24)
+ .padding(.leading, 15)
+
+ ScrollView {
+ VStack(alignment: .leading, spacing: 0) {
+ if scheduleMeetingViewModel.myself != nil {
+ getParticipantLine(participant: scheduleMeetingViewModel.myself!)
+ }
+ ForEach(0.. some View {
return Text(model.monthStr)
.fontWeight(.bold)
@@ -24,6 +25,7 @@ struct MeetingsFragment: View {
.default_text_style_500(styleSize: 22)
}
+ @ViewBuilder
func createWeekLine(model: MeetingsListItemModel) -> some View {
return Text(model.weekStr)
.padding(.leading, 43)
@@ -31,7 +33,7 @@ struct MeetingsFragment: View {
.padding(.bottom, 3)
.default_text_style_500(styleSize: 14)
}
-
+ @ViewBuilder
func createMeetingLine(model: MeetingsListItemModel) -> some View {
return VStack(alignment: .leading) {
if model.isToday {
@@ -40,7 +42,7 @@ struct MeetingsFragment: View {
.default_text_style_500(styleSize: 15)
} else {
HStack(alignment: .center) {
- Image("meetings")
+ Image("video-conference")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
@@ -64,12 +66,10 @@ struct MeetingsFragment: View {
.clipShape(RoundedRectangle(cornerRadius: 20))
.shadow(color: .black.opacity(0.2), radius: 4)
.onTapGesture {
- do {
- let meetingAddress = try Factory.Instance.createAddress(addr: model.model?.address ?? "")
- TelecomManager.shared.meetingWaitingRoomDisplayed = true
- TelecomManager.shared.meetingWaitingRoomSelected = meetingAddress
- } catch {
- Log.error("[MeetingsFragment] Couldn't create address from \(model.model?.address ?? "")")
+ withAnimation {
+ if let meetingModel = model.model {
+ scheduleMeetingViewModel.loadExistingMeeting(meeting: meetingModel)
+ }
}
}
}
diff --git a/Linphone/UI/Main/Meetings/Fragments/ScheduleMeetingFragment.swift b/Linphone/UI/Main/Meetings/Fragments/ScheduleMeetingFragment.swift
index b72a803ba..3e3a65890 100644
--- a/Linphone/UI/Main/Meetings/Fragments/ScheduleMeetingFragment.swift
+++ b/Linphone/UI/Main/Meetings/Fragments/ScheduleMeetingFragment.swift
@@ -74,11 +74,15 @@ struct ScheduleMeetingFragment: View {
.padding(.leading, -10)
.onTapGesture {
withAnimation {
+ if let meeting = scheduleMeetingViewModel.displayedMeeting {
+ // reload meeting to cancel change from edit
+ scheduleMeetingViewModel.loadExistingMeeting(meeting: meeting)
+ }
isShowScheduleMeetingFragment.toggle()
}
}
- Text("New meeting" )
+ Text("\(scheduleMeetingViewModel.displayedMeeting != nil ? "Edit" : "New") meeting" )
.multilineTextAlignment(.leading)
.default_text_style_orange_800(styleSize: 16)
@@ -143,10 +147,10 @@ struct ScheduleMeetingFragment: View {
}
*/
HStack(alignment: .center, spacing: 8) {
- Image("users-three")
+ Image("video-conference")
.renderingMode(.template)
.resizable()
- .foregroundStyle(Color.grayMain2c600)
+ .foregroundStyle(Color.grayMain2c800)
.frame(width: 24, height: 24)
.padding(.leading, 16)
TextField("Subject", text: $scheduleMeetingViewModel.subject)
diff --git a/Linphone/UI/Main/Meetings/Models/MeetingModel.swift b/Linphone/UI/Main/Meetings/Models/MeetingModel.swift
index fd7abac7a..ba89195dd 100644
--- a/Linphone/UI/Main/Meetings/Models/MeetingModel.swift
+++ b/Linphone/UI/Main/Meetings/Models/MeetingModel.swift
@@ -9,9 +9,10 @@ import linphonesw
class MeetingModel: ObservableObject {
- private var confInfo: ConferenceInfo
+ var confInfo: ConferenceInfo
var id: String
var meetingDate: Date
+ var endDate: Date
var isToday: Bool
var isAfterToday: Bool
@@ -24,7 +25,6 @@ class MeetingModel: ObservableObject {
@Published var isBroadcast: Bool
@Published var subject: String
@Published var address: String
- @Published var firstMeetingOfTheDay: Bool = false
init(conferenceInfo: ConferenceInfo) {
confInfo = conferenceInfo
@@ -34,7 +34,7 @@ class MeetingModel: ObservableObject {
let formatter = DateFormatter()
formatter.dateFormat = Locale.current.identifier == "fr_FR" ? "HH:mm" : "h:mm a"
startTime = formatter.string(from: meetingDate)
- let endDate = Calendar.current.date(byAdding: .minute, value: Int(confInfo.duration), to: meetingDate)!
+ endDate = Calendar.current.date(byAdding: .minute, value: Int(confInfo.duration), to: meetingDate)!
endTime = formatter.string(from: endDate)
time = "\(startTime) - \(endTime)"
diff --git a/Linphone/UI/Main/Meetings/ViewModel/MeetingViewModel.swift b/Linphone/UI/Main/Meetings/ViewModel/MeetingViewModel.swift
index 12e16a223..681bef225 100644
--- a/Linphone/UI/Main/Meetings/ViewModel/MeetingViewModel.swift
+++ b/Linphone/UI/Main/Meetings/ViewModel/MeetingViewModel.swift
@@ -22,7 +22,7 @@ import linphonesw
class MeetingViewModel: ObservableObject {
static let TAG = "[Meeting ViewModel]"
-
+ /*
private var coreContext = CoreContext.shared
@Published var showBackbutton: Bool = false
@@ -40,20 +40,20 @@ class MeetingViewModel: ObservableObject {
@Published var participants: [ParticipantModel] = []
@Published var conferenceInfoFoundEvent: Bool = false
- var conferenceInfo: ConferenceInfo?
+ var meetingModel: MeetingModel
- init() {
-
+ init(model: MeetingModel) {
+ meetingModel = model
}
func findConferenceInfo(uri: String) {
coreContext.doOnCoreQueue { core in
var confInfoFound = false
if let address = try? Factory.Instance.createAddress(addr: uri) {
- let foundConfInfo = core.findConferenceInformationFromUri(uri: address)
- if foundConfInfo != nil {
+
+ if let confInfo = core.findConferenceInformationFromUri(uri: address) {
Log.info("\(MeetingViewModel.TAG) Conference info with SIP URI \(uri) was found")
- self.conferenceInfo = foundConfInfo
+ self.meetingModel.confInfo = confInfo
self.configureConferenceInfo(core: core)
confInfoFound = true
} else {
@@ -71,68 +71,65 @@ class MeetingViewModel: ObservableObject {
}
private func configureConferenceInfo(core: Core) {
- if let confInfo = self.conferenceInfo {
+ /*
+ timezone.postValue(
+ AppUtils.getFormattedString(
+ R.string.meeting_schedule_timezone_title,
+ TimeZone.getDefault().displayName
+ )
+ .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
+ )
+ */
+
+ var isEditable = false
+
+ if let organizerAddress = meetingModel.confInfo.organizer {
+ let localAccount = core.accountList.first(where: {
+ if let address = $0.params?.identityAddress {
+ return organizerAddress.weakEqual(address2: address)
+ } else {
+ return false
+ }
+ })
- /*
- timezone.postValue(
- AppUtils.getFormattedString(
- R.string.meeting_schedule_timezone_title,
- TimeZone.getDefault().displayName
- )
- .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
- )
- */
-
- var isEditable = false
-
- if let organizerAddress = confInfo.organizer {
- let localAccount = core.accountList.first(where: {
- if let address = $0.params?.identityAddress {
- return organizerAddress.weakEqual(address2: address)
- } else {
- return false
- }
- })
-
- isEditable = localAccount != nil
- } else {
- Log.error("\(MeetingViewModel.TAG) No organizer SIP URI found for: \(confInfo.uri?.asStringUriOnly() ?? "(empty)")")
- }
-
- let startDate = Date(timeIntervalSince1970: TimeInterval(confInfo.dateTime))
- let endDate = Calendar.current.date(byAdding: .minute, value: Int(confInfo.duration), to: startDate)!
-
- let formatter = DateFormatter()
- formatter.dateFormat = Locale.current.identifier == "fr_FR" ? "HH:mm" : "h:mm a"
- let startTime = formatter.string(from: startDate)
- let endTime = formatter.string(from: endDate)
- let dateTime = "\(startTime) - \(endTime)"
-
- DispatchQueue.main.sync {
- self.subject = confInfo.subject ?? ""
- self.sipUri = confInfo.uri?.asStringUriOnly() ?? ""
- self.description = confInfo.description
- self.startDate = startDate
- self.endDate = endDate
- self.dateTime = dateTime
- self.isEditable = isEditable
- }
-
- self.computeParticipantsList(core: core, confInfo: confInfo)
+ isEditable = localAccount != nil
+ } else {
+ Log.error("\(MeetingViewModel.TAG) No organizer SIP URI found for: \(meetingModel.confInfo.uri?.asStringUriOnly() ?? "(empty)")")
}
+
+ let startDate = Date(timeIntervalSince1970: TimeInterval(meetingModel.confInfo.dateTime))
+ let endDate = Calendar.current.date(byAdding: .minute, value: Int(meetingModel.confInfo.duration), to: startDate)!
+
+ let formatter = DateFormatter()
+ formatter.dateFormat = Locale.current.identifier == "fr_FR" ? "HH:mm" : "h:mm a"
+ let startTime = formatter.string(from: startDate)
+ let endTime = formatter.string(from: endDate)
+ let dateTime = "\(startTime) - \(endTime)"
+
+ DispatchQueue.main.async {
+ self.subject = self.meetingModel.confInfo.subject ?? ""
+ self.sipUri = self.meetingModel.confInfo.uri?.asStringUriOnly() ?? ""
+ self.description = self.meetingModel.confInfo.description
+ self.startDate = startDate
+ self.endDate = endDate
+ self.dateTime = dateTime
+ self.isEditable = isEditable
+ }
+
+ self.computeParticipantsList()
}
- private func computeParticipantsList(core: Core, confInfo: ConferenceInfo) {
+ private func computeParticipantsList() {
var speakersList: [ParticipantModel] = []
var participantsList: [ParticipantModel] = []
var allSpeaker = true
- let organizer = confInfo.organizer
+ let organizer = meetingModel.confInfo.organizer
var organizerFound = false
- for pInfo in confInfo.participantInfos {
+ for pInfo in meetingModel.confInfo.participantInfos {
if let participantAddress = pInfo.address {
let isOrganizer = organizer != nil && organizer!.weakEqual(address2: participantAddress)
- Log.info("\(MeetingViewModel.TAG) Conference \(confInfo.subject)[${conferenceInfo.subject}] \(isOrganizer ? "organizer: " : "participant: ") \(participantAddress.asStringUriOnly()) is a \(pInfo.role)")
+ Log.info("\(MeetingViewModel.TAG) Conference \(meetingModel.confInfo.subject)[${conferenceInfo.subject}] \(isOrganizer ? "organizer: " : "participant: ") \(participantAddress.asStringUriOnly()) is a \(pInfo.role)")
if isOrganizer {
organizerFound = true
}
@@ -156,10 +153,11 @@ class MeetingViewModel: ObservableObject {
participantsList.append(ParticipantModel(address: organizerAddress))
}
- DispatchQueue.main.sync {
+ DispatchQueue.main.async {
self.isBroadcast = !allSpeaker
- speakers = speakersList
- participants = participantsList
+ self.speakers = speakersList
+ self.participants = participantsList
}
}
+ */
}
diff --git a/Linphone/UI/Main/Meetings/ViewModel/ScheduleMeetingViewModel.swift b/Linphone/UI/Main/Meetings/ViewModel/ScheduleMeetingViewModel.swift
index 0a43e13fc..579b34a56 100644
--- a/Linphone/UI/Main/Meetings/ViewModel/ScheduleMeetingViewModel.swift
+++ b/Linphone/UI/Main/Meetings/ViewModel/ScheduleMeetingViewModel.swift
@@ -38,13 +38,16 @@ class ScheduleMeetingViewModel: ObservableObject {
@Published var participants: [SelectedAddressModel] = []
@Published var operationInProgress: Bool = false
@Published var conferenceCreatedEvent: Bool = false
+ @Published var conferenceUri: String = ""
var conferenceScheduler: ConferenceScheduler?
private var mSchedulerSubscriptions = Set()
var conferenceInfoToEdit: ConferenceInfo?
-
+ @Published var displayedMeeting: MeetingModel? // if nil, then we are currently creating a new meeting
+ @Published var myself: SelectedAddressModel?
@Published var fromDate: Date
@Published var toDate: Date
+ @Published var errorMsg: String = ""
init() {
fromDate = Calendar.current.date(byAdding: .hour, value: 1, to: Date.now)!
@@ -65,7 +68,7 @@ class ScheduleMeetingViewModel: ObservableObject {
participants = []
operationInProgress = false
conferenceCreatedEvent = false
-
+ conferenceUri = ""
fromDate = Calendar.current.date(byAdding: .hour, value: 1, to: Date.now)!
toDate = Calendar.current.date(byAdding: .hour, value: 2, to: Date.now)!
computeDateLabels()
@@ -94,6 +97,14 @@ class ScheduleMeetingViewModel: ObservableObject {
toTime = formatter.string(from: toDate)
}
+ func getFullDateString() -> String {
+ var day = fromDate.formatted(Date.FormatStyle().weekday(.abbreviated))
+ var dayNumber = fromDate.formatted(Date.FormatStyle().day(.twoDigits))
+ var month = fromDate.formatted(Date.FormatStyle().month(.wide))
+ var year = fromDate.formatted(Date.FormatStyle().year(.defaultDigits))
+ return "\(day). \(dayNumber) \(month) \(year) | \(allDayMeeting ? "All day" : "\(fromTime) - \(toTime)")"
+ }
+
private func updateTimezone() {
// TODO
}
@@ -143,6 +154,8 @@ class ScheduleMeetingViewModel: ObservableObject {
if cbVal.state == ConferenceScheduler.State.Error {
DispatchQueue.main.async {
self.operationInProgress = false
+
+ self.errorMsg = (self.displayedMeeting != nil) ? "Could not edit conference" : "Could not create conference"
// TODO: show error toast
}
} else if cbVal.state == ConferenceScheduler.State.Ready {
@@ -207,11 +220,9 @@ class ScheduleMeetingViewModel: ObservableObject {
CoreContext.shared.doOnCoreQueue { core in
Log.info("\(ScheduleMeetingViewModel.TAG) Scheduling \(self.isBroadcastSelected ? "broadcast" : "meeting")")
- let localAccount = core.defaultAccount
- let localAddress = localAccount?.params?.identityAddress
-
- if let conferenceInfo = try? Factory.Instance.createConferenceInfo() {
- conferenceInfo.organizer = localAddress
+ if let conferenceInfo = self.displayedMeeting != nil ? self.displayedMeeting!.confInfo : try? Factory.Instance.createConferenceInfo() {
+ let localAccount = core.defaultAccount
+ conferenceInfo.organizer = localAccount?.params?.identityAddress
self.fillConferenceInfo(confInfo: conferenceInfo)
if self.conferenceScheduler == nil {
self.initConferenceSchedulerAndListeners(core: core)
@@ -243,6 +254,45 @@ class ScheduleMeetingViewModel: ObservableObject {
}
}
+ func loadExistingMeeting(meeting: MeetingModel) {
+ DispatchQueue.main.async {
+ self.resetViewModelData()
+ self.subject = meeting.confInfo.subject ?? ""
+ self.description = meeting.confInfo.description ?? ""
+ self.fromDate = meeting.meetingDate
+ self.toDate = meeting.endDate
+ self.participants = []
+
+ let organizer = meeting.confInfo.organizer
+ CoreContext.shared.doOnCoreQueue { core in
+ if let myAddr = core.defaultAccount?.contactAddress {
+ ContactAvatarModel.getAvatarModelFromAddress(address: myAddr) { avatarResult in
+ DispatchQueue.main.async {
+ let isOrganizer = (organizer != nil) ? myAddr.weakEqual(address2: organizer!) : false
+ self.myself = SelectedAddressModel(addr: myAddr, avModel: avatarResult, isOrg: isOrganizer)
+ }
+ }
+ }
+ }
+
+ for pInfo in meeting.confInfo.participantInfos {
+ if let addr = pInfo.address {
+ ContactAvatarModel.getAvatarModelFromAddress(address: addr) { avatarResult in
+ DispatchQueue.main.async {
+ let isOrganizer = (organizer != nil) ? addr.weakEqual(address2: organizer!) : false
+ self.participants.append(SelectedAddressModel(addr: addr, avModel: avatarResult, isOrg:isOrganizer))
+ }
+ }
+ }
+ }
+ self.conferenceUri = meeting.confInfo.uri?.asStringUriOnly() ?? ""
+ self.computeDateLabels()
+ self.computeTimeLabels()
+ self.updateTimezone()
+ self.displayedMeeting = meeting
+ }
+ }
+
func loadExistingConferenceInfoFromUri(conferenceUri: String) {
CoreContext.shared.doOnCoreQueue { core in
if let conferenceAddress = core.interpretUrl(url: conferenceUri, applyInternationalPrefix: false) {
diff --git a/Linphone/UI/Main/Viewmodel/AddParticipantsViewModel.swift b/Linphone/UI/Main/Viewmodel/AddParticipantsViewModel.swift
index 3db4b0bc7..6e1f2d647 100644
--- a/Linphone/UI/Main/Viewmodel/AddParticipantsViewModel.swift
+++ b/Linphone/UI/Main/Viewmodel/AddParticipantsViewModel.swift
@@ -12,10 +12,12 @@ import Combine
class SelectedAddressModel: ObservableObject {
var address: Address
var avatarModel: ContactAvatarModel
+ var isOrganizer: Bool = false
- init (addr: Address, avModel: ContactAvatarModel) {
+ init (addr: Address, avModel: ContactAvatarModel, isOrg: Bool = false) {
address = addr
avatarModel = avModel
+ isOrganizer = isOrg
}
}