forked from mirrors/linphone-iphone
Allow admins to update conversation participants list
This commit is contained in:
parent
bff25fc3f2
commit
d4b6fe6d8e
3 changed files with 311 additions and 23 deletions
|
|
@ -1500,6 +1500,57 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_admin_menu_remove_participant" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Remove from the group"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Retirer du groupe"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_admin_menu_set_participant_admin" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Give admin rights"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Donner les privilèges administrateur"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_admin_menu_unset_participant_admin" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Remove admin rights"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Retirer les privilèges administrateur"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_confirm_start_group_call_dialog_message" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import SwiftUI
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
struct ConversationInfoFragment: View {
|
||||
@State private var orientation = UIDevice.current.orientation
|
||||
|
||||
|
|
@ -30,6 +31,8 @@ struct ConversationInfoFragment: View {
|
|||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
|
||||
@State var addParticipantsViewModel = AddParticipantsViewModel()
|
||||
|
||||
@Binding var isMuted: Bool
|
||||
@Binding var isShowEphemeralFragment: Bool
|
||||
@Binding var isShowStartCallGroupPopup: Bool
|
||||
|
|
@ -282,7 +285,10 @@ struct ConversationInfoFragment: View {
|
|||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
if conversationViewModel.participantConversationModelAdmin != nil && participantConversationModel.address == conversationViewModel.participantConversationModelAdmin!.address {
|
||||
let participantConversationModelIsAdmin = conversationViewModel.participantConversationModelAdmin.first(
|
||||
where: {$0.address == participantConversationModel.address})
|
||||
|
||||
if participantConversationModelIsAdmin != nil {
|
||||
Text("conversation_info_participant_is_admin_label")
|
||||
.foregroundStyle(Color.grayMain2c400)
|
||||
.default_text_style(styleSize: 12)
|
||||
|
|
@ -290,12 +296,144 @@ struct ConversationInfoFragment: View {
|
|||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if conversationViewModel.myParticipantConversationModel != nil && conversationViewModel.myParticipantConversationModel!.address != participantConversationModel.address {
|
||||
Menu {
|
||||
Button(
|
||||
action: {
|
||||
let addressConv = participantConversationModel.address
|
||||
|
||||
let friendIndex = contactsManager.lastSearch.firstIndex(
|
||||
where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressConv})})
|
||||
if friendIndex != nil {
|
||||
withAnimation {
|
||||
conversationViewModel.displayedConversation = nil
|
||||
indexPage = 0
|
||||
contactViewModel.indexDisplayedFriend = friendIndex
|
||||
}
|
||||
} else {
|
||||
withAnimation {
|
||||
conversationViewModel.displayedConversation = nil
|
||||
indexPage = 0
|
||||
|
||||
isShowEditContactFragment.toggle()
|
||||
editContactViewModel.sipAddresses.removeAll()
|
||||
editContactViewModel.sipAddresses.append(String(participantConversationModel.address.dropFirst(4) ?? ""))
|
||||
editContactViewModel.sipAddresses.append("")
|
||||
}
|
||||
}
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
let addressConv = participantConversationModel.address
|
||||
|
||||
let friendIndex = contactsManager.lastSearch.firstIndex(
|
||||
where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressConv})})
|
||||
if friendIndex != nil {
|
||||
Image("address-book")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("conversation_info_menu_go_to_contact")
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Image("user-plus")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("conversation_info_menu_add_to_contacts")
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if conversationViewModel.isUserAdmin {
|
||||
let participantConversationModelIsAdmin = conversationViewModel.participantConversationModelAdmin.first(
|
||||
where: {$0.address == participantConversationModel.address})
|
||||
|
||||
Button {
|
||||
conversationViewModel.toggleAdminRights(address: participantConversationModel.address)
|
||||
} label: {
|
||||
HStack {
|
||||
Text(participantConversationModelIsAdmin != nil ? "conversation_info_admin_menu_unset_participant_admin" : "conversation_info_admin_menu_set_participant_admin")
|
||||
Spacer()
|
||||
Image("user-circle")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
}
|
||||
}
|
||||
|
||||
Button(role: .destructive) {
|
||||
conversationViewModel.removeParticipant(address: participantConversationModel.address)
|
||||
} label: {
|
||||
HStack {
|
||||
Text("conversation_info_admin_menu_remove_participant")
|
||||
Spacer()
|
||||
Image("trash-simple-red")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Image("dots-three-vertical")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 15)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
|
||||
if conversationViewModel.isUserAdmin {
|
||||
NavigationLink(destination: {
|
||||
AddParticipantsFragment(addParticipantsViewModel: addParticipantsViewModel, confirmAddParticipantsFunc: conversationViewModel.addParticipants)
|
||||
.onAppear {
|
||||
conversationViewModel.getParticipants()
|
||||
addParticipantsViewModel.participantsToAdd = conversationViewModel.participants
|
||||
}
|
||||
}, label: {
|
||||
HStack {
|
||||
Image("plus-circle")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 20, height: 20)
|
||||
|
||||
Text("conversation_info_add_participants_label")
|
||||
.default_text_style_orange_500(styleSize: 14)
|
||||
.frame(height: 35)
|
||||
}
|
||||
|
||||
})
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 5)
|
||||
.background(Color.orangeMain100)
|
||||
.cornerRadius(60)
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 20)
|
||||
|
||||
/*
|
||||
Button(
|
||||
action: {
|
||||
},
|
||||
|
|
@ -319,6 +457,7 @@ struct ConversationInfoFragment: View {
|
|||
.cornerRadius(60)
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 20)
|
||||
*/
|
||||
}
|
||||
}
|
||||
.background(.white)
|
||||
|
|
@ -513,6 +652,7 @@ struct ConversationInfoFragment: View {
|
|||
conversationsListViewModel: ConversationsListViewModel(),
|
||||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
addParticipantsViewModel: AddParticipantsViewModel(),
|
||||
isMuted: .constant(false),
|
||||
isShowEphemeralFragment: .constant(false),
|
||||
isShowStartCallGroupPopup: .constant(false),
|
||||
|
|
@ -521,3 +661,4 @@ struct ConversationInfoFragment: View {
|
|||
indexPage: .constant(0)
|
||||
)
|
||||
}
|
||||
// swiftlint:enable type_body_length
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ import AVFoundation
|
|||
|
||||
class ConversationViewModel: ObservableObject {
|
||||
|
||||
static let TAG = "[ConversationViewModel]"
|
||||
|
||||
private var coreContext = CoreContext.shared
|
||||
|
||||
@Published var displayedConversation: ConversationModel?
|
||||
|
|
@ -79,8 +81,10 @@ class ConversationViewModel: ObservableObject {
|
|||
|
||||
@Published var conversationMessagesSection: [MessagesSection] = []
|
||||
@Published var participantConversationModel: [ContactAvatarModel] = []
|
||||
@Published var participantConversationModelAdmin: ContactAvatarModel?
|
||||
@Published var participantConversationModelAdmin: [ContactAvatarModel] = []
|
||||
@Published var myParticipantConversationModel: ContactAvatarModel? = nil
|
||||
@Published var isUserAdmin: Bool = false
|
||||
@Published var participants: [SelectedAddressModel] = []
|
||||
|
||||
@Published var mediasToSend: [Attachment] = []
|
||||
var maxMediaCount = 12
|
||||
|
|
@ -125,10 +129,13 @@ class ConversationViewModel: ObservableObject {
|
|||
self.getNewMessages(eventLogs: [eventLog])
|
||||
}, onParticipantAdded: { (_: ChatRoom, eventLogs: EventLog) in
|
||||
self.getNewMessages(eventLogs: [eventLogs])
|
||||
self.getParticipantConversationModel()
|
||||
}, onParticipantRemoved: { (_: ChatRoom, eventLogs: EventLog) in
|
||||
self.getNewMessages(eventLogs: [eventLogs])
|
||||
self.getParticipantConversationModel()
|
||||
}, onParticipantAdminStatusChanged: { (_: ChatRoom, eventLogs: EventLog) in
|
||||
self.getNewMessages(eventLogs: [eventLogs])
|
||||
self.getParticipantConversationModel()
|
||||
}, onSubjectChanged: { (_: ChatRoom, eventLogs: EventLog) in
|
||||
self.getNewMessages(eventLogs: [eventLogs])
|
||||
}, onConferenceJoined: {(_: ChatRoom, eventLog: EventLog) in
|
||||
|
|
@ -317,7 +324,7 @@ class ConversationViewModel: ObservableObject {
|
|||
if self.displayedConversation != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.isUserAdmin = false
|
||||
self.participantConversationModelAdmin = nil
|
||||
self.participantConversationModelAdmin.removeAll()
|
||||
self.participantConversationModel.removeAll()
|
||||
}
|
||||
self.displayedConversation!.chatRoom.participants.forEach { participant in
|
||||
|
|
@ -326,7 +333,7 @@ class ConversationViewModel: ObservableObject {
|
|||
let avatarModelTmp = avatarResult
|
||||
if participant.isAdmin {
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModelAdmin = avatarModelTmp
|
||||
self.participantConversationModelAdmin.append(avatarModelTmp)
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -344,12 +351,14 @@ class ConversationViewModel: ObservableObject {
|
|||
if self.displayedConversation!.chatRoom.me!.isAdmin {
|
||||
DispatchQueue.main.async {
|
||||
self.isUserAdmin = true
|
||||
self.participantConversationModelAdmin = avatarModelTmp
|
||||
self.participantConversationModelAdmin.append(avatarModelTmp)
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
self.myParticipantConversationModel = avatarModelTmp
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
self.myParticipantConversationModel = avatarModelTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2076,24 +2085,6 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func setNewChatRoomSubject() {
|
||||
if self.displayedConversation != nil && self.conversationInfoPopupText != self.displayedConversation!.subject {
|
||||
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
self.displayedConversation!.chatRoom.subject = self.conversationInfoPopupText
|
||||
}
|
||||
|
||||
self.displayedConversation!.subject = self.conversationInfoPopupText
|
||||
self.displayedConversation!.avatarModel = ContactAvatarModel(
|
||||
friend: self.displayedConversation!.avatarModel.friend,
|
||||
name: self.conversationInfoPopupText,
|
||||
address: self.displayedConversation!.avatarModel.address,
|
||||
withPresence: false
|
||||
)
|
||||
self.isShowConversationInfoPopup = false
|
||||
}
|
||||
}
|
||||
|
||||
func getEphemeralTime() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.displayedConversation != nil {
|
||||
|
|
@ -2124,6 +2115,111 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setNewChatRoomSubject() {
|
||||
if self.displayedConversation != nil && self.conversationInfoPopupText != self.displayedConversation!.subject {
|
||||
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
self.displayedConversation!.chatRoom.subject = self.conversationInfoPopupText
|
||||
}
|
||||
|
||||
self.displayedConversation!.subject = self.conversationInfoPopupText
|
||||
self.displayedConversation!.avatarModel = ContactAvatarModel(
|
||||
friend: self.displayedConversation!.avatarModel.friend,
|
||||
name: self.conversationInfoPopupText,
|
||||
address: self.displayedConversation!.avatarModel.address,
|
||||
withPresence: false
|
||||
)
|
||||
self.isShowConversationInfoPopup = false
|
||||
}
|
||||
}
|
||||
|
||||
func getParticipants() {
|
||||
self.participants = []
|
||||
var list: [SelectedAddressModel] = []
|
||||
for participant in participantConversationModel {
|
||||
let addr = try? Factory.Instance.createAddress(addr: participant.address)
|
||||
if addr != nil {
|
||||
if let found = list.first(where: { $0.address.weakEqual(address2: addr!) }) {
|
||||
Log.info("\(ConversationViewModel.TAG) Participant \(found.address.asStringUriOnly()) already in list, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
if self.displayedConversation!.chatRoom.me != nil && self.displayedConversation!.chatRoom.me!.address != nil && !self.displayedConversation!.chatRoom.me!.address!.weakEqual(address2: addr!) {
|
||||
list.append(SelectedAddressModel(addr: addr!, avModel: participant))
|
||||
Log.info("\(ConversationViewModel.TAG) Added participant \(addr!.asStringUriOnly())")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.participants = list
|
||||
|
||||
Log.info("\(ConversationViewModel.TAG) \(list.count) participants added to chat room")
|
||||
}
|
||||
|
||||
func addParticipants(participantsToAdd: [SelectedAddressModel]) {
|
||||
var list: [SelectedAddressModel] = []
|
||||
for selectedAddr in participantsToAdd {
|
||||
if let found = list.first(where: { $0.address.weakEqual(address2: selectedAddr.address) }) {
|
||||
Log.info("\(ConversationViewModel.TAG) Participant \(found.address.asStringUriOnly()) already in list, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
list.append(selectedAddr)
|
||||
Log.info("\(ConversationViewModel.TAG) Added participant \(selectedAddr.address.asStringUriOnly())")
|
||||
}
|
||||
|
||||
let participantsAddress = self.displayedConversation!.chatRoom.participants.map { $0.address?.asStringUriOnly() }
|
||||
let listAddress = list.map { $0.address.asStringUriOnly() }
|
||||
|
||||
let differences = participantsAddress.difference(from: listAddress)
|
||||
|
||||
if !differences.isEmpty {
|
||||
let differenceAddresses = differences.compactMap { change -> String? in
|
||||
switch change {
|
||||
case .insert(_, let element, _), .remove(_, let element, _):
|
||||
return element
|
||||
}
|
||||
}
|
||||
|
||||
let filteredParticipants = self.displayedConversation!.chatRoom.participants.filter { participant in
|
||||
differenceAddresses.contains(participant.address!.asStringUriOnly())
|
||||
}
|
||||
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
_ = self.displayedConversation!.chatRoom.addParticipants(addresses: list.map { $0.address })
|
||||
self.displayedConversation!.chatRoom.removeParticipants(participants: filteredParticipants)
|
||||
}
|
||||
} else {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
_ = self.displayedConversation!.chatRoom.addParticipants(addresses: list.map { $0.address })
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("\(ConversationViewModel.TAG) \(list.count) participants added to chat room")
|
||||
}
|
||||
|
||||
func toggleAdminRights(address: String) {
|
||||
if self.displayedConversation != nil {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if let participant = self.displayedConversation!.chatRoom.participants.first(where: {$0.address?.asStringUriOnly() == address}) {
|
||||
self.displayedConversation!.chatRoom.setParticipantAdminStatus(participant: participant, isAdmin: !participant.isAdmin)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeParticipant(address: String) {
|
||||
if self.displayedConversation != nil {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if let participant = self.displayedConversation!.chatRoom.participants.first(where: {$0.address?.asStringUriOnly() == address}) {
|
||||
self.displayedConversation!.chatRoom.removeParticipant(participant: participant)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable line_length
|
||||
// swiftlint:enable type_body_length
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue