diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index a644fb4a2..dc2db14e0 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -3880,6 +3880,74 @@ } } }, + "manage_account_status_cleared_summary" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Account has been disabled, you won't receive any call or message." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Compte désactivé, vous ne recevrez ni appel ni message." + } + } + } + }, + "manage_account_status_connected_summary" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This account in online, everybody can call you." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vous êtes en ligne, on peut vous joindre." + } + } + } + }, + "manage_account_status_failed_summary" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Account connection failed, check your settings." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur de connexion, vérifiez vos paramètres." + } + } + } + }, + "manage_account_status_progress_summary" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Account is connecting to the server, please wait…" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Connexion en cours, merci de patienter…" + } + } + } + }, "manage_account_title" : { "extractionState" : "manual", "localizations" : { diff --git a/Linphone/UI/Main/Fragments/SideMenuAccountRow.swift b/Linphone/UI/Main/Fragments/SideMenuAccountRow.swift index 89c9bd195..a01f86782 100644 --- a/Linphone/UI/Main/Fragments/SideMenuAccountRow.swift +++ b/Linphone/UI/Main/Fragments/SideMenuAccountRow.swift @@ -35,88 +35,90 @@ struct SideMenuAccountRow: View { var body: some View { HStack { - AsyncImage(url: CoreContext.shared.accounts[accountProfileViewModel.accountModelIndex!].imagePathAvatar) { image in - switch image { - case .empty: - ProgressView() - .frame(width: avatarSize, height: avatarSize) - case .success(let image): - image + if accountProfileViewModel.accountModelIndex != nil && CoreContext.shared.accounts.count > accountProfileViewModel.accountModelIndex! { + AsyncImage(url: CoreContext.shared.accounts[accountProfileViewModel.accountModelIndex!].imagePathAvatar) { 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: model.avatarModel?.name ?? "", + lastName: "")) .resizable() - .aspectRatio(contentMode: .fill) .frame(width: avatarSize, height: avatarSize) .clipShape(Circle()) - case .failure: - Image(uiImage: contactsManager.textToImage( - firstName: model.avatarModel?.name ?? "", - lastName: "")) - .resizable() - .frame(width: avatarSize, height: avatarSize) - .clipShape(Circle()) - @unknown default: - EmptyView() + @unknown default: + EmptyView() + } } - } - .padding(.leading, 6) - - VStack { - Text(model.displayName) - .default_text_style_grey_400(styleSize: 14) - .lineLimit(1) - .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 6) VStack { - Text(model.humanReadableRegistrationState) - .default_text_style_uncolored(styleSize: 12) - .foregroundStyle(model.registrationStateAssociatedUIColor) - } - .padding(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) - .background(Color.grayMain2c200) - .cornerRadius(12) - .frame(height: 20) - .frame(maxWidth: .infinity, alignment: .leading) - .onTapGesture { - model.refreshRegiter() - } - } - .padding(.leading, 4) - - Spacer() - - HStack { - if model.notificationsCount > 0 { - Text(String(model.notificationsCount)) - .foregroundStyle(.white) - .default_text_style(styleSize: 12) + Text(model.displayName) + .default_text_style_grey_400(styleSize: 14) .lineLimit(1) - .frame(width: 20, height: 20) - .background(Color.redDanger500) - .cornerRadius(50) .frame(maxWidth: .infinity, alignment: .leading) + + VStack { + Text(model.humanReadableRegistrationState) + .default_text_style_uncolored(styleSize: 12) + .foregroundStyle(model.registrationStateAssociatedUIColor) + } + .padding(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) + .background(Color.grayMain2c200) + .cornerRadius(12) + .frame(height: 20) + .frame(maxWidth: .infinity, alignment: .leading) + .onTapGesture { + model.refreshRegiter() + } } + .padding(.leading, 4) - Menu { - Button { - withAnimation { - - isOpen = false - isShowAccountProfileFragment = true + Spacer() + + HStack { + if model.notificationsCount > 0 { + Text(String(model.notificationsCount)) + .foregroundStyle(.white) + .default_text_style(styleSize: 12) + .lineLimit(1) + .frame(width: 20, height: 20) + .background(Color.redDanger500) + .cornerRadius(50) + .frame(maxWidth: .infinity, alignment: .leading) + } + + Menu { + Button { + withAnimation { + + isOpen = false + isShowAccountProfileFragment = true + } + } label: { + Label("drawer_menu_manage_account", systemImage: "arrow.right.circle") } } label: { - Label("drawer_menu_manage_account", systemImage: "arrow.right.circle") + Image("dots-three-vertical") + .renderingMode(.template) + .resizable() + .foregroundColor(Color.gray) + .scaledToFit() + .frame(height: 30) } - } label: { - Image("dots-three-vertical") - .renderingMode(.template) - .resizable() - .foregroundColor(Color.gray) - .scaledToFit() - .frame(height: 30) } + .frame(width: 64, alignment: .trailing) + .padding(.top, 12) + .padding(.bottom, 12) } - .frame(width: 64, alignment: .trailing) - .padding(.top, 12) - .padding(.bottom, 12) } .frame(height: 61) .background(model.isDefaultAccount ? Color.grayMain2c100 : .clear) diff --git a/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift b/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift index 6c76755f7..1eb0f8d80 100644 --- a/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift +++ b/Linphone/UI/Main/Settings/Fragments/AccountProfileFragment.swift @@ -84,7 +84,7 @@ struct AccountProfileFragment: View { ScrollView { VStack(spacing: 0) { - if accountProfileViewModel.accountModelIndex != nil { + if accountProfileViewModel.accountModelIndex != nil && CoreContext.shared.accounts.count > accountProfileViewModel.accountModelIndex! { let accountModel = CoreContext.shared.accounts[accountProfileViewModel.accountModelIndex!] VStack(spacing: 0) { if #unavailable(iOS 16.0) { @@ -382,8 +382,13 @@ struct AccountProfileFragment: View { VStack(spacing: 0) { VStack(spacing: 15) { HStack(spacing: 20) { - Toggle("", isOn: $flag) - .labelsHidden() + Toggle("", isOn: Binding( + get: { accountModel.isRegistrered }, + set: { newValue in + accountProfileViewModel.toggleRegister() + } + )) + .labelsHidden() Text(accountModel.humanReadableRegistrationState) .default_text_style_700(styleSize: 15) @@ -392,11 +397,10 @@ struct AccountProfileFragment: View { .lineLimit(1) } - Text("manage_account_international_prefix") - .default_text_style_700(styleSize: 15) + Text(accountModel.summary) + .default_text_style(styleSize: 15) .frame(maxWidth: .infinity, alignment: .leading) .padding(.bottom, -5) - .lineLimit(1) } .padding(.vertical, 30) .padding(.horizontal, 20) diff --git a/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift index 501b39f42..71b303f3b 100644 --- a/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift +++ b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift @@ -21,6 +21,8 @@ import linphonesw class AccountProfileViewModel: ObservableObject { + static let TAG = "[AccountProfileViewModel]" + @Published var dialPlanValueSelected: String = "🇫🇷 France | +33" var dialPlanSelected: DialPlan? var dialPlansList: [DialPlan] = [] @@ -78,7 +80,7 @@ class AccountProfileViewModel: ObservableObject { var dialPlanValueSelectedTmp = "" if !prefix.isEmpty || !isoCountryCode.isEmpty { Log.info( - "$TAG Account \(CoreContext.shared.accounts[self.accountModelIndex!].account.params?.identityAddress?.asStringUriOnly() ?? "") prefix is \(prefix) \(isoCountryCode)" + "\(AccountProfileViewModel.TAG) Account \(CoreContext.shared.accounts[self.accountModelIndex!].account.params?.identityAddress?.asStringUriOnly() ?? "") prefix is \(prefix) \(isoCountryCode)" ) self.dialPlansList = Factory.Instance.dialPlans @@ -140,4 +142,19 @@ class AccountProfileViewModel: ObservableObject { return imagePath } + + func toggleRegister() { + CoreContext.shared.doOnCoreQueue { _ in + let account = CoreContext.shared.accounts[self.accountModelIndex ?? 0].account + if let params = account.params { + if let copy = params.clone() { + copy.registerEnabled = !params.registerEnabled + Log.info( + "\(AccountProfileViewModel.TAG) Account registration is now \(copy.registerEnabled ? "enabled" : "disabled") for account \(params.identityAddress?.asStringUriOnly())" + ) + account.params = copy + } + } + } + } } diff --git a/Linphone/UI/Main/Viewmodel/AccountModel.swift b/Linphone/UI/Main/Viewmodel/AccountModel.swift index 9f4cb7cf3..f72e204d6 100644 --- a/Linphone/UI/Main/Viewmodel/AccountModel.swift +++ b/Linphone/UI/Main/Viewmodel/AccountModel.swift @@ -25,7 +25,9 @@ import Combine class AccountModel: ObservableObject { let account: Account @Published var humanReadableRegistrationState: String = "" + @Published var summary: String = "" @Published var registrationStateAssociatedUIColor: Color = .clear + @Published var isRegistrered: Bool = false @Published var notificationsCount: Int = 0 @Published var isDefaultAccount: Bool = false @Published var displayName: String = "" @@ -99,20 +101,27 @@ class AccountModel: ObservableObject { switch state { case .Cleared, .None: humanReadableRegistrationState = "drawer_menu_account_connection_status_cleared".localized() + summary = "manage_account_status_cleared_summary".localized() registrationStateAssociatedUIColor = .orangeWarning600 case .Progress: humanReadableRegistrationState = "drawer_menu_account_connection_status_progress".localized() + summary = "manage_account_status_progress_summary".localized() registrationStateAssociatedUIColor = .greenSuccess500 case .Failed: humanReadableRegistrationState = "drawer_menu_account_connection_status_failed".localized() + summary = "manage_account_status_failed_summary".localized() registrationStateAssociatedUIColor = .redDanger500 case .Ok: humanReadableRegistrationState = "drawer_menu_account_connection_status_connected".localized() + summary = "manage_account_status_connected_summary".localized() registrationStateAssociatedUIColor = .greenSuccess500 case .Refreshing: humanReadableRegistrationState = "drawer_menu_account_connection_status_refreshing".localized() + summary = "manage_account_status_progress_summary".localized() registrationStateAssociatedUIColor = .grayMain2c500 } + + isRegistrered = state == .Ok isDefaultAccount = isDefault self.displayName = displayName address.map {self.address = $0}