From a66fe73aa98015bfcb2145e318dcb7003b1d7889 Mon Sep 17 00:00:00 2001 From: Christophe Deschamps Date: Thu, 18 Aug 2022 16:26:54 +0200 Subject: [PATCH] Conference participants list cosmetics --- Classes/ChatConversationCreateView.m | 7 +- Classes/LinphoneUI/StatusBarView.m | 3 +- .../Extensions/IOS/UIVIewExtensions.swift | 2 +- Classes/Swift/Voip/Theme/VoipTheme.swift | 4 +- .../Voip/ViewModels/ControlsViewModel.swift | 25 +++--- .../ParticipantsListView.swift | 3 +- .../VoipParticipantCell.swift | 87 +++++++++++-------- 7 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Classes/ChatConversationCreateView.m b/Classes/ChatConversationCreateView.m index 749cf69c9..41e3606b3 100644 --- a/Classes/ChatConversationCreateView.m +++ b/Classes/ChatConversationCreateView.m @@ -168,7 +168,12 @@ static UICompositeViewDescription *compositeDescription = nil; - (IBAction)onBackClick:(id)sender { [_tableController.contactsGroup removeAllObjects]; if (_isForVoipConference) { - [PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription]; + if (_isForOngoingVoipConference) { + [PhoneMainView.instance changeCurrentView:VIEW(ActiveCallOrConferenceView).compositeViewDescription]; + [ControlsViewModelBridge showParticipants]; + } else { + [PhoneMainView.instance popToView:ConferenceSchedulingView.compositeViewDescription]; + } } else { if (_tableController.isForEditing) [PhoneMainView.instance popToView:ChatConversationInfoView.compositeViewDescription]; diff --git a/Classes/LinphoneUI/StatusBarView.m b/Classes/LinphoneUI/StatusBarView.m index 5c3d557f8..381f54ab6 100644 --- a/Classes/LinphoneUI/StatusBarView.m +++ b/Classes/LinphoneUI/StatusBarView.m @@ -402,8 +402,7 @@ } - (IBAction)onQualityClick:(id)sender { - CallStatsViewModel* stats = [[CallStatsViewModel alloc]init]; - [stats toggleVisibility]; + [ControlsViewModelBridge toggleStatsVisibility]; } - (IBAction)onSideMenuClick:(id)sender { diff --git a/Classes/Swift/Extensions/IOS/UIVIewExtensions.swift b/Classes/Swift/Extensions/IOS/UIVIewExtensions.swift index c34f80730..bfd68490a 100644 --- a/Classes/Swift/Extensions/IOS/UIVIewExtensions.swift +++ b/Classes/Swift/Extensions/IOS/UIVIewExtensions.swift @@ -303,7 +303,7 @@ extension UIView { func alignParentRight(withMargin:Int = 0) -> UIView { snp.makeConstraints { (make) in - make.right.equalToSuperview().offset(-withMargin).priorityRequired() + make.right.equalToSuperview().offset(-withMargin) } return self } diff --git a/Classes/Swift/Voip/Theme/VoipTheme.swift b/Classes/Swift/Voip/Theme/VoipTheme.swift index 0d0ab2dfa..6b7558944 100644 --- a/Classes/Swift/Voip/Theme/VoipTheme.swift +++ b/Classes/Swift/Voip/Theme/VoipTheme.swift @@ -111,8 +111,8 @@ import UIKit static let conference_participant_admin_label = TextStyle(fgColor: primarySubtextLightColor, bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 13.0) - static let conference_participant_name_font = TextStyle(fgColor: LightDarkColor(dark_grey_color,dark_grey_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 18.0) - static let conference_participant_sip_uri_font = TextStyle(fgColor: LightDarkColor(primary_color,primary_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .center, font: fontName+"-Regular", size: 12.0) + static let conference_participant_name_font = TextStyle(fgColor: LightDarkColor(dark_grey_color,dark_grey_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 18.0) + static let conference_participant_sip_uri_font = TextStyle(fgColor: LightDarkColor(primary_color,primary_color), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Regular", size: 12.0) static let conference_participant_name_font_grid = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 15.0) static let conference_participant_name_font_as = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName+"-Bold", size: 12.0) static let conference_participant_name_font_audio_only = TextStyle(fgColor: LightDarkColor(.white,.white), bgColor: LightDarkColor(.clear,.clear), allCaps: false, align: .left, font: fontName, size: 14.0) diff --git a/Classes/Swift/Voip/ViewModels/ControlsViewModel.swift b/Classes/Swift/Voip/ViewModels/ControlsViewModel.swift index c7ee93807..3e2f66807 100644 --- a/Classes/Swift/Voip/ViewModels/ControlsViewModel.swift +++ b/Classes/Swift/Voip/ViewModels/ControlsViewModel.swift @@ -270,18 +270,15 @@ class ControlsViewModel { } -@objc class CallStatsViewModel: NSObject { - - override init() { - super.init() - } - - @objc - func toggleVisibility() -> Void { - if (ControlsViewModel.shared.callStatsVisible.value == true) { - ControlsViewModel.shared.callStatsVisible.value = false - } else { - ControlsViewModel.shared.callStatsVisible.value = true - } - } +@objc class ControlsViewModelBridge: NSObject { + @objc static func showParticipants() { + ControlsViewModel.shared.goToConferenceParticipantsListEvent.value = true + } + @objc static func toggleStatsVisibility() -> Void { + if (ControlsViewModel.shared.callStatsVisible.value == true) { + ControlsViewModel.shared.callStatsVisible.value = false + } else { + ControlsViewModel.shared.callStatsVisible.value = true + } + } } diff --git a/Classes/Swift/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift b/Classes/Swift/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift index 0009a1318..2fc971b89 100644 --- a/Classes/Swift/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift +++ b/Classes/Swift/Voip/Views/Fragments/ParticipantsList/ParticipantsListView.swift @@ -58,8 +58,9 @@ import linphonesw participantsListTableView.separatorColor = .white - CallsViewModel.shared.callsData.readCurrentAndObserve{ (callsData) in + ConferenceViewModel.shared.conferenceParticipants.readCurrentAndObserve{ _ in self.participantsListTableView.reloadData() + self.noParticipantsLabel.isHidden = ConferenceViewModel.shared.conferenceParticipants.value?.count ?? 0 > 0 } ConferenceViewModel.shared.isMeAdmin.readCurrentAndObserve { (meAdmin) in diff --git a/Classes/Swift/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift b/Classes/Swift/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift index 63af27e49..adb75de17 100644 --- a/Classes/Swift/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift +++ b/Classes/Swift/Voip/Views/Fragments/ParticipantsList/VoipParticipantCell.swift @@ -27,26 +27,27 @@ class VoipParticipantCell: UITableViewCell { // Layout Constants - let dismiss_icon_inset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + static let dismiss_icon_inset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) let dismiss_right_margin = 10 - let check_box_size = 20.0 + let check_box_size = 15 static let cell_height = 80.0 let avatar_left_margin = 15.0 let texts_left_margin = 20.0 let lime_badge_width = 18.0 let lime_badge_offset = -10.0 - let avatar = Avatar(color:VoipTheme.primaryTextColor, textStyle: VoipTheme.call_generated_avatar_small) let limeBadge = UIImageView(image: UIImage(named: "security_toggle_icon_green")) let displayName = StyledLabel(VoipTheme.conference_participant_name_font) let sipAddress = StyledLabel(VoipTheme.conference_participant_sip_uri_font) - let isAdminView = UIView() - var removePart : CallControlButton? + let isAdminView = UIStackView() + let isAdminLabel = StyledLabel(VoipTheme.conference_participant_admin_label,VoipTexts.chat_room_group_info_admin) + let isAdminCheck = UIImageView(image: UIImage(named:("check_unselected"))) + let removePart = CallControlButton(imageInset:dismiss_icon_inset,buttonTheme: VoipTheme.voip_cancel, onClickAction: {}) var owningParticpantsListView : ParticipantsListView? = nil - + var participantData: ConferenceParticipantData? = nil { didSet { if let data = participantData { @@ -54,19 +55,17 @@ class VoipParticipantCell: UITableViewCell { avatar.fillFromAddress(address: data.participant.address!) displayName.text = data.participant.address?.addressBookEnhancedDisplayName() sipAddress.text = data.participant.address?.asStringUriOnly() - data.isAdmin.readCurrentAndObserve { (isAdmin) in self.isAdminView.isHidden = isAdmin != true - + data.isAdmin.readCurrentAndObserve { _ in + self.setAdminStatus(data: data) } - data.isMeAdmin.readCurrentAndObserve { (isMeAdmin) in - self.removePart!.isHidden = isMeAdmin != true - self.isAdminView.alpha = isMeAdmin == true ? 1.0 : 0.6 - self.isAdminView.isUserInteractionEnabled = isMeAdmin == true + data.isMeAdmin.readCurrentAndObserve { _ in + self.setAdminStatus(data: data) } self.isAdminView.onClick { data.conference.setParticipantAdminStatus(participant: data.participant, isAdmin: data.isAdmin.value != true) self.owningParticpantsListView?.participantsListTableView.reloadData() } - self.removePart?.onClick { + self.removePart.onClick { try?data.conference.removeParticipant(participant: data.participant) self.owningParticpantsListView?.participantsListTableView.reloadData() } @@ -74,6 +73,15 @@ class VoipParticipantCell: UITableViewCell { } } + func setAdminStatus(data:ConferenceParticipantData) { + let isAdmin = data.isAdmin.value! + let isMeAdmin = data.isMeAdmin.value! + self.removePart.isHidden = !isMeAdmin + self.isAdminView.isUserInteractionEnabled = isMeAdmin + self.isAdminLabel.textColor = !isAdmin ? VoipTheme.primarySubtextLightColor.get() : VoipTheme.primaryTextColor.get() + self.isAdminView.isHidden = !isAdmin && !isMeAdmin // Non admin don't see status of others non admin (they just see admins) + } + var scheduleConfParticipantAddress: Address? = nil { didSet { if let address = scheduleConfParticipantAddress { @@ -81,7 +89,7 @@ class VoipParticipantCell: UITableViewCell { displayName.text = address.addressBookEnhancedDisplayName() sipAddress.text = address.asStringUriOnly() self.isAdminView.isHidden = true - self.removePart?.isHidden = true + self.removePart.isHidden = true } } } @@ -91,37 +99,40 @@ class VoipParticipantCell: UITableViewCell { super.init(style: style, reuseIdentifier: reuseIdentifier) contentView.height(VoipParticipantCell.cell_height).matchParentSideBorders().done() - contentView.addSubview(avatar) + addSubview(avatar) avatar.size(w: VoipCallCell.avatar_size, h: VoipCallCell.avatar_size).centerY().alignParentLeft(withMargin: avatar_left_margin).done() limeBadge.contentMode = .scaleAspectFit - contentView.addSubview(limeBadge) + addSubview(limeBadge) limeBadge.toRightOf(avatar,withLeftMargin: lime_badge_offset).width(lime_badge_width).done() - - let nameAddress = UIView() - nameAddress.addSubview(displayName) - nameAddress.addSubview(sipAddress) - displayName.alignParentTop().done() - sipAddress.alignUnder(view: displayName).done() - contentView.addSubview(nameAddress) - nameAddress.toRightOf(avatar,withLeftMargin:texts_left_margin).wrapContentY().centerY().done() - removePart = CallControlButton(imageInset:dismiss_icon_inset,buttonTheme: VoipTheme.voip_cancel, onClickAction: { - self.removeFromSuperview() - }) - contentView.addSubview(removePart!) - removePart!.alignParentRight(withMargin: dismiss_right_margin).centerY().done() + // Name Address - let isAdminLabel = StyledLabel(VoipTheme.conference_participant_admin_label,VoipTexts.chat_room_group_info_admin) - isAdminView.addSubview(isAdminLabel) - isAdminLabel.alignParentRight().centerY().done() + let nameAddress = UIStackView() + nameAddress.addArrangedSubview(displayName) + nameAddress.addArrangedSubview(sipAddress) + nameAddress.axis = .vertical + addSubview(nameAddress) + nameAddress.toRightOf(avatar,withLeftMargin:texts_left_margin).centerY().done() - let isAdminCheck = UIImageView(image: UIImage(named:("check_unselected"))) - isAdminView.addSubview(isAdminCheck) - isAdminCheck.size(w: check_box_size, h: check_box_size).toLeftOf(isAdminLabel).done() - - contentView.addSubview(isAdminView) - isAdminView.height(check_box_size).toLeftOf(removePart!).centerY().done() + // Admin section + isAdminView.spacing = 5 + + isAdminView.addArrangedSubview(isAdminCheck) + isAdminCheck.square(check_box_size).done() + isAdminCheck.contentMode = .scaleAspectFit + isAdminCheck.setContentHuggingPriority(.defaultHigh, for: .horizontal) + + isAdminView.addArrangedSubview(isAdminLabel) + isAdminLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) + + isAdminView.addArrangedSubview(removePart) + removePart.setContentHuggingPriority(.defaultHigh, for: .horizontal) + + addSubview(isAdminView) + isAdminView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).isActive = true + isAdminView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + isAdminView.matchParentHeight().toRightOf(nameAddress).alignParentRight(withMargin: dismiss_right_margin).done() }