UserProfileTableViewController+Utils.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. //
  2. // SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. import Foundation
  6. extension UserProfileTableViewController {
  7. // MARK: - User Profile
  8. func getUserProfileEditableFields() {
  9. editButton.isEnabled = false
  10. NCAPIController.sharedInstance().getUserProfileEditableFields(for: account) { userProfileEditableFields, error in
  11. if error == nil {
  12. if let userProfileEditableFields = userProfileEditableFields as NSArray? {
  13. self.editableFields = userProfileEditableFields
  14. self.editButton.isEnabled = true
  15. }
  16. }
  17. }
  18. }
  19. func refreshUserProfile() {
  20. NCSettingsController.sharedInstance().getUserProfile(forAccountId: account.accountId) { _ in
  21. self.account = NCDatabaseManager.sharedInstance().activeAccount()
  22. self.refreshProfileTableView()
  23. }
  24. }
  25. // MARK: - Notifications
  26. @objc func userProfileImageUpdated(notification: NSNotification) {
  27. self.account = NCDatabaseManager.sharedInstance().activeAccount()
  28. self.refreshProfileTableView()
  29. }
  30. // MARK: - Sections
  31. func getProfileSections() -> [Int] {
  32. var sections: [Int] = []
  33. if isEditable {
  34. sections.append(ProfileSection.kProfileSectionName.rawValue)
  35. sections.append(ProfileSection.kProfileSectionEmail.rawValue)
  36. sections.append(ProfileSection.kProfileSectionPhoneNumber.rawValue)
  37. sections.append(ProfileSection.kProfileSectionAddress.rawValue)
  38. sections.append(ProfileSection.kProfileSectionWebsite.rawValue)
  39. sections.append(ProfileSection.kProfileSectionTwitter.rawValue)
  40. } else if !(self.rowsInSummarySection().isEmpty) {
  41. sections.append(ProfileSection.kProfileSectionSummary.rawValue)
  42. }
  43. sections.append(ProfileSection.kProfileSectionRemoveAccount.rawValue)
  44. return sections
  45. }
  46. func rowsInSummarySection() -> [Int] {
  47. var rows = [Int]()
  48. if !account.email.isEmpty {
  49. rows.append(SummaryRow.kSummaryRowEmail.rawValue)
  50. }
  51. if !account.phone.isEmpty {
  52. rows.append(SummaryRow.kSummaryRowPhoneNumber.rawValue)
  53. }
  54. if !account.address.isEmpty {
  55. rows.append(SummaryRow.kSummaryRowAddress.rawValue)
  56. }
  57. if !account.website.isEmpty {
  58. rows.append(SummaryRow.kSummaryRowWebsite.rawValue)
  59. }
  60. if !account.twitter.isEmpty {
  61. rows.append(SummaryRow.kSummaryRowTwitter.rawValue)
  62. }
  63. return rows
  64. }
  65. // MARK: - User Interface
  66. func showEditButton() {
  67. self.editButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.edit, target: self, action: #selector(editButtonPressed))
  68. self.editButton.accessibilityHint = NSLocalizedString("Double tap to edit profile", comment: "")
  69. self.navigationItem.rightBarButtonItem = editButton
  70. }
  71. func showDoneButton() {
  72. self.editButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(editButtonPressed))
  73. self.editButton.accessibilityHint = NSLocalizedString("Double tap to end editing profile", comment: "")
  74. self.navigationItem.rightBarButtonItem = editButton
  75. }
  76. func setModifyingProfileUI() {
  77. modifyingProfileView.startAnimating()
  78. self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: modifyingProfileView)
  79. self.tableView.isUserInteractionEnabled = false
  80. }
  81. func removeModifyingProfileUI() {
  82. modifyingProfileView.stopAnimating()
  83. if isEditable {
  84. self.showDoneButton()
  85. } else {
  86. self.showEditButton()
  87. }
  88. self.tableView.isUserInteractionEnabled = true
  89. }
  90. func refreshProfileTableView() {
  91. tableView.tableHeaderView = self.avatarHeaderView()
  92. tableView.tableHeaderView?.setNeedsDisplay()
  93. tableView.reloadData()
  94. }
  95. func showProfileModificationErrorForField(inTextField field: Int, textField: UITextField?) {
  96. var errorDescription = ""
  97. // The textfield pointer might be pointing to a different textfield at this point because
  98. // if the user tapped the "Done" button in navigation bar (so the non-editable view is visible)
  99. // That's the reason why we check the field instead of textfield.tag
  100. switch field {
  101. case kNameTextFieldTag:
  102. errorDescription = NSLocalizedString("An error occurred setting user name", comment: "")
  103. case kEmailTextFieldTag:
  104. errorDescription = NSLocalizedString("An error occurred setting email address", comment: "")
  105. case kPhoneTextFieldTag:
  106. errorDescription = NSLocalizedString("An error occurred setting phone number", comment: "")
  107. case kAddressTextFieldTag:
  108. errorDescription = NSLocalizedString("An error occurred setting address", comment: "")
  109. case kWebsiteTextFieldTag:
  110. errorDescription = NSLocalizedString("An error occurred setting website", comment: "")
  111. case kTwitterTextFieldTag:
  112. errorDescription = NSLocalizedString("An error occurred setting Twitter account", comment: "")
  113. default:
  114. break
  115. }
  116. let errorDialog = UIAlertController(title: errorDescription, message: nil, preferredStyle: .alert)
  117. let okAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default) { _ in
  118. if self.isEditable {
  119. textField?.becomeFirstResponder()
  120. }
  121. }
  122. errorDialog.addAction(okAction)
  123. self.present(errorDialog, animated: true, completion: nil)
  124. }
  125. func imageForScope(scope: String) -> UIImage? {
  126. if scope == kUserProfileScopePrivate {
  127. return UIImage(systemName: "iphone")
  128. } else if scope == kUserProfileScopeLocal {
  129. return UIImage(systemName: "lock")
  130. } else if scope == kUserProfileScopeFederated {
  131. return UIImage(systemName: "person.2")
  132. } else if scope == kUserProfileScopePublished {
  133. return UIImage(systemName: "network")
  134. }
  135. return nil
  136. }
  137. @objc func showScopeSelectionDialog( _ sender: UIButton?) {
  138. guard let sender = sender else {
  139. return
  140. }
  141. let field: String
  142. let currentValue: String
  143. let title: String
  144. if sender.tag == kNameTextFieldTag {
  145. field = kUserProfileDisplayNameScope
  146. currentValue = account.userDisplayNameScope
  147. title = NSLocalizedString("Full name", comment: "")
  148. } else if sender.tag == kEmailTextFieldTag {
  149. field = kUserProfileEmailScope
  150. currentValue = account.emailScope
  151. title = NSLocalizedString("Email", comment: "")
  152. } else if sender.tag == kPhoneTextFieldTag {
  153. field = kUserProfilePhoneScope
  154. currentValue = account.phoneScope
  155. title = NSLocalizedString("Phone number", comment: "")
  156. } else if sender.tag == kAddressTextFieldTag {
  157. field = kUserProfileAddressScope
  158. currentValue = account.addressScope
  159. title = NSLocalizedString("Address", comment: "")
  160. } else if sender.tag == kWebsiteTextFieldTag {
  161. field = kUserProfileWebsiteScope
  162. currentValue = account.websiteScope
  163. title = NSLocalizedString("Website", comment: "")
  164. } else if sender.tag == kTwitterTextFieldTag {
  165. field = kUserProfileTwitterScope
  166. currentValue = account.twitterScope
  167. title = NSLocalizedString("Twitter", comment: "")
  168. } else if sender.tag == kAvatarScopeButtonTag {
  169. field = kUserProfileAvatarScope
  170. currentValue = account.avatarScope
  171. title = NSLocalizedString("Profile picture", comment: "")
  172. } else {
  173. return
  174. }
  175. presentScopeSelector(field: field, currentValue: currentValue, title: title)
  176. }
  177. func presentScopeSelector(field: String, currentValue: String, title: String) {
  178. var options = [DetailedOption]()
  179. let privateOption = setupDetailedOption(identifier: kUserProfileScopePrivate,
  180. image: UIImage(systemName: "iphone")?.applyingSymbolConfiguration(iconConfiguration),
  181. title: NSLocalizedString("Private", comment: ""),
  182. subtitle: NSLocalizedString("Only visible to people matched via phone number integration", comment: ""),
  183. selected: currentValue == kUserProfileScopePrivate)
  184. let localOption = setupDetailedOption(identifier: kUserProfileScopeLocal,
  185. image: UIImage(systemName: "lock")?.applyingSymbolConfiguration(iconConfiguration),
  186. title: NSLocalizedString("Local", comment: ""),
  187. subtitle: NSLocalizedString("Only visible to people on this instance and guests", comment: ""),
  188. selected: currentValue == kUserProfileScopeLocal)
  189. let federatedOption = setupDetailedOption(identifier: kUserProfileScopeFederated,
  190. image: UIImage(systemName: "person.2")?.applyingSymbolConfiguration(iconConfiguration),
  191. title: NSLocalizedString("Federated", comment: ""),
  192. subtitle: NSLocalizedString("Only synchronize to trusted servers", comment: ""),
  193. selected: currentValue == kUserProfileScopeFederated)
  194. let publishedOption = setupDetailedOption(identifier: kUserProfileScopePublished,
  195. image: UIImage(systemName: "network")?.applyingSymbolConfiguration(iconConfiguration),
  196. title: NSLocalizedString("Published", comment: ""),
  197. subtitle: NSLocalizedString("Synchronize to trusted servers and the global and public address book", comment: ""),
  198. selected: currentValue == kUserProfileScopePublished)
  199. if field != kUserProfileDisplayNameScope && field != kUserProfileEmailScope {
  200. options.append(privateOption)
  201. }
  202. options.append(localOption)
  203. if let serverCapabilities = NCDatabaseManager.sharedInstance().serverCapabilities(forAccountId: account.accountId) {
  204. // Legacy capability
  205. if serverCapabilities.accountPropertyScopesFederationEnabled {
  206. options.append(federatedOption)
  207. options.append(publishedOption)
  208. }
  209. if serverCapabilities.accountPropertyScopesFederatedEnabled {
  210. options.append(federatedOption)
  211. }
  212. if serverCapabilities.accountPropertyScopesPublishedEnabled {
  213. options.append(publishedOption)
  214. }
  215. }
  216. let optionSelectorVC = DetailedOptionsSelectorTableViewController(options: options, forSenderIdentifier: field, andStyle: .insetGrouped)
  217. if let optionSelectorVC = optionSelectorVC {
  218. optionSelectorVC.title = title
  219. optionSelectorVC.delegate = self
  220. let optionSelectorNC = UINavigationController(rootViewController: optionSelectorVC)
  221. self.present(optionSelectorNC, animated: true, completion: nil)
  222. }
  223. }
  224. func setUserProfileField(_ field: String?, scopeValue scope: String?) {
  225. setModifyingProfileUI()
  226. NCAPIController.sharedInstance().setUserProfileField(field, withValue: scope, for: account) { [self] error, _ in
  227. if error != nil {
  228. showScopeModificationError()
  229. } else {
  230. refreshUserProfile()
  231. }
  232. removeModifyingProfileUI()
  233. }
  234. }
  235. func showScopeModificationError() {
  236. let errorDialog = UIAlertController(title: NSLocalizedString("An error occurred changing privacy setting", comment: ""), message: nil, preferredStyle: .alert)
  237. let okAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)
  238. errorDialog.addAction(okAction)
  239. self.present(errorDialog, animated: true, completion: nil)
  240. }
  241. // Setup Dialog Options
  242. func setupDetailedOption(identifier: String, image: UIImage?, title: String, subtitle: String, selected: Bool) -> DetailedOption {
  243. let detailedOption = DetailedOption()
  244. detailedOption.identifier = identifier
  245. detailedOption.image = image
  246. detailedOption.title = title
  247. detailedOption.subtitle = subtitle
  248. detailedOption.selected = selected
  249. return detailedOption
  250. }
  251. }