mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Add participant list in conversation info fragment
This commit is contained in:
parent
75588af0e2
commit
a839c7d643
8 changed files with 304 additions and 30 deletions
|
|
@ -1466,6 +1466,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_add_participants_label" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Add participants"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ajouter des membres"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_confirm_start_group_call_dialog_message" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
@ -1517,6 +1534,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_menu_add_to_contacts" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Add to contacts"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ajouter aux contacts"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_menu_go_to_contact" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
@ -1534,6 +1568,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_participant_is_admin_label" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Admin"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Administrateur"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_participants_list_title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Group members"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Membres du groupe"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_invalid_participant_due_to_security_mode_toast" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ struct CallView: View {
|
|||
@ObservedObject var conversationViewModel: ConversationViewModel
|
||||
@ObservedObject var conversationsListViewModel: ConversationsListViewModel
|
||||
@ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel
|
||||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
|
||||
@State private var addParticipantsViewModel: AddParticipantsViewModel?
|
||||
|
||||
|
|
@ -71,6 +73,9 @@ struct CallView: View {
|
|||
|
||||
@State var buttonSize = 60.0
|
||||
|
||||
@Binding var isShowEditContactFragment: Bool
|
||||
@Binding var indexPage: Int
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
ZStack {
|
||||
|
|
@ -200,8 +205,12 @@ struct CallView: View {
|
|||
conversationViewModel: conversationViewModel,
|
||||
conversationsListViewModel: conversationsListViewModel,
|
||||
conversationForwardMessageViewModel: conversationForwardMessageViewModel,
|
||||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
indexPage: $indexPage
|
||||
)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.gray100)
|
||||
|
|
@ -2825,10 +2834,14 @@ struct PressedButtonStyle: ButtonStyle {
|
|||
conversationViewModel: ConversationViewModel(),
|
||||
conversationsListViewModel: ConversationsListViewModel(),
|
||||
conversationForwardMessageViewModel: ConversationForwardMessageViewModel(),
|
||||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
fullscreenVideo: .constant(false),
|
||||
isShowStartCallFragment: .constant(false),
|
||||
isShowConversationFragment: .constant(false),
|
||||
isShowStartCallGroupPopup: .constant(false)
|
||||
isShowStartCallGroupPopup: .constant(false),
|
||||
isShowEditContactFragment: .constant(false),
|
||||
indexPage: .constant(0)
|
||||
)
|
||||
}
|
||||
// swiftlint:enable type_body_length
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import Foundation
|
|||
import linphonesw
|
||||
import Combine
|
||||
|
||||
class ContactAvatarModel: ObservableObject {
|
||||
class ContactAvatarModel: ObservableObject, Identifiable {
|
||||
|
||||
let friend: Friend?
|
||||
|
||||
|
|
|
|||
|
|
@ -862,8 +862,12 @@ struct ContentView: View {
|
|||
conversationViewModel: conversationViewModel,
|
||||
conversationsListViewModel: conversationsListViewModel,
|
||||
conversationForwardMessageViewModel: conversationForwardMessageViewModel,
|
||||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
indexPage: $index
|
||||
)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.gray100)
|
||||
|
|
@ -1200,10 +1204,14 @@ struct ContentView: View {
|
|||
conversationViewModel: conversationViewModel,
|
||||
conversationsListViewModel: conversationsListViewModel,
|
||||
conversationForwardMessageViewModel: conversationForwardMessageViewModel,
|
||||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
fullscreenVideo: $fullscreenVideo,
|
||||
isShowStartCallFragment: $isShowStartCallFragment,
|
||||
isShowConversationFragment: $isShowConversationFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
indexPage: $index
|
||||
)
|
||||
.zIndex(5)
|
||||
.transition(.scale.combined(with: .move(edge: .top)))
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ struct ConversationFragment: View {
|
|||
@ObservedObject var conversationViewModel: ConversationViewModel
|
||||
@ObservedObject var conversationsListViewModel: ConversationsListViewModel
|
||||
@ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel
|
||||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
|
||||
@State var isMenuOpen = false
|
||||
@State private var isMuted: Bool = false
|
||||
|
|
@ -63,6 +65,9 @@ struct ConversationFragment: View {
|
|||
|
||||
@State private var selectedCategoryIndex = 0
|
||||
|
||||
@Binding var isShowEditContactFragment: Bool
|
||||
@Binding var indexPage: Int
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
GeometryReader { geometry in
|
||||
|
|
@ -977,10 +982,14 @@ struct ConversationFragment: View {
|
|||
ConversationInfoFragment(
|
||||
conversationViewModel: conversationViewModel,
|
||||
conversationsListViewModel: conversationsListViewModel,
|
||||
contactViewModel: contactViewModel,
|
||||
editContactViewModel: editContactViewModel,
|
||||
isMuted: $isMuted,
|
||||
isShowEphemeralFragment: $isShowEphemeralFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowInfoConversationFragment: $isShowInfoConversationFragment
|
||||
isShowInfoConversationFragment: $isShowInfoConversationFragment,
|
||||
isShowEditContactFragment: $isShowEditContactFragment,
|
||||
indexPage: $indexPage
|
||||
)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
|
|
|
|||
|
|
@ -22,15 +22,22 @@ import SwiftUI
|
|||
struct ConversationInfoFragment: View {
|
||||
@State private var orientation = UIDevice.current.orientation
|
||||
|
||||
@ObservedObject var contactsManager = ContactsManager.shared
|
||||
@ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared
|
||||
|
||||
@ObservedObject var conversationViewModel: ConversationViewModel
|
||||
@ObservedObject var conversationsListViewModel: ConversationsListViewModel
|
||||
@ObservedObject var contactViewModel: ContactViewModel
|
||||
@ObservedObject var editContactViewModel: EditContactViewModel
|
||||
|
||||
@Binding var isMuted: Bool
|
||||
@Binding var isShowEphemeralFragment: Bool
|
||||
@Binding var isShowStartCallGroupPopup: Bool
|
||||
@Binding var isShowInfoConversationFragment: Bool
|
||||
@Binding var isShowEditContactFragment: Bool
|
||||
@Binding var indexPage: Int
|
||||
|
||||
@State private var participantListIsOpen = true
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
|
|
@ -87,7 +94,7 @@ struct ConversationInfoFragment: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
.padding(.top, 10)
|
||||
|
||||
Text(conversationViewModel.displayedConversation!.avatarModel.address)
|
||||
Text(conversationViewModel.participantConversationModel.first?.address ?? "")
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style(styleSize: 14)
|
||||
|
|
@ -115,12 +122,29 @@ struct ConversationInfoFragment: View {
|
|||
Avatar(contactAvatarModel: conversationViewModel.displayedConversation!.avatarModel, avatarSize: 100)
|
||||
.padding(.top, 4)
|
||||
|
||||
Text(conversationViewModel.displayedConversation!.avatarModel.name)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.top, 10)
|
||||
HStack {
|
||||
Text(conversationViewModel.displayedConversation!.avatarModel.name)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style(styleSize: 14)
|
||||
.padding(.top, 10)
|
||||
|
||||
if conversationViewModel.isUserAdmin {
|
||||
Button(
|
||||
action: {
|
||||
},
|
||||
label: {
|
||||
Image("pencil-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 20, height: 20)
|
||||
}
|
||||
)
|
||||
.padding(.top, 10)
|
||||
}
|
||||
}
|
||||
.padding(.leading, conversationViewModel.isUserAdmin ? 20 : 0)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 150)
|
||||
|
|
@ -219,6 +243,91 @@ struct ConversationInfoFragment: View {
|
|||
.background(Color.gray100)
|
||||
}
|
||||
|
||||
if conversationViewModel.displayedConversation!.isGroup {
|
||||
HStack(alignment: .center) {
|
||||
Text("conversation_info_participants_list_title")
|
||||
.default_text_style_800(styleSize: 18)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(participantListIsOpen ? "caret-up" : "caret-down")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
}
|
||||
.padding(.top, 30)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.horizontal, 20)
|
||||
.background(Color.gray100)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
participantListIsOpen.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
if participantListIsOpen {
|
||||
VStack(spacing: 0) {
|
||||
ForEach(conversationViewModel.participantConversationModel) { participantConversationModel in
|
||||
HStack {
|
||||
Avatar(contactAvatarModel: participantConversationModel, avatarSize: 50)
|
||||
|
||||
VStack {
|
||||
Text(participantConversationModel.name)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
if conversationViewModel.participantConversationModelAdmin != nil && participantConversationModel.address == conversationViewModel.participantConversationModelAdmin!.address {
|
||||
Text("conversation_info_participant_is_admin_label")
|
||||
.foregroundStyle(Color.grayMain2c400)
|
||||
.default_text_style(styleSize: 12)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 15)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
|
||||
if conversationViewModel.isUserAdmin {
|
||||
Button(
|
||||
action: {
|
||||
},
|
||||
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)
|
||||
}
|
||||
}
|
||||
.background(.white)
|
||||
.cornerRadius(15)
|
||||
.padding(.horizontal)
|
||||
.zIndex(-1)
|
||||
.transition(.move(edge: .top))
|
||||
}
|
||||
}
|
||||
|
||||
Text("contact_details_actions_title")
|
||||
.default_text_style_800(styleSize: 18)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
|
@ -230,20 +339,60 @@ struct ConversationInfoFragment: View {
|
|||
if !conversationViewModel.displayedConversation!.isGroup {
|
||||
Button(
|
||||
action: {
|
||||
if conversationViewModel.displayedConversation != nil {
|
||||
|
||||
let addressConv = conversationViewModel.participantConversationModel.first?.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(conversationViewModel.participantConversationModel.first?.address.dropFirst(4) ?? ""))
|
||||
editContactViewModel.sipAddresses.append("")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
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)
|
||||
let addressConv = conversationViewModel.participantConversationModel.first?.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -361,9 +510,13 @@ struct ConversationInfoFragment: View {
|
|||
ConversationInfoFragment(
|
||||
conversationViewModel: ConversationViewModel(),
|
||||
conversationsListViewModel: ConversationsListViewModel(),
|
||||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
isMuted: .constant(false),
|
||||
isShowEphemeralFragment: .constant(false),
|
||||
isShowStartCallGroupPopup: .constant(false),
|
||||
isShowInfoConversationFragment: .constant(true)
|
||||
isShowInfoConversationFragment: .constant(true),
|
||||
isShowEditContactFragment: .constant(false),
|
||||
indexPage: .constant(0)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ class ConversationViewModel: ObservableObject {
|
|||
|
||||
@Published var conversationMessagesSection: [MessagesSection] = []
|
||||
@Published var participantConversationModel: [ContactAvatarModel] = []
|
||||
@Published var participantConversationModelAdmin: ContactAvatarModel?
|
||||
@Published var isUserAdmin: Bool = false
|
||||
|
||||
@Published var mediasToSend: [Attachment] = []
|
||||
var maxMediaCount = 12
|
||||
|
|
@ -310,12 +312,24 @@ class ConversationViewModel: ObservableObject {
|
|||
func getParticipantConversationModel() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.displayedConversation != nil {
|
||||
DispatchQueue.main.async {
|
||||
self.isUserAdmin = false
|
||||
self.participantConversationModelAdmin = nil
|
||||
self.participantConversationModel.removeAll()
|
||||
}
|
||||
self.displayedConversation!.chatRoom.participants.forEach { participant in
|
||||
if participant.address != nil {
|
||||
ContactAvatarModel.getAvatarModelFromAddress(address: participant.address!) { avatarResult in
|
||||
let avatarModelTmp = avatarResult
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
if participant.isAdmin {
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModelAdmin = avatarModelTmp
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -324,8 +338,16 @@ class ConversationViewModel: ObservableObject {
|
|||
if self.displayedConversation!.chatRoom.me != nil {
|
||||
ContactAvatarModel.getAvatarModelFromAddress(address: self.displayedConversation!.chatRoom.me!.address!) { avatarResult in
|
||||
let avatarModelTmp = avatarResult
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
if self.displayedConversation!.chatRoom.me!.isAdmin {
|
||||
DispatchQueue.main.async {
|
||||
self.isUserAdmin = true
|
||||
self.participantConversationModelAdmin = avatarModelTmp
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -338,7 +360,9 @@ class ConversationViewModel: ObservableObject {
|
|||
ContactAvatarModel.getAvatarModelFromAddress(address: address) { avatarResult in
|
||||
let avatarModelTmp = avatarResult
|
||||
DispatchQueue.main.async {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
if self.participantConversationModel.first(where: {$0.address == avatarModelTmp.address}) == nil {
|
||||
self.participantConversationModel.append(avatarModelTmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ struct HistoryContactFragment: View {
|
|||
let friendIndex = contactsManager.lastSearch.firstIndex(
|
||||
where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressCall!.asStringUriOnly()})})
|
||||
if friendIndex != nil {
|
||||
|
||||
withAnimation {
|
||||
historyViewModel.displayedCall = nil
|
||||
indexPage = 0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue