Merge branch 'pachyderm-immutable'

This commit is contained in:
Shadowfacts 2018-09-17 19:37:58 -04:00
commit c4fb93579c
23 changed files with 149 additions and 319 deletions

View File

@ -42,8 +42,7 @@ public class Client {
self.session = session
}
// MARK: - Internal Helpers
func run<Result>(_ request: Request<Result>, completion: @escaping Callback<Result>) {
public func run<Result>(_ request: Request<Result>, completion: @escaping Callback<Result>) {
guard let request = createURLRequest(request: request) else {
completion(.failure(Error.invalidRequest))
return

View File

@ -8,13 +8,7 @@
import Foundation
public class Account: Decodable, ClientModel {
var client: Client! {
didSet {
emojis.client = client
}
}
public class Account: Decodable {
public let id: String
public let username: String
public let acct: String
@ -35,78 +29,68 @@ public class Account: Decodable, ClientModel {
public let fields: [Field]?
public let bot: Bool?
public func authorizeFollowRequest(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(id)/authorize")
client.run(request, completion: completion)
public static func authorizeFollowRequest(_ account: Account) -> Request<Empty> {
return Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(account.id)/authorize")
}
public func rejectFollowRequest(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(id)/reject")
client.run(request, completion: completion)
public static func rejectFollowRequest(_ account: Account) -> Request<Empty> {
return Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(account.id)/reject")
}
public func removeFromFollowRequests(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .delete, path: "/api/v1/suggestions/\(id)")
client.run(request, completion: completion)
public static func removeFromFollowRequests(_ account: Account) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/suggestions/\(account.id)")
}
public func getFollowers(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(id)/followers")
public static func getFollowers(_ account: Account, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/followers")
request.range = range
client.run(request, completion: completion)
return request
}
public func getFollowing(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(id)/following")
public static func getFollowing(_ account: Account, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/following")
request.range = range
client.run(request, completion: completion)
return request
}
public func getStatuses(range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil, completion: @escaping Client.Callback<[Status]>) {
var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(id)/statuses", queryParameters: [
public static func getStatuses(_ account: Account, range: RequestRange = .default, onlyMedia: Bool? = nil, pinned: Bool? = nil, excludeReplies: Bool? = nil) -> Request<[Status]> {
var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(account.id)/statuses", queryParameters: [
"only_media" => onlyMedia,
"pinned" => pinned,
"exclude_replies" => excludeReplies
])
request.range = range
client.run(request, completion: completion)
return request
}
public func follow(completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/follow")
client.run(request, completion: completion)
public static func follow(_ account: Account) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/follow")
}
public func unfollow(completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unfollow")
client.run(request, completion: completion)
public static func unfollow(_ account: Account) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unfollow")
}
public func block(completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/block")
client.run(request, completion: completion)
public static func block(_ account: Account) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/block")
}
public func unblock(completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unblock")
client.run(request, completion: completion)
public static func unblock(_ account: Account) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unblock")
}
public func mute(notifications: Bool? = nil, completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/mute", body: .parameters([
public static func mute(_ account: Account, notifications: Bool? = nil) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/mute", body: .parameters([
"notifications" => notifications
]))
client.run(request, completion: completion)
}
public func unmute(completion: @escaping Client.Callback<Relationship>) {
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unmute")
client.run(request, completion: completion)
public static func unmute(_ account: Account) -> Request<Relationship> {
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unmute")
}
public func getLists(completion: @escaping Client.Callback<[List]>) {
let request = Request<[List]>(method: .get, path: "/api/v1/accounts/\(id)/lists")
client.run(request, completion: completion)
public static func getLists(_ account: Account) -> Request<[List]> {
return Request<[List]>(method: .get, path: "/api/v1/accounts/\(account.id)/lists")
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,9 +8,7 @@
import Foundation
public class Application: Decodable, ClientModel {
var client: Client!
public class Application: Decodable {
public let name: String
public let website: URL?

View File

@ -8,9 +8,7 @@
import Foundation
public class Attachment: Decodable, ClientModel {
var client: Client!
public class Attachment: Decodable {
public let id: String
public let kind: Kind
public let url: URL
@ -18,16 +16,13 @@ public class Attachment: Decodable, ClientModel {
public let previewURL: URL
public let textURL: URL?
public let meta: Metadata?
public var description: String?
public let description: String?
public func update(focus: (Float, Float)?, completion: Client.Callback<Attachment>?) {
let request = Request<Attachment>(method: .put, path: "/api/v1/media/\(id)", body: .formData([
"description" => description,
public static func update(_ attachment: Attachment, focus: (Float, Float)?, description: String?) -> Request<Attachment> {
return Request<Attachment>(method: .put, path: "/api/v1/media/\(attachment.id)", body: .formData([
"description" => (description ?? attachment.description),
"focus" => focus
], nil))
client.run(request) { result in
completion?(result)
}
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,9 +8,7 @@
import Foundation
public class Card: Decodable, ClientModel {
var client: Client!
public class Card: Decodable {
public let url: URL
public let title: String
public let description: String

View File

@ -8,16 +8,9 @@
import Foundation
public class ConversationContext: Decodable, ClientModel {
var client: Client! {
didSet {
ancestors.client = client
descendants.client = client
}
}
public private(set) var ancestors: [Status]
public private(set) var descendants: [Status]
public class ConversationContext: Decodable {
public let ancestors: [Status]
public let descendants: [Status]
private enum CodingKeys: String, CodingKey {
case ancestors

View File

@ -8,9 +8,7 @@
import Foundation
public class Emoji: Decodable, ClientModel {
var client: Client!
public class Emoji: Decodable {
let shortcode: String
let url: URL
let staticURL: URL

View File

@ -8,40 +8,31 @@
import Foundation
public class Filter: Decodable, ClientModel {
var client: Client!
public class Filter: Decodable {
public let id: String
public var phrase: String
private var context: [String]
public var expiresAt: Date?
public var irreversible: Bool
public var wholeWord: Bool
public let phrase: String
private let context: [String]
public let expiresAt: Date?
public let irreversible: Bool
public let wholeWord: Bool
public var contexts: [Context] {
get {
return context.compactMap(Context.init)
}
set {
context = contexts.contextStrings
}
}
public func update(completion: Client.Callback<Filter>?) {
let request = Request<Filter>(method: .put, path: "/api/v1/filters/\(id)", body: .parameters([
"phrase" => phrase,
"irreversible" => irreversible,
"whole_word" => wholeWord,
"expires_at" => expiresAt
] + "context" => context))
client.run(request) { result in
completion?(result)
}
public static func update(_ filter: Filter, phrase: String? = nil, context: [Context]? = nil, irreversible: Bool? = nil, wholeWord: Bool? = nil, expiresAt: Date? = nil) -> Request<Filter> {
return Request<Filter>(method: .put, path: "/api/v1/filters/\(filter.id)", body: .parameters([
"phrase" => (phrase ?? filter.phrase),
"irreversible" => (irreversible ?? filter.irreversible),
"whole_word" => (wholeWord ?? filter.wholeWord),
"expires_at" => (expiresAt ?? filter.expiresAt)
] + "context" => (context?.contextStrings ?? filter.context)))
}
public func delete(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .delete, path: "/api/v1/filters/\(id)")
client.run(request, completion: completion)
public static func delete(_ filter: Filter) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/filters/\(filter.id)")
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,9 +8,7 @@
import Foundation
public class Hashtag: Decodable, ClientModel {
var client: Client!
public class Hashtag: Decodable {
public let name: String
public let url: URL
public let history: [History]?

View File

@ -8,13 +8,7 @@
import Foundation
public class Instance: Decodable, ClientModel {
var client: Client! {
didSet {
contactAccount.client = client
}
}
public class Instance: Decodable {
public let uri: String
public let title: String
public let description: String

View File

@ -8,42 +8,34 @@
import Foundation
public class List: Decodable, ClientModel {
var client: Client!
public class List: Decodable {
public let id: String
public var title: String
public let title: String
public func getAccounts(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(id)/accounts")
public static func getAccounts(_ list: List, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(list.id)/accounts")
request.range = range
client.run(request, completion: completion)
return request
}
public func update(completion: Client.Callback<List>?) {
let request = Request<List>(method: .put, path: "/api/v1/lists/\(id)", body: .parameters(["title" => title]))
client.run(request) { result in
completion?(result)
}
public static func update(_ list: List, title: String) -> Request<List> {
return Request<List>(method: .put, path: "/api/v1/lists/\(list.id)", body: .parameters(["title" => title]))
}
public func delete(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .delete, path: "/api/v1/lists/\(id)")
client.run(request, completion: completion)
public static func delete(_ list: List) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/lists/\(list.id)")
}
public func add(accounts: [Account], completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .post, path: "/api/v1/lists/\(id)/accounts", body: .parameters(
public static func add(_ list: List, accounts: [Account]) -> Request<Empty> {
return Request<Empty>(method: .post, path: "/api/v1/lists/\(list.id)/accounts", body: .parameters(
"account_ids" => accounts.map { $0.id }
))
client.run(request, completion: completion)
}
public func remove(accounts: [Account], completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .delete, path: "/api/v1/lists/\(id)/accounts", body: .parameters(
public static func remove(_ list: List, accounts: [Account]) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/lists/\(list.id)/accounts", body: .parameters(
"account_ids" => accounts.map { $0.id }
))
client.run(request, completion: completion)
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,9 +8,7 @@
import Foundation
public class Mention: Decodable, ClientModel {
var client: Client!
public class Mention: Decodable {
public let url: URL
public let username: String
public let acct: String

View File

@ -8,25 +8,17 @@
import Foundation
public class Notification: Decodable, ClientModel {
var client: Client! {
didSet {
account.client = client
status?.client = client
}
}
public class Notification: Decodable {
public let id: String
public let kind: Kind
public let createdAt: Date
public let account: Account
public let status: Status?
public func dismiss(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .post, path: "/api/v1/notifications/dismiss", body: .parameters([
"id" => id
public static func dismiss(_ notification: Notification) -> Request<Empty> {
return Request<Empty>(method: .post, path: "/api/v1/notifications/dismiss", body: .parameters([
"id" => notification.id
]))
client.run(request, completion: completion)
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,9 +8,7 @@
import Foundation
public class PushSubscription: Decodable, ClientModel {
var client: Client!
public class PushSubscription: Decodable {
public let id: String
public let endpoint: URL
public let serverKey: String

View File

@ -8,9 +8,7 @@
import Foundation
public class Relationship: Decodable, ClientModel {
var client: Client!
public class Relationship: Decodable {
public let id: String
public let following: Bool
public let followedBy: Bool

View File

@ -8,9 +8,7 @@
import Foundation
public class Report: Decodable, ClientModel {
var client: Client!
public class Report: Decodable {
public let id: String
public let actionTaken: Bool

View File

@ -8,16 +8,9 @@
import Foundation
public class SearchResults: Decodable, ClientModel {
var client: Client! {
didSet {
accounts.client = client
statuses.client = client
}
}
public private(set) var accounts: [Account]
public private(set) var statuses: [Status]
public class SearchResults: Decodable {
public let accounts: [Account]
public let statuses: [Status]
public let hashtags: [String]
private enum CodingKeys: String, CodingKey {

View File

@ -8,183 +8,88 @@
import Foundation
public class Status: Decodable, ClientModel {
var client: Client! {
didSet {
didSetClient()
}
}
// when reblog.client is set directly from self.client didSet, reblog.client didSet is never called
private func didSetClient() {
account.client = client
reblog?.client = client
emojis.client = client
attachments.client = client
mentions.client = client
hashtags.client = client
application?.client = client
}
public class Status: Decodable {
public let id: String
public let uri: String
public let url: URL?
public let account: Account
public let inReplyToID: String?
public let inReplyToAccountID: String?
public private(set) var reblog: Status?
public let reblog: Status?
public let content: String
public let createdAt: Date
public private(set) var emojis: [Emoji]
public let emojis: [Emoji]
// TODO: missing from pleroma
// public let repliesCount: Int
public let reblogsCount: Int
public let favouritesCount: Int
public var reblogged: Bool?
public var favourited: Bool?
public var muted: Bool?
public let reblogged: Bool?
public let favourited: Bool?
public let muted: Bool?
public let sensitive: Bool
public let spoilerText: String
public let visibility: Visibility
public private(set) var attachments: [Attachment]
public private(set) var mentions: [Mention]
public private(set) var hashtags: [Hashtag]
public private(set) var application: Application?
public let attachments: [Attachment]
public let mentions: [Mention]
public let hashtags: [Hashtag]
public let application: Application?
public let language: String?
public var pinned: Bool?
public let pinned: Bool?
public func getContext(completion: @escaping Client.Callback<ConversationContext>) {
let request = Request<ConversationContext>(method: .get, path: "/api/v1/statuses/\(id)/context")
client.run(request, completion: completion)
public static func getContext(_ status: Status) -> Request<ConversationContext> {
return Request<ConversationContext>(method: .get, path: "/api/v1/statuses/\(status.id)/context")
}
public func getCard(completion: @escaping Client.Callback<Card>) {
let request = Request<Card>(method: .get, path: "/api/v1/statuses/\(id)/card")
client.run(request, completion: completion)
public static func getCard(_ status: Status) -> Request<Card> {
return Request<Card>(method: .get, path: "/api/v1/statuses/\(status.id)/card")
}
public func getFavourites(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(id)/favourited_by")
public static func getFavourites(_ status: Status, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/favourited_by")
request.range = range
client.run(request, completion: completion)
return request
}
public func getReblogs(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(id)/reblogged_by")
public static func getReblogs(_ status: Status, range: RequestRange = .default) -> Request<[Account]> {
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/reblogged_by")
request.range = range
client.run(request, completion: completion)
return request
}
public func delete(completion: @escaping Client.Callback<Empty>) {
let request = Request<Empty>(method: .delete, path: "/api/v1/statuses/\(id)")
client.run(request, completion: completion)
public static func delete(_ status: Status) -> Request<Empty> {
return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(status.id)")
}
public func reblog(completion: @escaping Client.Callback<Status>) {
let oldValue = reblogged
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/reblog")
client.run(request) { response in
if case .success = response {
self.reblogged = true
} else {
self.reblogged = oldValue
}
completion(response)
}
public static func reblog(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/reblog")
}
public func unreblog(completion: @escaping Client.Callback<Status>) {
let oldValue = reblogged
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/unreblog")
client.run(request) { response in
if case .success = response {
self.reblogged = false
} else {
self.reblogged = oldValue
}
completion(response)
}
public static func unreblog(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unreblog")
}
public func favourite(completion: @escaping Client.Callback<Status>) {
let oldValue = favourited
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/favourite")
client.run(request) { response in
if case .success = response {
self.favourited = true
self.reblog?.favourited = true
} else {
self.favourited = oldValue
self.reblog?.favourited = oldValue
}
completion(response)
}
public static func favourite(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/favourite")
}
public func unfavourite(completion: @escaping Client.Callback<Status>) {
let oldValue = favourited
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/unfavourite")
client.run(request) { response in
if case .success = response {
self.favourited = false
self.reblog?.favourited = false
} else {
self.favourited = oldValue
self.reblog?.favourited = oldValue
}
completion(response)
}
public static func unfavourite(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unfavourite")
}
public func pin(completion: @escaping Client.Callback<Status>) {
let oldValue = pinned
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/pin")
client.run(request) { response in
if case .success = response {
self.pinned = true
} else {
self.pinned = oldValue
}
completion(response)
}
public static func pin(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/pin")
}
public func unpin(completion: @escaping Client.Callback<Status>) {
let oldValue = pinned
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/unpin")
client.run(request) { response in
if case .success = response {
self.pinned = false
} else {
self.pinned = oldValue
}
completion(response)
}
public static func unpin(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unpin")
}
public func muteConversation(completion: @escaping Client.Callback<Status>) {
let oldValue = muted
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/mute")
client.run(request) { response in
if case .success = response {
self.muted = true
} else {
self.muted = oldValue
}
completion(response)
}
public static func muteConversation(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/mute")
}
public func unmuteConversation(completion: @escaping Client.Callback<Status>) {
let oldValue = muted
let request = Request<Status>(method: .post, path: "/api/v1/statuses/\(id)/unmute")
client.run(request) { response in
if case .success = response {
self.muted = false
} else {
self.muted = oldValue
}
completion(response)
}
public static func unmuteConversation(_ status: Status) -> Request<Status> {
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unmute")
}
private enum CodingKeys: String, CodingKey {

View File

@ -8,7 +8,7 @@
import Foundation
struct Request<ResultType: Decodable> {
public struct Request<ResultType: Decodable> {
let method: Method
let path: String
let body: Body

View File

@ -40,7 +40,8 @@ class ConversationViewController: UIViewController, UITableViewDataSource, UITab
statuses = [mainStatus]
mainStatus.getContext { response in
let request = Status.getContext(mainStatus)
MastodonController.shared.client.run(request) { response in
guard case let .success(context, _) = response else { fatalError() }
var statuses = self.getDirectParents(of: self.mainStatus, from: context.ancestors)
statuses.append(self.mainStatus)

View File

@ -32,7 +32,8 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
var newer: RequestRange?
func getStatuses(for range: RequestRange = .default, completion: @escaping Client.Callback<[Status]>) {
account.getStatuses(range: range, onlyMedia: false, pinned: false, excludeReplies: !Preferences.shared.showRepliesInProfiles, completion: completion)
let request = Account.getStatuses(account, range: range, onlyMedia: false, pinned: false, excludeReplies: !Preferences.shared.showRepliesInProfiles)
MastodonController.shared.client.run(request, completion: completion)
}
override func viewDidLoad() {

View File

@ -166,7 +166,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
let realStatus: Status = status.reblog ?? status
(favorited ? realStatus.favourite : realStatus.unfavourite)() { response in
let request = (favorited ? Status.favourite : Status.unfavourite)(realStatus)
MastodonController.shared.client.run(request) { response in
self.favorited = realStatus.favourited ?? false
DispatchQueue.main.async {
if case .success = response {
@ -186,7 +187,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
let realStatus: Status = status.reblog ?? status
(reblogged ? realStatus.reblog : realStatus.unreblog)() { response in
let request = (reblogged ? Status.reblog : Status.unreblog)(realStatus)
MastodonController.shared.client.run(request) { response in
self.reblogged = realStatus.reblogged ?? false
DispatchQueue.main.async {
if case .success = response {

View File

@ -210,16 +210,19 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
}
@IBAction func favoritePressed(_ sender: Any) {
let oldValue = favorited
favorited = !favorited
let realStatus: Status = status.reblog ?? status
(favorited ? realStatus.favourite : realStatus.unfavourite)() { response in
let request = (favorited ? Status.favourite : Status.unfavourite)(realStatus)
MastodonController.shared.client.run(request) { response in
DispatchQueue.main.async {
self.favorited = realStatus.favourited ?? false
if case .success = response {
self.favorited = realStatus.favourited ?? false
UIImpactFeedbackGenerator(style: .light).impactOccurred()
} else {
self.favorited = oldValue
print("Couldn't favorite status \(realStatus.id)")
// todo: display error message
UINotificationFeedbackGenerator().notificationOccurred(.error)
@ -233,8 +236,9 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
reblogged = !reblogged
let realStatus: Status = status.reblog ?? status
(reblogged ? realStatus.reblog : realStatus.unreblog)() { response in
let request = (reblogged ? Status.reblog : Status.unreblog)(realStatus)
MastodonController.shared.client.run(request) { response in
self.reblogged = realStatus.reblogged ?? false
DispatchQueue.main.async {
self.reblogged = realStatus.reblogged ?? false
if case .success = response {
@ -271,20 +275,20 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
let favoriteTitle: String
let favoriteAction: (@escaping Client.Callback<Status>) -> Void
let favoriteRequest: Request<Status>
let favoriteColor: UIColor
if status.favourited ?? false {
favoriteTitle = "Unfavorite"
favoriteAction = status.unfavourite
favoriteRequest = Status.unfavourite(status)
favoriteColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
} else {
favoriteTitle = "Favorite"
favoriteAction = status.favourite
favoriteRequest = Status.favourite(status)
favoriteColor = UIColor(displayP3Red: 1, green: 204/255, blue: 0, alpha: 1)
}
let favorite = UIContextualAction(style: .normal, title: favoriteTitle) { (action, view, completion) in
favoriteAction { response in
MastodonController.shared.client.run(favoriteRequest, completion: { response in
DispatchQueue.main.async {
if case .success = response {
completion(true)
@ -293,25 +297,25 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
completion(false)
}
}
}
})
}
favorite.image = StatusTableViewCell.favoriteActionImage
favorite.backgroundColor = favoriteColor
let reblogTitle: String
let reblogAction: (@escaping Client.Callback<Status>) -> Void
let reblogRequest: Request<Status>
let reblogColor: UIColor
if status.reblogged ?? false {
reblogTitle = "Unreblog"
reblogAction = status.unreblog
reblogRequest = Status.unreblog(status)
reblogColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
} else {
reblogTitle = "Reblog"
reblogAction = status.reblog
reblogRequest = Status.reblog(status)
reblogColor = tintColor
}
let reblog = UIContextualAction(style: .normal, title: reblogTitle) { (action, view, completion) in
reblogAction { response in
MastodonController.shared.client.run(reblogRequest, completion: { response in
DispatchQueue.main.async {
if case .success = response {
completion(true)
@ -320,7 +324,7 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
completion(false)
}
}
}
})
}
reblog.image = StatusTableViewCell.reblogActionImage
reblog.backgroundColor = reblogColor