From cacc61252d847a6d55287cabc2b5ce35c5eb926d Mon Sep 17 00:00:00 2001 From: "benoit.martins" Date: Wed, 14 Feb 2024 17:59:21 +0100 Subject: [PATCH] Add ConversationsList bottom sheet --- Linphone.xcodeproj/project.pbxproj | 8 + .../bell-slash.imageset/Contents.json | 21 ++ .../bell-slash.imageset/bell-slash.svg | 1 + Linphone/Localizable.xcstrings | 12 + .../Conversations/ConversationsView.swift | 2 +- .../Fragments/ConversationsFragment.swift | 35 +-- .../ConversationsListBottomSheet.swift | 231 ++++++++++++++++++ .../Fragments/ConversationsListFragment.swift | 7 +- .../ViewModel/ConversationViewModel.swift | 30 +++ 9 files changed, 321 insertions(+), 26 deletions(-) create mode 100644 Linphone/Assets.xcassets/bell-slash.imageset/Contents.json create mode 100644 Linphone/Assets.xcassets/bell-slash.imageset/bell-slash.svg create mode 100644 Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift create mode 100644 Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 7fbd4f875..d7d34d2da 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ 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 */; }; + D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */; }; + D70A26F02B7D02E6006CC8FC /* ConversationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A26EF2B7D02E6006CC8FC /* ConversationViewModel.swift */; }; D70C93DE2AC2D0F60063CA3B /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */; }; D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071D2AC5922E0037746F /* ColorExtension.swift */; }; D71707202AC5989C0037746F /* TextExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D717071F2AC5989C0037746F /* TextExtension.swift */; }; @@ -114,6 +116,8 @@ 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = ""; }; 66C492002B24DB6900CEA16D /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = ""; }; + D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsListBottomSheet.swift; sourceTree = ""; }; + D70A26EF2B7D02E6006CC8FC /* ConversationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationViewModel.swift; sourceTree = ""; }; D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; D717071D2AC5922E0037746F /* ColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtension.swift; sourceTree = ""; }; D717071F2AC5989C0037746F /* TextExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextExtension.swift; sourceTree = ""; }; @@ -544,6 +548,7 @@ isa = PBXGroup; children = ( D7CEE0372B7A214F00FD79B7 /* ConversationsListViewModel.swift */, + D70A26EF2B7D02E6006CC8FC /* ConversationViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -553,6 +558,7 @@ children = ( D7CEE03A2B7A234200FD79B7 /* ConversationsFragment.swift */, D7CEE03C2B7A23B200FD79B7 /* ConversationsListFragment.swift */, + D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */, ); path = Fragments; sourceTree = ""; @@ -741,6 +747,7 @@ D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */, D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */, D72992392ADD7F68003AF125 /* HistoryContactFragment.swift in Sources */, + D70A26F02B7D02E6006CC8FC /* ConversationViewModel.swift in Sources */, D7B5066D2AEFA9B900CEB4E9 /* ContactInnerFragment.swift in Sources */, D7E6D04D2AEBD77600A57AAF /* CustomBottomSheet.swift in Sources */, D7C48DF42AFA66F900D938CB /* EditContactController.swift in Sources */, @@ -780,6 +787,7 @@ D7B99E9B2B29F7C300BE7BF2 /* ActivityIndicator.swift in Sources */, D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */, D726E43F2B19E56F0083C415 /* StartCallViewModel.swift in Sources */, + D70A26EE2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift in Sources */, D7D1698C2AE66FA500109A5C /* MagicSearchSingleton.swift in Sources */, D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */, D7CEE0352B7A210300FD79B7 /* ConversationsView.swift in Sources */, diff --git a/Linphone/Assets.xcassets/bell-slash.imageset/Contents.json b/Linphone/Assets.xcassets/bell-slash.imageset/Contents.json new file mode 100644 index 000000000..1f035fcee --- /dev/null +++ b/Linphone/Assets.xcassets/bell-slash.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bell-slash.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Linphone/Assets.xcassets/bell-slash.imageset/bell-slash.svg b/Linphone/Assets.xcassets/bell-slash.imageset/bell-slash.svg new file mode 100644 index 000000000..9e4cec690 --- /dev/null +++ b/Linphone/Assets.xcassets/bell-slash.imageset/bell-slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 750aa39b8..561647542 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -400,12 +400,18 @@ }, "Logs URL copied into clipboard" : { + }, + "Marquer comme non lu" : { + }, "Message" : { }, "Messages" : { + }, + "Mettre en sourdine" : { + }, "Missed call" : { @@ -489,6 +495,9 @@ }, "QR code validated!" : { + }, + "Quitter la conversation" : { + }, "Record" : { @@ -558,6 +567,9 @@ }, "Suggestions" : { + }, + "Supprimer la conversation" : { + }, "TCP" : { diff --git a/Linphone/UI/Main/Conversations/ConversationsView.swift b/Linphone/UI/Main/Conversations/ConversationsView.swift index 9a79142f3..35ee68224 100644 --- a/Linphone/UI/Main/Conversations/ConversationsView.swift +++ b/Linphone/UI/Main/Conversations/ConversationsView.swift @@ -47,5 +47,5 @@ struct ConversationsView: View { } #Preview { - ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel()) + ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift index 90ae2cd1a..2f375edd9 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift @@ -22,47 +22,34 @@ import SwiftUI struct ConversationsFragment: View { @ObservedObject var conversationsListViewModel: ConversationsListViewModel + @ObservedObject var conversationViewModel: ConversationViewModel private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + @State var showingSheet: Bool = false + var body: some View { ZStack { if #available(iOS 16.0, *), idiom != .pad { - ConversationsListFragment(conversationsListViewModel: conversationsListViewModel) - /* + ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, conversationViewModel: conversationViewModel,showingSheet: $showingSheet) .sheet(isPresented: $showingSheet) { - HistoryListBottomSheet( - historyViewModel: historyViewModel, - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - historyListViewModel: historyListViewModel, - showingSheet: $showingSheet, - index: $index, - isShowEditContactFragment: $isShowEditContactFragment + ConversationsListBottomSheet( + showingSheet: $showingSheet ) - .presentationDetents([.fraction(0.2)]) + .presentationDetents([.fraction(0.4)]) } - */ } else { - ConversationsListFragment(conversationsListViewModel: conversationsListViewModel) - /* + ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, conversationViewModel: conversationViewModel,showingSheet: $showingSheet) .halfSheet(showSheet: $showingSheet) { - HistoryListBottomSheet( - historyViewModel: historyViewModel, - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - historyListViewModel: historyListViewModel, - showingSheet: $showingSheet, - index: $index, - isShowEditContactFragment: $isShowEditContactFragment + ConversationsListBottomSheet( + showingSheet: $showingSheet ) } onDismiss: {} - */ } } } } #Preview { - ConversationsFragment(conversationsListViewModel: ConversationsListViewModel()) + ConversationsFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel()) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift new file mode 100644 index 000000000..4bd5954c1 --- /dev/null +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * 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 . + */ + +import SwiftUI + +struct ConversationsListBottomSheet: View { + + @Environment(\.dismiss) var dismiss + + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + + @State private var orientation = UIDevice.current.orientation + + @Binding var showingSheet: Bool + + var body: some View { + VStack(alignment: .leading) { + if idiom != .pad && (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + Spacer() + HStack { + Spacer() + Button("Close") { + if #available(iOS 16.0, *) { + showingSheet.toggle() + } else { + showingSheet.toggle() + dismiss() + } + } + } + .padding(.trailing) + } + + Spacer() + + Button { + 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 #available(iOS 16.0, *) { + if idiom != .pad { + showingSheet.toggle() + } else { + showingSheet.toggle() + dismiss() + } + } else { + showingSheet.toggle() + dismiss() + } + } label: { + HStack { + Image("bell-slash") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + Text("Mettre en sourdine") + .default_text_style(styleSize: 16) + Spacer() + } + .frame(maxHeight: .infinity) + } + .padding(.horizontal, 30) + .background(Color.gray100) + + VStack { + Divider() + } + .frame(maxWidth: .infinity) + + Button { + 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 { + if #available(iOS 16.0, *) { + if idiom != .pad { + showingSheet.toggle() + } else { + showingSheet.toggle() + dismiss() + } + } else { + showingSheet.toggle() + dismiss() + } + } label: { + HStack { + Image("trash-simple") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.redDanger500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + Text("Supprimer la conversation") + .foregroundStyle(Color.redDanger500) + .default_text_style(styleSize: 16) + Spacer() + } + .frame(maxHeight: .infinity) + } + .padding(.horizontal, 30) + .background(Color.gray100) + + VStack { + Divider() + } + .frame(maxWidth: .infinity) + + Button { + if #available(iOS 16.0, *) { + if idiom != .pad { + showingSheet.toggle() + } 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) + } + .padding(.horizontal, 30) + .background(Color.gray100) + } + .background(Color.gray100) + .frame(maxWidth: .infinity) + .onRotate { newOrientation in + orientation = newOrientation + } + } +} + +#Preview { + ConversationsListBottomSheet(showingSheet: .constant(true)) +} diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift index c582fea2a..8ffa2a1f0 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift @@ -25,6 +25,9 @@ struct ConversationsListFragment: View { @ObservedObject var contactsManager = ContactsManager.shared @ObservedObject var conversationsListViewModel: ConversationsListViewModel + @ObservedObject var conversationViewModel: ConversationViewModel + + @Binding var showingSheet: Bool var body: some View { VStack { @@ -217,6 +220,8 @@ struct ConversationsListFragment: View { .onTapGesture { } .onLongPressGesture(minimumDuration: 0.2) { + conversationViewModel.selectedConversation = conversationsListViewModel.conversationsList[index] + showingSheet.toggle() } } } @@ -245,5 +250,5 @@ struct ConversationsListFragment: View { } #Preview { - ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel()) + ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift new file mode 100644 index 000000000..98707fa02 --- /dev/null +++ b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * 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 . + */ + +import Foundation +import linphonesw + +class ConversationViewModel: ObservableObject { + + @Published var displayedConversation: ChatRoom? + + var selectedConversation: ChatRoom? + + init() {} +}