diff --git a/Linphone/Assets.xcassets/lock_simple.imageset/Contents.json b/Linphone/Assets.xcassets/lock_simple.imageset/Contents.json
new file mode 100644
index 000000000..2f3e708ff
--- /dev/null
+++ b/Linphone/Assets.xcassets/lock_simple.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "lock_simple.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/lock_simple.imageset/lock_simple.svg b/Linphone/Assets.xcassets/lock_simple.imageset/lock_simple.svg
new file mode 100644
index 000000000..dcd3fb3e9
--- /dev/null
+++ b/Linphone/Assets.xcassets/lock_simple.imageset/lock_simple.svg
@@ -0,0 +1,3 @@
+
diff --git a/Linphone/Contacts/ContactsManager.swift b/Linphone/Contacts/ContactsManager.swift
index 84efe85fd..6808a6b49 100644
--- a/Linphone/Contacts/ContactsManager.swift
+++ b/Linphone/Contacts/ContactsManager.swift
@@ -143,8 +143,8 @@ final class ContactsManager: ObservableObject {
func textToImage(firstName: String, lastName: String) -> UIImage {
let lblNameInitialize = UILabel()
- lblNameInitialize.frame.size = CGSize(width: 100.0, height: 100.0)
- lblNameInitialize.font = UIFont(name: "NotoSans-ExtraBold", size: 40)
+ lblNameInitialize.frame.size = CGSize(width: 200.0, height: 200.0)
+ lblNameInitialize.font = UIFont(name: "NotoSans-ExtraBold", size: 80)
lblNameInitialize.textColor = UIColor(Color.grayMain2c600)
var textToDisplay = ""
diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings
index c48bf298e..589a8fa68 100644
--- a/Linphone/Localizable.xcstrings
+++ b/Linphone/Localizable.xcstrings
@@ -170,6 +170,9 @@
},
"Appel" : {
+ },
+ "Appel chiffré de bout en bout" : {
+
},
"assistant_account_login" : {
"extractionState" : "manual",
@@ -436,9 +439,6 @@
},
"Other actions" : {
- },
- "Outgoing call" : {
-
},
"password" : {
"extractionState" : "manual",
diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift
index 88c61e481..0a587abae 100644
--- a/Linphone/UI/Call/CallView.swift
+++ b/Linphone/UI/Call/CallView.swift
@@ -40,20 +40,18 @@ struct CallView: View {
@State var audioRouteSheet: Bool = false
@State var hideButtonsSheet: Bool = false
@State var options: Int = 1
-
@State var imageAudioRoute: String = ""
-
@State var angleDegree = 0.0
-
@State var showingDialer = false
+ @State var minBottomSheetHeight: CGFloat = 0.16
+ @State var maxBottomSheetHeight: CGFloat = 0.5
+ @State private var pointingUp: CGFloat = 0.0
+ @State private var currentOffset: CGFloat = 0.0
@Binding var fullscreenVideo: Bool
@Binding var isShowCallsListFragment: Bool
@Binding var isShowStartCallFragment: Bool
- @State private var pointingUp: CGFloat = 0.0
- @State private var currentOffset: CGFloat = 0.0
-
var body: some View {
GeometryReader { geo in
ZStack {
@@ -113,18 +111,6 @@ struct CallView: View {
CallsListFragment(callViewModel: callViewModel, isShowCallsListFragment: $isShowCallsListFragment)
.zIndex(4)
.transition(.move(edge: .bottom))
- /*
- .sheet(isPresented: $showingDialer) {
- DialerBottomSheet(
- startCallViewModel: startCallViewModel,
- showingDialer: $showingDialer,
- currentCall: nil
- )
- .presentationDetents([.medium])
- // .interactiveDismissDisabled()
- .presentationBackgroundInteraction(.enabled(upThrough: .medium))
- }
- */
}
if callViewModel.zrtpPopupDisplayed == true {
@@ -265,318 +251,349 @@ struct CallView: View {
@ViewBuilder
// swiftlint:disable:next cyclomatic_complexity
func innerView(geometry: GeometryProxy) -> some View {
- VStack {
- if !fullscreenVideo || (fullscreenVideo && telecomManager.isPausedByRemote) {
- 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 {
- Image("outgoing-call")
- .resizable()
- .frame(width: 15, height: 15)
- .padding(.horizontal)
-
- Text("Outgoing call")
- .foregroundStyle(.white)
- } else {
- Image("incoming-call")
- .resizable()
- .frame(width: 15, height: 15)
- .padding(.horizontal)
-
- Text("Incoming call")
- .foregroundStyle(.white)
+ ZStack {
+ VStack {
+ if !fullscreenVideo || (fullscreenVideo && telecomManager.isPausedByRemote) {
+ 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)
}
-
- if !telecomManager.outgoingCallStarted && telecomManager.callInProgress {
- Text("|")
- .foregroundStyle(.white)
-
- ZStack {
- Text(callViewModel.timeElapsed.convertDurationToString())
- .onReceive(callViewModel.timer) { _ in
- callViewModel.timeElapsed = callViewModel.currentCall?.duration ?? 0
- }
- .foregroundStyle(.white)
- .if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in
- view.hidden()
+ ZStack {
+ HStack {
+ Button {
+ withAnimation {
+ telecomManager.callDisplayed = false
}
+ } label: {
+ Image("caret-left")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ }
- if callViewModel.isPaused {
- Text("Paused")
- .foregroundStyle(.white)
- } else if telecomManager.isPausedByRemote {
- Text("Paused by remote")
+ Text(callViewModel.displayName)
+ .default_text_style_white_800(styleSize: 16)
+
+ if !telecomManager.outgoingCallStarted && telecomManager.callInProgress {
+ Text("|")
+ .default_text_style_white_800(styleSize: 16)
+
+ ZStack {
+ Text(callViewModel.timeElapsed.convertDurationToString())
+ .onReceive(callViewModel.timer) { _ in
+ callViewModel.timeElapsed = callViewModel.currentCall?.duration ?? 0
+ }
+ .default_text_style_white_800(styleSize: 16)
+ .if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in
+ view.hidden()
+ }
+
+ if callViewModel.isPaused {
+ Text("Paused")
+ .default_text_style_white_800(styleSize: 16)
+ } else if telecomManager.isPausedByRemote {
+ Text("Paused by remote")
+ .default_text_style_white_800(styleSize: 16)
+ }
+ }
+ }
+
+ Spacer()
+
+ Button {
+ } label: {
+ Image("cell-signal-full")
+ .renderingMode(.template)
+ .resizable()
.foregroundStyle(.white)
+ .frame(width: 30, height: 30)
+ .padding(.all, 10)
+ }
+
+ if telecomManager.remoteVideo {
+ Button {
+ callViewModel.switchCamera()
+ } label: {
+ Image("camera-rotate")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 30, height: 30)
+ .padding(.horizontal)
+ }
}
}
+ .frame(height: 40)
+ .zIndex(1)
+
+ if callViewModel.isMediaEncrypted {
+ HStack {
+ Image("lock_simple")
+ .resizable()
+ .frame(width: 15, height: 15, alignment: .leading)
+ .padding(.leading, 50)
+ .padding(.top, 35)
+
+ Text("Appel chiffré de bout en bout")
+ .foregroundStyle(Color.blueInfo500)
+ .default_text_style_white(styleSize: 12)
+ .padding(.top, 35)
+
+ Spacer()
+ }
+ .onTapGesture {
+ callViewModel.showZrtpSasDialogIfPossible()
+ }
+ .frame(height: 40)
+ .zIndex(1)
+ }
+ }
+ }
+
+ ZStack {
+ VStack {
+ Spacer()
+ ZStack {
+
+ if callViewModel.isRemoteDeviceTrusted {
+ Circle()
+ .fill(Color.blueInfo500)
+ .frame(width: 206, height: 206)
+ }
+
+ if callViewModel.remoteAddress != nil {
+ let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.remoteAddress!)
+
+ let contactAvatarModel = addressFriend != nil
+ ? ContactsManager.shared.avatarListModel.first(where: {
+ ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
+ && $0.friend!.name == addressFriend!.name
+ && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
+ })
+ : ContactAvatarModel(friend: nil, withPresence: false)
+
+ if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
+ if contactAvatarModel != nil {
+ Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 200, hidePresence: true)
+ }
+ } else {
+ if callViewModel.remoteAddress!.displayName != nil {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.remoteAddress!.displayName!,
+ lastName: callViewModel.remoteAddress!.displayName!.components(separatedBy: " ").count > 1
+ ? callViewModel.remoteAddress!.displayName!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+
+ } else {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.remoteAddress!.username ?? "Username Error",
+ lastName: callViewModel.remoteAddress!.username!.components(separatedBy: " ").count > 1
+ ? callViewModel.remoteAddress!.username!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+ }
+
+ }
+ } else {
+ Image("profil-picture-default")
+ .resizable()
+ .frame(width: 200, height: 200)
+ .clipShape(Circle())
+ }
+
+ if callViewModel.isRemoteDeviceTrusted {
+ VStack {
+ Spacer()
+ HStack {
+ Image("trusted")
+ .resizable()
+ .frame(width: 25, height: 25)
+ .padding(.all, 15)
+ Spacer()
+ }
+ }
+ .frame(width: 200, height: 200)
+ }
+ }
+
+ Text(callViewModel.displayName)
+ .padding(.top)
+ .default_text_style_white(styleSize: 22)
+
+ Text(callViewModel.remoteAddressString)
+ .default_text_style_white_300(styleSize: 16)
+
+ Spacer()
}
- Spacer()
-
- if callViewModel.isMediaEncrypted {
- Button {
- callViewModel.showZrtpSasDialogIfPossible()
- } label: {
- Image(callViewModel.isZrtpPq ? "media-encryption-zrtp-pq" : "media-encryption-srtp")
- .resizable()
- .frame(width: 30, height: 30)
- .padding(.horizontal)
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativeVideoWindow = view
+ }
+ }
+ .frame(
+ width:
+ angleDegree == 0
+ ? (fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8)
+ : (fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom),
+ height:
+ angleDegree == 0
+ ? (fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom)
+ : (fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8)
+ )
+ .scaledToFill()
+ .clipped()
+ .onTapGesture {
+ if telecomManager.remoteVideo {
+ fullscreenVideo.toggle()
}
}
if telecomManager.remoteVideo {
- Button {
- callViewModel.switchCamera()
- } label: {
- Image("camera-rotate")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 30, height: 30)
- .padding(.horizontal)
- }
- }
- }
- .frame(height: 40)
- .zIndex(1)
- }
-
- ZStack {
- VStack {
- Spacer()
- ZStack {
-
- if callViewModel.isRemoteDeviceTrusted {
- Circle()
- .fill(Color.blueInfo500)
- .frame(width: 105, height: 105)
- }
-
- if callViewModel.remoteAddress != nil {
- let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.remoteAddress!)
-
- let contactAvatarModel = addressFriend != nil
- ? ContactsManager.shared.avatarListModel.first(where: {
- ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
- && $0.friend!.name == addressFriend!.name
- && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
- })
- : ContactAvatarModel(friend: nil, withPresence: false)
-
- if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
- if contactAvatarModel != nil {
- Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 100, hidePresence: true)
- }
- } else {
- if callViewModel.remoteAddress!.displayName != nil {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.remoteAddress!.displayName!,
- lastName: callViewModel.remoteAddress!.displayName!.components(separatedBy: " ").count > 1
- ? callViewModel.remoteAddress!.displayName!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
-
- } else {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.remoteAddress!.username ?? "Username Error",
- lastName: callViewModel.remoteAddress!.username!.components(separatedBy: " ").count > 1
- ? callViewModel.remoteAddress!.username!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
- }
-
- }
- } else {
- Image("profil-picture-default")
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
- }
-
- if callViewModel.isRemoteDeviceTrusted {
+ HStack {
+ Spacer()
VStack {
Spacer()
- HStack {
- Image("trusted")
- .resizable()
- .frame(width: 25, height: 25)
- Spacer()
+ LinphoneVideoViewHolder { view in
+ coreContext.doOnCoreQueue { core in
+ core.nativePreviewWindow = view
+ }
}
+ .frame(width: angleDegree == 0 ? 120*1.2 : 160*1.2, height: angleDegree == 0 ? 160*1.2 : 120*1.2)
+ .cornerRadius(20)
+ .padding(10)
+ .padding(.trailing, abs(angleDegree/2))
}
- .frame(width: 100, height: 100)
}
+ .frame(
+ maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
+ )
}
- Text(callViewModel.displayName)
- .padding(.top)
- .foregroundStyle(.white)
+ if callViewModel.isRecording {
+ HStack {
+ VStack {
+ Image("record-fill")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.redDanger500)
+ .frame(width: 32, height: 32)
+ .padding(10)
+ .if(fullscreenVideo && !telecomManager.isPausedByRemote) { view in
+ view.padding(.top, 30)
+ }
+ Spacer()
+ }
+ Spacer()
+ }
+ .frame(
+ maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
+ )
+ }
- Text(callViewModel.remoteAddressString)
- .foregroundStyle(.white)
-
- Spacer()
- }
-
- LinphoneVideoViewHolder { view in
- coreContext.doOnCoreQueue { core in
- core.nativeVideoWindow = view
+ if telecomManager.outgoingCallStarted {
+ VStack {
+ ActivityIndicator()
+ .frame(width: 20, height: 20)
+ .padding(.top, 60)
+
+ Text(callViewModel.counterToMinutes())
+ .onAppear {
+ callViewModel.timeElapsed = 0
+ }
+ .onReceive(callViewModel.timer) { _ in
+ callViewModel.timeElapsed = callViewModel.currentCall?.duration ?? 0
+
+ }
+ .onDisappear {
+ callViewModel.timeElapsed = 0
+ }
+ .padding(.top)
+ .foregroundStyle(.white)
+
+ Spacer()
+ }
+ .background(.clear)
+ .frame(
+ maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
+ )
}
}
.frame(
- width:
- angleDegree == 0
- ? 120 * ((geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom) / 160)
- : 120 * ((geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) / 120),
- height:
- angleDegree == 0
- ? 160 * ((geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom) / 160)
- : 160 * ((geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) / 120)
+ maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78) - 40 - 20 + geometry.safeAreaInsets.bottom
)
- .scaledToFill()
- .clipped()
- .onTapGesture {
- if telecomManager.remoteVideo {
- fullscreenVideo.toggle()
- }
- }
-
- if telecomManager.remoteVideo {
- HStack {
- Spacer()
- VStack {
- Spacer()
- LinphoneVideoViewHolder { view in
- coreContext.doOnCoreQueue { core in
- core.nativePreviewWindow = view
- }
- }
- .frame(width: angleDegree == 0 ? 120*1.2 : 160*1.2, height: angleDegree == 0 ? 160*1.2 : 120*1.2)
- .cornerRadius(20)
- .padding(10)
- .padding(.trailing, abs(angleDegree/2))
+ .background(Color.gray900)
+ .cornerRadius(20)
+ .padding(.horizontal, fullscreenVideo && !telecomManager.isPausedByRemote ? 0 : 4)
+ .onRotate { newOrientation in
+ let oldOrientation = orientation
+ orientation = newOrientation
+ if orientation == .portrait || orientation == .portraitUpsideDown {
+ angleDegree = 0
+ } else {
+ if orientation == .landscapeLeft {
+ angleDegree = -90
+ } else if orientation == .landscapeRight {
+ angleDegree = 90
}
}
- .frame(
- maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (0.18 * geometry.size.height) - geometry.safeAreaInsets.bottom
- )
- }
-
- if callViewModel.isRecording {
- HStack {
- VStack {
- Image("record-fill")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(Color.redDanger500)
- .frame(width: 32, height: 32)
- .padding(10)
- .if(fullscreenVideo && !telecomManager.isPausedByRemote) { view in
- view.padding(.top, 30)
- }
- Spacer()
+
+ if (oldOrientation != orientation && oldOrientation != .faceUp) || (oldOrientation == .faceUp && (orientation == .landscapeLeft || orientation == .landscapeRight)) {
+ telecomManager.callStarted = false
+
+ DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
+ telecomManager.callStarted = true
}
- Spacer()
}
- .frame(
- maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (0.18 * geometry.size.height) - geometry.safeAreaInsets.bottom
- )
+
+ callViewModel.orientationUpdate(orientation: orientation)
}
-
- if telecomManager.outgoingCallStarted {
- VStack {
- ActivityIndicator()
- .frame(width: 20, height: 20)
- .padding(.top, 100)
-
- Text(callViewModel.counterToMinutes())
- .onAppear {
- callViewModel.timeElapsed = 0
- }
- .onReceive(callViewModel.timer) { _ in
- callViewModel.timeElapsed = callViewModel.currentCall?.duration ?? 0
-
- }
- .onDisappear {
- callViewModel.timeElapsed = 0
- }
- .padding(.top)
- .foregroundStyle(.white)
-
- Spacer()
+ .onAppear {
+ if orientation == .portrait && orientation == .portraitUpsideDown {
+ angleDegree = 0
+ } else {
+ if orientation == .landscapeLeft {
+ angleDegree = -90
+ } else if orientation == .landscapeRight {
+ angleDegree = 90
+ }
}
- .frame(
- maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (0.18 * geometry.size.height) - geometry.safeAreaInsets.bottom
- )
- .background(.clear)
- }
- }
- .frame(
- maxWidth: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.width : geometry.size.width - 8,
- maxHeight: fullscreenVideo && !telecomManager.isPausedByRemote ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - (0.18 * geometry.size.height) - geometry.safeAreaInsets.bottom
- )
- .background(Color.gray900)
- .cornerRadius(20)
- .padding(.horizontal, fullscreenVideo && !telecomManager.isPausedByRemote ? 0 : 4)
- .onRotate { newOrientation in
- let oldOrientation = orientation
- orientation = newOrientation
- if orientation == .portrait || orientation == .portraitUpsideDown {
- angleDegree = 0
- } else {
- if orientation == .landscapeLeft {
- angleDegree = -90
- } else if orientation == .landscapeRight {
- angleDegree = 90
- }
- }
-
- if (oldOrientation != orientation && oldOrientation != .faceUp) || (oldOrientation == .faceUp && (orientation == .landscapeLeft || orientation == .landscapeRight)) {
+
telecomManager.callStarted = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
telecomManager.callStarted = true
}
+
+ callViewModel.orientationUpdate(orientation: orientation)
}
- callViewModel.orientationUpdate(orientation: orientation)
+ Spacer()
}
- .onAppear {
- if orientation == .portrait && orientation == .portraitUpsideDown {
- angleDegree = 0
- } else {
- if orientation == .landscapeLeft {
- angleDegree = -90
- } else if orientation == .landscapeRight {
- angleDegree = 90
- }
- }
-
- telecomManager.callStarted = false
-
- DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
- telecomManager.callStarted = true
- }
-
- callViewModel.orientationUpdate(orientation: orientation)
+ .frame(height: geometry.size.height)
+ .frame(maxWidth: .infinity)
+ .background(Color.gray900)
+ .if(fullscreenVideo && !telecomManager.isPausedByRemote) { view in
+ view.ignoresSafeArea(.all)
}
if !fullscreenVideo || (fullscreenVideo && telecomManager.isPausedByRemote) {
@@ -586,74 +603,19 @@ struct CallView: View {
BottomSheetView(
content: bottomSheetContent(geo: geometry),
- minHeight: 0.18 * geometry.size.height,
- maxHeight: 0.5 * geometry.size.height,
+ minHeight: (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78),
+ maxHeight: (maxBottomSheetHeight * geometry.size.height),
currentOffset: $currentOffset,
pointingUp: $pointingUp,
bottomSafeArea: bottomInset?.bottom ?? 0
)
.onAppear {
- currentOffset = 0.18 * geometry.size.height
- pointingUp = 1 - ((currentOffset - 0.18 * geometry.size.height) / (0.5 * geometry.size.height - 0.18 * geometry.size.height))
+ currentOffset = (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78)
+ pointingUp = -(((currentOffset - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78)) / ((maxBottomSheetHeight * geometry.size.height) - (minBottomSheetHeight * geometry.size.height > 80 ? minBottomSheetHeight * geometry.size.height : 78))) - 0.5) * 2
}
- } else {
-#if targetEnvironment(simulator)
- HStack(spacing: 12) {
- HStack {
- Spacer()
-
- 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)
-
- Button {
- callViewModel.acceptCall()
- } label: {
- Image("phone")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
-
- }
- .frame(width: 90, height: 60)
- .background(Color.greenSuccess500)
- .cornerRadius(40)
-
- Spacer()
- }
- .frame(height: 60)
- }
- .padding(.horizontal, 25)
- .padding(.top, 20)
-#else
- HStack(spacing: 12) {
- HStack {
- }
- .frame(height: 60)
- }
- .padding(.horizontal, 25)
- .padding(.top, 20)
-#endif
+ .edgesIgnoringSafeArea(.bottom)
}
}
-
- Spacer()
- }
- .frame(maxWidth: .infinity)
- .background(Color.gray900)
- .if(fullscreenVideo && !telecomManager.isPausedByRemote) { view in
- view.ignoresSafeArea(.all)
}
}
@@ -662,18 +624,18 @@ struct CallView: View {
VStack(spacing: 0) {
Button {
withAnimation {
- if currentOffset < (0.5 * geo.size.height) {
- currentOffset = 0.5 * geo.size.height
+ if currentOffset < (maxBottomSheetHeight * geo.size.height) {
+ currentOffset = (maxBottomSheetHeight * geo.size.height)
} else {
- currentOffset = 0.18 * geo.size.height
+ currentOffset = (minBottomSheetHeight * geo.size.height > 80 ? minBottomSheetHeight * geo.size.height : 78)
}
- pointingUp = 1 - ((currentOffset - 0.18 * geo.size.height) / (0.5 * geo.size.height - 0.18 * geo.size.height))
+ pointingUp = -(((currentOffset - (minBottomSheetHeight * geo.size.height > 80 ? minBottomSheetHeight * geo.size.height : 78)) / ((maxBottomSheetHeight * geo.size.height) - (minBottomSheetHeight * geo.size.height > 80 ? minBottomSheetHeight * geo.size.height : 78))) - 0.5) * 2
}
} label: {
ChevronShape(pointingUp: pointingUp)
.stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round))
- .frame(width: 50, height: 10)
+ .frame(width: 40, height: 6)
.foregroundStyle(.white)
.contentShape(Rectangle())
.padding(.top, 15)
@@ -699,30 +661,34 @@ struct CallView: View {
Button {
callViewModel.toggleVideo()
} label: {
- Image(telecomManager.remoteVideo ? "video-camera" : "video-camera-slash")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
- .frame(width: 32, height: 32)
-
+ HStack {
+ Image(telecomManager.remoteVideo ? "video-camera" : "video-camera-slash")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
+ .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? .white : 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)
-
+ HStack {
+ Image(callViewModel.micMutted ? "microphone-slash" : "microphone")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background(callViewModel.micMutted ? .white : Color.gray500)
+ .background(callViewModel.micMutted ? Color.redDanger500 : Color.gray500)
.cornerRadius(40)
Button {
@@ -743,23 +709,26 @@ struct CallView: View {
}
} label: {
- Image(imageAudioRoute)
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- .onAppear(perform: getAudioRouteImage)
- .onReceive(pub) { _ in
- self.getAudioRouteImage()
- }
-
+ HStack {
+ Image(imageAudioRoute)
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ .onAppear(perform: getAudioRouteImage)
+ .onReceive(pub) { _ in
+ self.getAudioRouteImage()
+ }
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
}
.frame(height: geo.size.height * 0.15)
.padding(.horizontal, 20)
+ .padding(.top, -12)
if orientation != .landscapeLeft && orientation != .landscapeRight {
HStack(spacing: 0) {
@@ -775,12 +744,15 @@ struct CallView: View {
callViewModel.transferClicked()
}
} label: {
- Image("phone-transfer")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-transfer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -798,12 +770,15 @@ struct CallView: View {
isShowStartCallFragment.toggle()
}
} label: {
- Image("phone-plus")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-plus")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -822,12 +797,15 @@ struct CallView: View {
isShowCallsListFragment.toggle()
}
} label: {
- Image("phone-list")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-list")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -863,12 +841,15 @@ struct CallView: View {
Button {
showingDialer.toggle()
} label: {
- Image("dialer")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("dialer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -878,31 +859,26 @@ struct CallView: View {
.default_text_style(styleSize: 15)
}
.frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
-
}
.frame(height: geo.size.height * 0.15)
HStack(spacing: 0) {
VStack {
Button {
- withAnimation {
- telecomManager.callDisplayed = false
- }
} label: {
- Image("chat-teardrop-text")
- .renderingMode(.template)
- .resizable()
- //.foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
- .foregroundStyle(Color.gray500)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("chat-teardrop-text")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- //.background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
- .background(Color.gray600)
+ .background(.white)
.cornerRadius(40)
- //.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
- //.disabled(true)
+ .disabled(true)
Text("Messages")
.foregroundStyle(.white)
@@ -914,14 +890,17 @@ struct CallView: View {
Button {
callViewModel.togglePause()
} label: {
- Image(callViewModel.isPaused ? "play" : "pause")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(telecomManager.isPausedByRemote ? Color.gray500 : .white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image(callViewModel.isPaused ? "play" : "pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(telecomManager.isPausedByRemote ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background(telecomManager.isPausedByRemote ? Color.gray600 : (callViewModel.isPaused ? Color.greenSuccess500 : Color.gray500))
+ .background(telecomManager.isPausedByRemote ? .white : (callViewModel.isPaused ? Color.greenSuccess500 : Color.gray500))
.cornerRadius(40)
.disabled(telecomManager.isPausedByRemote)
@@ -935,14 +914,17 @@ struct CallView: View {
Button {
callViewModel.toggleRecording()
} label: {
- Image("record-fill")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("record-fill")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : (callViewModel.isRecording ? Color.redDanger500 : Color.gray500))
+ .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? .white : (callViewModel.isRecording ? Color.redDanger500 : Color.gray500))
.cornerRadius(40)
.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
@@ -955,12 +937,15 @@ struct CallView: View {
VStack {
Button {
} label: {
- Image("video-camera")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("video-camera")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -983,12 +968,15 @@ struct CallView: View {
isShowStartCallFragment.toggle()
}
} label: {
- Image("phone-transfer")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-transfer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -1006,12 +994,15 @@ struct CallView: View {
isShowStartCallFragment.toggle()
}
} label: {
- Image("phone-plus")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-plus")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -1026,12 +1017,15 @@ struct CallView: View {
ZStack {
Button {
} label: {
- Image("phone-list")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("phone-list")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -1067,12 +1061,15 @@ struct CallView: View {
Button {
showingDialer.toggle()
} label: {
- Image("dialer")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("dialer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
.background(Color.gray500)
.cornerRadius(40)
@@ -1086,18 +1083,18 @@ struct CallView: View {
VStack {
Button {
} label: {
- Image("chat-teardrop-text")
- .renderingMode(.template)
- .resizable()
- //.foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
- .foregroundStyle(Color.gray500)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("chat-teardrop-text")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- //.background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
- .background(Color.gray600)
+ .background(.white)
.cornerRadius(40)
- //.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
.disabled(true)
Text("Messages")
@@ -1110,14 +1107,17 @@ struct CallView: View {
Button {
callViewModel.togglePause()
} label: {
- Image(callViewModel.isPaused ? "play" : "pause")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(telecomManager.isPausedByRemote ? Color.gray500 : .white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image(callViewModel.isPaused ? "play" : "pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(telecomManager.isPausedByRemote ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background(telecomManager.isPausedByRemote ? Color.gray600 : (callViewModel.isPaused ? Color.greenSuccess500 : Color.gray500))
+ .background(telecomManager.isPausedByRemote ? .white : (callViewModel.isPaused ? Color.greenSuccess500 : Color.gray500))
.cornerRadius(40)
.disabled(telecomManager.isPausedByRemote)
@@ -1131,14 +1131,17 @@ struct CallView: View {
Button {
callViewModel.toggleRecording()
} label: {
- Image("record-fill")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
- .frame(width: 32, height: 32)
+ HStack {
+ Image("record-fill")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
}
+ .buttonStyle(PressedButtonStyle())
.frame(width: 60, height: 60)
- .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : (callViewModel.isRecording ? Color.redDanger500 : Color.gray500))
+ .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? .white : (callViewModel.isRecording ? Color.redDanger500 : Color.gray500))
.cornerRadius(40)
.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
@@ -1152,6 +1155,7 @@ struct CallView: View {
.padding(.horizontal, 20)
.padding(.top, 30)
}
+
Spacer()
}
.background(Color.gray600)
@@ -1214,16 +1218,16 @@ struct BottomSheetView: View {
.onChanged { value in
currentOffset -= value.translation.height
currentOffset = min(max(currentOffset, minHeight), maxHeight)
- pointingUp = 1 - ((currentOffset - minHeight) / (maxHeight - minHeight))
+ pointingUp = -(((currentOffset - minHeight) / (maxHeight - minHeight)) - 0.5) * 2
}
.onEnded { _ in
withAnimation {
currentOffset = (currentOffset - minHeight <= maxHeight - currentOffset) ? minHeight : maxHeight
- pointingUp = 1 - ((currentOffset - minHeight) / (maxHeight - minHeight))
+ pointingUp = -(((currentOffset - minHeight) / (maxHeight - minHeight)) - 0.5) * 2
}
}
)
- .offset(y: maxHeight - currentOffset + bottomSafeArea)
+ .offset(y: maxHeight - currentOffset)
}
}
}
@@ -1247,7 +1251,6 @@ struct ChevronShape: Shape {
let arrowTipStartingPoint = height - pointingUp * height * 0.9
path.move(to: .init(x: 0, y: height))
- //path.addLine(to: .init(x: horizontalCenter, y: arrowTipStartingPoint))
path.addLine(to: .init(x: horizontalCenter - horizontalCenterOffset, y: arrowTipStartingPoint))
path.addQuadCurve(to: .init(x: horizontalCenter + horizontalCenterOffset, y: arrowTipStartingPoint), control: .init(x: horizontalCenter, y: height * (1 - pointingUp)))
@@ -1258,6 +1261,15 @@ struct ChevronShape: Shape {
}
}
+struct PressedButtonStyle: ButtonStyle {
+ func makeBody(configuration: Self.Configuration) -> some View {
+ configuration.label
+ .frame(width: 60, height: 60)
+ .background(configuration.isPressed ? .white : .clear)
+ .cornerRadius(40)
+ }
+}
+
#Preview {
CallView(callViewModel: CallViewModel(), fullscreenVideo: .constant(false), isShowCallsListFragment: .constant(false), isShowStartCallFragment: .constant(false))
}