diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index eafdae478..53bd8a595 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -47,10 +47,12 @@ struct CallView: View { @State var angleDegree = 0.0 @State var fullscreenVideo = false + @State var showingDialer = false + var body: some View { GeometryReader { geo in ZStack { - if #available(iOS 16.0, *), idiom != .pad { + if #available(iOS 16.4, *), idiom != .pad { innerView(geometry: geo) .sheet(isPresented: $audioRouteSheet, onDismiss: { audioRouteSheet = false @@ -59,6 +61,32 @@ struct CallView: View { innerBottomSheet() .presentationDetents([.fraction(0.3)]) } + .sheet(isPresented: $showingDialer) { + DialerBottomSheet( + startCallViewModel: StartCallViewModel(), + showingDialer: $showingDialer, + currentCall: callViewModel.currentCall + ) + .presentationDetents([.medium]) + .presentationBackgroundInteraction(.enabled(upThrough: .medium)) + } + } else if #available(iOS 16.0, *), idiom != .pad { + innerView(geometry: geo) + .sheet(isPresented: $audioRouteSheet, onDismiss: { + audioRouteSheet = false + hideButtonsSheet = false + }) { + innerBottomSheet() + .presentationDetents([.fraction(0.3)]) + } + .sheet(isPresented: $showingDialer) { + DialerBottomSheet( + startCallViewModel: StartCallViewModel(), + showingDialer: $showingDialer, + currentCall: callViewModel.currentCall + ) + .presentationDetents([.medium]) + } } else { innerView(geometry: geo) .halfSheet(showSheet: $audioRouteSheet) { @@ -67,6 +95,13 @@ struct CallView: View { audioRouteSheet = false hideButtonsSheet = false } + .halfSheet(showSheet: $showingDialer) { + DialerBottomSheet( + startCallViewModel: StartCallViewModel(), + showingDialer: $showingDialer, + currentCall: callViewModel.currentCall + ) + } onDismiss: {} } if callViewModel.zrtpPopupDisplayed == true { ZRTPPopup(callViewModel: callViewModel) @@ -739,17 +774,17 @@ struct CallView: View { VStack { Button { + showingDialer.toggle() } label: { Image("dialer") .renderingMode(.template) .resizable() - .foregroundStyle(Color.gray500) + .foregroundStyle(.white) .frame(width: 32, height: 32) } .frame(width: 60, height: 60) - .background(Color.gray600) + .background(Color.gray500) .cornerRadius(40) - .disabled(true) Text("Dialer") .foregroundStyle(.white) @@ -912,17 +947,17 @@ struct CallView: View { VStack { Button { + showingDialer.toggle() } label: { Image("dialer") .renderingMode(.template) .resizable() - .foregroundStyle(Color.gray500) + .foregroundStyle(.white) .frame(width: 32, height: 32) } .frame(width: 60, height: 60) - .background(Color.gray600) + .background(Color.gray500) .cornerRadius(40) - .disabled(true) Text("Dialer") .foregroundStyle(.white) diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 242aa1d62..c966069af 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -523,7 +523,7 @@ struct ContentView: View { if isShowStartCallFragment { - if #available(iOS 16.4, *), idiom != .pad { + if #available(iOS 16.4, *), idiom != .pad { StartCallFragment( startCallViewModel: startCallViewModel, isShowStartCallFragment: $isShowStartCallFragment, @@ -534,7 +534,8 @@ struct ContentView: View { .sheet(isPresented: $showingDialer) { DialerBottomSheet( startCallViewModel: startCallViewModel, - showingDialer: $showingDialer + showingDialer: $showingDialer, + currentCall: nil ) .presentationDetents([.medium]) // .interactiveDismissDisabled() @@ -551,7 +552,8 @@ struct ContentView: View { .halfSheet(showSheet: $showingDialer) { DialerBottomSheet( startCallViewModel: startCallViewModel, - showingDialer: $showingDialer + showingDialer: $showingDialer, + currentCall: nil ) } onDismiss: {} } @@ -689,12 +691,12 @@ struct ContentView: View { if newPhase == .active { coreContext.onForeground() /* - if !isShowStartCallFragment { - contactsManager.fetchContacts() - DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { - historyListViewModel.computeCallLogsList() - } - } + if !isShowStartCallFragment { + contactsManager.fetchContacts() + DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { + historyListViewModel.computeCallLogsList() + } + } */ print("Active") } else if newPhase == .inactive { diff --git a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift index f8d2b0ddd..0fadeb5d0 100644 --- a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift +++ b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift @@ -36,8 +36,11 @@ struct DialerBottomSheet: View { @State private var orientation = UIDevice.current.orientation + @State var dialerField = "" @Binding var showingDialer: Bool + let currentCall: Call? + var body: some View { VStack(alignment: .center, spacing: 0) { VStack(alignment: .center, spacing: 0) { @@ -60,11 +63,47 @@ struct DialerBottomSheet: View { .padding(15) } - Spacer() + if currentCall != nil { + HStack { + Text(dialerField) + .default_text_style(styleSize: 25) + .frame(maxWidth: .infinity) + .padding(.horizontal, 10) + .lineLimit(1) + .truncationMode(.head) + + Button { + dialerField = String(dialerField.dropLast()) + } label: { + Image("backspace-fill") + .resizable() + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) + } + .padding(.horizontal, 20) + .padding(.top, 10) + .frame(maxWidth: sharedMainViewModel.maxWidth) + + Spacer() + } else { + Spacer() + } HStack { Button { - startCallViewModel.searchField += "1" + if currentCall != nil { + do { + let digit = ("1".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "1" + } catch { + + } + } else { + startCallViewModel.searchField += "1" + } } label: { Text("1") .default_text_style(styleSize: 32) @@ -78,7 +117,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "2" + if currentCall != nil { + do { + let digit = ("2".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "2" + } catch { + + } + } else { + startCallViewModel.searchField += "2" + } } label: { Text("2") .default_text_style(styleSize: 32) @@ -92,7 +141,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "3" + if currentCall != nil { + do { + let digit = ("3".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "3" + } catch { + + } + } else { + startCallViewModel.searchField += "3" + } } label: { Text("3") .default_text_style(styleSize: 32) @@ -108,7 +167,17 @@ struct DialerBottomSheet: View { HStack { Button { - startCallViewModel.searchField += "4" + if currentCall != nil { + do { + let digit = ("4".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "4" + } catch { + + } + } else { + startCallViewModel.searchField += "4" + } } label: { Text("4") .default_text_style(styleSize: 32) @@ -122,7 +191,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "5" + if currentCall != nil { + do { + let digit = ("5".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "5" + } catch { + + } + } else { + startCallViewModel.searchField += "5" + } } label: { Text("5") .default_text_style(styleSize: 32) @@ -136,7 +215,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "6" + if currentCall != nil { + do { + let digit = ("6".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "6" + } catch { + + } + } else { + startCallViewModel.searchField += "6" + } } label: { Text("6") .default_text_style(styleSize: 32) @@ -153,7 +242,17 @@ struct DialerBottomSheet: View { HStack { Button { - startCallViewModel.searchField += "7" + if currentCall != nil { + do { + let digit = ("7".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "7" + } catch { + + } + } else { + startCallViewModel.searchField += "7" + } } label: { Text("7") .default_text_style(styleSize: 32) @@ -167,7 +266,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "8" + if currentCall != nil { + do { + let digit = ("8".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "8" + } catch { + + } + } else { + startCallViewModel.searchField += "8" + } } label: { Text("8") .default_text_style(styleSize: 32) @@ -181,7 +290,17 @@ struct DialerBottomSheet: View { Spacer() Button { - startCallViewModel.searchField += "9" + if currentCall != nil { + do { + let digit = ("9".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "9" + } catch { + + } + } else { + startCallViewModel.searchField += "9" + } } label: { Text("9") .default_text_style(styleSize: 32) @@ -198,7 +317,17 @@ struct DialerBottomSheet: View { HStack { Button { - startCallViewModel.searchField += "*" + if currentCall != nil { + do { + let digit = ("*".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "*" + } catch { + + } + } else { + startCallViewModel.searchField += "*" + } } label: { Text("*") .default_text_style(styleSize: 32) @@ -211,43 +340,73 @@ struct DialerBottomSheet: View { Spacer() - Button { - } label: { - ZStack { + if currentCall == nil { + Button { + } label: { + ZStack { + Text("0") + .default_text_style(styleSize: 32) + .multilineTextAlignment(.center) + .frame(width: 60, height: 75) + .padding(.top, -15) + .background(.white) + .clipShape(Circle()) + .shadow(color: .black.opacity(0.2), radius: 4) + Text("+") + .default_text_style(styleSize: 20) + .multilineTextAlignment(.center) + .frame(width: 60, height: 85) + .padding(.bottom, -25) + .background(.clear) + .clipShape(Circle()) + } + } + .simultaneousGesture( + LongPressGesture() + .onEnded { _ in + startCallViewModel.searchField += "+" + } + ) + .highPriorityGesture( + TapGesture() + .onEnded { _ in + startCallViewModel.searchField += "0" + } + ) + } else { + Button { + do { + let digit = ("0".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "0" + } catch { + + } + } label: { Text("0") .default_text_style(styleSize: 32) .multilineTextAlignment(.center) - .frame(width: 60, height: 75) - .padding(.top, -15) + .frame(width: 60, height: 60) .background(.white) .clipShape(Circle()) .shadow(color: .black.opacity(0.2), radius: 4) - Text("+") - .default_text_style(styleSize: 20) - .multilineTextAlignment(.center) - .frame(width: 60, height: 85) - .padding(.bottom, -25) - .background(.clear) - .clipShape(Circle()) } } - .simultaneousGesture( - LongPressGesture() - .onEnded { _ in - startCallViewModel.searchField += "+" - } - ) - .highPriorityGesture( - TapGesture() - .onEnded { _ in - startCallViewModel.searchField += "0" - } - ) Spacer() Button { - startCallViewModel.searchField += "#" + if currentCall != nil { + do { + let digit = ("#".cString(using: String.Encoding.utf8)?[0])! + try currentCall!.sendDtmf(dtmf: digit) + dialerField += "#" + } catch { + + } + } else { + startCallViewModel.searchField += "#" + } } label: { Text("#") .default_text_style(styleSize: 32) @@ -262,52 +421,53 @@ struct DialerBottomSheet: View { .padding(.top, 10) .frame(maxWidth: sharedMainViewModel.maxWidth) - HStack { - + if currentCall == nil { HStack { + HStack { + + } + .frame(width: 60, height: 60) - } - .frame(width: 60, height: 60) - - Spacer() - - Button { - if !startCallViewModel.searchField.isEmpty { - do { - let address = try Factory.Instance.createAddress(addr: String("sip:" + startCallViewModel.searchField + "@" + startCallViewModel.domain)) - telecomManager.doCallWithCore(addr: address, isVideo: false) - } catch { - - } - } - } label: { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 32, height: 32) + Spacer() - } - .frame(width: 90, height: 60) - .background(Color.greenSuccess500) - .cornerRadius(40) - .shadow(color: .black.opacity(0.2), radius: 4) - - Spacer() - - Button { - startCallViewModel.searchField = String(startCallViewModel.searchField.dropLast()) - } label: { - Image("backspace-fill") - .resizable() - .frame(width: 32, height: 32) + Button { + if !startCallViewModel.searchField.isEmpty { + do { + let address = try Factory.Instance.createAddress(addr: String("sip:" + startCallViewModel.searchField + "@" + startCallViewModel.domain)) + telecomManager.doCallWithCore(addr: address, isVideo: false) + } catch { + + } + } + } label: { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 32, height: 32) + + } + .frame(width: 90, height: 60) + .background(Color.greenSuccess500) + .cornerRadius(40) + .shadow(color: .black.opacity(0.2), radius: 4) + Spacer() + + Button { + startCallViewModel.searchField = String(startCallViewModel.searchField.dropLast()) + } label: { + Image("backspace-fill") + .resizable() + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) } - .frame(width: 60, height: 60) + .padding(.horizontal, 60) + .padding(.top, 20) + .frame(maxWidth: sharedMainViewModel.maxWidth) } - .padding(.horizontal, 60) - .padding(.top, 20) - .frame(maxWidth: sharedMainViewModel.maxWidth) Spacer() } @@ -325,6 +485,6 @@ struct DialerBottomSheet: View { #Preview { DialerBottomSheet( - startCallViewModel: StartCallViewModel(), showingDialer: .constant(false) + startCallViewModel: StartCallViewModel(), showingDialer: .constant(false), currentCall: nil ) }