From dfcd501dc34fc5a9e02798b84a4474d583c1e048 Mon Sep 17 00:00:00 2001 From: Christophe Deschamps Date: Mon, 17 Jun 2024 10:28:39 +0000 Subject: [PATCH] Side menu --- Linphone.xcodeproj/project.pbxproj | 28 ++ Linphone/.DS_Store | Bin 8196 -> 0 bytes Linphone/Core/CoreContext.swift | 19 +- Linphone/Localizable.xcstrings | 182 +++++++++++- .../Assistant/Fragments/LoginFragment.swift | 29 ++ Linphone/UI/Main/ContentView.swift | 20 +- Linphone/UI/Main/Fragments/HelpView.swift | 62 +++++ Linphone/UI/Main/Fragments/SideMenu.swift | 259 +++++++++++------- .../Main/Fragments/SideMenuAccountRow.swift | 87 ++++++ .../UI/Main/Fragments/SideMenuEntry.swift | 53 ++++ Linphone/UI/Main/Viewmodel/AccountModel.swift | 81 ++++++ .../Utils/Extensions/AccountExtension.swift | 36 +++ .../Utils/Extensions/BundleExtenion.swift | 26 ++ .../Utils/Extensions/StringExtension.swift | 26 ++ Linphone/Utils/Extensions/TextExtension.swift | 26 ++ 15 files changed, 825 insertions(+), 109 deletions(-) delete mode 100644 Linphone/.DS_Store create mode 100644 Linphone/UI/Main/Fragments/HelpView.swift create mode 100644 Linphone/UI/Main/Fragments/SideMenuAccountRow.swift create mode 100644 Linphone/UI/Main/Fragments/SideMenuEntry.swift create mode 100644 Linphone/UI/Main/Viewmodel/AccountModel.swift create mode 100644 Linphone/Utils/Extensions/AccountExtension.swift create mode 100644 Linphone/Utils/Extensions/BundleExtenion.swift create mode 100644 Linphone/Utils/Extensions/StringExtension.swift diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 560c3787a..137de0f75 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -36,6 +36,11 @@ 66FBFC4A2B83BD3300BC6AB1 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FE2B24D4AC00CEA16D /* FileUtils.swift */; }; 66FBFC4B2B83BD7B00BC6AB1 /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; }; C60E8F192C0F649200A06DB8 /* UIApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */; }; + C62817282C1B389700DBA646 /* SideMenuAccountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62817272C1B389700DBA646 /* SideMenuAccountRow.swift */; }; + C628172E2C1C3A3600DBA646 /* AccountExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C628172D2C1C3A3600DBA646 /* AccountExtension.swift */; }; + C62817302C1C3DCC00DBA646 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C628172F2C1C3DCC00DBA646 /* AccountModel.swift */; }; + C62817322C1C400A00DBA646 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62817312C1C400A00DBA646 /* StringExtension.swift */; }; + C62817342C1C7C7400DBA646 /* HelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62817332C1C7C7400DBA646 /* HelpView.swift */; }; C67586AE2C09F23C002E77BF /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AD2C09F23C002E77BF /* URLExtension.swift */; }; C67586B02C09F247002E77BF /* URIHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586AF2C09F247002E77BF /* URIHandler.swift */; }; C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C67586B22C09F617002E77BF /* SingleSignOnManager.swift */; }; @@ -43,6 +48,8 @@ C6A5A9432C10B5ED0070FEA4 /* DecodableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */; }; C6A5A9452C10B6270070FEA4 /* OIDAuthStateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9442C10B6270070FEA4 /* OIDAuthStateExtension.swift */; }; C6A5A9482C10B6A30070FEA4 /* AuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A5A9472C10B6A30070FEA4 /* AuthState.swift */; }; + C6DC4E3D2C199C4E009096FD /* BundleExtenion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DC4E3C2C199C4E009096FD /* BundleExtenion.swift */; }; + C6DC4E3F2C19C289009096FD /* SideMenuEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DC4E3E2C19C289009096FD /* SideMenuEntry.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 */; }; @@ -201,6 +208,11 @@ 66E56BCD2BA9A1F8006CE56F /* MeetingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingModel.swift; sourceTree = ""; }; 66F626B12BCEBB86003E2DEC /* AddParticipantsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsFragment.swift; sourceTree = ""; }; C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtension.swift; sourceTree = ""; }; + C62817272C1B389700DBA646 /* SideMenuAccountRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuAccountRow.swift; sourceTree = ""; }; + C628172D2C1C3A3600DBA646 /* AccountExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExtension.swift; sourceTree = ""; }; + C628172F2C1C3DCC00DBA646 /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = ""; }; + C62817312C1C400A00DBA646 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; + C62817332C1C7C7400DBA646 /* HelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpView.swift; sourceTree = ""; }; C67586AD2C09F23C002E77BF /* URLExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = ""; }; C67586AF2C09F247002E77BF /* URIHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIHandler.swift; sourceTree = ""; }; C67586B22C09F617002E77BF /* SingleSignOnManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSignOnManager.swift; sourceTree = ""; }; @@ -208,6 +220,8 @@ C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodableExtension.swift; sourceTree = ""; }; C6A5A9442C10B6270070FEA4 /* OIDAuthStateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDAuthStateExtension.swift; sourceTree = ""; }; C6A5A9472C10B6A30070FEA4 /* AuthState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthState.swift; sourceTree = ""; }; + C6DC4E3C2C199C4E009096FD /* BundleExtenion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleExtenion.swift; sourceTree = ""; }; + C6DC4E3E2C19C289009096FD /* SideMenuEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuEntry.swift; sourceTree = ""; }; D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = ""; }; D70959F02B8DF3EC0014AC0B /* ConversationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationModel.swift; sourceTree = ""; }; D70A26ED2B7CF60B006CC8FC /* ConversationsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationsListBottomSheet.swift; sourceTree = ""; }; @@ -368,6 +382,9 @@ C60E8F182C0F649200A06DB8 /* UIApplicationExtension.swift */, C6A5A9402C10B5D50070FEA4 /* EncodableExtension.swift */, C6A5A9422C10B5ED0070FEA4 /* DecodableExtension.swift */, + C6DC4E3C2C199C4E009096FD /* BundleExtenion.swift */, + C628172D2C1C3A3600DBA646 /* AccountExtension.swift */, + C62817312C1C400A00DBA646 /* StringExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -624,6 +641,9 @@ D750D3382AD3E6EE00EC99C5 /* PopupLoadingView.swift */, D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */, D72250682ADFBF2D008FB426 /* SideMenu.swift */, + C62817332C1C7C7400DBA646 /* HelpView.swift */, + C6DC4E3E2C19C289009096FD /* SideMenuEntry.swift */, + C62817272C1B389700DBA646 /* SideMenuAccountRow.swift */, D7E6D04C2AEBD77600A57AAF /* CustomBottomSheet.swift */, ); path = Fragments; @@ -724,6 +744,7 @@ 66162A1F2BDFC2F900DCE913 /* AddParticipantsViewModel.swift */, D7A2EDD52AC18115005D90FC /* SharedMainViewModel.swift */, D796F1FF2B0BB61A0041115F /* ToastViewModel.swift */, + C628172F2C1C3DCC00DBA646 /* AccountModel.swift */, ); path = Viewmodel; sourceTree = ""; @@ -1014,6 +1035,7 @@ D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */, 66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */, D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */, + C6DC4E3D2C199C4E009096FD /* BundleExtenion.swift in Sources */, D7EAACCF2AD6ED8000AA6A8A /* PermissionsFragment.swift in Sources */, D777DBB32AE12C5900565A99 /* ContactsManager.swift in Sources */, D720E6AD2BAD822000DDFD87 /* ParticipantModel.swift in Sources */, @@ -1027,6 +1049,7 @@ D732A90F2B04C3B400DB42BA /* HistoryFragment.swift in Sources */, D79622342B1DFE600037EACD /* DialerBottomSheet.swift in Sources */, C67586B02C09F247002E77BF /* URIHandler.swift in Sources */, + C62817282C1B389700DBA646 /* SideMenuAccountRow.swift in Sources */, C60E8F192C0F649200A06DB8 /* UIApplicationExtension.swift in Sources */, D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */, C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */, @@ -1037,9 +1060,12 @@ 6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */, D7B5066D2AEFA9B900CEB4E9 /* ContactInnerFragment.swift in Sources */, D7E6D04D2AEBD77600A57AAF /* CustomBottomSheet.swift in Sources */, + C62817302C1C3DCC00DBA646 /* AccountModel.swift in Sources */, D73449992BC6932A00778C56 /* MeetingWaitingRoomFragment.swift in Sources */, D7C48DF42AFA66F900D938CB /* EditContactController.swift in Sources */, + C628172E2C1C3A3600DBA646 /* AccountExtension.swift in Sources */, 66C491FF2B24D4AC00CEA16D /* FileUtils.swift in Sources */, + C62817322C1C400A00DBA646 /* StringExtension.swift in Sources */, D74C9D012ACB098C0021626A /* PermissionManager.swift in Sources */, D7B99E992B29B39000BE7BF2 /* CallViewModel.swift in Sources */, D7702EF22AC7205000557C00 /* WelcomeView.swift in Sources */, @@ -1099,6 +1125,7 @@ D7D1698C2AE66FA500109A5C /* MagicSearchSingleton.swift in Sources */, D74DA0122C047F0700A8561D /* HistoryModel.swift in Sources */, D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */, + C6DC4E3F2C19C289009096FD /* SideMenuEntry.swift in Sources */, D7CEE0352B7A210300FD79B7 /* ConversationsView.swift in Sources */, D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */, D71968922B86369D00DF4459 /* ChatBubbleView.swift in Sources */, @@ -1108,6 +1135,7 @@ D74C9CFC2ACACF370021626A /* WelcomePage3Fragment.swift in Sources */, C6A5A9412C10B5D50070FEA4 /* EncodableExtension.swift in Sources */, D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */, + C62817342C1C7C7400DBA646 /* HelpView.swift in Sources */, D78E062C2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift in Sources */, D7C365082AEFAB7F00FE6142 /* ContactListBottomSheet.swift in Sources */, D7E6D04B2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift in Sources */, diff --git a/Linphone/.DS_Store b/Linphone/.DS_Store deleted file mode 100644 index 06ce575e56dfde609b73451038cc47f059aa7fea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM&2AGh5FV!~-L^t4h)TU6t;977{h?JWE@@hjDsey!KLpqPQe+ zKj)!TFf9v^3i?DTB~+&O)F5vNZ5u2DmI2FvWxz6E8Tc0%z&D$dbH#UG_uA4jU>W!? z8Q}B5MP^wsvZtjS9VjFOfGna}66%NpM8`FqcH|k+r2a;c| zE#&gKB-Hq7V4Gr!pz9&-#|^+BzVJPVFABa*{veLNUWKc7la{gnt=7`27*66(UnL4GcZ zSDl?d&n1?-A)fmO_)A@8pl^(@7HZ2}5A!}GzL8zk96bfrrxW0PSar2jevODW_A0&KJ$&`8n#B>WtkpH`p_m*RJWAm#!`6rMIajKIeh8Bh(wh zKePSk{m<@Nfu7UuAkPJU3$i{Un6dNvciwneOOD4$aFD`l!y%7jFU_)*L5`b`)#Z(n zyRvcJ6EL%)94lD5O(SPuLR(zq`2W$>_x~fGmo;b^undfj0ae_o?Nnj!;^%ALG{@R5 z@>^t1jO%GBDkvlzhm>#}vj2x6>Mo$HQ!%oqC0dY1ei1ObU;Os_FFPy+#{%~I|C^7o G*M0%tT_u CoreDelegatePublisher? { + return mCore.publisher + } + } // swiftlint:enable large_tuple diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 0890a892c..77a3aaae4 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -276,7 +276,7 @@ "Chiffrement du média" : { }, - "Clear logs" : { + "Clear Logs" : { }, "Close" : { @@ -365,6 +365,124 @@ }, "Don’t save modifications?" : { + }, + "drawer_menu_account_connection_status_cleared" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disabled" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désactivé" + } + } + } + }, + "drawer_menu_account_connection_status_connected" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connected" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connecté" + } + } + } + }, + "drawer_menu_account_connection_status_failed" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur" + } + } + } + }, + "drawer_menu_account_connection_status_progress" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connecting…" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "En cours de connexion…" + } + } + } + }, + "drawer_menu_account_connection_status_refreshing" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Refreshing ..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "En cours de rafraîchissement…" + } + } + } + }, + "drawer_menu_add_account" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add an account" + } + }, + "fr" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "Ajouter un compte" + } + } + } + }, + "drawer_menu_no_account_configured_yet" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No account configured yet" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucun compte configuré" + } + } + } }, "Earpiece" : { @@ -433,6 +551,23 @@ }, "Headphones" : { + }, + "help_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Help" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aide" + } + } + } }, "History has been deleted" : { @@ -490,6 +625,12 @@ "Key" : { "extractionState" : "manual" }, + "Key 1" : { + "extractionState" : "manual" + }, + "Key 2" : { + "extractionState" : "manual" + }, "Last name" : { }, @@ -647,6 +788,23 @@ }, "Record" : { + }, + "recordings_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recordings" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enregistrements" + } + } + } }, "Register" : { @@ -706,8 +864,25 @@ "Send invitations to participants" : { }, - "Send logs" : { + "Send Logs" : { + }, + "settings_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paramètres" + } + } + } }, "Share" : { @@ -747,6 +922,9 @@ }, "TCP" : { + }, + "Temp Help" : { + }, "The user name or password is incorrects" : { diff --git a/Linphone/UI/Assistant/Fragments/LoginFragment.swift b/Linphone/UI/Assistant/Fragments/LoginFragment.swift index c7e1da5e2..35c629ede 100644 --- a/Linphone/UI/Assistant/Fragments/LoginFragment.swift +++ b/Linphone/UI/Assistant/Fragments/LoginFragment.swift @@ -37,6 +37,10 @@ struct LoginFragment: View { @State private var isLinkSIPActive = false @State private var isLinkREGActive = false + var isShowBack = false + + var onBackPressed: (() -> Void)? + var body: some View { NavigationView { ZStack { @@ -49,6 +53,31 @@ struct LoginFragment: View { .scaledToFill() .frame(width: geometry.size.width, height: 100) .clipped() + + if isShowBack { + VStack(alignment: .leading) { + HStack { + Image("caret-left") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + .padding(.top, -75) + .padding(.leading, -10) + .onTapGesture { + withAnimation { + onBackPressed?() + } + } + + Spacer() + } + .padding(.leading) + } + .frame(width: geometry.size.width) + } + Text("assistant_account_login") .default_text_style_white_800(styleSize: 20) .padding(.top, 20) diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index f71015354..5e76f7dcc 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -64,6 +64,7 @@ struct ContentView: View { @State var fullscreenVideo = false @State var isShowScheduleMeetingFragment = false + @State private var isShowLoginFragment: Bool = false var body: some View { let pub = NotificationCenter.default @@ -765,15 +766,30 @@ struct ContentView: View { } SideMenu( - callViewModel: callViewModel, width: geometry.size.width / 5 * 4, isOpen: self.sideMenuIsOpen, menuClose: self.openMenu, - safeAreaInsets: geometry.safeAreaInsets + safeAreaInsets: geometry.safeAreaInsets, + isShowLoginFragment: $isShowLoginFragment ) .ignoresSafeArea(.all) .zIndex(2) + if isShowLoginFragment { + LoginFragment( + accountLoginViewModel: AccountLoginViewModel(), + isShowBack: true, + onBackPressed: { + withAnimation { + isShowLoginFragment.toggle() + } + }) + .zIndex(3) + .transition(.move(edge: .bottom)) + .onAppear { + } + } + if isShowEditContactFragment { EditContactFragment( editContactViewModel: editContactViewModel, diff --git a/Linphone/UI/Main/Fragments/HelpView.swift b/Linphone/UI/Main/Fragments/HelpView.swift new file mode 100644 index 000000000..af227f297 --- /dev/null +++ b/Linphone/UI/Main/Fragments/HelpView.swift @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2024 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 HelpView { // TODO (basic debug moved here until halp view is implemented) + + static func sendLogs() { + CoreContext.shared.doOnCoreQueue { core in + core.uploadLogCollection() + } + } + + static func clearLogs() { + CoreContext.shared.doOnCoreQueue { _ in + Core.resetLogCollection() + DispatchQueue.main.async { + ToastViewModel.shared.toastMessage = "Success_clear_logs" + ToastViewModel.shared.displayToast = true + } + } + } + + static func logout() { + CoreContext.shared.doOnCoreQueue { core in + if core.defaultAccount != nil { + let authInfo = core.defaultAccount!.findAuthInfo() + if authInfo != nil { + Log.info("$TAG Found auth info for account, removing it") + core.removeAuthInfo(info: authInfo!) + } else { + Log.warn("$TAG Failed to find matching auth info for account") + } + + core.removeAccount(account: core.defaultAccount!) + Log.info("$TAG Account has been removed") + + DispatchQueue.main.async { + CoreContext.shared.hasDefaultAccount = false + CoreContext.shared.loggedIn = false + } + } + } + } +} diff --git a/Linphone/UI/Main/Fragments/SideMenu.swift b/Linphone/UI/Main/Fragments/SideMenu.swift index 200619300..0df717379 100644 --- a/Linphone/UI/Main/Fragments/SideMenu.swift +++ b/Linphone/UI/Main/Fragments/SideMenu.swift @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2023 Belledonne Communications SARL. + * Copyright (c) 2010-2024 Belledonne Communications SARL. * * This file is part of linphone-iphone * @@ -23,114 +23,165 @@ import UniformTypeIdentifiers struct SideMenu: View { - @ObservedObject private var coreContext = CoreContext.shared + let width: CGFloat + let isOpen: Bool + let menuClose: () -> Void + let safeAreaInsets: EdgeInsets + @Binding var isShowLoginFragment: Bool + @State private var showHelp = false + @State private var selectedAccountIndex: Int = 0 - @ObservedObject var callViewModel: CallViewModel - - let width: CGFloat - let isOpen: Bool - let menuClose: () -> Void - let safeAreaInsets: EdgeInsets - - var body: some View { - ZStack { - GeometryReader { _ in - EmptyView() - } - .background(Color.gray.opacity(0.3)) - .opacity(self.isOpen ? 1.0 : 0.0) - .onTapGesture { - self.menuClose() - } - - HStack { - List { - /* - Text("My Profile") - .frame(height: 40) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color.white) - .onTapGesture { - print("My Profile") - self.menuClose() - } - */ - Text("Send logs") - .frame(height: 40) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color.white) - .onTapGesture { - print("Send logs") - sendLogs() - self.menuClose() - } - Text("Clear logs") - .frame(height: 40) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color.white) - .onTapGesture { - print("Clear logs") - clearLogs() - self.menuClose() - } - Text("Logout") - .frame(height: 40) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color.white) - .onTapGesture { - print("Logout") - logout() - self.menuClose() - } - } - .frame(width: self.width - safeAreaInsets.leading) - .background(Color.white) - .offset(x: self.isOpen ? 0 : -self.width) - - Spacer() - } - .padding(.leading, safeAreaInsets.leading) - .padding(.top, TelecomManager.shared.callInProgress ? 0 : safeAreaInsets.top) - .padding(.bottom, safeAreaInsets.bottom) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - } - - func sendLogs() { - coreContext.doOnCoreQueue { core in - core.uploadLogCollection() - } - } - - func clearLogs() { - coreContext.doOnCoreQueue { core in - Core.resetLogCollection() - DispatchQueue.main.async { - ToastViewModel.shared.toastMessage = "Success_clear_logs" - ToastViewModel.shared.displayToast = true + var body: some View { + ZStack { + GeometryReader { _ in + EmptyView() } - } - } - - func logout() { - coreContext.doOnCoreQueue { core in - if core.defaultAccount != nil { - let authInfo = core.defaultAccount!.findAuthInfo() - if authInfo != nil { - Log.info("$TAG Found auth info for account, removing it") - core.removeAuthInfo(info: authInfo!) - } else { - Log.warn("$TAG Failed to find matching auth info for account") + .background(.gray.opacity(0.3)) + .opacity(self.isOpen ? 1.0 : 0.0) + .onTapGesture { + self.menuClose() + } + VStack { + VStack { + HStack { + Image("linphone") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.orangeMain500) + .frame(width: 32, height: 32) + .padding(10) + Text(Bundle.main.displayName) + .default_text_style_800(styleSize: 16) + Spacer() + Image("x") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c600) + .frame(width: 24, height: 24) + .padding(10) + } + .padding(.leading, 10) + .onTapGesture { + self.menuClose() + } + + List { + ForEach(0... + */ + +import SwiftUI +import linphonesw +import UniformTypeIdentifiers + +struct SideMenuAccountRow: View { + @ObservedObject var model: AccountModel + var backgroundColor: Color + var body: some View { + HStack { + + Avatar(contactAvatarModel: + ContactAvatarModel(friend: nil, + name: model.account.displayName(), + address: model.account.params!.identityAddress!.asString(), + withPresence: true), + avatarSize: 45) + .padding(.leading, 6) + + VStack { + Text(model.account.displayName()) + .default_text_style_grey_400(styleSize: 14) + .lineLimit(1) + .frame(maxWidth: .infinity, alignment: .leading) + + VStack { + Text(model.humanReadableRegistrationState) + .default_text_style_uncolored(styleSize: 12) + .foregroundStyle(model.registrationStateAssociatedUIColor) + } + .padding(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) + .background(Color.grayMain2c200) + .cornerRadius(12) + .frame(height: 20) + .frame(maxWidth: .infinity, alignment: .leading) + .onTapGesture { + model.refreshRegiter() + } + } + .padding(.leading, 4) + + Spacer() + + HStack { + if model.notificationsCount > 0 { + Text(String(model.notificationsCount)) + .foregroundStyle(.white) + .default_text_style(styleSize: 12) + .lineLimit(1) + .frame(width: 20, height: 20) + .background(Color.redDanger500) + .cornerRadius(50) + .frame(maxWidth: .infinity, alignment: .leading) + } + Image("dots-three-vertical") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c600) + .scaledToFit() + .frame(height: 30) + } + .frame(width: 64, alignment: .trailing) + .padding(.top, 12) + .padding(.bottom, 12) + } + .frame(height: 61) + .background(backgroundColor) + } +} diff --git a/Linphone/UI/Main/Fragments/SideMenuEntry.swift b/Linphone/UI/Main/Fragments/SideMenuEntry.swift new file mode 100644 index 000000000..cc1240c56 --- /dev/null +++ b/Linphone/UI/Main/Fragments/SideMenuEntry.swift @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2024 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 +import linphonesw +import UniformTypeIdentifiers + +struct SideMenuEntry: View { + var iconName: String + var title: String + var body: some View { + HStack { + Image(iconName) + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c500) + .frame(width: 20, height: 20) + Text(NSLocalizedString(title, comment: title)) + .default_text_style_600(styleSize: 13) + .padding(.leading, 4) + Spacer() + Image("caret-right") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c600) + .frame(width: 20, height: 20) + } + .background() + } +} + +#Preview { + SideMenuEntry( + iconName: "linphone", + title: "some text" + ) +} diff --git a/Linphone/UI/Main/Viewmodel/AccountModel.swift b/Linphone/UI/Main/Viewmodel/AccountModel.swift new file mode 100644 index 000000000..2953e84a2 --- /dev/null +++ b/Linphone/UI/Main/Viewmodel/AccountModel.swift @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010-2024 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 . + */ + +import Foundation +import linphonesw +import SwiftUI + +class AccountModel: ObservableObject { + let account: Account + @Published var humanReadableRegistrationState: String = "" + @Published var registrationStateAssociatedUIColor: Color = .clear + @Published var notificationsCount: Int = 0 + + init(account: Account, corePublisher: CoreDelegatePublisher?) { + self.account = account + update() + account.publisher?.onRegistrationStateChanged? + .postOnMainQueue { _ in + self.update() + } + corePublisher?.onChatRoomRead?.postOnMainQueue( + receiveValue: { _ in + self.computeNotificationsCount() + }) + corePublisher?.onMessagesReceived?.postOnMainQueue( + receiveValue: { _ in + self.computeNotificationsCount() + }) + corePublisher?.onCallStateChanged?.postOnMainQueue( + receiveValue: { _ in + self.computeNotificationsCount() + }) + } + + func update() { + switch account.state { + case .Cleared, .None: + humanReadableRegistrationState = "drawer_menu_account_connection_status_cleared".localized() + registrationStateAssociatedUIColor = .orangeWarning600 + case .Progress: + humanReadableRegistrationState = "drawer_menu_account_connection_status_progress".localized() + registrationStateAssociatedUIColor = .greenSuccess500 + case .Failed: + humanReadableRegistrationState = "drawer_menu_account_connection_status_failed".localized() + registrationStateAssociatedUIColor = .redDanger500 + case .Ok: + humanReadableRegistrationState = "drawer_menu_account_connection_status_connected".localized() + registrationStateAssociatedUIColor = .greenSuccess500 + case .Refreshing: + humanReadableRegistrationState = "drawer_menu_account_connection_status_refreshing".localized() + registrationStateAssociatedUIColor = .grayMain2c500 + } + computeNotificationsCount() + } + + func computeNotificationsCount() { + notificationsCount = account.unreadChatMessageCount + account.missedCallsCount + } + + func refreshRegiter() { + CoreContext.shared.doOnCoreQueue { _ in + self.account.refreshRegister() + } + } +} diff --git a/Linphone/Utils/Extensions/AccountExtension.swift b/Linphone/Utils/Extensions/AccountExtension.swift new file mode 100644 index 000000000..cdfde1181 --- /dev/null +++ b/Linphone/Utils/Extensions/AccountExtension.swift @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010-2024 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 + +extension Account { + func displayName() -> String { + guard let address = params?.identityAddress else { + return "" + } + if address.displayName != nil && !address.displayName!.isEmpty { + return address.displayName! + } + if address.username != nil && !address.username!.isEmpty { + return address.username! + } + return address.asStringUriOnly() + } +} diff --git a/Linphone/Utils/Extensions/BundleExtenion.swift b/Linphone/Utils/Extensions/BundleExtenion.swift new file mode 100644 index 000000000..1acc59de5 --- /dev/null +++ b/Linphone/Utils/Extensions/BundleExtenion.swift @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2024 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 + +extension Bundle { + var displayName: String { + return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? "Linphone" + } +} diff --git a/Linphone/Utils/Extensions/StringExtension.swift b/Linphone/Utils/Extensions/StringExtension.swift new file mode 100644 index 000000000..47c681f12 --- /dev/null +++ b/Linphone/Utils/Extensions/StringExtension.swift @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2024 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 + +extension String { + func localized(comment: String? = nil) -> String { + return NSLocalizedString(self, comment: comment != nil ? comment! : self) + } +} diff --git a/Linphone/Utils/Extensions/TextExtension.swift b/Linphone/Utils/Extensions/TextExtension.swift index 8465dfbff..e48d97e57 100644 --- a/Linphone/Utils/Extensions/TextExtension.swift +++ b/Linphone/Utils/Extensions/TextExtension.swift @@ -20,6 +20,18 @@ import Foundation import SwiftUI +let cssWeightToFontWeightName = [ + 100: "UltraLight", + 200: "Thin", + 300: "Light", + 400: "Regular", + 500: "Medium", + 600: "SemiBold", + 700: "Bold", + 800: "Heavy", + 900: "Black" +] + extension View { func default_text_style_300(styleSize: CGFloat) -> some View { @@ -141,4 +153,18 @@ extension View { self.font(Font.custom("NotoSans-Medium", size: styleSize)) .foregroundStyle(Color.grayMain2c400) } + + func default_text_style_grey_400(styleSize: CGFloat) -> some View { + self.font(Font.custom("NotoSans", size: styleSize)) + .foregroundStyle(Color.grayMain2c700) + } + + func default_text_style_uncolored(styleSize: CGFloat) -> some View { + self.font(Font.custom("NotoSans-Light", size: styleSize)) + } + + func text_style(fontSize: CGFloat, fontWeight: Int, fontColor: Color) -> some View { + return self.font(Font.custom("NotoSans-"+cssWeightToFontWeightName[fontWeight]!, size: fontSize)) + .foregroundStyle(fontColor) + } }