From e1f5bc79b2af9bfafd28f5f59c2a8b51c914fe16 Mon Sep 17 00:00:00 2001 From: Dwayne Harris Date: Wed, 14 Nov 2018 00:12:27 -0800 Subject: [PATCH] Add Tooting --- elpha-ios/Base.lproj/Main.storyboard | 55 ++++++++++--------- elpha-ios/ComposeViewController.swift | 29 +++++++++- .../FLAnimatedImageView+LoadImageURL.swift | 4 +- elpha-ios/MastodonAPI.swift | 31 ++++++++++- elpha-ios/StatusTableViewController.swift | 41 ++++++++++---- elpha-ios/StatusView.swift | 20 +++---- elpha-ios/TimelineTableViewController.swift | 4 +- 7 files changed, 131 insertions(+), 53 deletions(-) diff --git a/elpha-ios/Base.lproj/Main.storyboard b/elpha-ios/Base.lproj/Main.storyboard index 38c1526..74b040a 100644 --- a/elpha-ios/Base.lproj/Main.storyboard +++ b/elpha-ios/Base.lproj/Main.storyboard @@ -1066,44 +1066,44 @@ - + - + - + - + - - + + - - + + @@ -1115,28 +1115,28 @@ - + - + - + - + - + - + @@ -1145,7 +1145,7 @@ - + @@ -1178,19 +1181,19 @@ - + @@ -1233,7 +1236,7 @@ - + @@ -1248,13 +1251,13 @@ - + - + diff --git a/elpha-ios/ComposeViewController.swift b/elpha-ios/ComposeViewController.swift index bf1fa53..7b6781d 100644 --- a/elpha-ios/ComposeViewController.swift +++ b/elpha-ios/ComposeViewController.swift @@ -21,11 +21,15 @@ class ComposeViewController: UIViewController { @IBOutlet var tootButton: UIButton! @IBOutlet var bottomConstraint: NSLayoutConstraint! + let characterLimit = 500 + var feedbackGenerator: UINotificationFeedbackGenerator? = nil var replyToStatus: StatusMO? = nil override func viewDidLoad() { super.viewDidLoad() + feedbackGenerator = UINotificationFeedbackGenerator() + replyToAvatarImageView.layer.cornerRadius = 10 replyToAvatarImageView.layer.masksToBounds = true @@ -84,11 +88,34 @@ class ComposeViewController: UIViewController { @IBAction func dismissTapped(_ sender: Any) { dismiss(animated: true) } + + @IBAction func tootTapped(_ sender: Any) { + if let content = statusTextView.text { + if !content.isEmpty && content.count <= characterLimit { + feedbackGenerator?.prepare() + + MastodonAPI.postStatus(content: content, replyToID: replyToStatus?.id, spoilerText: contentWarningTextField.text) { error in + guard error == nil else { + self.feedbackGenerator?.notificationOccurred(.error) + AlertManager.shared.show(message: "Couldn't toot!", category: .error) + return + } + + self.feedbackGenerator?.notificationOccurred(.success) + AlertManager.shared.show(message: "Toot!") + + self.statusTextView.text = "" + self.contentWarningTextField.text = "" + self.dismiss(animated: true) + } + } + } + } } extension ComposeViewController: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { let characters = statusTextView.text!.count - statusCharacterCountLabel.text = String(500 - characters) + statusCharacterCountLabel.text = String(characterLimit - characters) } } diff --git a/elpha-ios/FLAnimatedImageView+LoadImageURL.swift b/elpha-ios/FLAnimatedImageView+LoadImageURL.swift index 44a2339..b3c6788 100644 --- a/elpha-ios/FLAnimatedImageView+LoadImageURL.swift +++ b/elpha-ios/FLAnimatedImageView+LoadImageURL.swift @@ -49,7 +49,7 @@ extension FLAnimatedImageView { self.image = UIImage(named: "Help") } - func loadImageURL(_ url: URL) { + func loadImageURL(_ url: URL, contentMode: UIView.ContentMode = .scaleAspectFit) { if let data = ImageCache.get(url: url) { if url.absoluteString.hasSuffix(".gif") { self.animatedImage = FLAnimatedImage(animatedGIFData: data) @@ -63,7 +63,7 @@ extension FLAnimatedImageView { if let data = response.data { DispatchQueue.main.async { ImageCache.set(url: url, data: data) - self.contentMode = .scaleAspectFill + self.contentMode = contentMode if url.absoluteString.hasSuffix(".gif") { self.animatedImage = FLAnimatedImage(animatedGIFData: data) diff --git a/elpha-ios/MastodonAPI.swift b/elpha-ios/MastodonAPI.swift index e5b9abb..6b9f3be 100644 --- a/elpha-ios/MastodonAPI.swift +++ b/elpha-ios/MastodonAPI.swift @@ -14,8 +14,7 @@ typealias JSONArray = [Any] typealias JSONObjectArray = [JSONObject] enum MastodonRequestError: Error { - case noResponse - case unauthenticated + case noResponse, unauthenticated } enum TimelineCategory: String { @@ -26,6 +25,10 @@ enum PaginationDirection: String { case prev, next } +enum StatusVisibility: String { + case direct, `private`, unlisted, `public` +} + public class PaginationItem: NSObject, NSCoding { let direction: PaginationDirection let statusID: String @@ -360,6 +363,30 @@ class MastodonAPI { } } + static func postStatus(content: String, replyToID: String?, spoilerText: String?, visibility: StatusVisibility = .public, completion: @escaping (Error?) -> Void) { + var parameters: Parameters = [ + "status": content, + "visibility": visibility.rawValue, + ] + + if let replyToID = replyToID { + parameters["in_reply_to_id"] = replyToID + } + + if let spoilerText = spoilerText { + parameters["spoiler_text"] = spoilerText + } + + self.request(path: "api/v1/statuses", method: .post, parameters: parameters) { _, _, error in + guard error == nil else { + completion(error) + return + } + + completion(nil) + } + } + static func registerApp(serverURL: URL, completion: @escaping (JSONObject?, Error?) -> Void) { let requestURL = serverURL.appendingPathComponent("api/v1/apps") let parameters: Parameters = [ diff --git a/elpha-ios/StatusTableViewController.swift b/elpha-ios/StatusTableViewController.swift index eb791aa..cbad0d2 100644 --- a/elpha-ios/StatusTableViewController.swift +++ b/elpha-ios/StatusTableViewController.swift @@ -46,7 +46,7 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec @IBAction func boostTapped(_ sender: Any) { if let status = status { - feedbackGenerator!.prepare() + feedbackGenerator?.prepare() if status.reblogged { status.reblogged = false @@ -55,12 +55,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec MastodonAPI.unreblog(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Unboosted", category: .boosted) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } else { status.reblogged = true @@ -69,12 +69,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec MastodonAPI.reblog(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Boosted!", category: .boosted) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } @@ -84,7 +84,7 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec @IBAction func favoriteTapped(_ sender: Any) { if let status = status { - feedbackGenerator!.prepare() + feedbackGenerator?.prepare() if status.favorited { status.favorited = false @@ -93,12 +93,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec MastodonAPI.unfavorite(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Unfavorited", category: .favorited) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } else { status.favorited = true @@ -107,12 +107,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec MastodonAPI.favorite(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Favorited!", category: .favorited) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } @@ -262,6 +262,8 @@ extension StatusTableViewController { fatalError("Unable to find reusable cell") } + cell.contentTextView.delegate = self + cell.avatarImageView.layer.shadowColor = UIColor.black.cgColor cell.avatarImageView.layer.shadowOpacity = 0.8 cell.avatarImageView.layer.shadowOffset = CGSize.zero @@ -368,3 +370,22 @@ extension StatusTableViewController: AttachmentManagerDelegate { self.attachmentTapped(status: status!, index: index) } } + +extension StatusTableViewController: UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { + if let mentions = status?.mentions { + for mention in mentions { + if URL == mention.url { + if let account = MastodonDataManager.account(id: mention.id) { + self.accountTapped(account: account) + } + + return false + } + } + } + + self.urlTapped(url: URL) + return false + } +} diff --git a/elpha-ios/StatusView.swift b/elpha-ios/StatusView.swift index 6c7d3e9..966d4b2 100644 --- a/elpha-ios/StatusView.swift +++ b/elpha-ios/StatusView.swift @@ -125,7 +125,7 @@ class StatusView: UIView { @IBAction func boostTapped(_ sender: Any) { if let status = status { - feedbackGenerator!.prepare() + feedbackGenerator?.prepare() if status.reblogged { status.reblogged = false @@ -134,12 +134,12 @@ class StatusView: UIView { MastodonAPI.unreblog(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Unboosted", category: .boosted) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } else { status.reblogged = true @@ -148,12 +148,12 @@ class StatusView: UIView { MastodonAPI.reblog(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Boosted!", category: .boosted) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } @@ -164,7 +164,7 @@ class StatusView: UIView { @IBAction func favoriteTapped(_ sender: Any) { if let status = status { - feedbackGenerator!.prepare() + feedbackGenerator?.prepare() if status.favorited { status.favorited = false @@ -173,12 +173,12 @@ class StatusView: UIView { MastodonAPI.unfavorite(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Unfavorited", category: .favorited) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } else { status.favorited = true @@ -187,12 +187,12 @@ class StatusView: UIView { MastodonAPI.favorite(statusID: status.id!) { error in guard error == nil else { AlertManager.shared.show(message: error!.localizedDescription, category: .error) - self.feedbackGenerator!.notificationOccurred(.error) + self.feedbackGenerator?.notificationOccurred(.error) return } AlertManager.shared.show(message: "Favorited!", category: .favorited) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } } diff --git a/elpha-ios/TimelineTableViewController.swift b/elpha-ios/TimelineTableViewController.swift index ee63e24..fe7fb50 100644 --- a/elpha-ios/TimelineTableViewController.swift +++ b/elpha-ios/TimelineTableViewController.swift @@ -199,7 +199,7 @@ class TimelineTableViewController: AbstractStatusTableViewController { DispatchQueue.main.async { var newStatusCount = 0 - self.feedbackGenerator!.prepare() + self.feedbackGenerator?.prepare() for (index, status) in data.enumerated() { if let upsertResult = MastodonDataManager.upsertStatus(status) { @@ -239,7 +239,7 @@ class TimelineTableViewController: AbstractStatusTableViewController { if newStatusCount > 0 { let pluralization = newStatusCount == 1 ? "" : "s" AlertManager.shared.show(message: "\(newStatusCount) new toot\(pluralization)", category: .newStatuses) - self.feedbackGenerator!.notificationOccurred(.success) + self.feedbackGenerator?.notificationOccurred(.success) } CoreDataManager.shared.saveContext()