Add side menu

This commit is contained in:
benoit.martins 2023-10-18 16:48:25 +02:00
parent 8f733195d4
commit 146682e555
6 changed files with 321 additions and 237 deletions

View file

@ -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 = "<group>"; };
D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginViewModel.swift; sourceTree = "<group>"; };
D72250622ADE9615008FB426 /* HistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryViewModel.swift; sourceTree = "<group>"; };
D72250682ADFBF2D008FB426 /* SideMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenu.swift; sourceTree = "<group>"; };
D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeScannerFragment.swift; sourceTree = "<group>"; };
D72343312ACEFF58009AA24E /* QRScannerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = "<group>"; };
D72343332ACEFFC3009AA24E /* QRScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScanner.swift; sourceTree = "<group>"; };
@ -269,6 +271,7 @@
D72343352AD037AF009AA24E /* ToastView.swift */,
D750D3382AD3E6EE00EC99C5 /* PopupLoadingView.swift */,
D706BA812ADD72D100278F45 /* DeviceRotationViewModifier.swift */,
D72250682ADFBF2D008FB426 /* SideMenu.swift */,
);
path = Fragments;
sourceTree = "<group>";
@ -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 */,

View file

@ -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 :" : {

View file

@ -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

View file

@ -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())
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}
}

View file

@ -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")