mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
Add Conversation info fragment
This commit is contained in:
parent
0a162390a3
commit
baf1fcc0b9
7 changed files with 924 additions and 394 deletions
|
|
@ -130,6 +130,7 @@
|
|||
D78E06302BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E062F2BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift */; };
|
||||
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79622332B1DFE600037EACD /* DialerBottomSheet.swift */; };
|
||||
D796F2002B0BB61A0041115F /* ToastViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D796F1FF2B0BB61A0041115F /* ToastViewModel.swift */; };
|
||||
D79F1C162CD3D6AD00FF0A05 /* ConversationInfoFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79F1C152CD3D6AD00FF0A05 /* ConversationInfoFragment.swift */; };
|
||||
D79F2D0A2C47F4BF0038FA07 /* TouchFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79F2D092C47F4BF0038FA07 /* TouchFeedback.swift */; };
|
||||
D7A03FBD2ACC2DB60081A588 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A03FBC2ACC2DB60081A588 /* ContactsView.swift */; };
|
||||
D7A03FC02ACC2E390081A588 /* HistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A03FBF2ACC2E390081A588 /* HistoryView.swift */; };
|
||||
|
|
@ -319,6 +320,7 @@
|
|||
D78E062F2BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLayoutBottomSheet.swift; sourceTree = "<group>"; };
|
||||
D79622332B1DFE600037EACD /* DialerBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialerBottomSheet.swift; sourceTree = "<group>"; };
|
||||
D796F1FF2B0BB61A0041115F /* ToastViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastViewModel.swift; sourceTree = "<group>"; };
|
||||
D79F1C152CD3D6AD00FF0A05 /* ConversationInfoFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationInfoFragment.swift; sourceTree = "<group>"; };
|
||||
D79F2D092C47F4BF0038FA07 /* TouchFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchFeedback.swift; sourceTree = "<group>"; };
|
||||
D7A03FBC2ACC2DB60081A588 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = "<group>"; };
|
||||
D7A03FBF2ACC2E390081A588 /* HistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -857,6 +859,7 @@
|
|||
D759CB632C3FBD4200AC35E8 /* StartConversationFragment.swift */,
|
||||
D7A0ACBA2C415D630043AE79 /* StartGroupConversationFragment.swift */,
|
||||
D70C82A42C85EDC90087F43F /* ConversationForwardMessageFragment.swift */,
|
||||
D79F1C152CD3D6AD00FF0A05 /* ConversationInfoFragment.swift */,
|
||||
);
|
||||
path = Fragments;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1127,6 +1130,7 @@
|
|||
D71556362C297DB1009A8CEF /* StartGroupCallFragment.swift in Sources */,
|
||||
C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */,
|
||||
D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */,
|
||||
D79F1C162CD3D6AD00FF0A05 /* ConversationInfoFragment.swift in Sources */,
|
||||
D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */,
|
||||
C67586B02C09F247002E77BF /* URIHandler.swift in Sources */,
|
||||
C62817282C1B389700DBA646 /* SideMenuAccountRow.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -874,6 +874,23 @@
|
|||
},
|
||||
"Connexion à la réunion" : {
|
||||
|
||||
},
|
||||
"contact_details_actions_title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Other actions"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Autres actions"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"contact_dialog_pick_phone_number_or_sip_address_title" : {
|
||||
"extractionState" : "manual",
|
||||
|
|
@ -928,6 +945,57 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_action_call" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Call"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Appeler"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_action_configure_ephemeral_messages" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Configure ephemeral messages"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Configurer les messages éphémères"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_action_leave_group" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Leave the group"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Quitter le groupe"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_action_mute" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
@ -1432,6 +1500,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_delete_history_action" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Delete history"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Supprimer l'historique"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_info_menu_go_to_contact" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "See contact profile"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Voir le contact"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_invalid_participant_due_to_security_mode_toast" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
@ -2068,6 +2170,23 @@
|
|||
},
|
||||
"Meeting added to iPhone calendar" : {
|
||||
|
||||
},
|
||||
"meeting_schedule_meeting_label" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Meeting"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Réunion"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"meeting_waiting_room_join" : {
|
||||
"extractionState" : "manual",
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct ConversationFragment: View {
|
|||
|
||||
@State private var isShowConversationForwardMessageFragment = false
|
||||
@State private var isShowEphemeralFragment = false
|
||||
@State private var isShowInfoConversationFragment = false
|
||||
|
||||
@Binding var isShowConversationFragment: Bool
|
||||
@Binding var isShowStartCallGroupPopup: Bool
|
||||
|
|
@ -231,29 +232,40 @@ struct ConversationFragment: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.background(.white)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
isShowInfoConversationFragment = true
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 10)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
if conversationViewModel.displayedConversation!.isGroup {
|
||||
isShowStartCallGroupPopup.toggle()
|
||||
} else {
|
||||
conversationViewModel.displayedConversation!.call()
|
||||
if !conversationViewModel.displayedConversation!.isReadOnly {
|
||||
Button {
|
||||
if conversationViewModel.displayedConversation!.isGroup {
|
||||
isShowStartCallGroupPopup.toggle()
|
||||
} else {
|
||||
conversationViewModel.displayedConversation!.call()
|
||||
}
|
||||
} label: {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
} label: {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
|
||||
Menu {
|
||||
Button {
|
||||
isMenuOpen = false
|
||||
withAnimation {
|
||||
isShowInfoConversationFragment = true
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text("conversation_menu_go_to_info")
|
||||
|
|
@ -267,38 +279,40 @@ struct ConversationFragment: View {
|
|||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
isMenuOpen = false
|
||||
conversationViewModel.displayedConversation!.toggleMute()
|
||||
isMuted = !isMuted
|
||||
} label: {
|
||||
HStack {
|
||||
Text(isMuted ? "conversation_action_unmute" : "conversation_action_mute")
|
||||
Spacer()
|
||||
Image(isMuted ? "bell-simple" : "bell-simple-slash")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
if !conversationViewModel.displayedConversation!.isReadOnly {
|
||||
Button {
|
||||
isMenuOpen = false
|
||||
conversationViewModel.displayedConversation!.toggleMute()
|
||||
isMuted = !isMuted
|
||||
} label: {
|
||||
HStack {
|
||||
Text(isMuted ? "conversation_action_unmute" : "conversation_action_mute")
|
||||
Spacer()
|
||||
Image(isMuted ? "bell-simple" : "bell-simple-slash")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
isMenuOpen = false
|
||||
withAnimation {
|
||||
isShowEphemeralFragment = true
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text("conversation_menu_configure_ephemeral_messages")
|
||||
Spacer()
|
||||
Image("clock-countdown")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
|
||||
Button {
|
||||
isMenuOpen = false
|
||||
withAnimation {
|
||||
isShowEphemeralFragment = true
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text("conversation_menu_configure_ephemeral_messages")
|
||||
Spacer()
|
||||
Image("clock-countdown")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
|
|
@ -454,129 +468,42 @@ struct ConversationFragment: View {
|
|||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
|
||||
if conversationViewModel.messageToReply != nil {
|
||||
ZStack(alignment: .top) {
|
||||
HStack {
|
||||
VStack {
|
||||
(
|
||||
Text("conversation_reply_to_message_title")
|
||||
+ Text("**\(conversationViewModel.participantConversationModel.first(where: {$0.address == conversationViewModel.messageToReply!.message.address})?.name ?? "")**"))
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.bottom, 1)
|
||||
.lineLimit(1)
|
||||
|
||||
if conversationViewModel.messageToReply!.message.text.isEmpty {
|
||||
Text(conversationViewModel.messageToReply!.message.attachmentsNames)
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Text("\(conversationViewModel.messageToReply!.message.text)")
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.all, 20)
|
||||
.background(Color.gray100)
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
conversationViewModel.messageToReply = nil
|
||||
}
|
||||
}, label: {
|
||||
Image("x")
|
||||
.resizable()
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
})
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
|
||||
if !conversationViewModel.mediasToSend.isEmpty || mediasIsLoading {
|
||||
ZStack(alignment: .top) {
|
||||
HStack {
|
||||
if mediasIsLoading {
|
||||
HStack {
|
||||
Spacer()
|
||||
if conversationViewModel.displayedConversation != nil && !conversationViewModel.displayedConversation!.isReadOnly {
|
||||
if conversationViewModel.messageToReply != nil {
|
||||
ZStack(alignment: .top) {
|
||||
HStack {
|
||||
VStack {
|
||||
(
|
||||
Text("conversation_reply_to_message_title")
|
||||
+ Text("**\(conversationViewModel.participantConversationModel.first(where: {$0.address == conversationViewModel.messageToReply!.message.address})?.name ?? "")**"))
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.bottom, 1)
|
||||
.lineLimit(1)
|
||||
|
||||
ProgressView()
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(height: 120)
|
||||
}
|
||||
|
||||
if !mediasIsLoading {
|
||||
LazyVGrid(columns: [
|
||||
GridItem(.adaptive(minimum: 100), spacing: 1)
|
||||
], spacing: 3) {
|
||||
ForEach(conversationViewModel.mediasToSend, id: \.id) { attachment in
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(.white))
|
||||
.frame(width: 100, height: 100)
|
||||
|
||||
AsyncImage(url: attachment.thumbnail) { image in
|
||||
ZStack {
|
||||
image
|
||||
.resizable()
|
||||
.interpolation(.medium)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
|
||||
if attachment.type == .video {
|
||||
Image("play-fill")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 40, height: 40, alignment: .leading)
|
||||
}
|
||||
}
|
||||
} placeholder: {
|
||||
ProgressView()
|
||||
}
|
||||
.layoutPriority(-1)
|
||||
.onTapGesture {
|
||||
if conversationViewModel.mediasToSend.count == 1 {
|
||||
withAnimation {
|
||||
conversationViewModel.mediasToSend.removeAll()
|
||||
}
|
||||
} else {
|
||||
guard let index = self.conversationViewModel.mediasToSend.firstIndex(of: attachment) else { return }
|
||||
self.conversationViewModel.mediasToSend.remove(at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||
.contentShape(Rectangle())
|
||||
if conversationViewModel.messageToReply!.message.text.isEmpty {
|
||||
Text(conversationViewModel.messageToReply!.message.attachmentsNames)
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Text("\(conversationViewModel.messageToReply!.message.text)")
|
||||
.default_text_style_300(styleSize: 15)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
.frame(
|
||||
width: geometry.size.width > 0 && CGFloat(102 * conversationViewModel.mediasToSend.count) > geometry.size.width - 20
|
||||
? 102 * floor(CGFloat(geometry.size.width - 20) / 102)
|
||||
: CGFloat(102 * conversationViewModel.mediasToSend.count)
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.all, conversationViewModel.mediasToSend.isEmpty ? 0 : 10)
|
||||
.background(Color.gray100)
|
||||
|
||||
if !mediasIsLoading {
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.all, 20)
|
||||
.background(Color.gray100)
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
conversationViewModel.mediasToSend.removeAll()
|
||||
conversationViewModel.messageToReply = nil
|
||||
}
|
||||
}, label: {
|
||||
Image("x")
|
||||
|
|
@ -586,145 +513,234 @@ struct ConversationFragment: View {
|
|||
})
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
|
||||
HStack(spacing: 0) {
|
||||
if !voiceRecordingInProgress {
|
||||
Button {
|
||||
} label: {
|
||||
Image("smiley")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
Button {
|
||||
self.isShowPhotoLibrary = true
|
||||
self.mediasIsLoading = true
|
||||
} label: {
|
||||
Image("paperclip")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading ? Color.grayMain2c300 : Color.grayMain2c500)
|
||||
.frame(width: isMessageTextFocused ? 0 : 28, height: isMessageTextFocused ? 0 : 28, alignment: .leading)
|
||||
.padding(.all, isMessageTextFocused ? 0 : 6)
|
||||
.padding(.top, 4)
|
||||
.disabled(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
Button {
|
||||
self.isShowCamera = true
|
||||
} label: {
|
||||
Image("camera")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading ? Color.grayMain2c300 : Color.grayMain2c500)
|
||||
.frame(width: isMessageTextFocused ? 0 : 28, height: isMessageTextFocused ? 0 : 28, alignment: .leading)
|
||||
.padding(.all, isMessageTextFocused ? 0 : 6)
|
||||
.padding(.top, 4)
|
||||
.disabled(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
HStack {
|
||||
if #available(iOS 16.0, *) {
|
||||
TextField("Say something...", text: $conversationViewModel.messageText, axis: .vertical)
|
||||
.default_text_style(styleSize: 15)
|
||||
.focused($isMessageTextFocused)
|
||||
.padding(.vertical, 5)
|
||||
.onChange(of: conversationViewModel.messageText) { text in
|
||||
if !text.isEmpty && !CoreContext.shared.enteredForeground {
|
||||
conversationViewModel.compose()
|
||||
|
||||
if !conversationViewModel.mediasToSend.isEmpty || mediasIsLoading {
|
||||
ZStack(alignment: .top) {
|
||||
HStack {
|
||||
if mediasIsLoading {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
ProgressView()
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(height: 120)
|
||||
}
|
||||
|
||||
if !mediasIsLoading {
|
||||
LazyVGrid(columns: [
|
||||
GridItem(.adaptive(minimum: 100), spacing: 1)
|
||||
], spacing: 3) {
|
||||
ForEach(conversationViewModel.mediasToSend, id: \.id) { attachment in
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(Color(.white))
|
||||
.frame(width: 100, height: 100)
|
||||
|
||||
AsyncImage(url: attachment.thumbnail) { image in
|
||||
ZStack {
|
||||
image
|
||||
.resizable()
|
||||
.interpolation(.medium)
|
||||
.aspectRatio(contentMode: .fill)
|
||||
|
||||
if attachment.type == .video {
|
||||
Image("play-fill")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 40, height: 40, alignment: .leading)
|
||||
}
|
||||
}
|
||||
} placeholder: {
|
||||
ProgressView()
|
||||
}
|
||||
.layoutPriority(-1)
|
||||
.onTapGesture {
|
||||
if conversationViewModel.mediasToSend.count == 1 {
|
||||
withAnimation {
|
||||
conversationViewModel.mediasToSend.removeAll()
|
||||
}
|
||||
} else {
|
||||
guard let index = self.conversationViewModel.mediasToSend.firstIndex(of: attachment) else { return }
|
||||
self.conversationViewModel.mediasToSend.remove(at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ZStack(alignment: .leading) {
|
||||
TextEditor(text: $conversationViewModel.messageText)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(maxHeight: 160)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(
|
||||
width: geometry.size.width > 0 && CGFloat(102 * conversationViewModel.mediasToSend.count) > geometry.size.width - 20
|
||||
? 102 * floor(CGFloat(geometry.size.width - 20) / 102)
|
||||
: CGFloat(102 * conversationViewModel.mediasToSend.count)
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.all, conversationViewModel.mediasToSend.isEmpty ? 0 : 10)
|
||||
.background(Color.gray100)
|
||||
|
||||
if !mediasIsLoading {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
conversationViewModel.mediasToSend.removeAll()
|
||||
}
|
||||
}, label: {
|
||||
Image("x")
|
||||
.resizable()
|
||||
.frame(width: 30, height: 30, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
|
||||
HStack(spacing: 0) {
|
||||
if !voiceRecordingInProgress {
|
||||
Button {
|
||||
} label: {
|
||||
Image("smiley")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
Button {
|
||||
self.isShowPhotoLibrary = true
|
||||
self.mediasIsLoading = true
|
||||
} label: {
|
||||
Image("paperclip")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading ? Color.grayMain2c300 : Color.grayMain2c500)
|
||||
.frame(width: isMessageTextFocused ? 0 : 28, height: isMessageTextFocused ? 0 : 28, alignment: .leading)
|
||||
.padding(.all, isMessageTextFocused ? 0 : 6)
|
||||
.padding(.top, 4)
|
||||
.disabled(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
Button {
|
||||
self.isShowCamera = true
|
||||
} label: {
|
||||
Image("camera")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading ? Color.grayMain2c300 : Color.grayMain2c500)
|
||||
.frame(width: isMessageTextFocused ? 0 : 28, height: isMessageTextFocused ? 0 : 28, alignment: .leading)
|
||||
.padding(.all, isMessageTextFocused ? 0 : 6)
|
||||
.padding(.top, 4)
|
||||
.disabled(conversationViewModel.maxMediaCount <= conversationViewModel.mediasToSend.count || mediasIsLoading)
|
||||
}
|
||||
.padding(.horizontal, isMessageTextFocused ? 0 : 2)
|
||||
|
||||
HStack {
|
||||
if #available(iOS 16.0, *) {
|
||||
TextField("Say something...", text: $conversationViewModel.messageText, axis: .vertical)
|
||||
.default_text_style(styleSize: 15)
|
||||
.focused($isMessageTextFocused)
|
||||
.padding(.vertical, 5)
|
||||
.onChange(of: conversationViewModel.messageText) { text in
|
||||
if !text.isEmpty && !CoreContext.shared.enteredForeground {
|
||||
conversationViewModel.compose()
|
||||
}
|
||||
}
|
||||
|
||||
if conversationViewModel.messageText.isEmpty {
|
||||
Text("Say something...")
|
||||
.padding(.leading, 4)
|
||||
.lineLimit(1)
|
||||
.opacity(conversationViewModel.messageText.isEmpty ? 1 : 0)
|
||||
.foregroundStyle(Color.gray300)
|
||||
} else {
|
||||
ZStack(alignment: .leading) {
|
||||
TextEditor(text: $conversationViewModel.messageText)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(maxHeight: 160)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.default_text_style(styleSize: 15)
|
||||
.focused($isMessageTextFocused)
|
||||
.onChange(of: conversationViewModel.messageText) { text in
|
||||
if !text.isEmpty && !CoreContext.shared.enteredForeground {
|
||||
conversationViewModel.compose()
|
||||
}
|
||||
}
|
||||
|
||||
if conversationViewModel.messageText.isEmpty {
|
||||
Text("Say something...")
|
||||
.padding(.leading, 4)
|
||||
.lineLimit(1)
|
||||
.opacity(conversationViewModel.messageText.isEmpty ? 1 : 0)
|
||||
.foregroundStyle(Color.gray300)
|
||||
.default_text_style(styleSize: 15)
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
isMessageTextFocused = true
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
isMessageTextFocused = true
|
||||
}
|
||||
}
|
||||
|
||||
if conversationViewModel.messageText.isEmpty && conversationViewModel.mediasToSend.isEmpty {
|
||||
Button {
|
||||
voiceRecordingInProgress = true
|
||||
} label: {
|
||||
Image("microphone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
if conversationViewModel.displayedConversationHistorySize > 0 {
|
||||
NotificationCenter.default.post(name: .onScrollToBottom, object: nil)
|
||||
|
||||
if conversationViewModel.messageText.isEmpty && conversationViewModel.mediasToSend.isEmpty {
|
||||
Button {
|
||||
voiceRecordingInProgress = true
|
||||
} label: {
|
||||
Image("microphone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
}
|
||||
conversationViewModel.sendMessage()
|
||||
} label: {
|
||||
Image("paper-plane-tilt")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
.rotationEffect(.degrees(45))
|
||||
} else {
|
||||
Button {
|
||||
if conversationViewModel.displayedConversationHistorySize > 0 {
|
||||
NotificationCenter.default.post(name: .onScrollToBottom, object: nil)
|
||||
}
|
||||
conversationViewModel.sendMessage()
|
||||
} label: {
|
||||
Image("paper-plane-tilt")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 28, height: 28, alignment: .leading)
|
||||
.padding(.all, 6)
|
||||
.padding(.top, 4)
|
||||
.rotationEffect(.degrees(45))
|
||||
}
|
||||
.padding(.trailing, 4)
|
||||
}
|
||||
.padding(.trailing, 4)
|
||||
}
|
||||
.padding(.leading, 15)
|
||||
.padding(.trailing, 5)
|
||||
.padding(.vertical, 6)
|
||||
.frame(maxWidth: .infinity, minHeight: 55)
|
||||
.background(.white)
|
||||
.cornerRadius(30)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 30)
|
||||
.inset(by: 0.5)
|
||||
.stroke(Color.gray200, lineWidth: 1.5)
|
||||
)
|
||||
.padding(.horizontal, 4)
|
||||
} else {
|
||||
VoiceRecorderPlayer(conversationViewModel: conversationViewModel, voiceRecordingInProgress: $voiceRecordingInProgress)
|
||||
.frame(maxHeight: 60)
|
||||
}
|
||||
.padding(.leading, 15)
|
||||
.padding(.trailing, 5)
|
||||
.padding(.vertical, 6)
|
||||
.frame(maxWidth: .infinity, minHeight: 55)
|
||||
.background(.white)
|
||||
.cornerRadius(30)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 30)
|
||||
.inset(by: 0.5)
|
||||
.stroke(Color.gray200, lineWidth: 1.5)
|
||||
)
|
||||
.padding(.horizontal, 4)
|
||||
} else {
|
||||
VoiceRecorderPlayer(conversationViewModel: conversationViewModel, voiceRecordingInProgress: $voiceRecordingInProgress)
|
||||
.frame(maxHeight: 60)
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 60)
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? (isMessageTextFocused ? 12 : 0) : 12)
|
||||
.padding(.horizontal, 10)
|
||||
.background(Color.gray100)
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 60)
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? (isMessageTextFocused ? 12 : 0) : 12)
|
||||
.padding(.horizontal, 10)
|
||||
.background(Color.gray100)
|
||||
}
|
||||
}
|
||||
.blur(radius: conversationViewModel.selectedMessage != nil ? 8 : 0)
|
||||
|
|
@ -957,6 +973,19 @@ struct ConversationFragment: View {
|
|||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
|
||||
if isShowInfoConversationFragment {
|
||||
ConversationInfoFragment(
|
||||
conversationViewModel: conversationViewModel,
|
||||
conversationsListViewModel: conversationsListViewModel,
|
||||
isMuted: $isMuted,
|
||||
isShowEphemeralFragment: $isShowEphemeralFragment,
|
||||
isShowStartCallGroupPopup: $isShowStartCallGroupPopup,
|
||||
isShowInfoConversationFragment: $isShowInfoConversationFragment
|
||||
)
|
||||
.zIndex(5)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
|
||||
if isShowEphemeralFragment {
|
||||
EphemeralFragment(
|
||||
conversationViewModel: conversationViewModel,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* 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 SwiftUI
|
||||
|
||||
struct ConversationInfoFragment: View {
|
||||
@State private var orientation = UIDevice.current.orientation
|
||||
|
||||
@ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared
|
||||
|
||||
@ObservedObject var conversationViewModel: ConversationViewModel
|
||||
@ObservedObject var conversationsListViewModel: ConversationsListViewModel
|
||||
|
||||
@Binding var isMuted: Bool
|
||||
@Binding var isShowEphemeralFragment: Bool
|
||||
@Binding var isShowStartCallGroupPopup: Bool
|
||||
@Binding var isShowInfoConversationFragment: Bool
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
GeometryReader { geometry in
|
||||
if conversationViewModel.displayedConversation != nil {
|
||||
VStack(spacing: 1) {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.orangeMain500)
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
.frame(height: 0)
|
||||
|
||||
HStack {
|
||||
Image("caret-left")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
.padding(.top, 2)
|
||||
.padding(.leading, -10)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
isShowInfoConversationFragment = false
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 50)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 4)
|
||||
.background(.white)
|
||||
|
||||
ScrollView {
|
||||
VStack(spacing: 0) {
|
||||
VStack(spacing: 0) {
|
||||
if #unavailable(iOS 16.0) {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.gray100)
|
||||
.frame(height: 7)
|
||||
}
|
||||
|
||||
VStack(spacing: 0) {
|
||||
if conversationViewModel.displayedConversation != nil && !conversationViewModel.displayedConversation!.isGroup {
|
||||
|
||||
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)
|
||||
|
||||
Text(conversationViewModel.displayedConversation!.avatarModel.address)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.top, 5)
|
||||
|
||||
if !conversationViewModel.displayedConversation!.avatarModel.lastPresenceInfo.isEmpty {
|
||||
Text(conversationViewModel.displayedConversation!.avatarModel.lastPresenceInfo)
|
||||
.foregroundStyle(conversationViewModel.displayedConversation!.avatarModel.lastPresenceInfo == "Online"
|
||||
? Color.greenSuccess500
|
||||
: Color.orangeWarning600)
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style_300(styleSize: 12)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 20)
|
||||
.padding(.top, 5)
|
||||
} else {
|
||||
Text("")
|
||||
.multilineTextAlignment(.center)
|
||||
.default_text_style_300(styleSize: 12)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 20)
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 150)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 2)
|
||||
.background(Color.gray100)
|
||||
|
||||
if !conversationViewModel.displayedConversation!.isReadOnly {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
conversationViewModel.displayedConversation!.toggleMute()
|
||||
isMuted = !isMuted
|
||||
}, label: {
|
||||
VStack {
|
||||
HStack(alignment: .center) {
|
||||
Image(isMuted ? "bell-simple" : "bell-simple-slash")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
}
|
||||
.padding(16)
|
||||
.background(Color.grayMain2c200)
|
||||
.cornerRadius(40)
|
||||
|
||||
Text(isMuted ? "conversation_action_unmute" : "conversation_action_mute")
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(minWidth: 80)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.frame(width: geometry.size.width / 4)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
if conversationViewModel.displayedConversation!.isGroup {
|
||||
isShowStartCallGroupPopup.toggle()
|
||||
} else {
|
||||
conversationViewModel.displayedConversation!.call()
|
||||
}
|
||||
}, label: {
|
||||
VStack {
|
||||
HStack(alignment: .center) {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
}
|
||||
.padding(16)
|
||||
.background(Color.grayMain2c200)
|
||||
.cornerRadius(40)
|
||||
|
||||
Text("conversation_action_call")
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(minWidth: 80)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.frame(width: geometry.size.width / 4)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
// TODO Create Meeting
|
||||
}, label: {
|
||||
VStack {
|
||||
HStack(alignment: .center) {
|
||||
Image("video-conference")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
}
|
||||
.padding(16)
|
||||
.background(Color.grayMain2c200)
|
||||
.cornerRadius(40)
|
||||
|
||||
Text("meeting_schedule_meeting_label")
|
||||
.default_text_style(styleSize: 14)
|
||||
.frame(minWidth: 80)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.frame(width: geometry.size.width / 4)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.top, 20)
|
||||
.padding(.bottom, 10)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.gray100)
|
||||
}
|
||||
|
||||
Text("contact_details_actions_title")
|
||||
.default_text_style_800(styleSize: 18)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 20)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
if !conversationViewModel.displayedConversation!.isReadOnly {
|
||||
if !conversationViewModel.displayedConversation!.isGroup {
|
||||
Button(
|
||||
action: {
|
||||
},
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
.frame(height: 60)
|
||||
|
||||
Divider()
|
||||
}
|
||||
|
||||
Button(
|
||||
action: {
|
||||
withAnimation {
|
||||
isShowEphemeralFragment = true
|
||||
}
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
Image("clock-countdown")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("conversation_action_configure_ephemeral_messages")
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
.frame(height: 60)
|
||||
|
||||
Divider()
|
||||
|
||||
if conversationViewModel.displayedConversation!.isGroup {
|
||||
Button(
|
||||
action: {
|
||||
conversationViewModel.displayedConversation!.leave()
|
||||
conversationViewModel.displayedConversation!.isReadOnly = true
|
||||
isShowInfoConversationFragment = false
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
Image("sign-out")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c600)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("conversation_action_leave_group")
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
.frame(height: 60)
|
||||
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
Button(
|
||||
action: {
|
||||
conversationViewModel.displayedConversation!.deleteChatRoom()
|
||||
conversationsListViewModel.computeChatRoomsList(filter: "")
|
||||
conversationViewModel.displayedConversation = nil
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
Image("trash-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text("conversation_info_delete_history_action")
|
||||
.foregroundStyle(Color.redDanger500)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
.frame(height: 60)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 4)
|
||||
.background(.white)
|
||||
.cornerRadius(15)
|
||||
.padding(.all)
|
||||
}
|
||||
.frame(maxWidth: sharedMainViewModel.maxWidth)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
.background(Color.gray100)
|
||||
}
|
||||
.background(.white)
|
||||
.navigationBarHidden(true)
|
||||
.onRotate { newOrientation in
|
||||
orientation = newOrientation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ConversationInfoFragment(
|
||||
conversationViewModel: ConversationViewModel(),
|
||||
conversationsListViewModel: ConversationsListViewModel(),
|
||||
isMuted: .constant(false),
|
||||
isShowEphemeralFragment: .constant(false),
|
||||
isShowStartCallGroupPopup: .constant(false),
|
||||
isShowInfoConversationFragment: .constant(true)
|
||||
)
|
||||
}
|
||||
|
|
@ -39,7 +39,11 @@ struct ConversationsFragment: View {
|
|||
conversationsListViewModel: conversationsListViewModel,
|
||||
showingSheet: $showingSheet
|
||||
)
|
||||
.presentationDetents([.fraction(0.4)])
|
||||
.presentationDetents(
|
||||
conversationsListViewModel.selectedConversation != nil && !conversationsListViewModel.selectedConversation!.isReadOnly
|
||||
? [.fraction(0.4)]
|
||||
: [.fraction(0.1)]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
ConversationsListFragment(conversationViewModel: conversationViewModel,
|
||||
|
|
|
|||
|
|
@ -54,88 +54,11 @@ struct ConversationsListBottomSheet: View {
|
|||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.markAsReadSelectedConversation()
|
||||
conversationsListViewModel.updateUnreadMessagesCount()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("envelope-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Marquer comme non lu")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.selectedConversation!.toggleMute()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
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!.isMuted ? "Réactiver les notifications" : "Mettre en sourdine")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
if conversationsListViewModel.selectedConversation != nil
|
||||
&& !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
if conversationsListViewModel.selectedConversation != nil && !conversationsListViewModel.selectedConversation!.isReadOnly {
|
||||
Button {
|
||||
if !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
conversationsListViewModel.selectedConversation!.call()
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.markAsReadSelectedConversation()
|
||||
conversationsListViewModel.updateUnreadMessagesCount()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
|
|
@ -149,16 +72,15 @@ struct ConversationsListBottomSheet: View {
|
|||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
} label: {
|
||||
HStack {
|
||||
Image("phone")
|
||||
Image("envelope-simple")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Appel")
|
||||
Text("Marquer comme non lu")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
|
|
@ -171,9 +93,89 @@ struct ConversationsListBottomSheet: View {
|
|||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.selectedConversation!.toggleMute()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
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!.isMuted ? "Réactiver les notifications" : "Mettre en sourdine")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
if conversationsListViewModel.selectedConversation != nil
|
||||
&& !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
Button {
|
||||
if !conversationsListViewModel.selectedConversation!.isGroup {
|
||||
conversationsListViewModel.selectedConversation!.call()
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
} label: {
|
||||
HStack {
|
||||
Image("phone")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Appel")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Button {
|
||||
conversationsListViewModel.selectedConversation!.deleteChatRoom()
|
||||
conversationsListViewModel.computeChatRoomsList(filter: "")
|
||||
|
||||
|
|
@ -206,43 +208,46 @@ struct ConversationsListBottomSheet: View {
|
|||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.selectedConversation!.leave()
|
||||
if conversationsListViewModel.selectedConversation != nil && !conversationsListViewModel.selectedConversation!.isReadOnly {
|
||||
VStack {
|
||||
Divider()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
Button {
|
||||
if conversationsListViewModel.selectedConversation != nil {
|
||||
conversationsListViewModel.selectedConversation!.leave()
|
||||
conversationsListViewModel.selectedConversation!.isReadOnly = true
|
||||
}
|
||||
|
||||
if #available(iOS 16.0, *) {
|
||||
if idiom != .pad {
|
||||
showingSheet.toggle()
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
}
|
||||
} else {
|
||||
showingSheet.toggle()
|
||||
dismiss()
|
||||
} label: {
|
||||
HStack {
|
||||
Image("sign-out")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Quitter la conversation")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Image("sign-out")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.all, 10)
|
||||
Text("Quitter la conversation")
|
||||
.default_text_style(styleSize: 16)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.gray100)
|
||||
}
|
||||
.background(Color.gray100)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class ConversationModel: ObservableObject, Identifiable {
|
|||
let localSipUri: String
|
||||
let remoteSipUri: String
|
||||
let isGroup: Bool
|
||||
let isReadOnly: Bool
|
||||
@Published var isReadOnly: Bool
|
||||
@Published var subject: String
|
||||
@Published var participantsAddress: [String] = []
|
||||
@Published var isComposing: Bool
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue