mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Replace ChatRoom class with ConversationModel to update conversation views
This commit is contained in:
parent
4196fed865
commit
be09968a31
18 changed files with 520 additions and 369 deletions
|
|
@ -16,6 +16,7 @@
|
|||
66C491FF2B24D4AC00CEA16D /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */; };
|
||||
66C492012B24DB6900CEA16D /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C492002B24DB6900CEA16D /* Log.swift */; };
|
||||
D706BA822ADD72D100278F45 /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */; };
|
||||
D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */; };
|
||||
D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */; };
|
||||
D70A26F02B7D02E6006CC8FC /* ConversationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26EF2B7D02E6006CC8FC /* ConversationViewModel.swift */; };
|
||||
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26F12B7F5D95006CC8FC /* ConversationFragment.swift */; };
|
||||
|
|
@ -118,6 +119,7 @@
|
|||
66C491FE2B24D4AC00CEA16D /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
66C492002B24DB6900CEA16D /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
|
||||
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = "<group>"; };
|
||||
D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsListBottomSheet.swift; sourceTree = "<group>"; };
|
||||
D70A26EF2B7D02E6006CC8FC /* ConversationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationViewModel.swift; sourceTree = "<group>"; };
|
||||
D70A26F12B7F5D95006CC8FC /* ConversationFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationFragment.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -252,6 +254,14 @@
|
|||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D70959EF2B8DF33B0014AC0B /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D717071C2AC591EF0037746F /* Utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -542,6 +552,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D7CEE0392B7A232200FD79B7 /* Fragments */,
|
||||
D70959EF2B8DF33B0014AC0B /* Model */,
|
||||
D7CEE0362B7A212C00FD79B7 /* ViewModel */,
|
||||
D7CEE0342B7A210300FD79B7 /* ConversationsView.swift */,
|
||||
);
|
||||
|
|
@ -743,6 +754,7 @@
|
|||
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */,
|
||||
D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */,
|
||||
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */,
|
||||
D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */,
|
||||
D7EAACCF2AD6ED8000AA6A8A /* PermissionsFragment.swift in Sources */,
|
||||
D777DBB32AE12C5900565A99 /* ContactsManager.swift in Sources */,
|
||||
D796F2002B0BB61A0041115F /* ToastViewModel.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ struct CallView: View {
|
|||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: "", withPresence: false)
|
||||
|
||||
if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
|
||||
if contactAvatarModel != nil {
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ struct CallsListFragment: View {
|
|||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: "", withPresence: false)
|
||||
|
||||
if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
|
||||
if contactAvatarModel != nil {
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ struct ContactInnerFragment: View {
|
|||
|
||||
#Preview {
|
||||
ContactInnerFragment(
|
||||
contactAvatarModel: ContactAvatarModel(friend: nil, withPresence: true),
|
||||
contactAvatarModel: ContactAvatarModel(friend: nil, name: "", withPresence: true),
|
||||
contactViewModel: ContactViewModel(),
|
||||
editContactViewModel: EditContactViewModel(),
|
||||
isShowDeletePopup: .constant(false),
|
||||
|
|
|
|||
|
|
@ -154,7 +154,9 @@ struct EditContactFragment: View {
|
|||
&& editContactViewModel.selectedEditFriend!.photo != nil
|
||||
&& !editContactViewModel.selectedEditFriend!.photo!.isEmpty && selectedImage == nil && !removedImage {
|
||||
|
||||
Avatar(contactAvatarModel: ContactAvatarModel(friend: editContactViewModel.selectedEditFriend!, withPresence: false), avatarSize: 100)
|
||||
Avatar(contactAvatarModel:
|
||||
ContactAvatarModel(friend: editContactViewModel.selectedEditFriend!, name: editContactViewModel.selectedEditFriend?.name ?? "", withPresence: false), avatarSize: 100
|
||||
)
|
||||
|
||||
} else if selectedImage == nil {
|
||||
Image("profil-picture-default")
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ class ContactAvatarModel: ObservableObject {
|
|||
|
||||
let friend: Friend?
|
||||
|
||||
let name: String
|
||||
|
||||
let withPresence: Bool?
|
||||
|
||||
@Published var lastPresenceInfo: String
|
||||
|
|
@ -33,8 +35,9 @@ class ContactAvatarModel: ObservableObject {
|
|||
|
||||
private var friendSuscription: AnyCancellable?
|
||||
|
||||
init(friend: Friend?, withPresence: Bool?) {
|
||||
init(friend: Friend?, name: String, withPresence: Bool?) {
|
||||
self.friend = friend
|
||||
self.name = name
|
||||
self.withPresence = withPresence
|
||||
if friend != nil &&
|
||||
withPresence == true {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ struct ContentView: View {
|
|||
@State var isShowCallsListFragment = false
|
||||
|
||||
var body: some View {
|
||||
let pub = NotificationCenter.default
|
||||
.publisher(for: NSNotification.Name("ContactLoaded"))
|
||||
|
||||
GeometryReader { geometry in
|
||||
VStack(spacing: 0) {
|
||||
if telecomManager.callInProgress && !fullscreenVideo && ((!telecomManager.callDisplayed && callViewModel.calls.count == 1) || callViewModel.calls.count > 1) {
|
||||
|
|
@ -644,7 +647,7 @@ struct ContentView: View {
|
|||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: "", withPresence: false)
|
||||
|
||||
if contactAvatarModel != nil {
|
||||
HistoryContactFragment(
|
||||
|
|
@ -866,6 +869,12 @@ struct ContentView: View {
|
|||
.zIndex(3)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
|
||||
}
|
||||
.onReceive(pub) { _ in
|
||||
conversationsListViewModel.refreshContactAvatarModel()
|
||||
}
|
||||
}
|
||||
.overlay {
|
||||
if isMenuOpen {
|
||||
|
|
|
|||
|
|
@ -60,99 +60,14 @@ struct ConversationFragment: View {
|
|||
}
|
||||
}
|
||||
|
||||
let addressFriend =
|
||||
(conversationViewModel.displayedConversation!.participants.first != nil && conversationViewModel.displayedConversation!.participants.first!.address != nil)
|
||||
? contactsManager.getFriendWithAddress(address: conversationViewModel.displayedConversation!.participants.first!.address!)
|
||||
: nil
|
||||
|
||||
let contactAvatarModel = addressFriend != nil
|
||||
? ContactsManager.shared.avatarListModel.first(where: {
|
||||
($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
|
||||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
|
||||
if LinphoneUtils.isChatRoomAGroup(chatRoom: conversationViewModel.displayedConversation!) {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationViewModel.displayedConversation!.subject!,
|
||||
lastName: conversationViewModel.displayedConversation!.subject!.components(separatedBy: " ").count > 1
|
||||
? conversationViewModel.displayedConversation!.subject!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
Avatar(contactAvatarModel: conversationViewModel.displayedConversation!.avatarModel, avatarSize: 50)
|
||||
.padding(.top, 4)
|
||||
} else if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
|
||||
if contactAvatarModel != nil {
|
||||
Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 50)
|
||||
.padding(.top, 4)
|
||||
} else {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
.padding(.top, 4)
|
||||
}
|
||||
} else {
|
||||
if conversationViewModel.displayedConversation!.participants.first != nil
|
||||
&& conversationViewModel.displayedConversation!.participants.first!.address != nil {
|
||||
if conversationViewModel.displayedConversation!.participants.first!.address!.displayName != nil {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationViewModel.displayedConversation!.participants.first!.address!.displayName!,
|
||||
lastName: conversationViewModel.displayedConversation!.participants.first!.address!.displayName!.components(separatedBy: " ").count > 1
|
||||
? conversationViewModel.displayedConversation!.participants.first!.address!.displayName!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
.padding(.top, 4)
|
||||
|
||||
} else {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationViewModel.displayedConversation!.participants.first!.address!.username ?? "Username Error",
|
||||
lastName: conversationViewModel.displayedConversation!.participants.first!.address!.username!.components(separatedBy: " ").count > 1
|
||||
? conversationViewModel.displayedConversation!.participants.first!.address!.username!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
.padding(.top, 4)
|
||||
}
|
||||
|
||||
} else {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
.padding(.top, 4)
|
||||
}
|
||||
}
|
||||
|
||||
if LinphoneUtils.isChatRoomAGroup(chatRoom: conversationViewModel.displayedConversation!) {
|
||||
Text(conversationViewModel.displayedConversation!.subject ?? "No Subject")
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.top, 4)
|
||||
.lineLimit(1)
|
||||
} else if addressFriend != nil {
|
||||
Text(addressFriend!.name!)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.top, 4)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
if conversationViewModel.displayedConversation!.participants.first != nil
|
||||
&& conversationViewModel.displayedConversation!.participants.first!.address != nil {
|
||||
Text(conversationViewModel.displayedConversation!.participants.first!.address!.displayName != nil
|
||||
? conversationViewModel.displayedConversation!.participants.first!.address!.displayName!
|
||||
: conversationViewModel.displayedConversation!.participants.first!.address!.username!)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.top, 4)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
Text(conversationViewModel.displayedConversation!.subject)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.top, 4)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer()
|
||||
|
||||
|
|
@ -238,7 +153,7 @@ struct ConversationFragment: View {
|
|||
.scaleEffect(x: 1, y: -1, anchor: .center)
|
||||
.listRowInsets(EdgeInsets(top: 2, leading: 10, bottom: 2, trailing: 10))
|
||||
.listRowSeparator(.hidden)
|
||||
.transition(.move(edge: .top))
|
||||
.transition(.move(edge: .top))
|
||||
}
|
||||
}
|
||||
.scaleEffect(x: 1, y: -1, anchor: .center)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ struct ConversationsListBottomSheet: View {
|
|||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.objectWillChange.send()
|
||||
conversationsListViewModel.selectedConversation!.muted.toggle()
|
||||
conversationsListViewModel.selectedConversation!.toggleMute()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
|
|
@ -113,13 +113,13 @@ struct ConversationsListBottomSheet: View {
|
|||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image(conversationsListViewModel.selectedConversation!.muted ? "bell" : "bell-slash")
|
||||
Image(conversationsListViewModel.selectedConversation!.isMuted ? "bell" : "bell-slash")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text(conversationsListViewModel.selectedConversation!.muted ? "Réactiver les notifications" : "Mettre en sourdine")
|
||||
Text(conversationsListViewModel.selectedConversation!.isMuted ? "Réactiver les notifications" : "Mettre en sourdine")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
|
|
@ -134,12 +134,10 @@ struct ConversationsListBottomSheet: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
|
||||
if conversationsListViewModel.selectedConversation != nil
|
||||
&& conversationsListViewModel.selectedConversation!.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) {
|
||||
&& !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation!.participants.first != nil {
|
||||
TelecomManager.shared.doCallWithCore(
|
||||
addr: conversationsListViewModel.selectedConversation!.participants.first!.address!, isVideo: false
|
||||
)
|
||||
if !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
conversationsListViewModel.selectedConversation!.call()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
|
|
@ -178,12 +176,7 @@ struct ConversationsListBottomSheet: View {
|
|||
}
|
||||
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
CoreContext.shared.doOnCoreQueue { core in
|
||||
core.deleteChatRoom(chatRoom: conversationsListViewModel.selectedConversation!)
|
||||
//conversationsListViewModel.computeChatRoomsList(filter: "")
|
||||
}
|
||||
}
|
||||
conversationsListViewModel.computeChatRoomsList(filter: "")
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ import linphonesw
|
|||
|
||||
struct ConversationsListFragment: View {
|
||||
|
||||
@ObservedObject var contactsManager = ContactsManager.shared
|
||||
|
||||
@ObservedObject var conversationViewModel: ConversationViewModel
|
||||
@ObservedObject var conversationsListViewModel: ConversationsListViewModel
|
||||
|
||||
|
|
@ -34,111 +32,21 @@ struct ConversationsListFragment: View {
|
|||
List {
|
||||
ForEach(0..<conversationsListViewModel.conversationsList.count, id: \.self) { index in
|
||||
HStack {
|
||||
let addressFriend =
|
||||
(conversationsListViewModel.conversationsList[index].participants.first != nil && conversationsListViewModel.conversationsList[index].participants.first!.address != nil)
|
||||
? contactsManager.getFriendWithAddress(address: conversationsListViewModel.conversationsList[index].participants.first!.address!)
|
||||
: nil
|
||||
HStack {
|
||||
let contactAvatarModel = addressFriend != nil
|
||||
? ContactsManager.shared.avatarListModel.first(where: {
|
||||
($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
|
||||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
|
||||
if LinphoneUtils.isChatRoomAGroup(chatRoom: conversationsListViewModel.conversationsList[index]) {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationsListViewModel.conversationsList[index].subject!,
|
||||
lastName: conversationsListViewModel.conversationsList[index].subject!.components(separatedBy: " ").count > 1
|
||||
? conversationsListViewModel.conversationsList[index].subject!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
} else if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
|
||||
if contactAvatarModel != nil {
|
||||
Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 50)
|
||||
} else {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
} else {
|
||||
if conversationsListViewModel.conversationsList[index].participants.first != nil
|
||||
&& conversationsListViewModel.conversationsList[index].participants.first!.address != nil {
|
||||
if conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName != nil {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName!,
|
||||
lastName: conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName!.components(separatedBy: " ").count > 1
|
||||
? conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
|
||||
} else {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: conversationsListViewModel.conversationsList[index].participants.first!.address!.username ?? "Username Error",
|
||||
lastName: conversationsListViewModel.conversationsList[index].participants.first!.address!.username!.components(separatedBy: " ").count > 1
|
||||
? conversationsListViewModel.conversationsList[index].participants.first!.address!.username!.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
|
||||
} else {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
}
|
||||
Avatar(contactAvatarModel: conversationsListViewModel.conversationsList[index].avatarModel, avatarSize: 50)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
if LinphoneUtils.isChatRoomAGroup(chatRoom: conversationsListViewModel.conversationsList[index]) {
|
||||
Text(conversationsListViewModel.conversationsList[index].subject ?? "No Subject")
|
||||
.foregroundStyle(Color.grayMain2c800)
|
||||
.if(conversationsListViewModel.conversationsList[index].unreadMessagesCount > 0) { view in
|
||||
view.default_text_style_700(styleSize: 14)
|
||||
}
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
} else if addressFriend != nil {
|
||||
Text(addressFriend!.name!)
|
||||
.foregroundStyle(Color.grayMain2c800)
|
||||
.if(conversationsListViewModel.conversationsList[index].unreadMessagesCount > 0) { view in
|
||||
view.default_text_style_700(styleSize: 14)
|
||||
}
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
if conversationsListViewModel.conversationsList[index].participants.first != nil
|
||||
&& conversationsListViewModel.conversationsList[index].participants.first!.address != nil {
|
||||
Text(conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName != nil
|
||||
? conversationsListViewModel.conversationsList[index].participants.first!.address!.displayName!
|
||||
: conversationsListViewModel.conversationsList[index].participants.first!.address!.username!)
|
||||
.foregroundStyle(Color.grayMain2c800)
|
||||
.if(conversationsListViewModel.conversationsList[index].unreadMessagesCount > 0) { view in
|
||||
view.default_text_style_700(styleSize: 14)
|
||||
}
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(conversationsListViewModel.conversationsList[index].subject)
|
||||
.foregroundStyle(Color.grayMain2c800)
|
||||
.if(conversationsListViewModel.conversationsList[index].unreadMessagesCount > 0) { view in
|
||||
view.default_text_style_700(styleSize: 14)
|
||||
}
|
||||
}
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(
|
||||
conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil
|
||||
? conversationsListViewModel.getContentTextMessage(message: conversationsListViewModel.conversationsList[index].lastMessageInHistory!)
|
||||
: ""
|
||||
)
|
||||
Text(conversationsListViewModel.conversationsList[index].lastMessageText)
|
||||
.foregroundStyle(Color.grayMain2c400)
|
||||
.if(conversationsListViewModel.conversationsList[index].unreadMessagesCount > 0) { view in
|
||||
view.default_text_style_700(styleSize: 14)
|
||||
|
|
@ -156,8 +64,7 @@ struct ConversationsListFragment: View {
|
|||
Spacer()
|
||||
|
||||
HStack {
|
||||
if conversationsListViewModel.conversationsList[index].currentParams != nil
|
||||
&& !conversationsListViewModel.conversationsList[index].currentParams!.encryptionEnabled {
|
||||
if !conversationsListViewModel.conversationsList[index].encryptionEnabled {
|
||||
Image("warning-circle")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
|
|
@ -174,15 +81,15 @@ struct ConversationsListFragment: View {
|
|||
Spacer()
|
||||
|
||||
HStack {
|
||||
if conversationsListViewModel.conversationsList[index].muted == false
|
||||
&& !(conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil
|
||||
&& conversationsListViewModel.conversationsList[index].lastMessageInHistory!.isOutgoing == true)
|
||||
if conversationsListViewModel.conversationsList[index].isMuted == false
|
||||
&& !(!conversationsListViewModel.conversationsList[index].lastMessageText.isEmpty
|
||||
&& conversationsListViewModel.conversationsList[index].lastMessageIsOutgoing == true)
|
||||
&& conversationsListViewModel.conversationsList[index].unreadMessagesCount == 0 {
|
||||
Text("")
|
||||
.frame(width: 18, height: 18, alignment: .trailing)
|
||||
}
|
||||
|
||||
if conversationsListViewModel.conversationsList[index].muted {
|
||||
if conversationsListViewModel.conversationsList[index].isMuted {
|
||||
Image("bell-slash")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
|
|
@ -190,9 +97,9 @@ struct ConversationsListFragment: View {
|
|||
.frame(width: 18, height: 18, alignment: .trailing)
|
||||
}
|
||||
|
||||
if conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil
|
||||
&& conversationsListViewModel.conversationsList[index].lastMessageInHistory!.isOutgoing == true {
|
||||
let imageName = LinphoneUtils.getChatIconState(chatState: conversationsListViewModel.conversationsList[index].lastMessageInHistory!.state)
|
||||
if !conversationsListViewModel.conversationsList[index].lastMessageText.isEmpty
|
||||
&& conversationsListViewModel.conversationsList[index].lastMessageIsOutgoing == true {
|
||||
let imageName = LinphoneUtils.getChatIconState(chatState: conversationsListViewModel.conversationsList[index].lastMessageState)
|
||||
Image(imageName)
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
|
|
@ -220,7 +127,6 @@ struct ConversationsListFragment: View {
|
|||
Spacer()
|
||||
}
|
||||
.padding(.trailing, 10)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
.listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 20))
|
||||
|
|
@ -228,7 +134,7 @@ struct ConversationsListFragment: View {
|
|||
.background(.white)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
conversationViewModel.displayedConversation = conversationsListViewModel.conversationsList[index]
|
||||
conversationViewModel.changeDisplayedChatRoom(conversationModel: conversationsListViewModel.conversationsList[index])
|
||||
conversationViewModel.getMessage()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
231
Linphone/UI/Main/Conversations/Model/ConversationModel.swift
Normal file
231
Linphone/UI/Main/Conversations/Model/ConversationModel.swift
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of Linphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import linphonesw
|
||||
import Combine
|
||||
|
||||
class ConversationModel: ObservableObject {
|
||||
|
||||
private var coreContext = CoreContext.shared
|
||||
private var contactsManager = ContactsManager.shared
|
||||
|
||||
let chatRoom: ChatRoom
|
||||
let isDisabledBecauseNotSecured: Bool = false
|
||||
|
||||
static let TAG = "[Conversation Model]"
|
||||
|
||||
let id: String
|
||||
let localSipUri: String
|
||||
let remoteSipUri: String
|
||||
let isGroup: Bool
|
||||
let isReadOnly: Bool
|
||||
@Published var subject: String
|
||||
@Published var isComposing: Bool
|
||||
@Published var lastUpdateTime: time_t
|
||||
//@Published var composingLabel: String
|
||||
@Published var isMuted: Bool
|
||||
@Published var isEphemeral: Bool
|
||||
@Published var encryptionEnabled: Bool
|
||||
@Published var lastMessageText: String
|
||||
@Published var lastMessageIsOutgoing: Bool
|
||||
@Published var lastMessageState: Int
|
||||
//@Published var dateTime: String
|
||||
@Published var unreadMessagesCount: Int
|
||||
@Published var avatarModel: ContactAvatarModel
|
||||
//@Published var isBeingDeleted: Bool
|
||||
|
||||
//private let lastMessage: ChatMessage? = nil
|
||||
|
||||
init(chatRoom: ChatRoom) {
|
||||
self.chatRoom = chatRoom
|
||||
|
||||
self.id = LinphoneUtils.getChatRoomId(room: chatRoom)
|
||||
|
||||
self.localSipUri = chatRoom.localAddress?.asStringUriOnly() ?? ""
|
||||
|
||||
self.remoteSipUri = chatRoom.peerAddress?.asStringUriOnly() ?? ""
|
||||
|
||||
self.isGroup = !chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) && chatRoom.hasCapability(mask: ChatRoom.Capabilities.Conference.rawValue)
|
||||
|
||||
self.isReadOnly = chatRoom.isReadOnly
|
||||
|
||||
self.subject = chatRoom.subject ?? ""
|
||||
|
||||
self.lastUpdateTime = chatRoom.lastUpdateTime
|
||||
|
||||
self.isComposing = chatRoom.isRemoteComposing
|
||||
|
||||
//self.composingLabel = chatRoom.compo
|
||||
|
||||
self.isMuted = chatRoom.muted
|
||||
|
||||
self.isEphemeral = chatRoom.ephemeralEnabled
|
||||
|
||||
self.encryptionEnabled = chatRoom.currentParams != nil && chatRoom.currentParams!.encryptionEnabled
|
||||
|
||||
self.lastMessageText = ""
|
||||
|
||||
self.lastMessageIsOutgoing = false
|
||||
|
||||
self.lastMessageState = 0
|
||||
|
||||
//self.dateTime = chatRoom.date
|
||||
|
||||
self.unreadMessagesCount = chatRoom.unreadMessagesCount
|
||||
|
||||
self.avatarModel = ContactAvatarModel(friend: nil, name: "", withPresence: false)
|
||||
|
||||
//self.isBeingDeleted = MutableLiveData<Boolean>()
|
||||
|
||||
//self.lastMessage: ChatMessage? = null
|
||||
|
||||
getContentTextMessage()
|
||||
getChatRoomSubject()
|
||||
}
|
||||
|
||||
func leave(){
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
self.chatRoom.leave()
|
||||
}
|
||||
}
|
||||
|
||||
func markAsRead() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
self.chatRoom.markAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
func toggleMute() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
self.chatRoom.muted.toggle()
|
||||
self.isMuted = self.chatRoom.muted
|
||||
}
|
||||
}
|
||||
|
||||
func call() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.chatRoom.peerAddress != nil {
|
||||
TelecomManager.shared.doCallWithCore(
|
||||
addr: self.chatRoom.peerAddress!, isVideo: false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getContentTextMessage() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
let lastMessage = self.chatRoom.lastMessageInHistory
|
||||
if lastMessage != nil {
|
||||
var fromAddressFriend = lastMessage!.fromAddress != nil
|
||||
? self.contactsManager.getFriendWithAddress(address: lastMessage!.fromAddress!)?.name ?? nil
|
||||
: nil
|
||||
|
||||
if !lastMessage!.isOutgoing && lastMessage!.chatRoom != nil && !lastMessage!.chatRoom!.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) {
|
||||
if fromAddressFriend == nil {
|
||||
if lastMessage!.fromAddress!.displayName != nil {
|
||||
fromAddressFriend = lastMessage!.fromAddress!.displayName! + ": "
|
||||
} else if lastMessage!.fromAddress!.username != nil {
|
||||
fromAddressFriend = lastMessage!.fromAddress!.username! + ": "
|
||||
} else {
|
||||
fromAddressFriend = ""
|
||||
}
|
||||
} else {
|
||||
fromAddressFriend! += ": "
|
||||
}
|
||||
|
||||
} else {
|
||||
fromAddressFriend = nil
|
||||
}
|
||||
|
||||
let lastMessageTextTmp = (fromAddressFriend ?? "")
|
||||
+ (lastMessage!.contents.first(where: {$0.isText == true})?.utf8Text ?? (lastMessage!.contents.first(where: {$0.isFile == true || $0.isFileTransfer == true})?.name ?? ""))
|
||||
|
||||
let lastMessageIsOutgoingTmp = lastMessage?.isOutgoing ?? false
|
||||
|
||||
let lastMessageStateTmp = lastMessage?.state.rawValue ?? 0
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.lastMessageText = lastMessageTextTmp
|
||||
|
||||
self.lastMessageIsOutgoing = lastMessageIsOutgoingTmp
|
||||
|
||||
self.lastMessageState = lastMessageStateTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getChatRoomSubject() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
|
||||
let addressFriend =
|
||||
(self.chatRoom.participants.first != nil && self.chatRoom.participants.first!.address != nil)
|
||||
? self.contactsManager.getFriendWithAddress(address: self.chatRoom.participants.first!.address!)
|
||||
: nil
|
||||
|
||||
if self.isGroup {
|
||||
self.subject = self.chatRoom.subject!
|
||||
} else if addressFriend != nil {
|
||||
self.subject = addressFriend!.name!
|
||||
} else {
|
||||
if self.chatRoom.participants.first != nil
|
||||
&& self.chatRoom.participants.first!.address != nil {
|
||||
|
||||
self.subject = self.chatRoom.participants.first!.address!.displayName != nil
|
||||
? self.chatRoom.participants.first!.address!.displayName!
|
||||
: self.chatRoom.participants.first!.address!.username!
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let avatarModelTmp = addressFriend != nil && !self.isGroup
|
||||
? ContactsManager.shared.avatarListModel.first(where: {
|
||||
$0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
?? ContactAvatarModel(friend: nil, name: self.subject, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: self.subject, withPresence: false)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.avatarModel = avatarModelTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func refreshAvatarModel() {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
let addressFriend =
|
||||
(self.chatRoom.participants.first != nil && self.chatRoom.participants.first!.address != nil)
|
||||
? self.contactsManager.getFriendWithAddress(address: self.chatRoom.participants.first!.address!)
|
||||
: nil
|
||||
|
||||
if addressFriend != nil && !self.isGroup {
|
||||
let avatarModelTmp = ContactsManager.shared.avatarListModel.first(where: {
|
||||
$0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
}) ?? ContactAvatarModel(friend: nil, name: self.subject, withPresence: false)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.avatarModel = avatarModelTmp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ class ConversationViewModel: ObservableObject {
|
|||
|
||||
private var coreContext = CoreContext.shared
|
||||
|
||||
@Published var displayedConversation: ChatRoom?
|
||||
@Published var displayedConversation: ConversationModel?
|
||||
|
||||
@Published var messageText: String = ""
|
||||
|
||||
|
|
@ -37,14 +37,16 @@ class ConversationViewModel: ObservableObject {
|
|||
init() {}
|
||||
|
||||
func addConversationDelegate() {
|
||||
if displayedConversation != nil {
|
||||
self.chatRoomSuscriptions.insert(displayedConversation!.publisher?.onChatMessageSent?.postOnMainQueue { (cbValue: (chatRoom: ChatRoom, eventLog: EventLog)) in
|
||||
self.getNewMessages(eventLogs: [cbValue.eventLog])
|
||||
})
|
||||
|
||||
self.chatRoomSuscriptions.insert(displayedConversation!.publisher?.onChatMessagesReceived?.postOnMainQueue { (cbValue: (chatRoom: ChatRoom, eventLogs: [EventLog])) in
|
||||
self.getNewMessages(eventLogs: cbValue.eventLogs)
|
||||
})
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.displayedConversation != nil {
|
||||
self.chatRoomSuscriptions.insert(self.displayedConversation?.chatRoom.publisher?.onChatMessageSent?.postOnCoreQueue { (cbValue: (chatRoom: ChatRoom, eventLog: EventLog)) in
|
||||
self.getNewMessages(eventLogs: [cbValue.eventLog])
|
||||
})
|
||||
|
||||
self.chatRoomSuscriptions.insert(self.displayedConversation?.chatRoom.publisher?.onChatMessagesReceived?.postOnMainQueue { (cbValue: (chatRoom: ChatRoom, eventLogs: [EventLog])) in
|
||||
self.getNewMessages(eventLogs: cbValue.eventLogs)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,20 +55,36 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
func getMessage() {
|
||||
if self.displayedConversation != nil {
|
||||
let historyEvents = displayedConversation!.getHistoryRangeEvents(begin: conversationMessagesList.count, end: conversationMessagesList.count + 30)
|
||||
|
||||
historyEvents.reversed().forEach { eventLog in
|
||||
conversationMessagesList.append(LinphoneCustomEventLog(eventLog: eventLog))
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.displayedConversation != nil {
|
||||
let historyEvents = self.displayedConversation!.chatRoom.getHistoryRangeEvents(begin: self.conversationMessagesList.count, end: self.conversationMessagesList.count + 30)
|
||||
|
||||
historyEvents.reversed().forEach { eventLog in
|
||||
DispatchQueue.main.async {
|
||||
self.conversationMessagesList.append(LinphoneCustomEventLog(eventLog: eventLog))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getNewMessages(eventLogs: [EventLog]) {
|
||||
withAnimation {
|
||||
eventLogs.forEach { eventLog in
|
||||
conversationMessagesList.insert(LinphoneCustomEventLog(eventLog: eventLog), at: 0)
|
||||
//conversationMessagesList.append(LinphoneCustomEventLog(eventLog: eventLog))
|
||||
|
||||
//let conversationMessagesListTmp = self.conversationMessagesList
|
||||
//self.conversationMessagesList = []
|
||||
|
||||
eventLogs.forEach { eventLog in
|
||||
DispatchQueue.main.async {
|
||||
/*
|
||||
withAnimation {
|
||||
self.conversationMessagesList.append(LinphoneCustomEventLog(eventLog: eventLog))
|
||||
}
|
||||
|
||||
self.conversationMessagesList.append(contentsOf: conversationMessagesListTmp)
|
||||
*/
|
||||
withAnimation(.spring(duration: 2)) {
|
||||
self.conversationMessagesList.insert(LinphoneCustomEventLog(eventLog: eventLog), at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,83 +94,93 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
func sendMessage() {
|
||||
//val messageToReplyTo = chatMessageToReplyTo
|
||||
//val message = if (messageToReplyTo != null) {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
//val messageToReplyTo = chatMessageToReplyTo
|
||||
//val message = if (messageToReplyTo != null) {
|
||||
//Log.i("$TAG Sending message as reply to [${messageToReplyTo.messageId}]")
|
||||
//chatRoom.createReplyMessage(messageToReplyTo)
|
||||
//} else {
|
||||
let message = try? self.displayedConversation!.createEmptyMessage()
|
||||
//}
|
||||
|
||||
let toSend = self.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !toSend.isEmpty {
|
||||
if message != nil {
|
||||
message!.addUtf8TextContent(text: toSend)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (isVoiceRecording.value == true && voiceMessageRecorder.file != null) {
|
||||
stopVoiceRecorder()
|
||||
val content = voiceMessageRecorder.createContent()
|
||||
if (content != null) {
|
||||
Log.i(
|
||||
"$TAG Voice recording content created, file name is ${content.name} and duration is ${content.fileDuration}"
|
||||
)
|
||||
message.addContent(content)
|
||||
} else {
|
||||
Log.e("$TAG Voice recording content couldn't be created!")
|
||||
}
|
||||
} else {
|
||||
for (attachment in attachments.value.orEmpty()) {
|
||||
val content = Factory.instance().createContent()
|
||||
|
||||
content.type = when (attachment.mimeType) {
|
||||
FileUtils.MimeType.Image -> "image"
|
||||
FileUtils.MimeType.Audio -> "audio"
|
||||
FileUtils.MimeType.Video -> "video"
|
||||
FileUtils.MimeType.Pdf -> "application"
|
||||
FileUtils.MimeType.PlainText -> "text"
|
||||
else -> "file"
|
||||
//} else {
|
||||
let message = try? self.displayedConversation!.chatRoom.createEmptyMessage()
|
||||
//}
|
||||
|
||||
let toSend = self.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !toSend.isEmpty {
|
||||
if message != nil {
|
||||
message!.addUtf8TextContent(text: toSend)
|
||||
}
|
||||
content.subtype = if (attachment.mimeType == FileUtils.MimeType.PlainText) {
|
||||
"plain"
|
||||
} else {
|
||||
FileUtils.getExtensionFromFileName(attachment.fileName)
|
||||
}
|
||||
content.name = attachment.fileName
|
||||
// Let the file body handler take care of the upload
|
||||
content.filePath = attachment.file
|
||||
|
||||
message.addFileContent(content)
|
||||
}
|
||||
|
||||
/*
|
||||
if (isVoiceRecording.value == true && voiceMessageRecorder.file != null) {
|
||||
stopVoiceRecorder()
|
||||
val content = voiceMessageRecorder.createContent()
|
||||
if (content != null) {
|
||||
Log.i(
|
||||
"$TAG Voice recording content created, file name is ${content.name} and duration is ${content.fileDuration}"
|
||||
)
|
||||
message.addContent(content)
|
||||
} else {
|
||||
Log.e("$TAG Voice recording content couldn't be created!")
|
||||
}
|
||||
} else {
|
||||
for (attachment in attachments.value.orEmpty()) {
|
||||
val content = Factory.instance().createContent()
|
||||
|
||||
content.type = when (attachment.mimeType) {
|
||||
FileUtils.MimeType.Image -> "image"
|
||||
FileUtils.MimeType.Audio -> "audio"
|
||||
FileUtils.MimeType.Video -> "video"
|
||||
FileUtils.MimeType.Pdf -> "application"
|
||||
FileUtils.MimeType.PlainText -> "text"
|
||||
else -> "file"
|
||||
}
|
||||
content.subtype = if (attachment.mimeType == FileUtils.MimeType.PlainText) {
|
||||
"plain"
|
||||
} else {
|
||||
FileUtils.getExtensionFromFileName(attachment.fileName)
|
||||
}
|
||||
content.name = attachment.fileName
|
||||
// Let the file body handler take care of the upload
|
||||
content.filePath = attachment.file
|
||||
|
||||
message.addFileContent(content)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if message != nil && !message!.contents.isEmpty {
|
||||
Log.info("[ConversationViewModel] Sending message")
|
||||
message!.send()
|
||||
}
|
||||
|
||||
Log.info("[ConversationViewModel] Message sent, re-setting defaults")
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.messageText = ""
|
||||
}
|
||||
|
||||
/*
|
||||
isReplying.postValue(false)
|
||||
isFileAttachmentsListOpen.postValue(false)
|
||||
isParticipantsListOpen.postValue(false)
|
||||
isEmojiPickerOpen.postValue(false)
|
||||
|
||||
if (::voiceMessageRecorder.isInitialized) {
|
||||
stopVoiceRecorder()
|
||||
}
|
||||
isVoiceRecording.postValue(false)
|
||||
|
||||
// Warning: do not delete files
|
||||
val attachmentsList = arrayListOf<FileModel>()
|
||||
attachments.postValue(attachmentsList)
|
||||
|
||||
chatMessageToReplyTo = null
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
if message != nil && !message!.contents.isEmpty {
|
||||
Log.info("[ConversationViewModel] Sending message")
|
||||
message!.send()
|
||||
}
|
||||
|
||||
Log.info("[ConversationViewModel] Message sent, re-setting defaults")
|
||||
self.messageText = ""
|
||||
/*
|
||||
isReplying.postValue(false)
|
||||
isFileAttachmentsListOpen.postValue(false)
|
||||
isParticipantsListOpen.postValue(false)
|
||||
isEmojiPickerOpen.postValue(false)
|
||||
|
||||
if (::voiceMessageRecorder.isInitialized) {
|
||||
stopVoiceRecorder()
|
||||
}
|
||||
isVoiceRecording.postValue(false)
|
||||
|
||||
// Warning: do not delete files
|
||||
val attachmentsList = arrayListOf<FileModel>()
|
||||
attachments.postValue(attachmentsList)
|
||||
|
||||
chatMessageToReplyTo = null
|
||||
*/
|
||||
}
|
||||
|
||||
func changeDisplayedChatRoom(conversationModel: ConversationModel) {
|
||||
self.displayedConversation = conversationModel
|
||||
}
|
||||
}
|
||||
struct LinphoneCustomEventLog: Hashable {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ class ConversationsListViewModel: ObservableObject {
|
|||
|
||||
private var mCoreSuscriptions = Set<AnyCancellable?>()
|
||||
|
||||
@Published var conversationsList: [ChatRoom] = []
|
||||
@Published var conversationsList: [ConversationModel] = []
|
||||
@Published var unreadMessages: Int = 0
|
||||
|
||||
var selectedConversation: ChatRoom?
|
||||
var selectedConversation: ConversationModel?
|
||||
|
||||
init() {
|
||||
computeChatRoomsList(filter: "")
|
||||
|
|
@ -43,47 +43,64 @@ class ConversationsListViewModel: ObservableObject {
|
|||
let account = core.defaultAccount
|
||||
let chatRooms = account?.chatRooms != nil ? account!.chatRooms : core.chatRooms
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.conversationsList = []
|
||||
chatRooms.forEach { chatRoom in
|
||||
//let disabledBecauseNotSecured = (account?.isInSecureMode() == true && !chatRoom.hasCapability) ? Capabilities.Encrypted.toInt() : 0
|
||||
if chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) {
|
||||
}
|
||||
|
||||
if filter.isEmpty {
|
||||
//val model = ConversationModel(chatRoom, disabledBecauseNotSecured)
|
||||
self.conversationsList.append(chatRoom)
|
||||
}
|
||||
/*
|
||||
else {
|
||||
val participants = chatRoom.participants
|
||||
val found = participants.find {
|
||||
// Search in address but also in contact name if exists
|
||||
val model =
|
||||
coreContext.contactsManager.getContactAvatarModelForAddress(it.address)
|
||||
model.contactName?.contains(
|
||||
filter,
|
||||
ignoreCase = true
|
||||
) == true || it.address.asStringUriOnly().contains(
|
||||
filter,
|
||||
ignoreCase = true
|
||||
)
|
||||
}
|
||||
if (
|
||||
found != null ||
|
||||
chatRoom.peerAddress.asStringUriOnly().contains(filter, ignoreCase = true) ||
|
||||
chatRoom.subject.orEmpty().contains(filter, ignoreCase = true)
|
||||
) {
|
||||
val model = ConversationModel(chatRoom, disabledBecauseNotSecured)
|
||||
list.add(model)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
*/
|
||||
var conversationsListTmp: [ConversationModel] = []
|
||||
|
||||
chatRooms.forEach { chatRoom in
|
||||
//let disabledBecauseNotSecured = (account?.isInSecureMode() == true && !chatRoom.hasCapability) ? Capabilities.Encrypted.toInt() : 0
|
||||
if chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) {
|
||||
}
|
||||
|
||||
self.updateUnreadMessagesCount()
|
||||
if filter.isEmpty {
|
||||
let model = ConversationModel(chatRoom: chatRoom)
|
||||
conversationsListTmp.append(model)
|
||||
}
|
||||
/*
|
||||
else {
|
||||
val participants = chatRoom.participants
|
||||
val found = participants.find {
|
||||
// Search in address but also in contact name if exists
|
||||
val model =
|
||||
coreContext.contactsManager.getContactAvatarModelForAddress(it.address)
|
||||
model.contactName?.contains(
|
||||
filter,
|
||||
ignoreCase = true
|
||||
) == true || it.address.asStringUriOnly().contains(
|
||||
filter,
|
||||
ignoreCase = true
|
||||
)
|
||||
}
|
||||
if (
|
||||
found != null ||
|
||||
chatRoom.peerAddress.asStringUriOnly().contains(filter, ignoreCase = true) ||
|
||||
chatRoom.subject.orEmpty().contains(filter, ignoreCase = true)
|
||||
) {
|
||||
val model = ConversationModel(chatRoom, disabledBecauseNotSecured)
|
||||
list.add(model)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if !self.conversationsList.isEmpty {
|
||||
for (index, element) in conversationsListTmp.enumerated() {
|
||||
if index > 0 && element.id != self.conversationsList[index].id {
|
||||
DispatchQueue.main.async {
|
||||
self.conversationsList[index] = element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.conversationsList[0] = conversationsListTmp.first!
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
self.conversationsList = conversationsListTmp
|
||||
}
|
||||
}
|
||||
|
||||
self.updateUnreadMessagesCount()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +110,8 @@ class ConversationsListViewModel: ObservableObject {
|
|||
//Log.info("[ConversationsListViewModel] Conversation [${LinphoneUtils.getChatRoomId(chatRoom)}] state changed [$state]")
|
||||
switch cbValue.state {
|
||||
case ChatRoom.State.Created:
|
||||
self.addChatRoom(cbChatRoom: cbValue.chatRoom)
|
||||
let model = ConversationModel(chatRoom: cbValue.chatRoom)
|
||||
self.addChatRoom(cbChatRoom: model)
|
||||
case ChatRoom.State.Deleted:
|
||||
self.computeChatRoomsList(filter: "")
|
||||
//ToastViewModel.shared.toastMessage = "toast_conversation_deleted"
|
||||
|
|
@ -109,14 +127,13 @@ class ConversationsListViewModel: ObservableObject {
|
|||
|
||||
self.mCoreSuscriptions.insert(core.publisher?.onMessagesReceived?.postOnMainQueue { _ in
|
||||
self.computeChatRoomsList(filter: "")
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func addChatRoom(cbChatRoom: ChatRoom) {
|
||||
func addChatRoom(cbChatRoom: ConversationModel) {
|
||||
Log.info("[ConversationsListViewModel] Re-ordering conversations")
|
||||
var sortedList: [ChatRoom] = []
|
||||
var sortedList: [ConversationModel] = []
|
||||
sortedList.append(cbChatRoom)
|
||||
sortedList.append(contentsOf: self.conversationsList)
|
||||
|
||||
|
|
@ -129,7 +146,7 @@ class ConversationsListViewModel: ObservableObject {
|
|||
|
||||
func reorderChatRooms() {
|
||||
Log.info("[ConversationsListViewModel] Re-ordering conversations")
|
||||
var sortedList: [ChatRoom] = []
|
||||
var sortedList: [ConversationModel] = []
|
||||
sortedList.append(contentsOf: conversationsList)
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
|
|
@ -204,4 +221,10 @@ class ConversationsListViewModel: ObservableObject {
|
|||
return formatter.string(from: myNSDate)
|
||||
}
|
||||
}
|
||||
|
||||
func refreshContactAvatarModel() {
|
||||
conversationsList.forEach { conversationModel in
|
||||
conversationModel.refreshAvatarModel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ struct HistoryContactFragment: View {
|
|||
|
||||
#Preview {
|
||||
HistoryContactFragment(
|
||||
contactAvatarModel: ContactAvatarModel(friend: nil, withPresence: false),
|
||||
contactAvatarModel: ContactAvatarModel(friend: nil, name: "", withPresence: false),
|
||||
historyViewModel: HistoryViewModel(),
|
||||
historyListViewModel: HistoryListViewModel(),
|
||||
contactViewModel: ContactViewModel(),
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ struct HistoryListFragment: View {
|
|||
&& $0.friend!.name == addressFriend!.name
|
||||
&& $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
|
||||
})
|
||||
: ContactAvatarModel(friend: nil, withPresence: false)
|
||||
: ContactAvatarModel(friend: nil, name: "", withPresence: false)
|
||||
|
||||
if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
|
||||
if contactAvatarModel != nil {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import linphonesw
|
|||
|
||||
struct Avatar: View {
|
||||
|
||||
private var contactsManager = ContactsManager.shared
|
||||
|
||||
@ObservedObject var contactAvatarModel: ContactAvatarModel
|
||||
|
||||
let avatarSize: CGFloat
|
||||
|
|
@ -71,6 +73,15 @@ struct Avatar: View {
|
|||
EmptyView()
|
||||
}
|
||||
}
|
||||
} else if !contactAvatarModel.name.isEmpty {
|
||||
Image(uiImage: contactsManager.textToImage(
|
||||
firstName: contactAvatarModel.name,
|
||||
lastName: contactAvatarModel.name.components(separatedBy: " ").count > 1
|
||||
? contactAvatarModel.name.components(separatedBy: " ")[1]
|
||||
: ""))
|
||||
.resizable()
|
||||
.frame(width: 50, height: 50)
|
||||
.clipShape(Circle())
|
||||
} else {
|
||||
Image("profil-picture-default")
|
||||
.resizable()
|
||||
|
|
|
|||
|
|
@ -27,20 +27,36 @@ class LinphoneUtils: NSObject {
|
|||
return !oneToOne && conference
|
||||
}
|
||||
|
||||
public class func getChatIconState(chatState: ChatMessage.State) -> String {
|
||||
public class func getChatIconState(chatState: Int) -> String {
|
||||
return switch chatState {
|
||||
case ChatMessage.State.Displayed, ChatMessage.State.FileTransferDone:
|
||||
case ChatMessage.State.Displayed.rawValue, ChatMessage.State.FileTransferDone.rawValue:
|
||||
"checks"
|
||||
case ChatMessage.State.DeliveredToUser:
|
||||
case ChatMessage.State.DeliveredToUser.rawValue:
|
||||
"check"
|
||||
case ChatMessage.State.Delivered:
|
||||
case ChatMessage.State.Delivered.rawValue:
|
||||
"envelope-simple"
|
||||
case ChatMessage.State.NotDelivered, ChatMessage.State.FileTransferError:
|
||||
case ChatMessage.State.NotDelivered.rawValue, ChatMessage.State.FileTransferError.rawValue:
|
||||
"warning-circle"
|
||||
case ChatMessage.State.InProgress, ChatMessage.State.FileTransferInProgress:
|
||||
case ChatMessage.State.InProgress.rawValue, ChatMessage.State.FileTransferInProgress.rawValue:
|
||||
"animated-in-progress"
|
||||
default:
|
||||
"animated-in-progress"
|
||||
}
|
||||
}
|
||||
|
||||
public class func getChatRoomId(room: ChatRoom) -> String {
|
||||
return getChatRoomId(localAddress: room.localAddress!, remoteAddress: room.peerAddress!)
|
||||
}
|
||||
|
||||
public class func getChatRoomId(localAddress: Address, remoteAddress: Address) -> String {
|
||||
let localSipUri = localAddress.clone()
|
||||
localSipUri!.clean()
|
||||
let remoteSipUri = remoteAddress.clone()
|
||||
remoteSipUri!.clean()
|
||||
return getChatRoomId(localSipUri: localSipUri!.asStringUriOnly(), remoteSipUri: remoteSipUri!.asStringUriOnly())
|
||||
}
|
||||
|
||||
public class func getChatRoomId(localSipUri: String, remoteSipUri: String) -> String {
|
||||
return "\(localSipUri)#~#\(remoteSipUri)"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@ final class MagicSearchSingleton: ObservableObject {
|
|||
|
||||
self.contactsManager.lastSearch.forEach { searchResult in
|
||||
if searchResult.friend != nil {
|
||||
self.contactsManager.avatarListModel.append(ContactAvatarModel(friend: searchResult.friend!, withPresence: true))
|
||||
self.contactsManager.avatarListModel.append(ContactAvatarModel(friend: searchResult.friend!, name: searchResult.friend?.name ?? "", withPresence: true))
|
||||
}
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(name: NSNotification.Name("ContactLoaded"), object: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue