diff --git a/Classes/Swift/Conference/Data/ScheduledConferenceData.swift b/Classes/Swift/Conference/Data/ScheduledConferenceData.swift index 9b08d18a6..9ee0d07ac 100644 --- a/Classes/Swift/Conference/Data/ScheduledConferenceData.swift +++ b/Classes/Swift/Conference/Data/ScheduledConferenceData.swift @@ -35,6 +35,7 @@ class ScheduledConferenceData { let organizer = MutableLiveData() let participantsShort = MutableLiveData() let participantsExpanded = MutableLiveData() + let participantsGuestExpanded = MutableLiveData() let rawDate : Date let isConferenceCancelled = MutableLiveData(false) let canEdit = MutableLiveData(false) @@ -43,6 +44,8 @@ class ScheduledConferenceData { private var conferenceSchedulerDelegate : ConferenceSchedulerDelegateStub? = nil private var conferenceScheduler : ConferenceScheduler? = nil + var isBroadcast = false + init (conferenceInfo: ConferenceInfo, isFinished: Bool = false) { self.conferenceInfo = conferenceInfo self.isFinished = isFinished @@ -93,8 +96,20 @@ class ScheduledConferenceData { participantsShort.value = " " } - participantsExpanded.value = conferenceInfo.participants.map {(participant) in - String(describing: participant.addressBookEnhancedDisplayName())+" ("+String(describing: participant.asStringUriOnly())+")" + isBroadcast = conferenceInfo.participantInfos.filter({$0.role == .Speaker}).count != 0 && conferenceInfo.participantInfos.filter({$0.role == .Listener}).count != 0 + + if isBroadcast { + participantsExpanded.value = conferenceInfo.participantInfos.filter({$0.role == .Speaker}).map {(participant) in + String(describing: participant.address!.addressBookEnhancedDisplayName())+" ("+String(describing: participant.address!.asStringUriOnly())+")" + }.joined(separator: "\n") + } else { + participantsExpanded.value = conferenceInfo.participantInfos.map {(participant) in + String(describing: participant.address!.addressBookEnhancedDisplayName())+" ("+String(describing: participant.address!.asStringUriOnly())+")" + }.joined(separator: "\n") + } + + participantsGuestExpanded.value = conferenceInfo.participantInfos.filter({$0.role == .Listener}).map {(participant) in + String(describing: participant.address!.addressBookEnhancedDisplayName())+" ("+String(describing: participant.address!.asStringUriOnly())+")" }.joined(separator: "\n") } diff --git a/Classes/Swift/Conference/ViewModels/ConferenceSchedulingViewModel.swift b/Classes/Swift/Conference/ViewModels/ConferenceSchedulingViewModel.swift index 9a9b9ab37..888858eab 100644 --- a/Classes/Swift/Conference/ViewModels/ConferenceSchedulingViewModel.swift +++ b/Classes/Swift/Conference/ViewModels/ConferenceSchedulingViewModel.swift @@ -57,8 +57,7 @@ class ConferenceSchedulingViewModel { let continueEnabled: MutableLiveData = MutableLiveData() - let selectedAddresses = MutableLiveData<[Address]>([]) - let selectedSpeakerAddresses = MutableLiveData<[Address]>([]) + let selectedParticipants = MutableLiveData<[ParticipantInfo]>([]) private var conferenceScheduler: ConferenceScheduler? = nil @@ -173,14 +172,11 @@ class ConferenceSchedulingViewModel { ConferenceSchedulingViewModel.durationList[$0].value == 60 }.first continueEnabled.value = false - selectedAddresses.value = [] + selectedParticipants.value = [] existingConfInfo.value = nil description.value = "" - } - - func destroy() { conferenceScheduler?.removeDelegate(delegate: conferenceSchedulerDelegate!) } @@ -192,7 +188,7 @@ class ConferenceSchedulingViewModel { func createConference() { - if (selectedAddresses.value?.count == 0) { + if (selectedParticipants.value?.count == 0) { Log.e("[Conference Creation] Couldn't create conference without any participant!") return } @@ -214,7 +210,7 @@ class ConferenceSchedulingViewModel { conferenceInfo.organizer = localAddress subject.value.map { conferenceInfo.subject = $0} description.value.map { conferenceInfo.description = $0} - conferenceInfo.participants = selectedAddresses.value! + conferenceInfo.participantInfos = selectedParticipants.value! if (scheduleForLater.value == true) { let timestamp = getConferenceStartTimestamp() conferenceInfo.dateTime = time_t(timestamp) @@ -229,8 +225,6 @@ class ConferenceSchedulingViewModel { } } - - private func allMandatoryFieldsFilled() -> Bool { return subject.value != nil && subject.value!.count > 0 && (scheduleForLater.value != true || (scheduledDate.value != nil && scheduledTime.value != nil) ); } diff --git a/Classes/Swift/Conference/Views/ConferenceSchedulingSummaryView.swift b/Classes/Swift/Conference/Views/ConferenceSchedulingSummaryView.swift index 33d78af51..f2d04539d 100644 --- a/Classes/Swift/Conference/Views/ConferenceSchedulingSummaryView.swift +++ b/Classes/Swift/Conference/Views/ConferenceSchedulingSummaryView.swift @@ -29,6 +29,7 @@ import SVProgressHUD let viaChatLabel = StyledLabel(VoipTheme.conference_scheduling_font, VoipTexts.conference_schedule_send_invite_chat_summary) let speakersLabel = StyledLabel(VoipTheme.conference_scheduling_font, " "+VoipTexts.conference_schedule_speakers_list) + let participantsLabel = StyledLabel(VoipTheme.conference_scheduling_font, " "+VoipTexts.conference_schedule_participants_list) let speakersListTableView = UITableView() let participantsListTableView = UITableView() @@ -158,7 +159,6 @@ import SVProgressHUD speakersListTableView.backgroundColor = .clear // Participants - let participantsLabel = StyledLabel(VoipTheme.conference_scheduling_font, " "+VoipTexts.conference_schedule_participants_list) contentView.addSubview(participantsLabel) participantsLabel.matchParentSideBorders().height(form_input_height).alignUnder(view: speakersListTableView,withMargin: form_margin).done() participantsLabel.textAlignment = .left @@ -175,12 +175,19 @@ import SVProgressHUD participantsListTableView.separatorStyle = .singleLine participantsListTableView.backgroundColor = .clear - ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.readCurrentAndObserve { (addresses) in + + self.createButton.isEnabled = ConferenceSchedulingViewModel.shared.getMode() == 0 ? true : (ConferenceSchedulingViewModel.shared.selectedParticipants.value!.filter({$0.role == .Speaker}).count > 0 && ConferenceSchedulingViewModel.shared.selectedParticipants.value!.filter({$0.role == .Listener}).count > 0) + + ConferenceSchedulingViewModel.shared.selectedParticipants.readCurrentAndObserve { (participants) in self.speakersListTableView.reloadData() self.speakersListTableView.removeConstraints().done() self.speakersListTableView.matchParentSideBorders().alignUnder(view: self.speakersLabel,withMargin: self.form_margin).done() - self.speakersListTableView.height((addresses!.count > 0 ? Double(addresses!.count) : 0.5) * VoipParticipantCell.cell_height).done() - if addresses!.count == 0 { + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + self.speakersListTableView.height((participants!.filter({$0.role == .Speaker}).count > 0 ? Double(participants!.filter({$0.role == .Speaker}).count) : 0.5) * VoipParticipantCell.cell_height).done() + } else { + self.speakersListTableView.height(0).done() + } + if participants!.count == 0 { let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) emptyLabel.text = VoipTexts.conference_schedule_speakers_list_empty emptyLabel.textAlignment = NSTextAlignment.center @@ -190,13 +197,29 @@ import SVProgressHUD } else { self.speakersListTableView.backgroundView?.isHidden = true } - } - - ConferenceSchedulingViewModel.shared.selectedAddresses.readCurrentAndObserve { (addresses) in + self.participantsListTableView.reloadData() self.participantsListTableView.removeConstraints().done() - self.participantsListTableView.matchParentSideBorders().alignUnder(view: participantsLabel,withMargin: self.form_margin).done() - self.participantsListTableView.height(Double(addresses!.count) * VoipParticipantCell.cell_height).done() + self.participantsListTableView.matchParentSideBorders().alignUnder(view: self.participantsLabel,withMargin: self.form_margin).done() + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + self.participantsListTableView.height((participants!.filter({$0.role == .Listener}).count > 0 ? Double(participants!.filter({$0.role == .Listener}).count) : 0.5) * VoipParticipantCell.cell_height).done() + } else { + self.participantsListTableView.height(Double(participants!.filter({$0.role == .Speaker}).count) * VoipParticipantCell.cell_height).done() + } + + if ConferenceSchedulingViewModel.shared.getMode() != 0 && ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener}).count == 0 { + self.participantsListTableView.reloadData() + self.participantsListTableView.removeConstraints().done() + self.participantsListTableView.matchParentSideBorders().alignUnder(view: self.participantsLabel,withMargin: self.form_margin).done() + self.participantsListTableView.height(0.5 * VoipParticipantCell.cell_height).done() + let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) + emptyLabel.text = VoipTexts.conference_schedule_participants_list_empty + emptyLabel.textAlignment = NSTextAlignment.center + self.participantsListTableView.backgroundView = emptyLabel + self.participantsListTableView.separatorStyle = UITableViewCell.SeparatorStyle.none + } else { + self.participantsListTableView.backgroundView?.isHidden = true + } } // Create / Schedule @@ -258,13 +281,18 @@ import SVProgressHUD self.view.backgroundColor = VoipTheme.voipBackgroundBWColor.get() self.speakersLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get() self.speakersListTableView.separatorColor = VoipTheme.separatorColor.get() - participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get() + self.participantsLabel.backgroundColor = VoipTheme.voipFormBackgroundColor.get() self.participantsListTableView.separatorColor = VoipTheme.separatorColor.get() } } override func viewWillAppear(_ animated: Bool) { + if ConferenceSchedulingViewModel.shared.existingConfInfo.value != nil { + let isBroadcastExisting = ConferenceSchedulingViewModel.shared.existingConfInfo.value??.participantInfos.filter({$0.role == .Speaker}).count != 0 && ConferenceSchedulingViewModel.shared.existingConfInfo.value??.participantInfos.filter({$0.role == .Listener}).count != 0 + ConferenceSchedulingViewModel.shared.mode.value = isBroadcastExisting ? 1 : 0 + } + titleLabel.text = ConferenceSchedulingViewModel.shared.getMode() == 0 ? VoipTexts.conference_schedule_summary : VoipTexts.conference_schedule_broadcast_summary datePicker.liveValue = ConferenceSchedulingViewModel.shared.scheduledDate @@ -288,9 +316,9 @@ import SVProgressHUD speakersListTableView.removeConstraints().done() speakersListTableView.matchParentSideBorders().alignUnder(view: self.speakersLabel,withMargin: self.form_margin).done() - speakersListTableView.height(Double(ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value!.count) * VoipParticipantCell.cell_height).done() + speakersListTableView.height(Double((ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker}).count)!) * VoipParticipantCell.cell_height).done() - if ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?.count == 0 { + if ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker}).count == 0 { self.speakersListTableView.reloadData() self.speakersListTableView.removeConstraints().done() self.speakersListTableView.matchParentSideBorders().alignUnder(view: self.speakersLabel,withMargin: self.form_margin).done() @@ -302,6 +330,18 @@ import SVProgressHUD self.speakersListTableView.separatorStyle = UITableViewCell.SeparatorStyle.none } + if ConferenceSchedulingViewModel.shared.getMode() != 0 && ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener}).count == 0 { + self.participantsListTableView.reloadData() + self.participantsListTableView.removeConstraints().done() + self.participantsListTableView.matchParentSideBorders().alignUnder(view: self.participantsLabel,withMargin: self.form_margin).done() + self.participantsListTableView.height(0.5 * VoipParticipantCell.cell_height).done() + let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) + emptyLabel.text = VoipTexts.conference_schedule_participants_list_empty + emptyLabel.textAlignment = NSTextAlignment.center + self.participantsListTableView.backgroundView = emptyLabel + self.participantsListTableView.separatorStyle = UITableViewCell.SeparatorStyle.none + } + if ConferenceSchedulingViewModel.shared.getMode() == 0 { speakersLabel.isHidden = true speakersListTableView.isHidden = true @@ -314,6 +354,11 @@ import SVProgressHUD super.viewWillAppear(animated) } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + reloadLists() + } @@ -321,13 +366,7 @@ import SVProgressHUD let view: ChatConversationCreateView = VIEW(ChatConversationCreateView.compositeViewDescription()) view.unfragmentCompositeDescription() - ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value!.forEach { address in - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append(address) - } - - ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value!.removeAll() - - let addresses = ConferenceSchedulingViewModel.shared.selectedAddresses.value!.map { (address) in String(address.asStringUriOnly()) } + let addresses = ConferenceSchedulingViewModel.shared.selectedParticipants.value!.map { (participant) in String(participant.address!.asStringUriOnly()) } view.tableController.contactsGroup = (addresses as NSArray).mutableCopy() as? NSMutableArray view.tableController.notFirstTime = true view.isForEditing = false @@ -337,37 +376,51 @@ import SVProgressHUD // Objc - bridge, as can't access easily to the view model. @objc func setParticipants(addresses:[String]) { - ConferenceSchedulingViewModel.shared.selectedAddresses.value = [] + ConferenceSchedulingViewModel.shared.selectedParticipants.value = [] return addresses.forEach { (address) in - if let address = try?Factory.Instance.createAddress(addr: address) { - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append(address) + do { + let createAddress = try Factory.Instance.createAddress(addr: address) + if let address = try?Factory.Instance.createParticipantInfo(address: createAddress) { + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.append(address) + address.role = ConferenceSchedulingViewModel.shared.getMode() != 0 ? .Listener : .Speaker + } + } catch { + Log.e("[goBackParticipantsListSelection] unable to create ParticipantInfo \(error)") } + } } // TableView datasource delegate func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if(tableView == speakersListTableView){ - guard let speakers = ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value else { + guard let speakers = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker}) else { return 0 } return speakers.count } else { - guard let participants = ConferenceSchedulingViewModel.shared.selectedAddresses.value else { - return 0 + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + guard let participants = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener}) else { + return 0 + } + return participants.count + } else { + guard let participants = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker}) else { + return 0 + } + return participants.count } - return participants.count } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if(tableView == speakersListTableView){ let cell:VoipSpeakerCell = tableView.dequeueReusableCell(withIdentifier: "VoipSpeakerCellSSchedule") as! VoipSpeakerCell - guard let speaker = ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?[indexPath.row] else { + guard let speaker = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker})[indexPath.row] else { return cell } cell.selectionStyle = .none - cell.scheduleConfSpeakerAddress = speaker + cell.scheduleConfSpeakerAddress = speaker.address cell.limeBadge.isHidden = ConferenceSchedulingViewModel.shared.isEncrypted.value != true cell.deleteButton.addTarget(self, action: #selector(deleteButtonPressed), for: .touchUpInside) @@ -376,11 +429,18 @@ import SVProgressHUD return cell } else { let cell:VoipParticipantCell = tableView.dequeueReusableCell(withIdentifier: "VoipParticipantCellSSchedule") as! VoipParticipantCell - guard let participant = ConferenceSchedulingViewModel.shared.selectedAddresses.value?[indexPath.row] else { - return cell + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + guard let participant = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener})[indexPath.row] else { + return cell + } + cell.scheduleConfParticipantAddress = participant.address + } else { + guard let speaker = ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker})[indexPath.row] else { + return cell + } + cell.scheduleConfParticipantAddress = speaker.address } cell.selectionStyle = .none - cell.scheduleConfParticipantAddress = participant cell.limeBadge.isHidden = ConferenceSchedulingViewModel.shared.isEncrypted.value != true if ConferenceSchedulingViewModel.shared.getMode() == 0 { @@ -395,21 +455,63 @@ import SVProgressHUD } @objc func addButtonPressed(sender:UIButton!) { - if(ConferenceSchedulingViewModel.shared.selectedAddresses.value?[sender.tag] != nil) { - ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?.append((ConferenceSchedulingViewModel.shared.selectedAddresses.value?[sender.tag])!) - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.remove(at: sender.tag) + if(ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener})[sender.tag] != nil) { + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener})[sender.tag].role = .Speaker } - speakersListTableView.reloadData() - participantsListTableView.reloadData() + reloadLists() } @objc func deleteButtonPressed(sender:UIButton!) { - if(ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?[sender.tag] != nil) { - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append((ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?[sender.tag])!) - ConferenceSchedulingViewModel.shared.selectedSpeakerAddresses.value?.remove(at: sender.tag) + if(ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker})[sender.tag] != nil) { + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Speaker})[sender.tag].role = .Listener } - speakersListTableView.reloadData() - participantsListTableView.reloadData() + reloadLists() } + func reloadLists(){ + let participants = ConferenceSchedulingViewModel.shared.selectedParticipants.value + + self.speakersListTableView.reloadData() + self.speakersListTableView.removeConstraints().done() + self.speakersListTableView.matchParentSideBorders().alignUnder(view: self.speakersLabel,withMargin: self.form_margin).done() + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + self.speakersListTableView.height((participants!.filter({$0.role == .Speaker}).count > 0 ? Double(participants!.filter({$0.role == .Speaker}).count) : 0.5) * VoipParticipantCell.cell_height).done() + } else { + self.speakersListTableView.height(0).done() + } + if participants!.filter({$0.role == .Speaker}).count == 0 { + let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) + emptyLabel.text = VoipTexts.conference_schedule_speakers_list_empty + emptyLabel.textAlignment = NSTextAlignment.center + self.speakersListTableView.backgroundView = emptyLabel + self.speakersListTableView.separatorStyle = UITableViewCell.SeparatorStyle.none + self.speakersListTableView.backgroundView?.isHidden = false + } else { + self.speakersListTableView.backgroundView?.isHidden = true + } + + self.participantsListTableView.reloadData() + self.participantsListTableView.removeConstraints().done() + self.participantsListTableView.matchParentSideBorders().alignUnder(view: participantsLabel,withMargin: self.form_margin).done() + if ConferenceSchedulingViewModel.shared.getMode() != 0 { + self.participantsListTableView.height(Double(participants!.filter({$0.role == .Listener}).count) * VoipParticipantCell.cell_height).done() + } else { + self.participantsListTableView.height(Double(participants!.filter({$0.role == .Speaker}).count) * VoipParticipantCell.cell_height).done() + } + + if ConferenceSchedulingViewModel.shared.getMode() != 0 && ConferenceSchedulingViewModel.shared.selectedParticipants.value?.filter({$0.role == .Listener}).count == 0 { + self.participantsListTableView.reloadData() + self.participantsListTableView.removeConstraints().done() + self.participantsListTableView.matchParentSideBorders().alignUnder(view: self.participantsLabel,withMargin: self.form_margin).done() + self.participantsListTableView.height(0.5 * VoipParticipantCell.cell_height).done() + let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) + emptyLabel.text = VoipTexts.conference_schedule_participants_list_empty + emptyLabel.textAlignment = NSTextAlignment.center + self.participantsListTableView.backgroundView = emptyLabel + self.participantsListTableView.separatorStyle = UITableViewCell.SeparatorStyle.none + } else { + self.participantsListTableView.backgroundView?.isHidden = true + } + self.createButton.isEnabled = ConferenceSchedulingViewModel.shared.getMode() == 0 ? true : (ConferenceSchedulingViewModel.shared.selectedParticipants.value!.filter({$0.role == .Speaker}).count > 0 && ConferenceSchedulingViewModel.shared.selectedParticipants.value!.filter({$0.role == .Listener}).count > 0) + } } diff --git a/Classes/Swift/Conference/Views/ConferenceSchedulingView.swift b/Classes/Swift/Conference/Views/ConferenceSchedulingView.swift index 9c485c976..4a56cd7bc 100644 --- a/Classes/Swift/Conference/Views/ConferenceSchedulingView.swift +++ b/Classes/Swift/Conference/Views/ConferenceSchedulingView.swift @@ -259,7 +259,9 @@ import IQKeyboardManager func gotoParticipantsListSelection() { let view: ChatConversationCreateView = self.VIEW(ChatConversationCreateView.compositeViewDescription()) view.unfragmentCompositeDescription() - let addresses = ConferenceSchedulingViewModel.shared.selectedAddresses.value!.map { (address) in String(address.asStringUriOnly()) } + let addresses = ConferenceSchedulingViewModel.shared.selectedParticipants.value!.map { (address) in + address.address != nil ? String(address.address!.asStringUriOnly()) : "" + } view.tableController.contactsGroup = (addresses as NSArray).mutableCopy() as? NSMutableArray view.isForEditing = false view.isForVoipConference = true diff --git a/Classes/Swift/Conference/Views/ICSBubbleView.swift b/Classes/Swift/Conference/Views/ICSBubbleView.swift index 52632b6c6..db0323a81 100644 --- a/Classes/Swift/Conference/Views/ICSBubbleView.swift +++ b/Classes/Swift/Conference/Views/ICSBubbleView.swift @@ -38,6 +38,9 @@ import EventKitUI let inviteTitle = StyledLabel(VoipTheme.conference_invite_title_font, VoipTexts.conference_invite_title) let inviteCancelled = StyledLabel(VoipTheme.conference_cancelled_title_font, VoipTexts.conference_cancel_title) let inviteUpdated = StyledLabel(VoipTheme.conference_updated_title_font, VoipTexts.conference_update_title) + let inviteBroadcastTitle = StyledLabel(VoipTheme.conference_invite_title_font, VoipTexts.conference_invite_broadcast_title) + let inviteBroadcastCancelled = StyledLabel(VoipTheme.conference_cancelled_title_font, VoipTexts.conference_cancel_broadcast_title) + let inviteBroadcastUpdated = StyledLabel(VoipTheme.conference_updated_title_font, VoipTexts.conference_update_broadcast_title) let subject = StyledLabel(VoipTheme.conference_invite_subject_font) let participants = StyledLabel(VoipTheme.conference_invite_desc_font) @@ -48,12 +51,33 @@ import EventKitUI let joinShare = UIStackView() let join = FormButton(title:VoipTexts.conference_invite_join.uppercased(), backgroundStateColors: VoipTheme.button_green_background) let share = UIImageView(image:UIImage(named:"voip_export")?.tinted(with: VoipTheme.primaryTextColor.get())) + + var isBroadcast = false + var isMe = false var conferenceData: ScheduledConferenceData? = nil { didSet { if let data = conferenceData { + isBroadcast = data.conferenceInfo.participantInfos.filter({$0.role == .Speaker}).count != 0 && data.conferenceInfo.participantInfos.filter({$0.role == .Listener}).count != 0 subject.text = data.subject.value - participants.text = VoipTexts.conference_invite_participants_count.replacingOccurrences(of: "%d", with: String(data.conferenceInfo.participants.count+1)) + data.conferenceInfo.participantInfos.forEach { participant in + if participant.address != nil && participant.address!.isMe() { + isMe = true + } + } + + participants.text = VoipTexts.conference_invite_participants_count.replacingOccurrences(of: "%d", with: String(data.conferenceInfo.participants.count + (isMe ? 0 : 1))) + if isBroadcast && participants.text != nil { + var isMeSpeaker = false + data.conferenceInfo.participantInfos.filter({$0.role == .Speaker}).forEach { participant in + if isMe && participant.address != nil && participant.address!.isMe() { + isMeSpeaker = true + } + } + if isMeSpeaker || !isMe { + participants.text! += " (" + VoipTexts.conference_you_are_speaker + ")" + } + } participants.addIndicatorIcon(iconName: "conference_schedule_participants_default",padding : 0.0, y: -indicator_y, trailing: false) date.text = TimestampUtils.dateToString(date: data.rawDate) date.addIndicatorIcon(iconName: "conference_schedule_calendar_default", padding: 0.0, y:-indicator_y, trailing:false) @@ -62,9 +86,22 @@ import EventKitUI descriptionTitle.isHidden = data.description.value == nil || data.description.value!.count == 0 descriptionValue.isHidden = descriptionTitle.isHidden descriptionValue.text = data.description.value - inviteTitle.isHidden = [.Cancelled,.Updated].contains(data.conferenceInfo.state) - inviteCancelled.isHidden = data.conferenceInfo.state != .Cancelled - inviteUpdated.isHidden = data.conferenceInfo.state != .Updated + if isBroadcast { + inviteTitle.isHidden = true + inviteCancelled.isHidden = true + inviteUpdated.isHidden = true + inviteBroadcastTitle.isHidden = [.Cancelled,.Updated].contains(data.conferenceInfo.state) + inviteBroadcastCancelled.isHidden = data.conferenceInfo.state != .Cancelled + inviteBroadcastUpdated.isHidden = data.conferenceInfo.state != .Updated + } else { + inviteTitle.isHidden = [.Cancelled,.Updated].contains(data.conferenceInfo.state) + inviteCancelled.isHidden = data.conferenceInfo.state != .Cancelled + inviteUpdated.isHidden = data.conferenceInfo.state != .Updated + inviteBroadcastTitle.isHidden = true + inviteBroadcastCancelled.isHidden = true + inviteBroadcastUpdated.isHidden = true + } + join.isEnabled = data.isConferenceCancelled.value != true } } @@ -88,6 +125,9 @@ import EventKitUI rows.addArrangedSubview(inviteTitle) rows.addArrangedSubview(inviteCancelled) rows.addArrangedSubview(inviteUpdated) + rows.addArrangedSubview(inviteBroadcastTitle) + rows.addArrangedSubview(inviteBroadcastCancelled) + rows.addArrangedSubview(inviteBroadcastUpdated) rows.addArrangedSubview(subject) rows.addArrangedSubview(participants) rows.addArrangedSubview(date) diff --git a/Classes/Swift/Conference/Views/ScheduledConferencesCell.swift b/Classes/Swift/Conference/Views/ScheduledConferencesCell.swift index 7291a05ff..4f7793c6d 100644 --- a/Classes/Swift/Conference/Views/ScheduledConferencesCell.swift +++ b/Classes/Swift/Conference/Views/ScheduledConferencesCell.swift @@ -44,7 +44,7 @@ class ScheduledConferencesCell: UITableViewCell { let descriptionTitle = StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_description_title) let descriptionValue = StyledLabel(VoipTheme.conference_list_address_desc_font) - var urlTitle = StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_schedule_address_title) + var urlTitle = StyledLabel(VoipTheme.conference_list_address_desc_font) let urlValue = StyledLabel(VoipTheme.conference_scheduling_font) let copyLink = CallControlButton(width:button_size,height:button_size,buttonTheme: VoipTheme.scheduled_conference_action("voip_copy")) let joinConf = FormButton(title:VoipTexts.conference_invite_join.uppercased(), backgroundStateColors: VoipTheme.button_green_background) @@ -56,11 +56,12 @@ class ScheduledConferencesCell: UITableViewCell { let selectionCheckBox = StyledCheckBox() let myContentView = UIView() - let isBroadcast = true + var isBroadcast = false var conferenceData: ScheduledConferenceData? = nil { didSet { if let data = conferenceData { + isBroadcast = data.conferenceInfo.participantInfos.filter({$0.role == .Speaker}).count != 0 && data.conferenceInfo.participantInfos.filter({$0.role == .Listener}).count != 0 timeDuration.text = "\(data.time.value)"+(data.duration.value != nil ? " (\(data.duration.value))" : "") organiser.text = VoipTexts.conference_schedule_organizer+data.organizer.value! subject.text = (isBroadcast ? VoipTexts.conference_scheduled_title_broadcast_cell : VoipTexts.conference_scheduled_title_meeting_cell) + data.subject.value! @@ -85,8 +86,9 @@ class ScheduledConferencesCell: UITableViewCell { self.participantsGuestTitle.text = VoipTexts.conference_scheduled_title_guests_cell self.participantsTitle.isHidden = expanded != true self.participants.text = expanded == true ? data.participantsExpanded.value : data.participantsShort.value - self.participantsGuest.text = data.participantsExpanded.value - self.participants.numberOfLines = expanded == true ? 6 : 2 + self.participantsGuest.text = data.participantsGuestExpanded.value + self.participants.numberOfLines = expanded == true ? 10 : 2 + self.participantsGuest.numberOfLines = expanded == true ? 10 : 2 self.expandedRows.isHidden = expanded != true self.joinEditDelete.isHidden = expanded != true if let myAddress = Core.get().defaultAccount?.params?.identityAddress { @@ -106,7 +108,7 @@ class ScheduledConferencesCell: UITableViewCell { self.participantsGuestTitle.removeConstraints().alignUnder(view: self.participants,withMargin: 10).toRightOf(self.participantsGuestIcon,withLeftMargin:10).toLeftOf(self.infoConf,withRightMargin: 15).done() self.participantsGuestTitle.isHidden = false - self.participantsGuest.removeConstraints().alignUnder(view: self.participantsGuestTitle, withMargin: 10).toRightOf(self.participantsGuestIcon,withLeftMargin:10).toLeftOf(self.infoConf,withRightMargin: 15).done() + self.participantsGuest.removeConstraints().alignUnder(view: self.participantsGuestTitle, withMargin: 4).toRightOf(self.participantsGuestIcon,withLeftMargin:10).toLeftOf(self.infoConf,withRightMargin: 15).done() self.participantsGuest.isHidden = false } } else { @@ -118,6 +120,7 @@ class ScheduledConferencesCell: UITableViewCell { self.isBroadcast ? self.expandedRows.removeConstraints().alignUnder(view: self.participantsGuest,withMargin: 15).matchParentSideBorders(insetedByDx:10).done() : self.expandedRows.removeConstraints().alignUnder(view: self.participants,withMargin: 15).matchParentSideBorders(insetedByDx:10).done() + self.urlTitle.text = self.isBroadcast ? VoipTexts.conference_schedule_address_broadcast_title : VoipTexts.conference_schedule_address_title self.joinEditDelete.removeConstraints().alignUnder(view: self.expandedRows,withMargin: 10).alignParentRight(withMargin: 10).done() if (expanded == true) { @@ -180,10 +183,6 @@ class ScheduledConferencesCell: UITableViewCell { myContentView.addSubview(participants) participants.alignUnder(view: participantsTitle, withMargin: 10).toRightOf(participantsIcon,withLeftMargin:10).toLeftOf(infoConf,withRightMargin: 15).done() - - - - myContentView.addSubview(participantsGuestIcon) participantsGuestIcon.alignUnder(view: participants,withMargin: 5).square(25).alignParentLeft(withMargin: 10).done() participantsGuestIcon.isHidden = true @@ -196,12 +195,6 @@ class ScheduledConferencesCell: UITableViewCell { participantsGuest.alignUnder(view: participantsGuestTitle, withMargin: 10).toRightOf(participantsGuestIcon,withLeftMargin:10).toLeftOf(infoConf,withRightMargin: 15).done() participantsGuest.isHidden = true - - - - - - expandedRows.axis = .vertical expandedRows.spacing = 10 myContentView.addSubview(expandedRows) @@ -210,8 +203,6 @@ class ScheduledConferencesCell: UITableViewCell { expandedRows.addArrangedSubview(descriptionTitle) expandedRows.addArrangedSubview(descriptionValue) - urlTitle = isBroadcast ? StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_schedule_address_broadcast_title) : StyledLabel(VoipTheme.conference_list_address_desc_font, VoipTexts.conference_schedule_address_title) - expandedRows.addArrangedSubview(urlTitle) let urlAndCopy = UIStackView() urlAndCopy.addArrangedSubview(urlValue) @@ -257,9 +248,14 @@ class ScheduledConferencesCell: UITableViewCell { ConferenceSchedulingViewModel.shared.subject.value = confData.subject.value ConferenceSchedulingViewModel.shared.scheduledDuration.value = ConferenceSchedulingViewModel.durationList.firstIndex(where: {$0.value == confData.conferenceInfo.duration}) ConferenceSchedulingViewModel.shared.scheduleForLater.value = true - ConferenceSchedulingViewModel.shared.selectedAddresses.value = [] - confData.conferenceInfo.participants.forEach { - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append($0) + ConferenceSchedulingViewModel.shared.selectedParticipants.value = [] + do { + try confData.conferenceInfo.participants.forEach { + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.append(try Factory.Instance.createParticipantInfo(address: $0)) + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.last?.role = .Listener + } + } catch { + Log.e("[ScheduleFromGroupChat] unable to create ParticipantInfo \(error)") } ConferenceSchedulingViewModel.shared.existingConfInfo.value = confData.conferenceInfo // TOODO TimeZone (as Android 14.6.2022) ConferenceSchedulingViewModel.shared.scheduledTimeZone.value = self.conferenceData?.timezone diff --git a/Classes/Swift/Voip/Theme/VoipTexts.swift b/Classes/Swift/Voip/Theme/VoipTexts.swift index 3a01e79ec..8d94ca3e2 100644 --- a/Classes/Swift/Voip/Theme/VoipTexts.swift +++ b/Classes/Swift/Voip/Theme/VoipTexts.swift @@ -101,6 +101,9 @@ import UIKit @objc static let conference_invite_title = NSLocalizedString("Meeting invite:",comment:"") @objc static let conference_update_title = NSLocalizedString("Meeting has been updated:",comment:"") @objc static let conference_cancel_title = NSLocalizedString("Meeting has been cancelled:",comment:"") + @objc static let conference_invite_broadcast_title = NSLocalizedString("Broadcast invite:",comment:"") + @objc static let conference_update_broadcast_title = NSLocalizedString("Broadcast has been updated:",comment:"") + @objc static let conference_cancel_broadcast_title = NSLocalizedString("Broadcast has been cancelled:",comment:"") @objc static let conference_last_user = NSLocalizedString("All other participants have left the group call",comment:"") @objc static let conference_local_title = NSLocalizedString("Local group call",comment:"") @objc static let conference_no_schedule = NSLocalizedString("No scheduled meeting yet.",comment:"") @@ -127,11 +130,12 @@ import UIKit @objc static let conference_schedule_participants_list = NSLocalizedString("Participants list",comment:"") @objc static let conference_schedule_speakers_list = NSLocalizedString("Speakers list",comment:"") @objc static let conference_schedule_speakers_list_empty = NSLocalizedString("Select at least one speaker",comment:"") + @objc static let conference_schedule_participants_list_empty = NSLocalizedString("Select at least one participant",comment:"") @objc static let conference_schedule_send_invite_chat = NSLocalizedString("Send invite via &appName;",comment:"").replacingOccurrences(of: "&appName;", with: appName) @objc static let conference_schedule_send_invite_chat_summary = NSLocalizedString("Invite will be sent out from my &appName; account",comment:"").replacingOccurrences(of: "&appName;", with: appName) @objc static let conference_schedule_send_invite_email = NSLocalizedString("Send invite via email",comment:"") - @objc static let conference_schedule_start = NSLocalizedString("Schedule meeting",comment:"") - @objc static let conference_schedule_edit = NSLocalizedString("Edit meeting",comment:"") + @objc static let conference_schedule_start = NSLocalizedString("Schedule",comment:"") + @objc static let conference_schedule_edit = NSLocalizedString("Edit",comment:"") @objc static let conference_schedule_subject_hint = NSLocalizedString("Meeting subject",comment:"") @objc static let conference_group_call_subject_hint = NSLocalizedString("Group call subject",comment:"") @objc static let conference_schedule_subject_title = NSLocalizedString("Subject",comment:"") @@ -161,6 +165,7 @@ import UIKit @objc static let conference_scheduled_title_participant_cell = NSLocalizedString("Participants",comment:"") @objc static let conference_scheduled_title_speakers_cell = NSLocalizedString("Speakers",comment:"") @objc static let conference_scheduled_title_guests_cell = NSLocalizedString("Guests",comment:"") + @objc static let conference_you_are_speaker = NSLocalizedString("You're Speaker",comment:"") @objc static let image_picker_view_alert_action_title = NSLocalizedString("Select the source",comment:"") @objc static let image_picker_view_alert_action_camera = NSLocalizedString("Camera",comment:"") diff --git a/Classes/Swift/Voip/ViewModels/ConferenceViewModel.swift b/Classes/Swift/Voip/ViewModels/ConferenceViewModel.swift index 555e48516..bd3352c57 100644 --- a/Classes/Swift/Voip/ViewModels/ConferenceViewModel.swift +++ b/Classes/Swift/Voip/ViewModels/ConferenceViewModel.swift @@ -504,9 +504,18 @@ class ConferenceViewModel { @objc static func scheduleFromGroupChat(cChatRoom: OpaquePointer ) { ConferenceSchedulingViewModel.shared.reset() - ChatRoom.getSwiftObject(cObject: cChatRoom).participants.forEach { - ConferenceSchedulingViewModel.shared.selectedAddresses.value?.append($0.address!) + + do { + try ChatRoom.getSwiftObject(cObject: cChatRoom).participants.forEach { + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.append( + try Factory.Instance.createParticipantInfo(address: $0.address!) + ) + ConferenceSchedulingViewModel.shared.selectedParticipants.value?.last?.role = .Listener + } + } catch { + Log.e("[ScheduleFromGroupChat] unable to create ParticipantInfo \(error)") } + ConferenceSchedulingViewModel.shared.scheduleForLater.value = true }