diff --git a/Linphone/Assets.xcassets/question.imageset/question.svg b/Linphone/Assets.xcassets/question.imageset/question.svg
index 6d8013ceb..7825afec1 100644
--- a/Linphone/Assets.xcassets/question.imageset/question.svg
+++ b/Linphone/Assets.xcassets/question.imageset/question.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings
index 5f68bafe7..a644fb4a2 100644
--- a/Linphone/Localizable.xcstrings
+++ b/Linphone/Localizable.xcstrings
@@ -3814,6 +3814,23 @@
}
}
},
+ "manage_account_dialog_international_prefix_help_message" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Pick your country to allow Linphone to match your contacts."
+ }
+ },
+ "fr" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Choisissez votre pays pour permettre à Linphone de faire le lien avec vos contacts."
+ }
+ }
+ }
+ },
"manage_account_edit_picture" : {
"localizations" : {
"en" : {
@@ -3830,6 +3847,23 @@
}
}
},
+ "manage_account_international_prefix" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "International Prefix"
+ }
+ },
+ "fr" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Indicatif international"
+ }
+ }
+ }
+ },
"manage_account_remove_picture" : {
"localizations" : {
"en" : {
diff --git a/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift b/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift
index 1ce788ecb..844597cc4 100644
--- a/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift
+++ b/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift
@@ -34,127 +34,183 @@ struct AccountProfileFragment: View {
@State private var showPhotoPicker = false
@State private var selectedImage: UIImage?
@State private var removedImage = false
+ @State private var isShowPopup = false
@FocusState var isDisplayNameFocused: Bool
private let avatarSize = 100.0
var body: some View {
- VStack(spacing: 1) {
- Rectangle()
- .foregroundColor(Color.orangeMain500)
- .edgesIgnoringSafeArea(.top)
- .frame(height: 0)
-
- HStack {
- Image("caret-left")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(Color.orangeMain500)
- .frame(width: 25, height: 25, alignment: .leading)
- .padding(.all, 10)
- .padding(.top, 4)
- .padding(.leading, -10)
- .onTapGesture {
- accountProfileViewModel.saveChangesWhenLeaving()
- withAnimation {
- if isShowAccountProfileFragment {
- isShowAccountProfileFragment = false
+ ZStack {
+ VStack(spacing: 1) {
+ Rectangle()
+ .foregroundColor(Color.orangeMain500)
+ .edgesIgnoringSafeArea(.top)
+ .frame(height: 0)
+
+ HStack {
+ Image("caret-left")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.orangeMain500)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ .padding(.top, 4)
+ .padding(.leading, -10)
+ .onTapGesture {
+ accountProfileViewModel.saveChangesWhenLeaving()
+ withAnimation {
+ if isShowAccountProfileFragment {
+ isShowAccountProfileFragment = false
+ }
}
}
- }
+
+ Text("manage_account_title")
+ .default_text_style_orange_800(styleSize: 16)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .padding(.top, 4)
+ .lineLimit(1)
+
+ Spacer()
+ }
+ .frame(maxWidth: .infinity)
+ .frame(height: 50)
+ .padding(.horizontal)
+ .padding(.bottom, 4)
+ .background(.white)
- Text("manage_account_title")
- .default_text_style_orange_800(styleSize: 16)
- .frame(maxWidth: .infinity, alignment: .leading)
- .padding(.top, 4)
- .lineLimit(1)
-
- Spacer()
- }
- .frame(maxWidth: .infinity)
- .frame(height: 50)
- .padding(.horizontal)
- .padding(.bottom, 4)
- .background(.white)
-
- ScrollView {
- VStack(spacing: 0) {
+ ScrollView {
VStack(spacing: 0) {
- if #unavailable(iOS 16.0) {
- Rectangle()
- .foregroundColor(Color.gray100)
- .frame(height: 7)
- }
-
- if accountProfileViewModel.avatarModel != nil {
- VStack(spacing: 0) {
- if accountProfileViewModel.avatarModel != nil
- && accountProfileViewModel.photoAvatarModel != nil
- && !accountProfileViewModel.photoAvatarModel!.isEmpty
- && selectedImage == nil && !removedImage {
-
- AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
- switch image {
- case .empty:
- ProgressView()
- .frame(width: avatarSize, height: avatarSize)
- case .success(let image):
- image
+ VStack(spacing: 0) {
+ if #unavailable(iOS 16.0) {
+ Rectangle()
+ .foregroundColor(Color.gray100)
+ .frame(height: 7)
+ }
+
+ if accountProfileViewModel.avatarModel != nil {
+ VStack(spacing: 0) {
+ if accountProfileViewModel.avatarModel != nil
+ && accountProfileViewModel.photoAvatarModel != nil
+ && !accountProfileViewModel.photoAvatarModel!.isEmpty
+ && selectedImage == nil && !removedImage {
+
+ AsyncImage(url: accountProfileViewModel.getImagePath()) { image in
+ switch image {
+ case .empty:
+ ProgressView()
+ .frame(width: avatarSize, height: avatarSize)
+ case .success(let image):
+ image
+ .resizable()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: avatarSize, height: avatarSize)
+ .clipShape(Circle())
+ case .failure:
+ Image(uiImage: contactsManager.textToImage(
+ firstName: accountProfileViewModel.avatarModel?.name ?? "",
+ lastName: ""))
.resizable()
- .aspectRatio(contentMode: .fill)
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
- case .failure:
- Image(uiImage: contactsManager.textToImage(
- firstName: accountProfileViewModel.avatarModel?.name ?? "",
- lastName: ""))
- .resizable()
- .frame(width: avatarSize, height: avatarSize)
- .clipShape(Circle())
- @unknown default:
- EmptyView()
+ @unknown default:
+ EmptyView()
+ }
}
- }
- } else if selectedImage == nil {
- Image(uiImage: contactsManager.textToImage(
- firstName: accountProfileViewModel.avatarModel?.name ?? "",
- lastName: ""))
- .resizable()
- .frame(width: avatarSize, height: avatarSize)
- .clipShape(Circle())
- } else {
- Image(uiImage: selectedImage!)
+ } else if selectedImage == nil {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: accountProfileViewModel.avatarModel?.name ?? "",
+ lastName: ""))
.resizable()
- .aspectRatio(contentMode: .fill)
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
- }
-
- if accountProfileViewModel.avatarModel != nil
- && accountProfileViewModel.photoAvatarModel != nil
- && !accountProfileViewModel.photoAvatarModel!.isEmpty
- && (accountProfileViewModel.photoAvatarModel!.suffix(11) != "default.png" || selectedImage != nil)
- && !removedImage {
- HStack {
- Spacer()
-
+ } else {
+ Image(uiImage: selectedImage!)
+ .resizable()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: avatarSize, height: avatarSize)
+ .clipShape(Circle())
+ }
+
+ if accountProfileViewModel.avatarModel != nil
+ && accountProfileViewModel.photoAvatarModel != nil
+ && !accountProfileViewModel.photoAvatarModel!.isEmpty
+ && (accountProfileViewModel.photoAvatarModel!.suffix(11) != "default.png" || selectedImage != nil)
+ && !removedImage {
+ HStack {
+ Spacer()
+
+ Button(action: {
+ showPhotoPicker = true
+ }, label: {
+ HStack {
+ Image("pencil-simple")
+ .resizable()
+ .frame(width: 20, height: 20)
+
+ Text("manage_account_edit_picture")
+ .foregroundStyle(Color.grayMain2c700)
+ .multilineTextAlignment(.center)
+ .default_text_style(styleSize: 14)
+ }
+ })
+ .padding(.top, 10)
+ .padding(.trailing, 10)
+ .sheet(isPresented: $showPhotoPicker) {
+ PhotoPicker(filter: .images, limit: 1) { results in
+ PhotoPicker.convertToUIImageArray(fromResults: results) { imagesOrNil, errorOrNil in
+ if let error = errorOrNil {
+ print(error)
+ }
+ if let images = imagesOrNil {
+ if let first = images.first {
+ selectedImage = first
+ removedImage = false
+ saveImage()
+ }
+ }
+ }
+ }
+ .edgesIgnoringSafeArea(.all)
+ }
+
+ Button(action: {
+ removedImage = true
+ selectedImage = nil
+ saveImage()
+ }, label: {
+ HStack {
+ Image("trash-simple")
+ .resizable()
+ .frame(width: 20, height: 20)
+
+ Text("manage_account_remove_picture")
+ .foregroundStyle(Color.grayMain2c700)
+ .multilineTextAlignment(.center)
+ .default_text_style(styleSize: 14)
+ }
+ })
+ .padding(.top, 10)
+
+ Spacer()
+ }
+ } else {
Button(action: {
showPhotoPicker = true
}, label: {
HStack {
- Image("pencil-simple")
+ Image("camera")
.resizable()
.frame(width: 20, height: 20)
- Text("manage_account_edit_picture")
+ Text("manage_account_add_picture")
.foregroundStyle(Color.grayMain2c700)
.multilineTextAlignment(.center)
.default_text_style(styleSize: 14)
}
})
.padding(.top, 10)
- .padding(.trailing, 10)
.sheet(isPresented: $showPhotoPicker) {
PhotoPicker(filter: .images, limit: 1) { results in
PhotoPicker.convertToUIImageArray(fromResults: results) { imagesOrNil, errorOrNil in
@@ -165,6 +221,7 @@ struct AccountProfileFragment: View {
if let first = images.first {
selectedImage = first
removedImage = false
+ showPhotoPicker = false
saveImage()
}
}
@@ -172,193 +229,171 @@ struct AccountProfileFragment: View {
}
.edgesIgnoringSafeArea(.all)
}
-
- Button(action: {
- removedImage = true
- selectedImage = nil
- saveImage()
- }, label: {
- HStack {
- Image("trash-simple")
+ }
+ }
+ .frame(minHeight: 150)
+ .frame(maxWidth: .infinity)
+ .padding(.top, 10)
+ .padding(.bottom, 2)
+ .background(Color.gray100)
+ }
+
+ HStack(alignment: .center) {
+ Text("manage_account_details_title")
+ .default_text_style_800(styleSize: 18)
+ .frame(maxWidth: .infinity, alignment: .leading)
+
+ Spacer()
+
+ Image(detailIsOpen ? "caret-up" : "caret-down")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c600)
+ .frame(width: 25, height: 25, alignment: .leading)
+ .padding(.all, 10)
+ }
+ .padding(.top, 30)
+ .padding(.bottom, 10)
+ .padding(.horizontal, 20)
+ .background(Color.gray100)
+ .onTapGesture {
+ withAnimation {
+ detailIsOpen.toggle()
+ }
+ }
+
+ if detailIsOpen {
+ VStack(spacing: 0) {
+ VStack(spacing: 30) {
+ HStack {
+ Text(String(localized: "sip_address") + ":")
+ .default_text_style_600(styleSize: 14)
+
+ Text(accountProfileViewModel.avatarModel!.address)
+ .foregroundStyle(Color.grayMain2c700)
+ .default_text_style(styleSize: 14)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .lineLimit(1)
+
+ Button(action: {
+ UIPasteboard.general.setValue(
+ accountProfileViewModel.avatarModel!.address,
+ forPasteboardType: UTType.plainText.identifier
+ )
+
+ ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
+ ToastViewModel.shared.displayToast.toggle()
+ }, label: {
+ Image("copy")
.resizable()
.frame(width: 20, height: 20)
-
- Text("manage_account_remove_picture")
- .foregroundStyle(Color.grayMain2c700)
- .multilineTextAlignment(.center)
- .default_text_style(styleSize: 14)
- }
- })
- .padding(.top, 10)
-
- Spacer()
- }
- } else {
- Button(action: {
- showPhotoPicker = true
- }, label: {
- HStack {
- Image("camera")
- .resizable()
- .frame(width: 20, height: 20)
-
- Text("manage_account_add_picture")
- .foregroundStyle(Color.grayMain2c700)
- .multilineTextAlignment(.center)
- .default_text_style(styleSize: 14)
+ })
}
- })
- .padding(.top, 10)
- .sheet(isPresented: $showPhotoPicker) {
- PhotoPicker(filter: .images, limit: 1) { results in
- PhotoPicker.convertToUIImageArray(fromResults: results) { imagesOrNil, errorOrNil in
- if let error = errorOrNil {
- print(error)
- }
- if let images = imagesOrNil {
- if let first = images.first {
- selectedImage = first
- removedImage = false
- showPhotoPicker = false
- saveImage()
+
+ VStack(alignment: .leading) {
+ Text("sip_address_display_name")
+ .default_text_style_700(styleSize: 15)
+ .padding(.bottom, -5)
+ TextField(accountProfileViewModel.displayName, text: $accountProfileViewModel.displayName)
+ .default_text_style(styleSize: 15)
+ .frame(height: 25)
+ .padding(.horizontal, 20)
+ .padding(.vertical, 15)
+ .background(.white)
+ .cornerRadius(60)
+ .overlay(
+ RoundedRectangle(cornerRadius: 60)
+ .inset(by: 0.5)
+ .stroke(isDisplayNameFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1)
+ )
+ .focused($isDisplayNameFocused)
+ }
+
+ VStack(alignment: .leading) {
+ HStack {
+ Text("manage_account_international_prefix")
+ .default_text_style_700(styleSize: 15)
+ .padding(.bottom, -5)
+ .lineLimit(1)
+
+ Button(action: {
+ isShowPopup = true
+ }, label: {
+ Image("question")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.grayMain2c600)
+ .frame(width: 20, height: 20)
+ })
+ .padding(.bottom, -5)
+ }
+ Menu {
+ Picker("", selection: $accountProfileViewModel.dialPlanValueSelected) {
+ ForEach(registerViewModel.dialPlansLabelList, id: \.self) { dialPlan in
+ Text(dialPlan).tag(dialPlan)
}
}
- }
- }
- .edgesIgnoringSafeArea(.all)
- }
- }
- }
- .frame(minHeight: 150)
- .frame(maxWidth: .infinity)
- .padding(.top, 10)
- .padding(.bottom, 2)
- .background(Color.gray100)
- }
-
- HStack(alignment: .center) {
- Text("manage_account_details_title")
- .default_text_style_800(styleSize: 18)
- .frame(maxWidth: .infinity, alignment: .leading)
-
- Spacer()
-
- Image(detailIsOpen ? "caret-up" : "caret-down")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(Color.grayMain2c600)
- .frame(width: 25, height: 25, alignment: .leading)
- .padding(.all, 10)
- }
- .padding(.top, 30)
- .padding(.bottom, 10)
- .padding(.horizontal, 20)
- .background(Color.gray100)
- .onTapGesture {
- withAnimation {
- detailIsOpen.toggle()
- }
- }
-
- if detailIsOpen {
- VStack(spacing: 0) {
- VStack(spacing: 30) {
- HStack {
- Text(String(localized: "sip_address") + ":")
- .default_text_style_600(styleSize: 14)
-
- Text(accountProfileViewModel.avatarModel!.address)
- .foregroundStyle(Color.grayMain2c700)
- .default_text_style(styleSize: 14)
- .frame(maxWidth: .infinity, alignment: .leading)
- .lineLimit(1)
-
- Button(action: {
- UIPasteboard.general.setValue(
- accountProfileViewModel.avatarModel!.address,
- forPasteboardType: UTType.plainText.identifier
- )
-
- ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
- ToastViewModel.shared.displayToast.toggle()
- }, label: {
- Image("copy")
- .resizable()
- .frame(width: 20, height: 20)
- })
- }
-
- VStack(alignment: .leading) {
- Text("sip_address_display_name")
- .default_text_style_700(styleSize: 15)
- .padding(.bottom, -5)
- TextField(accountProfileViewModel.displayName, text: $accountProfileViewModel.displayName)
- .default_text_style(styleSize: 15)
- .frame(height: 25)
- .padding(.horizontal, 20)
- .padding(.vertical, 15)
- .background(.white)
- .cornerRadius(60)
- .overlay(
- RoundedRectangle(cornerRadius: 60)
- .inset(by: 0.5)
- .stroke(isDisplayNameFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1)
- )
- .focused($isDisplayNameFocused)
- }
-
- VStack(alignment: .leading) {
- Text("sip_address_display_name")
- .default_text_style_700(styleSize: 15)
- .padding(.bottom, -5)
-
- Menu {
- Picker("", selection: $accountProfileViewModel.dialPlanValueSelected) {
- ForEach(registerViewModel.dialPlansLabelList, id: \.self) { dialPlan in
- Text(dialPlan).tag(dialPlan)
+ .onChange(of: accountProfileViewModel.dialPlanValueSelected) { newValue in
+ accountProfileViewModel.updateDialPlan(newDialPlan: newValue)
}
+ } label: {
+ HStack {
+ Text(accountProfileViewModel.dialPlanValueSelected)
+ .default_text_style(styleSize: 15)
+ .frame(maxWidth: .infinity, alignment: .leading)
+
+ Image("caret-down")
+ .resizable()
+ .frame(width: 20, height: 20)
+ }
+ .frame(height: 25)
+ .padding(.horizontal, 20)
+ .padding(.vertical, 15)
+ .background(.white)
+ .cornerRadius(60)
+ .overlay(
+ RoundedRectangle(cornerRadius: 60)
+ .inset(by: 0.5)
+ .stroke(Color.gray200, lineWidth: 1)
+ )
}
- } label: {
- HStack {
- Text(accountProfileViewModel.dialPlanValueSelected)
- .default_text_style(styleSize: 15)
- .frame(maxWidth: .infinity, alignment: .leading)
-
- Image("caret-down")
- .resizable()
- .frame(width: 20, height: 20)
- }
- .frame(height: 25)
- .padding(.horizontal, 20)
- .padding(.vertical, 15)
- .background(.white)
- .cornerRadius(60)
- .overlay(
- RoundedRectangle(cornerRadius: 60)
- .inset(by: 0.5)
- .stroke(Color.gray200, lineWidth: 1)
- )
}
}
+ .padding(.vertical, 30)
+ .padding(.horizontal, 20)
}
- .padding(.vertical, 30)
- .padding(.horizontal, 20)
+ .background(.white)
+ .cornerRadius(15)
+ .padding(.horizontal)
+ .zIndex(-1)
+ .transition(.move(edge: .top))
}
- .background(.white)
- .cornerRadius(15)
- .padding(.horizontal)
- .zIndex(-1)
- .transition(.move(edge: .top))
}
+ .frame(maxWidth: sharedMainViewModel.maxWidth)
}
- .frame(maxWidth: sharedMainViewModel.maxWidth)
+ .frame(maxWidth: .infinity)
}
- .frame(maxWidth: .infinity)
- .padding(.top, 2)
+ .background(Color.gray100)
}
.background(Color.gray100)
+
+ if self.isShowPopup {
+ PopupView(isShowPopup: $isShowPopup,
+ title: Text("manage_account_international_prefix"),
+ content: Text("manage_account_dialog_international_prefix_help_message"),
+ titleFirstButton: nil,
+ actionFirstButton: {},
+ titleSecondButton: Text("Ok"),
+ actionSecondButton: {
+ self.isShowPopup.toggle()
+ }
+ )
+ .background(.black.opacity(0.65))
+ .onTapGesture {
+ self.isShowPopup.toggle()
+ }
+ }
}
- .background(Color.gray100)
}
func saveImage() {
diff --git a/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift
index 4a21f1c47..e02714a9e 100644
--- a/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift
+++ b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift
@@ -54,11 +54,12 @@ class AccountProfileViewModel: ObservableObject {
}
}
- /*
- newParams?.internationalPrefix = self.dialPlanSelected?.countryCallingCode
- newParams?.internationalPrefixIsoCountryCode = self.dialPlanSelected?.isoCountryCode
- newParams?.useInternationalPrefixForCallsAndChats = true
- */
+ if self.dialPlanSelected != nil
+ && (self.dialPlanSelected!.countryCallingCode != newParams?.internationalPrefix || self.dialPlanSelected!.isoCountryCode != newParams?.internationalPrefixIsoCountryCode) {
+ newParams?.internationalPrefix = self.dialPlanSelected?.countryCallingCode
+ newParams?.internationalPrefixIsoCountryCode = self.dialPlanSelected?.isoCountryCode
+ newParams?.useInternationalPrefixForCallsAndChats = true
+ }
core.defaultAccount!.params = newParams
}
@@ -105,8 +106,11 @@ class AccountProfileViewModel: ObservableObject {
}
}
- func changeDialPlan() {
-
+ func updateDialPlan(newDialPlan: String) {
+ if let dialPlan = self.dialPlansList.first(where: { newDialPlan.contains($0.isoCountryCode) }) ??
+ self.dialPlansList.first(where: { newDialPlan.contains($0.countryCallingCode) }) {
+ self.dialPlanSelected = dialPlan
+ }
}
func saveImage(image: UIImage, name: String, prefix: String) {