SettingsController.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. //
  2. // SettingsController.swift
  3. // deltachat-ios
  4. //
  5. // Created by Friedel Ziegelmayer on 26.12.18.
  6. // Copyright © 2018 Jonas Reinsch. All rights reserved.
  7. //
  8. import UIKit
  9. import MessageKit
  10. import MessageInputBar
  11. import QuickTableViewController
  12. import JGProgressHUD
  13. final internal class SettingsViewController: QuickTableViewController {
  14. let documentInteractionController = UIDocumentInteractionController()
  15. var backupProgressObserver: Any?
  16. var backupHud: JGProgressHUD?
  17. // MARK: - Properties
  18. override var preferredStatusBarStyle: UIStatusBarStyle {
  19. return .lightContent
  20. }
  21. // MARK: - View lifecycle
  22. override func viewDidLoad() {
  23. super.viewDidLoad()
  24. title = "Settings"
  25. documentInteractionController.delegate = self as? UIDocumentInteractionControllerDelegate
  26. setTable()
  27. }
  28. override func viewDidAppear(_ animated: Bool) {
  29. super.viewDidAppear(animated)
  30. let nc = NotificationCenter.default
  31. backupProgressObserver = nc.addObserver(
  32. forName: dc_notificationBackupProgress,
  33. object: nil,
  34. queue: nil) {
  35. notification in
  36. if let ui = notification.userInfo {
  37. if ui["error"] as! Bool {
  38. self.setHudError()
  39. } else if ui["done"] as! Bool {
  40. self.setHudDone()
  41. } else {
  42. self.setHudProgress(ui["progress"] as! Int)
  43. }
  44. }
  45. }
  46. }
  47. private func setHudError() {
  48. if let hud = self.backupHud {
  49. DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
  50. UIView.animate(withDuration: 0.1, animations: {
  51. hud.textLabel.text = "Error"
  52. hud.detailTextLabel.text = nil
  53. hud.indicatorView = JGProgressHUDErrorIndicatorView()
  54. })
  55. hud.dismiss(afterDelay: 1.0)
  56. }
  57. }
  58. }
  59. private func setHudDone() {
  60. if let hud = self.backupHud {
  61. DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
  62. UIView.animate(withDuration: 0.1, animations: {
  63. hud.textLabel.text = "Success"
  64. hud.detailTextLabel.text = nil
  65. hud.indicatorView = JGProgressHUDSuccessIndicatorView()
  66. })
  67. hud.dismiss(afterDelay: 1.0)
  68. }
  69. }
  70. }
  71. private func setHudProgress(_ progress: Int) {
  72. if let hud = self.backupHud {
  73. hud.progress = Float(progress)/1000.0
  74. hud.detailTextLabel.text = "\(progress/10)% Complete"
  75. }
  76. }
  77. private func showBackupHud() {
  78. let hud = JGProgressHUD(style: .dark)
  79. hud.vibrancyEnabled = true
  80. hud.indicatorView = JGProgressHUDPieIndicatorView()
  81. hud.detailTextLabel.text = "0% Complete"
  82. hud.textLabel.text = "Creating Backup"
  83. hud.show(in: self.view)
  84. backupHud = hud
  85. }
  86. override func viewDidDisappear(_ animated: Bool) {
  87. super.viewDidDisappear(animated)
  88. let nc = NotificationCenter.default
  89. if let backupProgressObserver = self.backupProgressObserver {
  90. nc.removeObserver(backupProgressObserver)
  91. }
  92. }
  93. private func setTable() {
  94. tableContents = [
  95. Section(
  96. title: "Basics",
  97. rows: [
  98. NavigationRow(title: "Email", subtitle: .rightAligned(MRConfig.addr ?? ""), action: editCell()),
  99. NavigationRow(title: "Password", subtitle: .rightAligned("********"), action: editCell()),
  100. ]),
  101. Section(
  102. title: "User Details",
  103. rows: [
  104. NavigationRow(title: "Display Name", subtitle: .rightAligned(MRConfig.displayname ?? ""), action: editCell()),
  105. NavigationRow(title: "Status", subtitle: .rightAligned(MRConfig.selfstatus ?? ""), action: editCell()),
  106. ]),
  107. Section(
  108. title: "Advanced",
  109. rows: [
  110. NavigationRow(title: "IMAP Server", subtitle: .rightAligned(MRConfig.mailServer ?? ""), action: editCell()),
  111. NavigationRow(title: "IMAP User", subtitle: .rightAligned(MRConfig.mailUser ?? ""), action: editCell()),
  112. NavigationRow(title: "IMAP Port", subtitle: .rightAligned(MRConfig.mailPort ?? ""), action: editCell()),
  113. NavigationRow(title: "SMTP Server", subtitle: .rightAligned(MRConfig.sendServer ?? ""), action: editCell()),
  114. NavigationRow(title: "SMTP User", subtitle: .rightAligned(MRConfig.sendUser ?? ""), action: editCell()),
  115. NavigationRow(title: "SMTP Port", subtitle: .rightAligned(MRConfig.sendPort ?? ""), action: editCell()),
  116. NavigationRow(title: "SMTP Password", subtitle: .rightAligned("********"), action: editCell()),
  117. ]),
  118. Section(
  119. title: "Flags",
  120. rows: [
  121. SwitchRow(title: "E2EE enabled", switchValue: MRConfig.e2eeEnabled, action: editCell()),
  122. SwitchRow(title: "MDNS enabled", switchValue: MRConfig.mdnsEnabled, action: editCell()),
  123. SwitchRow(title: "Watch Inbox", switchValue: MRConfig.inboxWatch, action: editCell()),
  124. SwitchRow(title: "Watch Sentbox", switchValue: MRConfig.sentboxWatch, action: editCell()),
  125. SwitchRow(title: "Watch Mvbox", switchValue: MRConfig.mvboxWatch, action: editCell()),
  126. SwitchRow(title: "Move to Mvbox", switchValue: MRConfig.mvboxMove, action: editCell()),
  127. SwitchRow(title: "Save Mime Headers", switchValue: MRConfig.saveMimeHeaders, action: editCell()),
  128. ]),
  129. Section(
  130. title: "Backups",
  131. rows: [
  132. TapActionRow(title: "Create backup", action: { [weak self] in self?.createBackup($0) }),
  133. TapActionRow(title: "Restore from backup", action: { [weak self] in self?.restoreBackup($0) })
  134. ]),
  135. ]
  136. }
  137. // MARK: - Actions
  138. private func editCell() -> (Row) -> Void {
  139. return { [weak self] sender in
  140. print("row edit", sender.title)
  141. let title = sender.title
  142. let subtitle: String = sender.subtitle?.text ?? ""
  143. let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
  144. if let sender = sender as? SwitchRow {
  145. print("got bool switch")
  146. let value = sender.switchValue
  147. switch title {
  148. case "E2EE enabled":
  149. MRConfig.e2eeEnabled = value
  150. case "MDNS enabled":
  151. MRConfig.mdnsEnabled = value
  152. case "Watch Inbox":
  153. MRConfig.inboxWatch = value
  154. case "Watch Sentbox":
  155. MRConfig.sentboxWatch = value
  156. case "Watch Mvbox":
  157. MRConfig.mvboxWatch = value
  158. case "Move to Mvbox":
  159. MRConfig.mvboxMove = value
  160. case "Save Mime Headers":
  161. MRConfig.saveMimeHeaders = value
  162. default:
  163. print("unknown title", title)
  164. }
  165. return
  166. }
  167. let confirmAction = UIAlertAction(title: "Save", style: .default) { (_) in
  168. guard let textFields = alertController.textFields,
  169. textFields.count > 0 else {
  170. // Could not find textfield
  171. return
  172. }
  173. let field = textFields[0]
  174. // TODO: add field validation
  175. var needRefresh = false
  176. switch title {
  177. case "Email":
  178. MRConfig.addr = field.text
  179. needRefresh = true
  180. case "Password":
  181. MRConfig.mailPw = field.text
  182. case "Display Name":
  183. MRConfig.displayname = field.text
  184. needRefresh = true
  185. case "Status":
  186. MRConfig.selfstatus = field.text
  187. needRefresh = true
  188. case "IMAP Server":
  189. MRConfig.mailServer = field.text
  190. needRefresh = true
  191. case "IMAP User":
  192. MRConfig.mailUser = field.text
  193. needRefresh = true
  194. case "IMAP Port":
  195. MRConfig.mailPort = field.text
  196. needRefresh = true
  197. case "SMTP Server":
  198. MRConfig.sendServer = field.text
  199. needRefresh = true
  200. case "SMTP User":
  201. MRConfig.sendUser = field.text
  202. needRefresh = true
  203. case "SMTP Port":
  204. MRConfig.sendPort = field.text
  205. needRefresh = true
  206. case "SMTP Password":
  207. MRConfig.sendPw = field.text
  208. default:
  209. print("unknown title", title)
  210. }
  211. if needRefresh {
  212. self?.setTable()
  213. self?.tableView.reloadData()
  214. }
  215. }
  216. let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in
  217. print("canceled")
  218. }
  219. alertController.addTextField { (textField) in
  220. textField.placeholder = subtitle
  221. }
  222. alertController.addAction(confirmAction)
  223. alertController.addAction(cancelAction)
  224. self?.present(alertController, animated: true, completion: nil)
  225. }
  226. }
  227. private func createBackup(_ sender: Row) {
  228. if let documents = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.delta.chat.ios")?.path {
  229. print("create backup in", documents)
  230. dc_imex(mailboxPointer, DC_IMEX_EXPORT_BACKUP, documents, nil)
  231. showBackupHud()
  232. }
  233. }
  234. private func restoreBackup(_ sender: Row) {
  235. if let documents = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.delta.chat.ios")?.path {
  236. print("looking for backup in", documents)
  237. if let file = dc_imex_has_backup(mailboxPointer, documents) {
  238. // Close as we are resetting the world
  239. dc_close(mailboxPointer)
  240. mailboxPointer = dc_context_new(callback_ios, nil, "iOS")
  241. guard mailboxPointer != nil else {
  242. fatalError("Error: dc_context_new returned nil")
  243. }
  244. let hud = JGProgressHUD(style: .dark)
  245. hud.textLabel.text = "Restoring Backup"
  246. hud.show(in: self.view)
  247. dc_imex(mailboxPointer, DC_IMEX_IMPORT_BACKUP, file, nil)
  248. hud.dismiss(afterDelay: 1.0)
  249. } else {
  250. let alert = UIAlertController(title: "Can not restore", message: "No Backup found", preferredStyle: .alert)
  251. self.present(alert, animated: true, completion: nil)
  252. }
  253. }
  254. }
  255. }