PollCreationViewController.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //
  2. // SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. import UIKit
  6. @objc protocol PollCreationViewControllerDelegate {
  7. func pollCreationViewControllerWantsToCreatePoll(pollCreationViewController: PollCreationViewController, question: String, options: [String], resultMode: NCPollResultMode, maxVotes: Int)
  8. }
  9. @objcMembers class PollCreationViewController: UITableViewController, UITextFieldDelegate {
  10. enum PollCreationSection: Int {
  11. case kPollCreationSectionQuestion = 0
  12. case kPollCreationSectionOptions
  13. case kPollCreationSectionSettings
  14. case kPollCreationSectionCount
  15. }
  16. enum PollSetting: Int {
  17. case kPollSettingPrivate = 0
  18. case kPollSettingMultiple
  19. case kPollSettingCount
  20. }
  21. let kQuestionTextFieldTag = 9999
  22. public weak var pollCreationDelegate: PollCreationViewControllerDelegate?
  23. var question: String = ""
  24. var options: [String] = ["", ""]
  25. var privateSwitch = UISwitch()
  26. var multipleSwitch = UISwitch()
  27. let footerView = PollFooterView(frame: CGRect.zero)
  28. required init?(coder aDecoder: NSCoder) {
  29. super.init(coder: aDecoder)
  30. self.initPollCreationView()
  31. }
  32. required override init(style: UITableView.Style) {
  33. super.init(style: style)
  34. self.initPollCreationView()
  35. }
  36. override func viewDidLoad() {
  37. super.viewDidLoad()
  38. self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: NCAppBranding.themeTextColor()]
  39. self.navigationController?.navigationBar.tintColor = NCAppBranding.themeTextColor()
  40. self.navigationController?.navigationBar.barTintColor = NCAppBranding.themeColor()
  41. self.navigationController?.navigationBar.isTranslucent = false
  42. self.navigationItem.title = NSLocalizedString("New poll", comment: "")
  43. let appearance = UINavigationBarAppearance()
  44. appearance.configureWithOpaqueBackground()
  45. appearance.titleTextAttributes = [.foregroundColor: NCAppBranding.themeTextColor()]
  46. appearance.backgroundColor = NCAppBranding.themeColor()
  47. self.navigationItem.standardAppearance = appearance
  48. self.navigationItem.compactAppearance = appearance
  49. self.navigationItem.scrollEdgeAppearance = appearance
  50. self.tableView.isEditing = true
  51. // Set footer buttons
  52. self.tableView.tableFooterView = pollFooterView()
  53. self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(self.cancelButtonPressed))
  54. self.navigationItem.leftBarButtonItem?.tintColor = NCAppBranding.themeTextColor()
  55. }
  56. override func viewDidAppear(_ animated: Bool) {
  57. if let questionCell = self.tableView.cellForRow(at: IndexPath(row: 0, section: PollCreationSection.kPollCreationSectionQuestion.rawValue)) as? TextInputTableViewCell {
  58. questionCell.textField.becomeFirstResponder()
  59. }
  60. }
  61. func cancelButtonPressed() {
  62. close()
  63. }
  64. func close() {
  65. self.dismiss(animated: true, completion: nil)
  66. }
  67. func showCreationError() {
  68. let alert = UIAlertController(title: NSLocalizedString("Creating poll failed", comment: ""),
  69. message: NSLocalizedString("An error occurred while creating the poll", comment: ""),
  70. preferredStyle: .alert)
  71. alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
  72. self.present(alert, animated: true)
  73. footerView.primaryButton.setButtonEnabled(enabled: true)
  74. }
  75. func pollFooterView() -> UIView {
  76. footerView.primaryButton.setTitle(NSLocalizedString("Create poll", comment: ""), for: .normal)
  77. footerView.primaryButton.setButtonAction(target: self, selector: #selector(createPollButtonPressed))
  78. footerView.frame = CGRect(x: 0, y: 0, width: 0, height: PollFooterView.heightForOption)
  79. footerView.secondaryButtonContainerView.isHidden = true
  80. checkIfPollIsReadyToCreate()
  81. return footerView
  82. }
  83. func createPollButtonPressed() {
  84. let resultMode: NCPollResultMode = privateSwitch.isOn ? .hidden : .public
  85. let maxVotes: Int = multipleSwitch.isOn ? 0 : 1
  86. footerView.primaryButton.setButtonEnabled(enabled: false)
  87. self.pollCreationDelegate?.pollCreationViewControllerWantsToCreatePoll(pollCreationViewController: self, question: question, options: options, resultMode: resultMode, maxVotes: maxVotes)
  88. }
  89. func checkIfPollIsReadyToCreate() {
  90. footerView.primaryButton.setButtonEnabled(enabled: false)
  91. if !question.isEmpty && options.filter({!$0.isEmpty}).count >= 2 {
  92. footerView.primaryButton.setButtonEnabled(enabled: true)
  93. }
  94. }
  95. func initPollCreationView() {
  96. self.tableView.dataSource = self
  97. self.tableView.delegate = self
  98. self.tableView.keyboardDismissMode = UIScrollView.KeyboardDismissMode.onDrag
  99. self.tableView.register(UINib(nibName: kTextInputTableViewCellNibName, bundle: nil), forCellReuseIdentifier: kTextInputCellIdentifier)
  100. }
  101. // MARK: - Table view data source
  102. override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
  103. if indexPath.section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  104. return true
  105. }
  106. return false
  107. }
  108. override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
  109. if indexPath.section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  110. if indexPath.row == options.count {
  111. return .insert
  112. }
  113. if indexPath.row > 1 || options.count > 2 {
  114. return .delete
  115. }
  116. }
  117. return .none
  118. }
  119. override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
  120. if indexPath.section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  121. if indexPath.row == options.count {
  122. options.insert("", at: indexPath.row)
  123. tableView.beginUpdates()
  124. tableView.insertRows(at: [indexPath], with: .automatic)
  125. tableView.endUpdates()
  126. if let optionCell = self.tableView.cellForRow(at: indexPath) as? TextInputTableViewCell {
  127. optionCell.textField.becomeFirstResponder()
  128. }
  129. } else {
  130. options.remove(at: indexPath.row)
  131. self.tableView.reloadSections([PollCreationSection.kPollCreationSectionOptions.rawValue], with: .automatic)
  132. }
  133. checkIfPollIsReadyToCreate()
  134. }
  135. }
  136. override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
  137. return false
  138. }
  139. override func numberOfSections(in tableView: UITableView) -> Int {
  140. return PollCreationSection.kPollCreationSectionCount.rawValue
  141. }
  142. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  143. if section == PollCreationSection.kPollCreationSectionQuestion.rawValue {
  144. return 1
  145. } else if section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  146. return options.count + 1
  147. } else if section == PollCreationSection.kPollCreationSectionSettings.rawValue {
  148. return PollSetting.kPollSettingCount.rawValue
  149. }
  150. return 0
  151. }
  152. override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
  153. if section == PollCreationSection.kPollCreationSectionQuestion.rawValue {
  154. return NSLocalizedString("Question", comment: "")
  155. } else if section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  156. return NSLocalizedString("Answers", comment: "")
  157. } else if section == PollCreationSection.kPollCreationSectionSettings.rawValue {
  158. return NSLocalizedString("Settings", comment: "")
  159. }
  160. return nil
  161. }
  162. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  163. let textInputCell = tableView.dequeueReusableCell(withIdentifier: kTextInputCellIdentifier) as? TextInputTableViewCell ??
  164. TextInputTableViewCell(style: .default, reuseIdentifier: kTextInputCellIdentifier)
  165. textInputCell.textField.delegate = self
  166. textInputCell.textField.autocapitalizationType = .sentences
  167. let actionCell = tableView.dequeueReusableCell(withIdentifier: "PollSettingCellIdentifier") ?? UITableViewCell(style: .default, reuseIdentifier: "PollSettingCellIdentifier")
  168. if indexPath.section == PollCreationSection.kPollCreationSectionQuestion.rawValue {
  169. textInputCell.textField.placeholder = NSLocalizedString("Ask a question", comment: "")
  170. textInputCell.textField.tag = kQuestionTextFieldTag
  171. textInputCell.textField.text = question
  172. return textInputCell
  173. } else if indexPath.section == PollCreationSection.kPollCreationSectionOptions.rawValue {
  174. if indexPath.row == options.count {
  175. actionCell.textLabel?.text = NSLocalizedString("Add answer", comment: "")
  176. return actionCell
  177. } else if indexPath.row < options.count {
  178. textInputCell.textField.placeholder = NSLocalizedString("Answer", comment: "") + " " + String(indexPath.row + 1)
  179. textInputCell.textField.tag = indexPath.row
  180. textInputCell.textField.text = options[indexPath.row]
  181. return textInputCell
  182. }
  183. } else if indexPath.section == PollCreationSection.kPollCreationSectionSettings.rawValue {
  184. if indexPath.row == PollSetting.kPollSettingPrivate.rawValue {
  185. actionCell.textLabel?.text = NSLocalizedString("Private poll", comment: "")
  186. actionCell.accessoryView = privateSwitch
  187. return actionCell
  188. } else if indexPath.row == PollSetting.kPollSettingMultiple.rawValue {
  189. actionCell.textLabel?.text = NSLocalizedString("Multiple answers", comment: "")
  190. actionCell.accessoryView = multipleSwitch
  191. return actionCell
  192. }
  193. return actionCell
  194. }
  195. return actionCell
  196. }
  197. override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  198. tableView.deselectRow(at: indexPath, animated: true)
  199. }
  200. // MARK: - UITextField delegate
  201. func textFieldDidEndEditing(_ textField: UITextField) {
  202. let value = textField.text!.trimmingCharacters(in: CharacterSet.whitespaces)
  203. textField.text = value
  204. setValueFromTextField(textField: textField, value: value)
  205. }
  206. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  207. let value = (textField.text as NSString?)?.replacingCharacters(in: range, with: string).trimmingCharacters(in: CharacterSet.whitespaces)
  208. setValueFromTextField(textField: textField, value: value ?? "")
  209. return true
  210. }
  211. func textFieldShouldClear(_ textField: UITextField) -> Bool {
  212. setValueFromTextField(textField: textField, value: "")
  213. return true
  214. }
  215. func setValueFromTextField(textField: UITextField, value: String) {
  216. if textField.tag == kQuestionTextFieldTag {
  217. question = value
  218. } else if textField.tag < options.count {
  219. options[textField.tag] = value
  220. }
  221. checkIfPollIsReadyToCreate()
  222. }
  223. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  224. textField.resignFirstResponder()
  225. return true
  226. }
  227. }