Dactyloidae/mobile/ios/Client/Frontend/Settings/AdvanceAccountSettingViewController.swift
2026-06-26 21:04:09 -07:00

183 lines
9 KiB
Swift

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import UIKit
import Shared
import SnapKit
import Foundation
import FxA
import Account
class AdvanceAccountSettingViewController: SettingsTableViewController {
fileprivate let SectionHeaderIdentifier = "SectionHeaderIdentifier"
fileprivate var customSyncUrl: String?
override func viewDidLoad() {
super.viewDidLoad()
title = Strings.SettingsAdvanceAccountSectionName
self.customSyncUrl = self.profile.prefs.stringForKey(PrefsKeys.KeyCustomSyncWeb)
}
func clearCustomAccountPrefs() {
self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncToken)
self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncProfile)
self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncOauth)
self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncAuth)
self.profile.prefs.setString("", forKey: PrefsKeys.KeyCustomSyncWeb)
// To help prevent the account being in a strange state, we force it to
// log out when user clears their custom server preferences.
self.profile.removeAccount()
}
func setCustomAccountPrefs(_ data: Data, url: URL) {
guard let settings = (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)) as? [String:Any],
let customSyncToken = settings["sync_tokenserver_base_url"] as? String,
let customSyncProfile = settings["profile_server_base_url"] as? String,
let customSyncOauth = settings["oauth_server_base_url"] as? String,
let customSyncAuth = settings["auth_server_base_url"] as? String else {
return
}
self.profile.prefs.setBool(true, forKey: PrefsKeys.KeyUseCustomSyncService)
self.profile.prefs.setString(customSyncToken, forKey: PrefsKeys.KeyCustomSyncToken)
self.profile.prefs.setString(customSyncProfile, forKey: PrefsKeys.KeyCustomSyncProfile)
self.profile.prefs.setString(customSyncOauth, forKey: PrefsKeys.KeyCustomSyncOauth)
self.profile.prefs.setString(customSyncAuth, forKey: PrefsKeys.KeyCustomSyncAuth)
self.profile.prefs.setString(url.absoluteString, forKey: PrefsKeys.KeyCustomSyncWeb)
self.profile.removeAccount()
self.displaySuccessAlert()
}
func setCustomAccountPrefs() {
guard let urlString = self.customSyncUrl, let url = URL(string: urlString) else {
// If the user attempts to set a nil url, clear all the custom service perferences
// and use default FxA servers.
self.displayNoServiceSetAlert()
return
}
// FxA stores its server configuation under a well-known path. This attempts to download the configuration
// and save it into the users preferences.
let syncConfigureString = urlString + "/.well-known/fxa-client-configuration"
guard let syncConfigureURL = URL(string: syncConfigureString) else {
return
}
URLSession.shared.dataTask(with: syncConfigureURL, completionHandler: {(data, response, error) in
guard let data = data, error == nil else {
// Something went wrong while downloading or parsing the configuration.
self.displayErrorAlert()
return
}
self.setCustomAccountPrefs(data, url: url)
}).resume()
}
func displaySuccessAlert() {
let alertController = UIAlertController(title: "", message: Strings.SettingsAdvanceAccountUrlUpdatedAlertMessage, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true)
}
func displayErrorAlert() {
self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
DispatchQueue.main.async {
self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
}
let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: Strings.SettingsAdvanceAccountUrlErrorAlertMessage, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlErrorAlertOk, style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true)
}
func displayNoServiceSetAlert() {
self.profile.prefs.setBool(false, forKey: PrefsKeys.KeyUseCustomSyncService)
DispatchQueue.main.async {
self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
}
let alertController = UIAlertController(title: Strings.SettingsAdvanceAccountUrlErrorAlertTitle, message: Strings.SettingsAdvanceAccountEmptyUrlErrorAlertMessage, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: Strings.SettingsAdvanceAccountUrlUpdatedAlertOk, style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true)
}
override func generateSettings() -> [SettingSection] {
let prefs = profile.prefs
let customSyncSetting = CustomSyncWebPageSetting(prefs: prefs,
prefKey: PrefsKeys.KeyCustomSyncWeb,
placeholder: Strings.SettingsAdvanceAccountUrlPlaceholder,
accessibilityIdentifier: "CustomSyncSetting",
settingDidChange: { fieldText in
self.customSyncUrl = fieldText
if let customSyncUrl = self.customSyncUrl, customSyncUrl.isEmpty {
self.clearCustomAccountPrefs()
return
}
})
var basicSettings: [Setting] = []
basicSettings += [
CustomSyncEnableSetting(
prefs: prefs,
settingDidChange: { result in
if result == true {
// Reload the table data to ensure that the updated custom url is set
self.tableView?.reloadData()
self.setCustomAccountPrefs()
}
}),
customSyncSetting
]
let settings: [SettingSection] = [
SettingSection(title: NSAttributedString(string: ""), children: basicSettings),
SettingSection(title: NSAttributedString(string: Strings.SettingsAdvanceAccountSectionFooter), children: [])
]
return settings
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderIdentifier) as! SettingsTableSectionHeaderFooterView
let sectionSetting = settings[section]
headerView.titleLabel.text = sectionSetting.title?.string
switch section {
// Hide the bottom border for the FxA custom server notes.
case 1:
headerView.titleAlignment = .top
headerView.titleLabel.numberOfLines = 0
headerView.showBottomBorder = false
default:
return super.tableView(tableView, viewForHeaderInSection: section)
}
return headerView
}
}
class CustomSyncEnableSetting: BoolSetting {
init(prefs: Prefs, settingDidChange: ((Bool?) -> Void)? = nil) {
super.init(
prefs: prefs, prefKey: PrefsKeys.KeyUseCustomSyncService, defaultValue: false,
attributedTitleText: NSAttributedString(string: Strings.SettingsAdvanceAccountUseCustomAccountsServiceTitle),
settingDidChange: settingDidChange
)
}
}
class CustomSyncWebPageSetting: WebPageSetting {
override init(prefs: Prefs, prefKey: String, defaultValue: String? = nil, placeholder: String, accessibilityIdentifier: String, settingDidChange: ((String?) -> Void)? = nil) {
super.init(prefs: prefs,
prefKey: prefKey,
defaultValue: defaultValue,
placeholder: placeholder,
accessibilityIdentifier: accessibilityIdentifier,
settingDidChange: settingDidChange)
textField.clearButtonMode = UITextFieldViewMode.always
}
}