forked from mirrors/linphone-iphone
Continue ScheduleMeetingViewModel impelmentation: ConferenceScheduler listeners, schedule(), update(), addparticipants(), and fillConferenceInfo()
This commit is contained in:
parent
728678a02c
commit
62a027b397
2 changed files with 220 additions and 32 deletions
|
|
@ -34,27 +34,8 @@ class ParticipantModel: ObservableObject {
|
|||
self.address = address
|
||||
|
||||
self.sipUri = address.asStringUriOnly()
|
||||
|
||||
let addressFriend = ContactsManager.shared.getFriendWithAddress(address: self.address)
|
||||
|
||||
var nameTmp = ""
|
||||
|
||||
if addressFriend != nil {
|
||||
nameTmp = addressFriend!.name!
|
||||
} else {
|
||||
nameTmp = address.displayName != nil
|
||||
? address.displayName!
|
||||
: address.username!
|
||||
}
|
||||
|
||||
self.name = nameTmp
|
||||
|
||||
self.avatarModel = addressFriend != nil
|
||||
? ContactsManager.shared.avatarListModel.first(where: {
|
||||
$0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == address.asStringUriOnly()
|
||||
}) ?? ContactAvatarModel(friend: nil, name: nameTmp, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: nameTmp, withPresence: false)
|
||||
|
||||
self.avatarModel = ContactAvatarModel.getAvatarModelFromAddress(address: self.address)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,26 +21,37 @@ import Foundation
|
|||
import linphonesw
|
||||
import Combine
|
||||
|
||||
class SelectedAddressModel {
|
||||
var address: Address
|
||||
var avatarModel: ContactAvatarModel?
|
||||
|
||||
init (addr: Address, avModel: ContactAvatarModel?) {
|
||||
address = addr
|
||||
avatarModel = avModel
|
||||
}
|
||||
}
|
||||
|
||||
class ScheduleMeetingViewModel: ObservableObject {
|
||||
private let TAG = "[ScheduleMeetingViewModel]"
|
||||
static let TAG = "[ScheduleMeetingViewModel]"
|
||||
|
||||
@Published var isBroadcastSelected: Bool = false
|
||||
@Published var showBroadcastHelp: Bool = false
|
||||
@Published var subject: String = ""
|
||||
@Published var description: String = ""
|
||||
@Published var description: String = "aaaaaa aaaaaa"
|
||||
@Published var allDayMeeting: Bool = false
|
||||
@Published var fromDateStr: String = ""
|
||||
@Published var fromTime: String = ""
|
||||
@Published var toDateStr: String = ""
|
||||
@Published var toTime: String = ""
|
||||
@Published var timezone: String = ""
|
||||
@Published var sendInvitations: Bool = true
|
||||
// var participants = MutableLiveData<ArrayList<SelectedAddressModel>>()
|
||||
@Published var operationInProgress: Bool = false
|
||||
@Published var conferenceCreatedEvent: Bool = false
|
||||
@Published var toTime: String = ""
|
||||
@Published var timezone: String = ""
|
||||
@Published var sendInvitations: Bool = true
|
||||
@Published var participants: [SelectedAddressModel] = []
|
||||
@Published var operationInProgress: Bool = false
|
||||
@Published var conferenceCreatedEvent: Bool = false
|
||||
|
||||
var conferenceScheduler: ConferenceScheduler?
|
||||
var conferenceInfoToEdit: ConferenceScheduler?
|
||||
private var mSchedulerSubscriptions = Set<AnyCancellable?>()
|
||||
var conferenceInfoToEdit: ConferenceInfo?
|
||||
|
||||
private var fromDate: Date
|
||||
private var toDate: Date
|
||||
|
|
@ -59,13 +70,13 @@ class ScheduleMeetingViewModel: ObservableObject {
|
|||
var dayNumber = fromDate.formatted(Date.FormatStyle().day(.twoDigits))
|
||||
var month = fromDate.formatted(Date.FormatStyle().month(.wide))
|
||||
fromDateStr = "\(day) \(dayNumber), \(month)"
|
||||
Log.info("\(TAG) computed start date is \(fromDateStr)")
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) computed start date is \(fromDateStr)")
|
||||
|
||||
day = toDate.formatted(Date.FormatStyle().weekday(.wide))
|
||||
dayNumber = toDate.formatted(Date.FormatStyle().day(.twoDigits))
|
||||
month = toDate.formatted(Date.FormatStyle().month(.wide))
|
||||
toDateStr = "\(day) \(dayNumber), \(month)"
|
||||
Log.info("\(TAG) computed end date is \(toDateStr)")
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG)) computed end date is \(toDateStr)")
|
||||
}
|
||||
|
||||
private func computeTimeLabels() {
|
||||
|
|
@ -78,4 +89,200 @@ class ScheduleMeetingViewModel: ObservableObject {
|
|||
private func updateTimezone() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func addParticipants(toAdd: [String]) {
|
||||
CoreContext.shared.doOnCoreQueue { _ in
|
||||
var list = self.participants
|
||||
for participant in toAdd {
|
||||
if let address = try? Factory.Instance.createAddress(addr: participant) {
|
||||
if let found = list.first(where: { $0.address.weakEqual(address2: address) }) {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Participant \(found.address.asStringUriOnly()) already in list, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
let avatarModel = ContactAvatarModel.getAvatarModelFromAddress(address: address)
|
||||
list.append(SelectedAddressModel(addr: address, avModel: avatarModel))
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Added participant \(address.asStringUriOnly())")
|
||||
} else {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Failed to parse \(participant) as address!")
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) [\(toAdd.count) participants added, now there are \(list.count) participants in list")
|
||||
DispatchQueue.main.async {
|
||||
self.participants = list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fillConferenceInfo(confInfo: ConferenceInfo) {
|
||||
confInfo.subject = self.subject
|
||||
confInfo.description = self.description
|
||||
confInfo.dateTime = time_t(self.fromDate.timeIntervalSince1970)
|
||||
confInfo.duration = UInt(self.fromDate.distance(to: self.toDate) / 60)
|
||||
|
||||
let participantsList = self.participants
|
||||
var participantsInfoList: [ParticipantInfo] = []
|
||||
for participant in participantsList {
|
||||
if let info = try? Factory.Instance.createParticipantInfo(address: participant.address) {
|
||||
// For meetings, all participants must have Speaker role
|
||||
info.role = Participant.Role.Speaker
|
||||
participantsInfoList.append(info)
|
||||
} else {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Failed to create Participant Info from address \(participant.address.asStringUriOnly())")
|
||||
}
|
||||
}
|
||||
confInfo.participantInfos = participantsInfoList
|
||||
}
|
||||
|
||||
private func initConferenceSchedulerAndListeners(core: Core) {
|
||||
self.conferenceScheduler = try? core.createConferenceScheduler()
|
||||
|
||||
self.mSchedulerSubscriptions.insert(self.conferenceScheduler?.publisher?.onStateChanged?.postOnCoreQueue { (cbVal: (conferenceScheduler: ConferenceScheduler, state: ConferenceScheduler.State)) in
|
||||
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Conference state changed \(cbVal.state)")
|
||||
if cbVal.state == ConferenceScheduler.State.Error {
|
||||
DispatchQueue.main.async {
|
||||
self.operationInProgress = false
|
||||
// TODO: show error toast
|
||||
}
|
||||
} else if cbVal.state == ConferenceScheduler.State.Ready {
|
||||
let conferenceAddress = self.conferenceScheduler?.info?.uri
|
||||
if let confInfoToEdit = self.conferenceInfoToEdit {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Conference info \(confInfoToEdit.uri?.asStringUriOnly() ?? "'nil'") has been updated")
|
||||
} else {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Conference info created, address will be \(conferenceAddress?.asStringUriOnly() ?? "'nil'")")
|
||||
}
|
||||
|
||||
if self.sendInvitations {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) User asked for invitations to be sent, let's do it")
|
||||
if let chatRoomParams = try? core.createDefaultChatRoomParams() {
|
||||
chatRoomParams.groupEnabled = false
|
||||
chatRoomParams.backend = ChatRoom.Backend.FlexisipChat
|
||||
chatRoomParams.encryptionEnabled = true
|
||||
chatRoomParams.subject = "Meeting invitation" // Won't be used
|
||||
self.conferenceScheduler?.sendInvitations(chatRoomParams: chatRoomParams)
|
||||
} else {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Failed to create default chatroom parameters. This should not happen")
|
||||
}
|
||||
} else {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) User didn't asked for invitations to be sent")
|
||||
DispatchQueue.main.async {
|
||||
self.operationInProgress = false
|
||||
self.conferenceCreatedEvent = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.mSchedulerSubscriptions.insert(self.conferenceScheduler?.publisher?.onInvitationsSent?.postOnCoreQueue { (cbVal: (conferenceScheduler: ConferenceScheduler, failedInvitations: [Address])) in
|
||||
|
||||
if cbVal.failedInvitations.isEmpty {
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) All invitations have been sent")
|
||||
} else if cbVal.failedInvitations.count == self.participants.count {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) No invitation sent!")
|
||||
// TODO: show error toast
|
||||
} else {
|
||||
Log.warn("\(ScheduleMeetingViewModel.TAG) \(cbVal.failedInvitations.count) invitations couldn't have been sent for:")
|
||||
for failInv in cbVal.failedInvitations {
|
||||
Log.warn(failInv.asStringUriOnly())
|
||||
}
|
||||
// TODO: show error toast
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.operationInProgress = false
|
||||
self.conferenceCreatedEvent = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
if subject.isEmpty || participants.isEmpty {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Either no subject was set or no participant was selected, can't schedule meeting.")
|
||||
// TODO: show red toast
|
||||
return
|
||||
}
|
||||
operationInProgress = true
|
||||
|
||||
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
|
||||
self.fillConferenceInfo(confInfo: conferenceInfo)
|
||||
if self.conferenceScheduler == nil {
|
||||
self.initConferenceSchedulerAndListeners(core: core)
|
||||
}
|
||||
self.conferenceScheduler?.account = localAccount
|
||||
// Will trigger the conference creation automatically
|
||||
self.conferenceScheduler?.info = conferenceInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update() {
|
||||
self.operationInProgress = true
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Updating \(self.isBroadcastSelected ? "broadcast" : "meeting")")
|
||||
|
||||
if let conferenceInfo = self.conferenceInfoToEdit {
|
||||
self.fillConferenceInfo(confInfo: conferenceInfo)
|
||||
if self.conferenceScheduler == nil {
|
||||
self.initConferenceSchedulerAndListeners(core: core)
|
||||
}
|
||||
|
||||
// Will trigger the conference update automatically
|
||||
self.conferenceScheduler?.info = conferenceInfo
|
||||
} else {
|
||||
Log.error("No conference info to edit found!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadExistingConferenceInfoFromUri(conferenceUri: String) {
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
if let conferenceAddress = core.interpretUrl(url: conferenceUri, applyInternationalPrefix: false) {
|
||||
if let conferenceInfo = core.findConferenceInformationFromUri(uri: conferenceAddress) {
|
||||
|
||||
self.conferenceInfoToEdit = conferenceInfo
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Found conference info matching URI \(conferenceInfo.uri?.asString()) with subject \(conferenceInfo.subject)")
|
||||
|
||||
self.fromDate = Date(timeIntervalSince1970: TimeInterval(conferenceInfo.dateTime))
|
||||
self.toDate = Calendar.current.date(byAdding: .minute, value: Int(conferenceInfo.duration), to: self.fromDate)!
|
||||
|
||||
var list: [SelectedAddressModel] = []
|
||||
for partInfo in conferenceInfo.participantInfos {
|
||||
if let addr = partInfo.address {
|
||||
let avatarModel = ContactAvatarModel.getAvatarModelFromAddress(address: addr)
|
||||
list.append(SelectedAddressModel(addr: addr, avModel: avatarModel))
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) Loaded participant \(addr.asStringUriOnly())")
|
||||
}
|
||||
}
|
||||
Log.info("\(ScheduleMeetingViewModel.TAG) \(list.count) participants loaded from found conference info")
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.subject = conferenceInfo.subject ?? ""
|
||||
self.description = conferenceInfo.description ?? ""
|
||||
self.isBroadcastSelected = false // TODO FIXME
|
||||
self.computeDateLabels()
|
||||
self.computeTimeLabels()
|
||||
self.updateTimezone()
|
||||
self.participants = list
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Failed to find a conference info matching URI [${conferenceAddress.asString()}], abort")
|
||||
}
|
||||
} else {
|
||||
Log.error("\(ScheduleMeetingViewModel.TAG) Failed to parse conference URI [$conferenceUri], abort")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue