From 146682e5555d9418799a04b67a9406ab68cd0218 Mon Sep 17 00:00:00 2001 From: "benoit.martins" Date: Wed, 18 Oct 2023 16:48:25 +0200 Subject: [PATCH] Add side menu --- Linphone.xcodeproj/project.pbxproj | 4 + Linphone/Localizable.xcstrings | 9 + Linphone/UI/Main/Contacts/ContactsView.swift | 30 -- Linphone/UI/Main/ContentView.swift | 422 +++++++++++-------- Linphone/UI/Main/Fragments/SideMenu.swift | 63 +++ Linphone/UI/Main/History/HistoryView.swift | 30 -- 6 files changed, 321 insertions(+), 237 deletions(-) create mode 100644 Linphone/UI/Main/Fragments/SideMenu.swift diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 8dd980a3b..3e27fc401 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCB2ABC769C00B41C10 /* AssistantView.swift */; }; D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */; }; D72250632ADE9615008FB426 /* HistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72250622ADE9615008FB426 /* HistoryViewModel.swift */; }; + D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72250682ADFBF2D008FB426 /* SideMenu.swift */; }; D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */; }; D72343322ACEFF58009AA24E /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72343312ACEFF58009AA24E /* QRScannerController.swift */; }; D72343342ACEFFC3009AA24E /* QRScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72343332ACEFFC3009AA24E /* QRScanner.swift */; }; @@ -69,6 +70,7 @@ D719ABCB2ABC769C00B41C10 /* AssistantView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssistantView.swift; sourceTree = ""; }; D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginViewModel.swift; sourceTree = ""; }; D72250622ADE9615008FB426 /* HistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryViewModel.swift; sourceTree = ""; }; + D72250682ADFBF2D008FB426 /* SideMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenu.swift; sourceTree = ""; }; D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeScannerFragment.swift; sourceTree = ""; }; D72343312ACEFF58009AA24E /* QRScannerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = ""; }; D72343332ACEFFC3009AA24E /* QRScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScanner.swift; sourceTree = ""; }; @@ -269,6 +271,7 @@ D72343352AD037AF009AA24E /* ToastView.swift */, D750D3382AD3E6EE00EC99C5 /* PopupLoadingView.swift */, D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */, + D72250682ADFBF2D008FB426 /* SideMenu.swift */, ); path = Fragments; sourceTree = ""; @@ -519,6 +522,7 @@ D72343322ACEFF58009AA24E /* QRScannerController.swift in Sources */, D72343342ACEFFC3009AA24E /* QRScanner.swift in Sources */, D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */, + D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */, D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */, D78290B82ADD3910004AA85C /* ContactFragment.swift in Sources */, D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */, diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 7d9056b79..8bd88f0a8 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -187,6 +187,12 @@ }, "Log out" : { + }, + "Logout" : { + + }, + "My Profile" : { + }, "Next" : { @@ -228,6 +234,9 @@ }, "Plus tard" : { + }, + "Posts" : { + }, "Pour vous permettre de vous profitez pleinement de Linphone nous avons besoin des autorisations suivantes :" : { diff --git a/Linphone/UI/Main/Contacts/ContactsView.swift b/Linphone/UI/Main/Contacts/ContactsView.swift index 8b44da54f..cecad9f2a 100644 --- a/Linphone/UI/Main/Contacts/ContactsView.swift +++ b/Linphone/UI/Main/Contacts/ContactsView.swift @@ -36,36 +36,6 @@ struct ContactsView: View { NavigationView { ZStack(alignment: .bottomTrailing) { VStack(spacing: 0) { - HStack { - Image("profile-image-example") - .resizable() - .frame(width: 40, height: 40) - .clipShape(Circle()) - - Text("Contacts") - .default_text_style_white_800(styleSize: 20) - .padding(.leading, 10) - - Spacer() - - Button { - - } label: { - Image("search") - } - - Button { - - } label: { - Image("filtres") - } - .padding(.leading) - } - .frame(maxWidth: .infinity) - .frame(height: 50) - .padding(.horizontal) - .background(Color.orangeMain500) - VStack { List { ForEach(objects, id: \.self) { index in diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 97991cd9d..32bc8f301 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -20,184 +20,252 @@ import SwiftUI struct ContentView: View { - - @ObservedObject var sharedMainViewModel: SharedMainViewModel - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject private var coreContext = CoreContext.shared - - @State var index = 0 - @State private var orientation = UIDevice.current.orientation - - var body: some View { - if !sharedMainViewModel.welcomeViewDisplayed { - WelcomeView(sharedMainViewModel: sharedMainViewModel) - } else if coreContext.mCore.defaultAccount == nil || sharedMainViewModel.displayProfileMode { - AssistantView(sharedMainViewModel: sharedMainViewModel) - } else { - GeometryReader { geometry in - ZStack { - VStack(spacing: 0) { - HStack(spacing: 0) { - if orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { - VStack { - Group { - Spacer() - Button(action: { - self.index = 0 - }, label: { - VStack { - Image("address-book") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 0 { - Text("Contacts") - .default_text_style_700(styleSize: 10) - } else { - Text("Contacts") - .default_text_style(styleSize: 10) - } - } - }) - - Spacer() - - Button(action: { - self.index = 1 - contactViewModel.contactTitle = "" - }, label: { - VStack { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 1 { - Text("Calls") - .default_text_style_700(styleSize: 10) - } else { - Text("Calls") - .default_text_style(styleSize: 10) - } - } - }) - - Spacer() - } - } - .frame(width: 75) - .padding(.leading, orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 ? -geometry.safeAreaInsets.leading : 0) - } - - VStack { - if self.index == 0 { - ContactsView(contactViewModel: contactViewModel, historyViewModel: historyViewModel) - } else if self.index == 1 { - HistoryView() - } - } - .frame(maxWidth: - (orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? geometry.size.width/100*40 - : .infinity - ) - - if orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { - Spacer() - } - } - .shadow(color: Color.gray200, radius: 2) - - if !(orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { - HStack { - Group { - Spacer() - Button(action: { - self.index = 0 - }, label: { - VStack { - Image("address-book") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 0 { - Text("Contacts") - .default_text_style_700(styleSize: 10) - } else { - Text("Contacts") - .default_text_style(styleSize: 10) - } - } - }) - .padding(.top) - - Spacer() - - Button(action: { - self.index = 1 - contactViewModel.contactTitle = "" - }, label: { - VStack { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 1 { - Text("Calls") - .default_text_style_700(styleSize: 10) - } else { - Text("Calls") - .default_text_style(styleSize: 10) - } - } - }) - .padding(.top) - Spacer() - } - } - .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15) - .background( - Color.white - .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) - .mask(Rectangle().padding(.top, -8)) - ) - } - } - - if !contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty { - HStack(spacing: 0) { - Spacer() - .frame(maxWidth: - (orientation == .landscapeLeft || orientation == .landscapeRight || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? (geometry.size.width/100*40) + 75 - : 0 - ) - if self.index == 0 { - ContactFragment(contactViewModel: contactViewModel) - .frame(maxWidth: .infinity) - .background(Color.gray100) - } else if self.index == 1 { - HistoryContactFragment() - .frame(maxWidth: .infinity) - .background(Color.gray100) - } - } - .padding(.leading, orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 ? -geometry.safeAreaInsets.leading : 0) - .transition(.move(edge: .trailing)) - } - } - } - .onRotate { newOrientation in - orientation = newOrientation - } - } - } + + @ObservedObject var sharedMainViewModel: SharedMainViewModel + @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var historyViewModel: HistoryViewModel + @ObservedObject private var coreContext = CoreContext.shared + + @State var index = 0 + @State private var orientation = UIDevice.current.orientation + @State var menuOpen: Bool = false + + var body: some View { + if !sharedMainViewModel.welcomeViewDisplayed { + WelcomeView(sharedMainViewModel: sharedMainViewModel) + } else if coreContext.mCore.defaultAccount == nil || sharedMainViewModel.displayProfileMode { + AssistantView(sharedMainViewModel: sharedMainViewModel) + } else { + GeometryReader { geometry in + ZStack { + VStack(spacing: 0) { + HStack(spacing: 0) { + if orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { + VStack { + Group { + Spacer() + Button(action: { + self.index = 0 + }, label: { + VStack { + Image("address-book") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 0 { + Text("Contacts") + .default_text_style_700(styleSize: 10) + } else { + Text("Contacts") + .default_text_style(styleSize: 10) + } + } + }) + + Spacer() + + Button(action: { + self.index = 1 + contactViewModel.contactTitle = "" + }, label: { + VStack { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 1 { + Text("Calls") + .default_text_style_700(styleSize: 10) + } else { + Text("Calls") + .default_text_style(styleSize: 10) + } + } + }) + + Spacer() + } + } + .frame(width: 75) + .padding(.leading, + orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 + ? -geometry.safeAreaInsets.leading + : 0) + } + + VStack(spacing: 0) { + HStack { + Image("profile-image-example") + .resizable() + .frame(width: 40, height: 40) + .clipShape(Circle()) + .onTapGesture { + openMenu() + } + + Text(index == 0 ? "Contacts" : "Calls") + .default_text_style_white_800(styleSize: 20) + .padding(.leading, 10) + + Spacer() + + Button { + + } label: { + Image("search") + } + + Button { + + } label: { + Image(index == 0 ? "filtres" : "more") + } + .padding(.leading) + } + .frame(maxWidth: .infinity) + .frame(height: 50) + .padding(.horizontal) + .background(Color.orangeMain500) + + if self.index == 0 { + ContactsView(contactViewModel: contactViewModel, historyViewModel: historyViewModel) + } else if self.index == 1 { + HistoryView() + } + } + .frame(maxWidth: + (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? geometry.size.width/100*40 + : .infinity + ) + .background( + Color.white + .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) + .mask(Rectangle().padding(.horizontal, -8)) + ) + + if orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { + Spacer() + } + } + + if !(orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + HStack { + Group { + Spacer() + Button(action: { + self.index = 0 + }, label: { + VStack { + Image("address-book") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 0 { + Text("Contacts") + .default_text_style_700(styleSize: 10) + } else { + Text("Contacts") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + + Spacer() + + Button(action: { + self.index = 1 + contactViewModel.contactTitle = "" + }, label: { + VStack { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 1 { + Text("Calls") + .default_text_style_700(styleSize: 10) + } else { + Text("Calls") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + Spacer() + } + } + .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15) + .background( + Color.white + .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) + .mask(Rectangle().padding(.top, -8)) + ) + } + } + + if !contactViewModel.contactTitle.isEmpty || !historyViewModel.historyTitle.isEmpty { + HStack(spacing: 0) { + Spacer() + .frame(maxWidth: + (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? (geometry.size.width/100*40) + 75 + : 0 + ) + if self.index == 0 { + ContactFragment(contactViewModel: contactViewModel) + .frame(maxWidth: .infinity) + .background(Color.gray100) + } else if self.index == 1 { + HistoryContactFragment() + .frame(maxWidth: .infinity) + .background(Color.gray100) + } + } + .padding(.leading, + orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 + ? -geometry.safeAreaInsets.leading + : 0) + .transition(.move(edge: .trailing)) + } + + SideMenu( + width: geometry.size.width / 5 * 4, + isOpen: self.menuOpen, + menuClose: self.openMenu, + safeAreaInsets: geometry.safeAreaInsets + ) + .ignoresSafeArea(.all) + } + } + .onRotate { newOrientation in + orientation = newOrientation + } + } + } + + func openMenu() { + withAnimation { + self.menuOpen.toggle() + } + } } #Preview { - ContentView(sharedMainViewModel: SharedMainViewModel(), contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel()) + ContentView(sharedMainViewModel: SharedMainViewModel(), contactViewModel: ContactViewModel(), historyViewModel: HistoryViewModel()) } diff --git a/Linphone/UI/Main/Fragments/SideMenu.swift b/Linphone/UI/Main/Fragments/SideMenu.swift new file mode 100644 index 000000000..317490553 --- /dev/null +++ b/Linphone/UI/Main/Fragments/SideMenu.swift @@ -0,0 +1,63 @@ +/* + * 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 SideMenu: View { + 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").onTapGesture { + print("My Profile") + } + Text("Posts").onTapGesture { + print("Posts") + } + Text("Logout").onTapGesture { + print("Logout") + } + } + .frame(width: self.width - safeAreaInsets.leading) + .background(Color.white) + .offset(x: self.isOpen ? 0 : -self.width) + + Spacer() + } + .padding(.leading, safeAreaInsets.leading) + .padding(.top, safeAreaInsets.top) + .padding(.bottom, safeAreaInsets.bottom) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} diff --git a/Linphone/UI/Main/History/HistoryView.swift b/Linphone/UI/Main/History/HistoryView.swift index e2510ed9b..c876cf67e 100644 --- a/Linphone/UI/Main/History/HistoryView.swift +++ b/Linphone/UI/Main/History/HistoryView.swift @@ -24,36 +24,6 @@ struct HistoryView: View { var body: some View { NavigationView { VStack(spacing: 0) { - HStack { - Image("profile-image-example") - .resizable() - .frame(width: 40, height: 40) - .clipShape(Circle()) - - Text("Calls") - .default_text_style_white_800(styleSize: 20) - .padding(.leading, 10) - - Spacer() - - Button { - - } label: { - Image("search") - } - - Button { - - } label: { - Image("more") - } - .padding(.leading) - } - .frame(maxWidth: .infinity) - .frame(height: 50) - .padding(.horizontal) - .background(Color.orangeMain500) - VStack { Spacer() Image("illus-belledonne1")