mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-04-17 11:48:27 +00:00
Add media and document lists to the contact detail view
This commit is contained in:
parent
75e96ed8a5
commit
bfb4ac3c22
10 changed files with 220 additions and 7 deletions
|
|
@ -2,6 +2,6 @@ import Foundation
|
|||
|
||||
public enum AppGitInfo {
|
||||
public static let branch = "master"
|
||||
public static let commit = "9cc8923e3"
|
||||
public static let commit = "75e96ed8a"
|
||||
public static let tag = "6.1.0-alpha"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ import linphonesw
|
|||
// swiftlint:disable type_body_length
|
||||
struct ContactInnerActionsFragment: View {
|
||||
|
||||
@ObservedObject var contactsManager = ContactsManager.shared
|
||||
@ObservedObject private var telecomManager = TelecomManager.shared
|
||||
@ObservedObject private var contactsManager = ContactsManager.shared
|
||||
@ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared
|
||||
|
||||
@EnvironmentObject var contactAvatarModel: ContactAvatarModel
|
||||
@EnvironmentObject var contactsListViewModel: ContactsListViewModel
|
||||
|
|
@ -37,6 +38,8 @@ struct ContactInnerActionsFragment: View {
|
|||
@Binding var isShowDeletePopup: Bool
|
||||
@Binding var isShowDismissPopup: Bool
|
||||
@Binding var isShowTrustLevelPopup: Bool
|
||||
@Binding var isShowMediaFilesFragment: Bool
|
||||
@Binding var isShowDocumentsFilesFragment: Bool
|
||||
@Binding var isShowIncreaseTrustLevelPopup: Bool
|
||||
@Binding var isShowEditContactFragmentInContactDetails: Bool
|
||||
|
||||
|
|
@ -386,6 +389,87 @@ struct ContactInnerActionsFragment: View {
|
|||
.transition(.move(edge: .top))
|
||||
}
|
||||
|
||||
if sharedMainViewModel.displayedFriendExistingChatRoom != nil {
|
||||
HStack(alignment: .center) {
|
||||
Text("conversation_details_media_documents_title")
|
||||
.default_text_style_800(styleSize: 16)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image("caret-up")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.hidden()
|
||||
}
|
||||
.padding(.top, 20)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.horizontal, 16)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Button {
|
||||
withAnimation {
|
||||
isShowMediaFilesFragment = true
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("image")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
.padding(.all, 10)
|
||||
|
||||
Text("conversation_menu_media_files")
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical, 15)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
Button {
|
||||
withAnimation {
|
||||
isShowDocumentsFilesFragment = true
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("file-pdf")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
.padding(.all, 10)
|
||||
|
||||
Text("conversation_menu_documents_files")
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical, 15)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
.background(.white)
|
||||
.cornerRadius(15)
|
||||
.padding(.horizontal)
|
||||
.zIndex(-1)
|
||||
.transition(.move(edge: .top))
|
||||
}
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Text("contact_details_actions_title")
|
||||
.default_text_style_800(styleSize: 16)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ struct ContactInnerFragment: View {
|
|||
|
||||
@State var cnContact: CNContact?
|
||||
@State private var presentingEditContact = false
|
||||
@State private var isShowMediaFilesFragment = false
|
||||
@State private var isShowDocumentsFilesFragment = false
|
||||
|
||||
@Binding var isShowDeletePopup: Bool
|
||||
@Binding var showingSheet: Bool
|
||||
|
|
@ -280,6 +282,8 @@ struct ContactInnerFragment: View {
|
|||
isShowDeletePopup: $isShowDeletePopup,
|
||||
isShowDismissPopup: $isShowDismissPopup,
|
||||
isShowTrustLevelPopup: $isShowTrustLevelPopup,
|
||||
isShowMediaFilesFragment: $isShowMediaFilesFragment,
|
||||
isShowDocumentsFilesFragment: $isShowDocumentsFilesFragment,
|
||||
isShowIncreaseTrustLevelPopup: $isShowIncreaseTrustLevelPopup,
|
||||
isShowEditContactFragmentInContactDetails: $isShowEditContactFragmentInContactDetails,
|
||||
geometry: geometry,
|
||||
|
|
@ -287,9 +291,18 @@ struct ContactInnerFragment: View {
|
|||
)
|
||||
.onAppear {
|
||||
contactsListViewModel.fetchDevicesAndTrust()
|
||||
contactsListViewModel.getOneToOneChatRoomWith()
|
||||
}
|
||||
.onChange(of: SharedMainViewModel.shared.displayedFriend?.id) { _ in
|
||||
isShowMediaFilesFragment = false
|
||||
isShowDocumentsFilesFragment = false
|
||||
SharedMainViewModel.shared.displayedFriendExistingChatRoom = nil
|
||||
|
||||
contactsListViewModel.fetchDevicesAndTrust()
|
||||
contactsListViewModel.getOneToOneChatRoomWith()
|
||||
}
|
||||
.onDisappear {
|
||||
SharedMainViewModel.shared.displayedFriendExistingChatRoom = nil
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: SharedMainViewModel.shared.maxWidth)
|
||||
|
|
@ -311,6 +324,22 @@ struct ContactInnerFragment: View {
|
|||
.edgesIgnoringSafeArea(.vertical)
|
||||
}
|
||||
}
|
||||
|
||||
if isShowMediaFilesFragment {
|
||||
ConversationMediaListFragment(
|
||||
isShowMediaFilesFragment: $isShowMediaFilesFragment
|
||||
)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
|
||||
if isShowDocumentsFilesFragment {
|
||||
ConversationDocumentsListFragment(
|
||||
isShowDocumentsFilesFragment: $isShowDocumentsFilesFragment
|
||||
)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,5 +337,102 @@ class ContactsListViewModel: ObservableObject {
|
|||
devices = devicesList
|
||||
}
|
||||
}
|
||||
|
||||
func getOneToOneChatRoomWith() {
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
if let contactAvatarModel = SharedMainViewModel.shared.displayedFriend {
|
||||
var remote: Address?
|
||||
|
||||
if contactAvatarModel.addresses.count == 1 {
|
||||
do {
|
||||
remote = try Factory.Instance.createAddress(addr: contactAvatarModel.address)
|
||||
} catch {
|
||||
Log.error("\(Self.TAG) unable to create address for a new outgoing call : \(contactAvatarModel.address) \(error)")
|
||||
return
|
||||
}
|
||||
} else if contactAvatarModel.addresses.isEmpty &&
|
||||
contactAvatarModel.phoneNumbersWithLabel.count == 1 {
|
||||
|
||||
if let firstPhone = contactAvatarModel.phoneNumbersWithLabel.first,
|
||||
let address = core.interpretUrl(
|
||||
url: firstPhone.phoneNumber,
|
||||
applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)
|
||||
) {
|
||||
remote = address
|
||||
}
|
||||
}
|
||||
|
||||
guard let remote else {
|
||||
Log.error("\(Self.TAG) No valid remote address found")
|
||||
return
|
||||
}
|
||||
|
||||
let account = core.defaultAccount
|
||||
if account == nil {
|
||||
Log.error(
|
||||
"\(Self.TAG) No default account found, can't create conversation with \(remote.asStringUriOnly())"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let params = try core.createConferenceParams(conference: nil)
|
||||
params.chatEnabled = true
|
||||
params.groupEnabled = false
|
||||
params.subject = NSLocalizedString("conversation_one_to_one_hidden_subject", comment: "")
|
||||
params.account = account
|
||||
|
||||
guard let chatParams = params.chatParams else { return }
|
||||
chatParams.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default
|
||||
|
||||
let sameDomain = remote.domain == AppServices.corePreferences.defaultDomain && remote.domain == account!.params?.domain
|
||||
if account!.params != nil && (account!.params!.instantMessagingEncryptionMandatory && sameDomain) {
|
||||
Log.info("\(ConversationForwardMessageViewModel.TAG) Account is in secure mode & domain matches, creating an E2E encrypted conversation")
|
||||
chatParams.backend = ChatRoom.Backend.FlexisipChat
|
||||
params.securityLevel = Conference.SecurityLevel.EndToEnd
|
||||
} else if account!.params != nil && (!account!.params!.instantMessagingEncryptionMandatory) {
|
||||
if LinphoneUtils.isEndToEndEncryptedChatAvailable(core: core) {
|
||||
Log.info(
|
||||
"\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME is available, creating an E2E encrypted conversation"
|
||||
)
|
||||
chatParams.backend = ChatRoom.Backend.FlexisipChat
|
||||
params.securityLevel = Conference.SecurityLevel.EndToEnd
|
||||
} else {
|
||||
Log.info(
|
||||
"\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME isn't available, creating a SIP simple conversation"
|
||||
)
|
||||
chatParams.backend = ChatRoom.Backend.Basic
|
||||
params.securityLevel = Conference.SecurityLevel.None
|
||||
}
|
||||
} else {
|
||||
Log.error(
|
||||
"\(ConversationForwardMessageViewModel.TAG) Account is in secure mode, can't chat with SIP address of different domain \(remote.asStringUriOnly())"
|
||||
)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
SharedMainViewModel.shared.operationInProgress = false
|
||||
ToastViewModel.shared.show("Failed_to_create_conversation_error")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let participants = [remote]
|
||||
let localAddress = account?.params?.identityAddress
|
||||
if let existingChatRoomTmp = core.searchChatRoom(params: params, localAddr: localAddress, remoteAddr: nil, participants: participants) {
|
||||
Log.warn(
|
||||
"\(ConversationForwardMessageViewModel.TAG) A 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) for given parameters already exists!"
|
||||
)
|
||||
|
||||
let conversationModel = ConversationModel(chatRoom: existingChatRoomTmp)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
SharedMainViewModel.shared.displayedFriendExistingChatRoom = conversationModel
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable line_length
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import SwiftUI
|
|||
import linphonesw
|
||||
|
||||
struct ConversationDocumentsListFragment: View {
|
||||
@EnvironmentObject var conversationViewModel: ConversationViewModel
|
||||
|
||||
@StateObject private var conversationDocumentsListViewModel = ConversationDocumentsListViewModel()
|
||||
|
||||
|
|
|
|||
|
|
@ -1603,7 +1603,6 @@ struct ConversationFragment: View {
|
|||
ConversationMediaListFragment(
|
||||
isShowMediaFilesFragment: $isShowMediaFilesFragment
|
||||
)
|
||||
.environmentObject(conversationViewModel)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
|
|
@ -1612,7 +1611,6 @@ struct ConversationFragment: View {
|
|||
ConversationDocumentsListFragment(
|
||||
isShowDocumentsFilesFragment: $isShowDocumentsFilesFragment
|
||||
)
|
||||
.environmentObject(conversationViewModel)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import SwiftUI
|
|||
import linphonesw
|
||||
|
||||
struct ConversationMediaListFragment: View {
|
||||
@EnvironmentObject var conversationViewModel: ConversationViewModel
|
||||
|
||||
@StateObject private var conversationMediaListViewModel = ConversationMediaListViewModel()
|
||||
|
||||
@Binding var isShowMediaFilesFragment: Bool
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ final class ConversationDocumentsListViewModel: ObservableObject {
|
|||
if let conversationModelTmp = SharedMainViewModel.shared.displayedConversation {
|
||||
self.conversationModel = conversationModelTmp
|
||||
loadDocumentsList()
|
||||
} else if let conversationModelTmp = SharedMainViewModel.shared.displayedFriendExistingChatRoom {
|
||||
self.conversationModel = conversationModelTmp
|
||||
loadDocumentsList()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ final class ConversationMediaListViewModel: ObservableObject {
|
|||
if let conversationModelTmp = SharedMainViewModel.shared.displayedConversation {
|
||||
self.conversationModel = conversationModelTmp
|
||||
loadMediaList()
|
||||
} else if let conversationModelTmp = SharedMainViewModel.shared.displayedFriendExistingChatRoom {
|
||||
self.conversationModel = conversationModelTmp
|
||||
loadMediaList()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ class SharedMainViewModel: ObservableObject {
|
|||
@Published var displayedConversation: ConversationModel?
|
||||
@Published var displayedMeeting: MeetingModel?
|
||||
|
||||
@Published var displayedFriendExistingChatRoom: ConversationModel?
|
||||
|
||||
@Published var dialPlansList: [DialPlan?] = []
|
||||
@Published var dialPlansLabelList: [String] = []
|
||||
@Published var dialPlansShortLabelList: [String] = []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue