This commit is contained in:
Benoit Martins 2024-01-09 17:29:51 +01:00 committed by QuentinArguillere
parent 1ddf2602b9
commit 04dbce540c
24 changed files with 474 additions and 282 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -1,6 +1,7 @@
{
"images" : [
{
"filename" : "1024.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"

View file

@ -113,11 +113,14 @@ final class CoreContext: ObservableObject {
NSLog("New configuration state is \(cbVal.status) = \(cbVal.message)\n")
if cbVal.status == Config.ConfiguringState.Successful {
ToastViewModel.shared.toastMessage = "Successful"
ToastViewModel.shared.displayToast.toggle()
} else {
ToastViewModel.shared.toastMessage = "Failed"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.displayToast = true
}
/*
else {
ToastViewModel.shared.toastMessage = "Failed"
ToastViewModel.shared.displayToast = true
}
*/
})
self.mCoreSuscriptions.insert(self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnMainQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in
@ -135,7 +138,7 @@ final class CoreContext: ObservableObject {
self.loggingInProgress = true
} else {
ToastViewModel.shared.toastMessage = "Registration failed"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.displayToast = true
self.loggingInProgress = false
self.loggedIn = false
}
@ -168,7 +171,7 @@ final class CoreContext: ObservableObject {
)
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.displayToast = true
}
})

View file

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>NSCameraUsageDescription</key>
<string>Camera usage is required for video VOIP calls</string>
<key>NSMicrophoneUsageDescription</key>

View file

@ -38,8 +38,14 @@ struct LinphoneApp: App {
if !sharedMainViewModel.welcomeViewDisplayed {
WelcomeView()
} else if coreContext.defaultAccount == nil || sharedMainViewModel.displayProfileMode {
ZStack {
AssistantView()
ToastView()
.zIndex(3)
}
} else if coreContext.defaultAccount != nil
&& coreContext.loggedIn
&& contactViewModel != nil
&& editContactViewModel != nil
&& historyViewModel != nil

View file

@ -120,10 +120,10 @@ class TelecomManager: ObservableObject {
}
}
func doCallWithCore(addr: Address) {
func doCallWithCore(addr: Address, isVideo: Bool) {
CoreContext.shared.doOnCoreQueue { core in
do {
try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: false, isConference: false)
try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: isVideo, isConference: false)
} catch {
Log.error("[TelecomManager] unable to create address for a new outgoing call : \(addr) \(error) ")
}

View file

@ -63,6 +63,8 @@ struct LoginFragment: View {
TextField("username", text: $accountLoginViewModel.username)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.disabled(coreContext.loggedIn)
.frame(height: 25)
.padding(.horizontal, 20)
@ -90,6 +92,8 @@ struct LoginFragment: View {
} else {
TextField("password", text: $accountLoginViewModel.passwd)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.frame(height: 25)
.focused($isPasswordFocused)
}
@ -287,6 +291,8 @@ struct LoginFragment: View {
.background(.black.opacity(0.65))
}
}
.navigationTitle("")
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
}

View file

@ -65,8 +65,11 @@ struct RegisterFragment: View {
}
}
}
.navigationTitle("")
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationTitle("")
.navigationBarHidden(true)
}
}

View file

@ -81,6 +81,8 @@ struct ThirdPartySipAccountLoginFragment: View {
TextField("username", text: $accountLoginViewModel.username)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.disabled(coreContext.loggedIn)
.frame(height: 25)
.padding(.horizontal, 20)
@ -108,6 +110,8 @@ struct ThirdPartySipAccountLoginFragment: View {
} else {
TextField("password", text: $accountLoginViewModel.passwd)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.frame(height: 25)
.focused($isPasswordFocused)
}
@ -139,6 +143,8 @@ struct ThirdPartySipAccountLoginFragment: View {
TextField("sip.linphone.org", text: $accountLoginViewModel.domain)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.disabled(coreContext.loggedIn)
.frame(height: 25)
.padding(.horizontal, 20)
@ -158,6 +164,8 @@ struct ThirdPartySipAccountLoginFragment: View {
TextField("Display Name", text: $accountLoginViewModel.displayName)
.default_text_style(styleSize: 15)
.disableAutocorrection(true)
.autocapitalization(.none)
.disabled(coreContext.loggedIn)
.frame(height: 25)
.padding(.horizontal, 20)
@ -204,8 +212,6 @@ struct ThirdPartySipAccountLoginFragment: View {
Button(action: {
self.accountLoginViewModel.login()
accountLoginViewModel.domain = "sip.linphone.org"
accountLoginViewModel.transportType = "TLS"
}, label: {
Text(coreContext.loggedIn ? "Log out" : "assistant_account_login")
.default_text_style_white_600(styleSize: 20)

View file

@ -171,8 +171,11 @@ struct ThirdPartySipAccountWarningFragment: View {
.frame(minHeight: geometry.size.height)
}
}
.navigationTitle("")
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationTitle("")
.navigationBarHidden(true)
}
}

View file

@ -106,6 +106,9 @@ class AccountLoginViewModel: ObservableObject {
self.coreContext.defaultAccount = account
}
self.domain = "sip.linphone.org"
self.transportType = "TLS"
} catch { NSLog(error.localizedDescription) }
}
}

View file

@ -427,18 +427,29 @@ struct CallView: View {
.presentationDetents([.fraction(0.3)])
.frame(maxHeight: .infinity)
}
} else {
innerView(geometry: geo)
}
}
}
@ViewBuilder
// swiftlint:disable:next cyclomatic_complexity
func innerView(geometry: GeometryProxy) -> some View {
VStack {
if !fullscreenVideo {
if #available(iOS 16.0, *) {
Rectangle()
.foregroundColor(Color.orangeMain500)
.edgesIgnoringSafeArea(.top)
.frame(height: 0)
} else if idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
Rectangle()
.foregroundColor(Color.orangeMain500)
.edgesIgnoringSafeArea(.top)
.frame(height: 1)
}
HStack {
if callViewModel.direction == .Outgoing {
@ -465,13 +476,8 @@ struct CallView: View {
ZStack {
Text(callViewModel.timeElapsed.convertDurationToString())
.onAppear {
callViewModel.timeElapsed = 0
startDate = Date.now
}
.onReceive(callViewModel.timer) { firedDate in
callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate))
}
.foregroundStyle(.white)
.if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in
@ -646,6 +652,10 @@ struct CallView: View {
callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate))
}
.onDisappear {
callViewModel.timeElapsed = 0
startDate = Date.now
}
.padding(.top)
.foregroundStyle(.white)
@ -695,6 +705,7 @@ struct CallView: View {
if !fullscreenVideo {
if telecomManager.callStarted {
if #available(iOS 16.0, *) {
if telecomManager.callStarted && idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
HStack(spacing: 12) {
@ -726,7 +737,7 @@ struct CallView: View {
Button {
callViewModel.toggleVideo()
} label: {
Image("video-camera")
Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash")
.renderingMode(.template)
.resizable()
.foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
@ -753,12 +764,116 @@ struct CallView: View {
.cornerRadius(40)
Button {
if AVAudioSession.sharedInstance().availableInputs != nil
&& !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty {
hideButtonsSheet = true
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
audioRouteSheet = true
}
} else {
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none)
} catch _ {
}
}
} label: {
Image("speaker-high")
Image(imageAudioRoute)
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
.onAppear(perform: getAudioRouteImage)
.onReceive(pub) { _ in
self.getAudioRouteImage()
}
}
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
}
.frame(height: geometry.size.height * 0.15)
.padding(.horizontal, 20)
.padding(.top, -6)
}
} else {
HStack(spacing: 12) {
Button {
callViewModel.terminateCall()
} label: {
Image("phone-disconnect")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
}
.frame(width: 90, height: 60)
.background(Color.redDanger500)
.cornerRadius(40)
Spacer()
Button {
callViewModel.toggleVideo()
} label: {
Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash")
.renderingMode(.template)
.resizable()
.foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
.frame(width: 32, height: 32)
}
.frame(width: 60, height: 60)
.background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
.cornerRadius(40)
.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
Button {
callViewModel.toggleMuteMicrophone()
} label: {
Image(callViewModel.micMutted ? "microphone-slash" : "microphone")
.renderingMode(.template)
.resizable()
.foregroundStyle(callViewModel.micMutted ? .black : .white)
.frame(width: 32, height: 32)
}
.frame(width: 60, height: 60)
.background(callViewModel.micMutted ? .white : Color.gray500)
.cornerRadius(40)
Button {
if AVAudioSession.sharedInstance().availableInputs != nil
&& !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty {
hideButtonsSheet = true
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
audioRouteSheet = true
}
} else {
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none)
} catch _ {
}
}
} label: {
Image(imageAudioRoute)
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 32, height: 32)
.onAppear(perform: getAudioRouteImage)
.onReceive(pub) { _ in
self.getAudioRouteImage()
}
}
.frame(width: 60, height: 60)

View file

@ -41,8 +41,10 @@ struct ContactsView: View {
}
} label: {
Image("user-plus")
.renderingMode(.template)
.foregroundStyle(.white)
.padding()
.background(.white)
.background(Color.orangeMain500)
.clipShape(Circle())
.shadow(color: .black.opacity(0.2), radius: 4)

View file

@ -90,7 +90,7 @@ struct ContactInnerActionsFragment: View {
.onTapGesture {
withAnimation {
telecomManager.doCallWithCore(
addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index]
addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index], isVideo: false
)
}
}
@ -272,7 +272,9 @@ struct ContactInnerActionsFragment: View {
Button {
if contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend != nil {
contactViewModel.objectWillChange.send()
contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.edit()
contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.starred.toggle()
contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.done()
}
} label: {
HStack {

View file

@ -151,7 +151,7 @@ struct ContactInnerFragment: View {
Spacer()
Button(action: {
telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!)
telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: false)
}, label: {
VStack {
HStack(alignment: .center) {
@ -180,7 +180,8 @@ struct ContactInnerFragment: View {
Image("chat-teardrop-text")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
//.foregroundStyle(Color.grayMain2c600)
.foregroundStyle(Color.grayMain2c300)
.frame(width: 25, height: 25)
.onTapGesture {
withAnimation {
@ -200,7 +201,7 @@ struct ContactInnerFragment: View {
Spacer()
Button(action: {
telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: true)
}, label: {
VStack {
HStack(alignment: .center) {
@ -209,11 +210,6 @@ struct ContactInnerFragment: View {
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
.onTapGesture {
withAnimation {
}
}
}
.padding(16)
.background(Color.grayMain2c200)

View file

@ -58,7 +58,9 @@ struct ContactsListBottomSheet: View {
Spacer()
Button {
if contactViewModel.selectedFriend != nil {
contactViewModel.selectedFriend!.edit()
contactViewModel.selectedFriend!.starred.toggle()
contactViewModel.selectedFriend!.done()
}
MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)

View file

@ -151,6 +151,7 @@ struct ContentView: View {
Menu {
if index == 0 {
Button {
contactViewModel.indexDisplayedFriend = nil
isMenuOpen = false
magicSearch.allContact = true
MagicSearchSingleton.shared.searchForContacts(
@ -168,6 +169,7 @@ struct ContentView: View {
}
Button {
contactViewModel.indexDisplayedFriend = nil
isMenuOpen = false
magicSearch.allContact = false
MagicSearchSingleton.shared.searchForContacts(
@ -282,9 +284,8 @@ struct ContentView: View {
text = newValue
}
))
.default_text_style_white_700(styleSize: 15)
.default_text_style_700(styleSize: 15)
.padding(.all, 6)
.accentColor(.white)
.focused($focusedField)
.onAppear {
self.focusedField = true
@ -671,10 +672,8 @@ struct ContentView: View {
}
}
// if sharedMainViewModel.displayToast {
ToastView()
.zIndex(3)
// }
}
}
.overlay {
@ -698,12 +697,14 @@ struct ContentView: View {
.onChange(of: scenePhase) { newPhase in
if newPhase == .active {
coreContext.onForeground()
/*
if !isShowStartCallFragment {
contactsManager.fetchContacts()
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
historyListViewModel.computeCallLogsList()
}
}
*/
print("Active")
} else if newPhase == .inactive {
print("Inactive")

View file

@ -275,7 +275,7 @@ struct DialerBottomSheet: View {
if !startCallViewModel.searchField.isEmpty {
do {
let address = try Factory.Instance.createAddress(addr: String("sip:" + startCallViewModel.searchField + "@" + startCallViewModel.domain))
telecomManager.doCallWithCore(addr: address)
telecomManager.doCallWithCore(addr: address, isVideo: false)
} catch {
}

View file

@ -194,8 +194,12 @@ struct HistoryContactFragment: View {
ScrollView {
VStack(spacing: 0) {
VStack(spacing: 0) {
if #unavailable(iOS 16.0) {
Rectangle()
.foregroundColor(Color.gray100)
.frame(height: 7)
}
VStack(spacing: 0) {
let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil
let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil
let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil
@ -369,6 +373,7 @@ struct HistoryContactFragment: View {
.frame(minHeight: 150)
.frame(maxWidth: .infinity)
.padding(.top, 10)
.padding(.bottom, 2)
.background(Color.gray100)
HStack {
@ -377,11 +382,11 @@ struct HistoryContactFragment: View {
Button(action: {
if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil {
telecomManager.doCallWithCore(
addr: historyViewModel.displayedCall!.toAddress!
addr: historyViewModel.displayedCall!.toAddress!, isVideo: false
)
} else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil {
telecomManager.doCallWithCore(
addr: historyViewModel.displayedCall!.fromAddress!
addr: historyViewModel.displayedCall!.fromAddress!, isVideo: false
)
}
}, label: {
@ -399,6 +404,7 @@ struct HistoryContactFragment: View {
Text("Appel")
.default_text_style(styleSize: 14)
.frame(minWidth: 80)
}
})
@ -412,7 +418,8 @@ struct HistoryContactFragment: View {
Image("chat-teardrop-text")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
//.foregroundStyle(Color.grayMain2c600)
.foregroundStyle(Color.grayMain2c300)
.frame(width: 25, height: 25)
.onTapGesture {
withAnimation {
@ -426,13 +433,22 @@ struct HistoryContactFragment: View {
Text("Message")
.default_text_style(styleSize: 14)
.frame(minWidth: 80)
}
})
Spacer()
Button(action: {
if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil {
telecomManager.doCallWithCore(
addr: historyViewModel.displayedCall!.toAddress!, isVideo: true
)
} else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil {
telecomManager.doCallWithCore(
addr: historyViewModel.displayedCall!.fromAddress!, isVideo: true
)
}
}, label: {
VStack {
HStack(alignment: .center) {
@ -441,11 +457,6 @@ struct HistoryContactFragment: View {
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
.onTapGesture {
withAnimation {
}
}
}
.padding(16)
.background(Color.grayMain2c200)
@ -453,12 +464,14 @@ struct HistoryContactFragment: View {
Text("Video Call")
.default_text_style(styleSize: 14)
.frame(minWidth: 80)
}
})
Spacer()
}
.padding(.top, 20)
.padding(.bottom, 10)
.frame(maxWidth: .infinity)
.background(Color.gray100)
@ -486,7 +499,8 @@ struct HistoryContactFragment: View {
callStatus: callLogsFilter[index].status,
callDir: callLogsFilter[index].dir
).contains("rejected") ? 6 : 8)
.padding(.top, 5)
.padding(.top, 6)
Spacer()
}
@ -517,6 +531,7 @@ struct HistoryContactFragment: View {
}
.padding(.vertical, 15)
.padding(.horizontal, 20)
.frame(maxHeight: 65)
}
}
.background(.white)
@ -526,6 +541,7 @@ struct HistoryContactFragment: View {
.frame(maxWidth: sharedMainViewModel.maxWidth)
}
.frame(maxWidth: .infinity)
.padding(.top, 2)
}
.background(Color.gray100)
}

View file

@ -166,11 +166,11 @@ struct HistoryListFragment: View {
withAnimation {
if historyListViewModel.callLogs[index].dir == .Outgoing && historyListViewModel.callLogs[index].toAddress != nil {
telecomManager.doCallWithCore(
addr: historyListViewModel.callLogs[index].toAddress!
addr: historyListViewModel.callLogs[index].toAddress!, isVideo: false
)
} else if historyListViewModel.callLogs[index].fromAddress != nil {
telecomManager.doCallWithCore(
addr: historyListViewModel.callLogs[index].fromAddress!
addr: historyListViewModel.callLogs[index].fromAddress!, isVideo: false
)
}
historyViewModel.displayedCall = nil
@ -213,6 +213,8 @@ struct HistoryListFragment: View {
.padding(.all)
)
}
.navigationTitle("")
.navigationBarHidden(true)
}
}

View file

@ -90,6 +90,9 @@ struct StartCallFragment: View {
magicSearch.currentFilterSuggestions = newValue
magicSearch.searchForSuggestions()
}
.simultaneousGesture(TapGesture().onEnded {
showingDialer = false
})
HStack {
Button(action: {
@ -105,10 +108,18 @@ struct StartCallFragment: View {
if startCallViewModel.searchField.isEmpty {
Button(action: {
if !showingDialer {
isSearchFieldFocused = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
showingDialer.toggle()
showingDialer = true
}
} else {
showingDialer = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
isSearchFieldFocused = true
}
}
}, label: {
Image(!showingDialer ? "dialer" : "keyboard")
@ -169,7 +180,7 @@ struct StartCallFragment: View {
withAnimation {
isShowStartCallFragment.toggle()
telecomManager.doCallWithCore(addr: addr)
telecomManager.doCallWithCore(addr: addr, isVideo: false)
}
})
.padding(.horizontal, 16)
@ -208,6 +219,25 @@ struct StartCallFragment: View {
var suggestionsList: some View {
ForEach(0..<contactsManager.lastSearchSuggestions.count, id: \.self) { index in
Button {
showingDialer = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
magicSearch.searchForContacts(
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
}
startCallViewModel.searchField = ""
magicSearch.currentFilterSuggestions = ""
delayColorDismiss()
withAnimation {
isShowStartCallFragment.toggle()
if contactsManager.lastSearchSuggestions[index].address != nil {
telecomManager.doCallWithCore(
addr: contactsManager.lastSearchSuggestions[index].address!, isVideo: false
)
}
}
} label: {
HStack {
if index < contactsManager.lastSearchSuggestions.count
@ -237,27 +267,6 @@ struct StartCallFragment: View {
.foregroundStyle(Color.orangeMain500)
}
}
.onTapGesture {
showingDialer = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
magicSearch.searchForContacts(
sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue)
}
startCallViewModel.searchField = ""
magicSearch.currentFilterSuggestions = ""
delayColorDismiss()
withAnimation {
isShowStartCallFragment.toggle()
if contactsManager.lastSearchSuggestions[index].address != nil {
telecomManager.doCallWithCore(
addr: contactsManager.lastSearchSuggestions[index].address!
)
}
}
}
.padding(.horizontal)
}
.buttonStyle(.borderless)

View file

@ -50,8 +50,10 @@ struct HistoryView: View {
}
} label: {
Image("phone-plus")
.renderingMode(.template)
.foregroundStyle(.white)
.padding()
.background(.white)
.background(Color.orangeMain500)
.clipShape(Circle())
.shadow(color: .black.opacity(0.2), radius: 4)

View file

@ -134,6 +134,8 @@ struct WelcomeView: View {
.frame(minHeight: geometry.size.height)
}
}
.navigationTitle("")
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
}

View file

@ -28,15 +28,25 @@ class PermissionManager: ObservableObject {
@Published var photoLibraryPermissionGranted = false
@Published var cameraPermissionGranted = false
@Published var contactsPermissionGranted = false
@Published var microphonePermissionGranted = false
private init() {}
func getPermissions() {
microphoneRequestPermission()
photoLibraryRequestPermission()
cameraRequestPermission()
contactsRequestPermission()
}
func microphoneRequestPermission() {
AVAudioSession.sharedInstance().requestRecordPermission({ granted in
DispatchQueue.main.async {
self.microphonePermissionGranted = granted
}
})
}
func photoLibraryRequestPermission() {
PHPhotoLibrary.requestAuthorization(for: .readWrite, handler: {status in
DispatchQueue.main.async {