[ABANDONED] Mastodon iOS client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
6.1 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. //
  2. // ComposeViewController.swift
  3. // elpha-ios
  4. //
  5. // Created by Dwayne Harris on 11/12/18.
  6. // Copyright © 2018 Elpha. All rights reserved.
  7. //
  8. import Kingfisher
  9. import UIKit
  10. class ComposeViewController: UIViewController {
  11. @IBOutlet var replyToView: UIView!
  12. @IBOutlet var replyToAvatarImageView: UIImageView!
  13. @IBOutlet var replyToDisplayNameLabel: UILabel!
  14. @IBOutlet var replyToUsernameLabel: UILabel!
  15. @IBOutlet var replyToContentTextView: UITextViewFixed!
  16. @IBOutlet var statusTextView: UITextView!
  17. @IBOutlet var statusCharacterCountLabel: UILabel!
  18. @IBOutlet var contentWarningTextField: UITextField!
  19. @IBOutlet var bottomConstraint: NSLayoutConstraint!
  20. let characterLimit = 500
  21. let composeAccessoryViewHeight: CGFloat = 55.0
  22. var feedbackGenerator: UINotificationFeedbackGenerator?
  23. var replyToStatus: StatusMO?
  24. var composeAccessoryView: ComposeAccessoryView?
  25. var selectedVisibility: StatusVisibility = .public
  26. var attachmentInputView: AttachmentInputView?
  27. var visibilityInputView: VisibilityInputView?
  28. override func viewDidLoad() {
  29. super.viewDidLoad()
  30. feedbackGenerator = UINotificationFeedbackGenerator()
  31. statusTextView.layer.cornerRadius = 10
  32. statusTextView.layer.masksToBounds = true
  33. statusTextView.textContainerInset = UIEdgeInsets(top: 10, left: 5, bottom: 10, right: 5)
  34. replyToAvatarImageView.setRoundedCorners()
  35. composeAccessoryView = ComposeAccessoryView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: composeAccessoryViewHeight))
  36. composeAccessoryView!.delegate = self
  37. composeAccessoryView!.selectedVisibility = selectedVisibility
  38. visibilityInputView = VisibilityInputView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 250))
  39. visibilityInputView!.delegate = self
  40. attachmentInputView = AttachmentInputView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 400))
  41. statusTextView.delegate = self
  42. statusTextView.inputAccessoryView = composeAccessoryView
  43. statusCharacterCountLabel.text = String(characterLimit)
  44. NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotification(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
  45. if let replyToStatus = replyToStatus {
  46. replyToView.isHidden = false
  47. if let reblog = replyToStatus.reblog {
  48. self.setupReplyTo(status: reblog)
  49. } else {
  50. self.setupReplyTo(status: replyToStatus)
  51. }
  52. } else {
  53. replyToView.isHidden = true
  54. }
  55. }
  56. deinit {
  57. NotificationCenter.default.removeObserver(self)
  58. }
  59. override func viewDidAppear(_ animated: Bool) {
  60. super.viewDidAppear(animated)
  61. statusTextView.becomeFirstResponder()
  62. }
  63. func setupReplyTo(status: StatusMO) {
  64. if let account = status.account {
  65. let options: KingfisherOptionsInfo = SettingsManager.automaticallyPlayGIFs ? [] : [.onlyLoadFirstFrame]
  66. replyToAvatarImageView.kf.setImage(with: account.avatarURL!, options: options)
  67. replyToDisplayNameLabel.text = account.displayName
  68. replyToUsernameLabel.text = "@\(account.acct!)"
  69. statusTextView.text = "@\(account.acct!) "
  70. }
  71. replyToContentTextView.attributedText = status.content?.htmlAttributed(size: 13.0)
  72. }
  73. @objc func keyboardNotification(notification: NSNotification) {
  74. if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
  75. bottomConstraint.constant = keyboardSize.height + 10
  76. }
  77. }
  78. @IBAction func dismissTapped(_ sender: Any) {
  79. dismiss(animated: true)
  80. }
  81. }
  82. extension ComposeViewController: UITextViewDelegate {
  83. func textViewDidChange(_ textView: UITextView) {
  84. let characters = statusTextView.text!.count
  85. let remainingCharacters = characterLimit - characters
  86. statusCharacterCountLabel.text = String(remainingCharacters)
  87. statusCharacterCountLabel.textColor = remainingCharacters < 1 ? UIColor.red : UIColor(named: "Primary")
  88. }
  89. }
  90. extension ComposeViewController: ComposeAccessoryViewDelegate, VisibilityInputViewDelegate {
  91. func attachmentTapped(_ sender: Any) {
  92. statusTextView.inputView = statusTextView.inputView == nil ? attachmentInputView : nil
  93. statusTextView.reloadInputViews()
  94. }
  95. func visibilityTapped(_ sender: Any) {
  96. statusTextView.inputView = statusTextView.inputView == nil ? visibilityInputView : nil
  97. statusTextView.reloadInputViews()
  98. }
  99. func tootTapped(_ sender: Any) {
  100. if let content = statusTextView.text {
  101. if !content.isEmpty && content.count <= characterLimit {
  102. feedbackGenerator?.prepare()
  103. MastodonAPI.postStatus(content: content, replyToID: replyToStatus?.id, spoilerText: contentWarningTextField.text, visibility: selectedVisibility) { error in
  104. guard error == nil else {
  105. self.feedbackGenerator?.notificationOccurred(.error)
  106. AlertManager.shared.show(message: "Couldn't toot!", category: .error)
  107. return
  108. }
  109. self.feedbackGenerator?.notificationOccurred(.success)
  110. AlertManager.shared.show(message: "Toot!", category: .toot)
  111. self.statusTextView.text = ""
  112. self.contentWarningTextField.text = ""
  113. self.dismiss(animated: true)
  114. }
  115. }
  116. }
  117. }
  118. func visibilitySelected(_ sender: Any, visibility: StatusVisibility) {
  119. selectedVisibility = visibility
  120. composeAccessoryView?.selectedVisibility = visibility
  121. statusTextView.inputView = nil
  122. statusTextView.reloadInputViews()
  123. }
  124. }