forked from shadowfacts/Tusker
Merge branch 'pachyderm-immutable'
This commit is contained in:
commit
266ebddd43
|
@ -42,8 +42,7 @@ public class Client {
|
||||||
self.session = session
|
self.session = session
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Internal Helpers
|
public func run<Result>(_ request: Request<Result>, completion: @escaping Callback<Result>) {
|
||||||
func run<Result>(_ request: Request<Result>, completion: @escaping Callback<Result>) {
|
|
||||||
guard let request = createURLRequest(request: request) else {
|
guard let request = createURLRequest(request: request) else {
|
||||||
completion(.failure(Error.invalidRequest))
|
completion(.failure(Error.invalidRequest))
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,13 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Account: Decodable, ClientModel {
|
public class Account: Decodable {
|
||||||
var client: Client! {
|
|
||||||
didSet {
|
|
||||||
emojis.client = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let username: String
|
public let username: String
|
||||||
public let acct: String
|
public let acct: String
|
||||||
|
@ -35,78 +29,68 @@ public class Account: Decodable, ClientModel {
|
||||||
public let fields: [Field]?
|
public let fields: [Field]?
|
||||||
public let bot: Bool?
|
public let bot: Bool?
|
||||||
|
|
||||||
public func authorizeFollowRequest(completion: @escaping Client.Callback<Empty>) {
|
public static func authorizeFollowRequest(_ account: Account) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(id)/authorize")
|
return Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(account.id)/authorize")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func rejectFollowRequest(completion: @escaping Client.Callback<Empty>) {
|
public static func rejectFollowRequest(_ account: Account) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(id)/reject")
|
return Request<Empty>(method: .post, path: "/api/v1/follow_requests/\(account.id)/reject")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeFromFollowRequests(completion: @escaping Client.Callback<Empty>) {
|
public static func removeFromFollowRequests(_ account: Account) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .delete, path: "/api/v1/suggestions/\(id)")
|
return Request<Empty>(method: .delete, path: "/api/v1/suggestions/\(account.id)")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getFollowers(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
|
public static func getFollowers(_ account: Account, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(id)/followers")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/followers")
|
||||||
request.range = range
|
request.range = range
|
||||||
client.run(request, completion: completion)
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getFollowing(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
|
public static func getFollowing(_ account: Account, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(id)/following")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/accounts/\(account.id)/following")
|
||||||
request.range = range
|
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]>) {
|
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/\(id)/statuses", queryParameters: [
|
var request = Request<[Status]>(method: .get, path: "/api/v1/accounts/\(account.id)/statuses", queryParameters: [
|
||||||
"only_media" => onlyMedia,
|
"only_media" => onlyMedia,
|
||||||
"pinned" => pinned,
|
"pinned" => pinned,
|
||||||
"exclude_replies" => excludeReplies
|
"exclude_replies" => excludeReplies
|
||||||
])
|
])
|
||||||
request.range = range
|
request.range = range
|
||||||
client.run(request, completion: completion)
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public func follow(completion: @escaping Client.Callback<Relationship>) {
|
public static func follow(_ account: Account) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/follow")
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/follow")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func unfollow(completion: @escaping Client.Callback<Relationship>) {
|
public static func unfollow(_ account: Account) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unfollow")
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unfollow")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func block(completion: @escaping Client.Callback<Relationship>) {
|
public static func block(_ account: Account) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/block")
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/block")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func unblock(completion: @escaping Client.Callback<Relationship>) {
|
public static func unblock(_ account: Account) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unblock")
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unblock")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func mute(notifications: Bool? = nil, completion: @escaping Client.Callback<Relationship>) {
|
public static func mute(_ account: Account, notifications: Bool? = nil) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/mute", body: .parameters([
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/mute", body: .parameters([
|
||||||
"notifications" => notifications
|
"notifications" => notifications
|
||||||
]))
|
]))
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func unmute(completion: @escaping Client.Callback<Relationship>) {
|
public static func unmute(_ account: Account) -> Request<Relationship> {
|
||||||
let request = Request<Relationship>(method: .post, path: "/api/v1/accounts/\(id)/unmute")
|
return Request<Relationship>(method: .post, path: "/api/v1/accounts/\(account.id)/unmute")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getLists(completion: @escaping Client.Callback<[List]>) {
|
public static func getLists(_ account: Account) -> Request<[List]> {
|
||||||
let request = Request<[List]>(method: .get, path: "/api/v1/accounts/\(id)/lists")
|
return Request<[List]>(method: .get, path: "/api/v1/accounts/\(account.id)/lists")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Application: Decodable, ClientModel {
|
public class Application: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let website: URL?
|
public let website: URL?
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Attachment: Decodable, ClientModel {
|
public class Attachment: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let kind: Kind
|
public let kind: Kind
|
||||||
public let url: URL
|
public let url: URL
|
||||||
|
@ -18,16 +16,13 @@ public class Attachment: Decodable, ClientModel {
|
||||||
public let previewURL: URL
|
public let previewURL: URL
|
||||||
public let textURL: URL?
|
public let textURL: URL?
|
||||||
public let meta: Metadata?
|
public let meta: Metadata?
|
||||||
public var description: String?
|
public let description: String?
|
||||||
|
|
||||||
public func update(focus: (Float, Float)?, completion: Client.Callback<Attachment>?) {
|
public static func update(_ attachment: Attachment, focus: (Float, Float)?, description: String?) -> Request<Attachment> {
|
||||||
let request = Request<Attachment>(method: .put, path: "/api/v1/media/\(id)", body: .formData([
|
return Request<Attachment>(method: .put, path: "/api/v1/media/\(attachment.id)", body: .formData([
|
||||||
"description" => description,
|
"description" => (description ?? attachment.description),
|
||||||
"focus" => focus
|
"focus" => focus
|
||||||
], nil))
|
], nil))
|
||||||
client.run(request) { result in
|
|
||||||
completion?(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Card: Decodable, ClientModel {
|
public class Card: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let url: URL
|
public let url: URL
|
||||||
public let title: String
|
public let title: String
|
||||||
public let description: String
|
public let description: String
|
||||||
|
|
|
@ -8,16 +8,9 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class ConversationContext: Decodable, ClientModel {
|
public class ConversationContext: Decodable {
|
||||||
var client: Client! {
|
public let ancestors: [Status]
|
||||||
didSet {
|
public let descendants: [Status]
|
||||||
ancestors.client = client
|
|
||||||
descendants.client = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public private(set) var ancestors: [Status]
|
|
||||||
public private(set) var descendants: [Status]
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case ancestors
|
case ancestors
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Emoji: Decodable, ClientModel {
|
public class Emoji: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
let shortcode: String
|
let shortcode: String
|
||||||
let url: URL
|
let url: URL
|
||||||
let staticURL: URL
|
let staticURL: URL
|
||||||
|
|
|
@ -8,40 +8,31 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Filter: Decodable, ClientModel {
|
public class Filter: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public var phrase: String
|
public let phrase: String
|
||||||
private var context: [String]
|
private let context: [String]
|
||||||
public var expiresAt: Date?
|
public let expiresAt: Date?
|
||||||
public var irreversible: Bool
|
public let irreversible: Bool
|
||||||
public var wholeWord: Bool
|
public let wholeWord: Bool
|
||||||
|
|
||||||
public var contexts: [Context] {
|
public var contexts: [Context] {
|
||||||
get {
|
get {
|
||||||
return context.compactMap(Context.init)
|
return context.compactMap(Context.init)
|
||||||
}
|
}
|
||||||
set {
|
|
||||||
context = contexts.contextStrings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(completion: Client.Callback<Filter>?) {
|
public static func update(_ filter: Filter, phrase: String? = nil, context: [Context]? = nil, irreversible: Bool? = nil, wholeWord: Bool? = nil, expiresAt: Date? = nil) -> Request<Filter> {
|
||||||
let request = Request<Filter>(method: .put, path: "/api/v1/filters/\(id)", body: .parameters([
|
return Request<Filter>(method: .put, path: "/api/v1/filters/\(filter.id)", body: .parameters([
|
||||||
"phrase" => phrase,
|
"phrase" => (phrase ?? filter.phrase),
|
||||||
"irreversible" => irreversible,
|
"irreversible" => (irreversible ?? filter.irreversible),
|
||||||
"whole_word" => wholeWord,
|
"whole_word" => (wholeWord ?? filter.wholeWord),
|
||||||
"expires_at" => expiresAt
|
"expires_at" => (expiresAt ?? filter.expiresAt)
|
||||||
] + "context" => context))
|
] + "context" => (context?.contextStrings ?? filter.context)))
|
||||||
client.run(request) { result in
|
|
||||||
completion?(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func delete(completion: @escaping Client.Callback<Empty>) {
|
public static func delete(_ filter: Filter) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .delete, path: "/api/v1/filters/\(id)")
|
return Request<Empty>(method: .delete, path: "/api/v1/filters/\(filter.id)")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Hashtag: Decodable, ClientModel {
|
public class Hashtag: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let url: URL
|
public let url: URL
|
||||||
public let history: [History]?
|
public let history: [History]?
|
||||||
|
|
|
@ -8,13 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Instance: Decodable, ClientModel {
|
public class Instance: Decodable {
|
||||||
var client: Client! {
|
|
||||||
didSet {
|
|
||||||
contactAccount.client = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public let uri: String
|
public let uri: String
|
||||||
public let title: String
|
public let title: String
|
||||||
public let description: String
|
public let description: String
|
||||||
|
|
|
@ -8,42 +8,34 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class List: Decodable, ClientModel {
|
public class List: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public var title: String
|
public let title: String
|
||||||
|
|
||||||
public func getAccounts(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
|
public static func getAccounts(_ list: List, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(id)/accounts")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/lists/\(list.id)/accounts")
|
||||||
request.range = range
|
request.range = range
|
||||||
client.run(request, completion: completion)
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(completion: Client.Callback<List>?) {
|
public static func update(_ list: List, title: String) -> Request<List> {
|
||||||
let request = Request<List>(method: .put, path: "/api/v1/lists/\(id)", body: .parameters(["title" => title]))
|
return Request<List>(method: .put, path: "/api/v1/lists/\(list.id)", body: .parameters(["title" => title]))
|
||||||
client.run(request) { result in
|
|
||||||
completion?(result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func delete(completion: @escaping Client.Callback<Empty>) {
|
public static func delete(_ list: List) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .delete, path: "/api/v1/lists/\(id)")
|
return Request<Empty>(method: .delete, path: "/api/v1/lists/\(list.id)")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func add(accounts: [Account], completion: @escaping Client.Callback<Empty>) {
|
public static func add(_ list: List, accounts: [Account]) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .post, path: "/api/v1/lists/\(id)/accounts", body: .parameters(
|
return Request<Empty>(method: .post, path: "/api/v1/lists/\(list.id)/accounts", body: .parameters(
|
||||||
"account_ids" => accounts.map { $0.id }
|
"account_ids" => accounts.map { $0.id }
|
||||||
))
|
))
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func remove(accounts: [Account], completion: @escaping Client.Callback<Empty>) {
|
public static func remove(_ list: List, accounts: [Account]) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .delete, path: "/api/v1/lists/\(id)/accounts", body: .parameters(
|
return Request<Empty>(method: .delete, path: "/api/v1/lists/\(list.id)/accounts", body: .parameters(
|
||||||
"account_ids" => accounts.map { $0.id }
|
"account_ids" => accounts.map { $0.id }
|
||||||
))
|
))
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Mention: Decodable, ClientModel {
|
public class Mention: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let url: URL
|
public let url: URL
|
||||||
public let username: String
|
public let username: String
|
||||||
public let acct: String
|
public let acct: String
|
||||||
|
|
|
@ -8,25 +8,17 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Notification: Decodable, ClientModel {
|
public class Notification: Decodable {
|
||||||
var client: Client! {
|
|
||||||
didSet {
|
|
||||||
account.client = client
|
|
||||||
status?.client = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let kind: Kind
|
public let kind: Kind
|
||||||
public let createdAt: Date
|
public let createdAt: Date
|
||||||
public let account: Account
|
public let account: Account
|
||||||
public let status: Status?
|
public let status: Status?
|
||||||
|
|
||||||
public func dismiss(completion: @escaping Client.Callback<Empty>) {
|
public static func dismiss(_ notification: Notification) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .post, path: "/api/v1/notifications/dismiss", body: .parameters([
|
return Request<Empty>(method: .post, path: "/api/v1/notifications/dismiss", body: .parameters([
|
||||||
"id" => id
|
"id" => notification.id
|
||||||
]))
|
]))
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class PushSubscription: Decodable, ClientModel {
|
public class PushSubscription: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let endpoint: URL
|
public let endpoint: URL
|
||||||
public let serverKey: String
|
public let serverKey: String
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Relationship: Decodable, ClientModel {
|
public class Relationship: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let following: Bool
|
public let following: Bool
|
||||||
public let followedBy: Bool
|
public let followedBy: Bool
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Report: Decodable, ClientModel {
|
public class Report: Decodable {
|
||||||
var client: Client!
|
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let actionTaken: Bool
|
public let actionTaken: Bool
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,9 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class SearchResults: Decodable, ClientModel {
|
public class SearchResults: Decodable {
|
||||||
var client: Client! {
|
public let accounts: [Account]
|
||||||
didSet {
|
public let statuses: [Status]
|
||||||
accounts.client = client
|
|
||||||
statuses.client = client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public private(set) var accounts: [Account]
|
|
||||||
public private(set) var statuses: [Status]
|
|
||||||
public let hashtags: [String]
|
public let hashtags: [String]
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,183 +8,88 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public class Status: Decodable, ClientModel {
|
public class Status: Decodable {
|
||||||
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 let id: String
|
public let id: String
|
||||||
public let uri: String
|
public let uri: String
|
||||||
public let url: URL?
|
public let url: URL?
|
||||||
public let account: Account
|
public let account: Account
|
||||||
public let inReplyToID: String?
|
public let inReplyToID: String?
|
||||||
public let inReplyToAccountID: String?
|
public let inReplyToAccountID: String?
|
||||||
public private(set) var reblog: Status?
|
public let reblog: Status?
|
||||||
public let content: String
|
public let content: String
|
||||||
public let createdAt: Date
|
public let createdAt: Date
|
||||||
public private(set) var emojis: [Emoji]
|
public let emojis: [Emoji]
|
||||||
// TODO: missing from pleroma
|
// TODO: missing from pleroma
|
||||||
// public let repliesCount: Int
|
// public let repliesCount: Int
|
||||||
public let reblogsCount: Int
|
public let reblogsCount: Int
|
||||||
public let favouritesCount: Int
|
public let favouritesCount: Int
|
||||||
public var reblogged: Bool?
|
public let reblogged: Bool?
|
||||||
public var favourited: Bool?
|
public let favourited: Bool?
|
||||||
public var muted: Bool?
|
public let muted: Bool?
|
||||||
public let sensitive: Bool
|
public let sensitive: Bool
|
||||||
public let spoilerText: String
|
public let spoilerText: String
|
||||||
public let visibility: Visibility
|
public let visibility: Visibility
|
||||||
public private(set) var attachments: [Attachment]
|
public let attachments: [Attachment]
|
||||||
public private(set) var mentions: [Mention]
|
public let mentions: [Mention]
|
||||||
public private(set) var hashtags: [Hashtag]
|
public let hashtags: [Hashtag]
|
||||||
public private(set) var application: Application?
|
public let application: Application?
|
||||||
public let language: String?
|
public let language: String?
|
||||||
public var pinned: Bool?
|
public let pinned: Bool?
|
||||||
|
|
||||||
public func getContext(completion: @escaping Client.Callback<ConversationContext>) {
|
public static func getContext(_ status: Status) -> Request<ConversationContext> {
|
||||||
let request = Request<ConversationContext>(method: .get, path: "/api/v1/statuses/\(id)/context")
|
return Request<ConversationContext>(method: .get, path: "/api/v1/statuses/\(status.id)/context")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getCard(completion: @escaping Client.Callback<Card>) {
|
public static func getCard(_ status: Status) -> Request<Card> {
|
||||||
let request = Request<Card>(method: .get, path: "/api/v1/statuses/\(id)/card")
|
return Request<Card>(method: .get, path: "/api/v1/statuses/\(status.id)/card")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getFavourites(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
|
public static func getFavourites(_ status: Status, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(id)/favourited_by")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/favourited_by")
|
||||||
request.range = range
|
request.range = range
|
||||||
client.run(request, completion: completion)
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getReblogs(range: RequestRange = .default, completion: @escaping Client.Callback<[Account]>) {
|
public static func getReblogs(_ status: Status, range: RequestRange = .default) -> Request<[Account]> {
|
||||||
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(id)/reblogged_by")
|
var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/reblogged_by")
|
||||||
request.range = range
|
request.range = range
|
||||||
client.run(request, completion: completion)
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
public func delete(completion: @escaping Client.Callback<Empty>) {
|
public static func delete(_ status: Status) -> Request<Empty> {
|
||||||
let request = Request<Empty>(method: .delete, path: "/api/v1/statuses/\(id)")
|
return Request<Empty>(method: .delete, path: "/api/v1/statuses/\(status.id)")
|
||||||
client.run(request, completion: completion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func reblog(completion: @escaping Client.Callback<Status>) {
|
public static func reblog(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = reblogged
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/reblog")
|
||||||
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 func unreblog(completion: @escaping Client.Callback<Status>) {
|
public static func unreblog(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = reblogged
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unreblog")
|
||||||
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 func favourite(completion: @escaping Client.Callback<Status>) {
|
public static func favourite(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = favourited
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/favourite")
|
||||||
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 func unfavourite(completion: @escaping Client.Callback<Status>) {
|
public static func unfavourite(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = favourited
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unfavourite")
|
||||||
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 func pin(completion: @escaping Client.Callback<Status>) {
|
public static func pin(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = pinned
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/pin")
|
||||||
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 func unpin(completion: @escaping Client.Callback<Status>) {
|
public static func unpin(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = pinned
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unpin")
|
||||||
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 func muteConversation(completion: @escaping Client.Callback<Status>) {
|
public static func muteConversation(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = muted
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/mute")
|
||||||
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 func unmuteConversation(completion: @escaping Client.Callback<Status>) {
|
public static func unmuteConversation(_ status: Status) -> Request<Status> {
|
||||||
let oldValue = muted
|
return Request<Status>(method: .post, path: "/api/v1/statuses/\(status.id)/unmute")
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Request<ResultType: Decodable> {
|
public struct Request<ResultType: Decodable> {
|
||||||
let method: Method
|
let method: Method
|
||||||
let path: String
|
let path: String
|
||||||
let body: Body
|
let body: Body
|
||||||
|
|
|
@ -40,7 +40,8 @@ class ConversationViewController: UIViewController, UITableViewDataSource, UITab
|
||||||
|
|
||||||
statuses = [mainStatus]
|
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() }
|
guard case let .success(context, _) = response else { fatalError() }
|
||||||
var statuses = self.getDirectParents(of: self.mainStatus, from: context.ancestors)
|
var statuses = self.getDirectParents(of: self.mainStatus, from: context.ancestors)
|
||||||
statuses.append(self.mainStatus)
|
statuses.append(self.mainStatus)
|
||||||
|
|
|
@ -32,7 +32,8 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
var newer: RequestRange?
|
var newer: RequestRange?
|
||||||
|
|
||||||
func getStatuses(for range: RequestRange = .default, completion: @escaping Client.Callback<[Status]>) {
|
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() {
|
override func viewDidLoad() {
|
||||||
|
|
|
@ -166,7 +166,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
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
|
self.favorited = realStatus.favourited ?? false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
|
@ -186,7 +187,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
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
|
self.reblogged = realStatus.reblogged ?? false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
|
|
|
@ -210,16 +210,19 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func favoritePressed(_ sender: Any) {
|
@IBAction func favoritePressed(_ sender: Any) {
|
||||||
|
let oldValue = favorited
|
||||||
favorited = !favorited
|
favorited = !favorited
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
let realStatus: Status = status.reblog ?? status
|
||||||
|
let request = (favorited ? Status.favourite : Status.unfavourite)(realStatus)
|
||||||
(favorited ? realStatus.favourite : realStatus.unfavourite)() { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.favorited = realStatus.favourited ?? false
|
self.favorited = realStatus.favourited ?? false
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
|
self.favorited = realStatus.favourited ?? false
|
||||||
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
||||||
} else {
|
} else {
|
||||||
|
self.favorited = oldValue
|
||||||
print("Couldn't favorite status \(realStatus.id)")
|
print("Couldn't favorite status \(realStatus.id)")
|
||||||
// todo: display error message
|
// todo: display error message
|
||||||
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
||||||
|
@ -233,8 +236,9 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
reblogged = !reblogged
|
reblogged = !reblogged
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
let realStatus: Status = status.reblog ?? status
|
||||||
|
let request = (reblogged ? Status.reblog : Status.unreblog)(realStatus)
|
||||||
(reblogged ? realStatus.reblog : realStatus.unreblog)() { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
|
self.reblogged = realStatus.reblogged ?? false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.reblogged = realStatus.reblogged ?? false
|
self.reblogged = realStatus.reblogged ?? false
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
|
@ -271,20 +275,20 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
|
|
||||||
func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
||||||
let favoriteTitle: String
|
let favoriteTitle: String
|
||||||
let favoriteAction: (@escaping Client.Callback<Status>) -> Void
|
let favoriteRequest: Request<Status>
|
||||||
let favoriteColor: UIColor
|
let favoriteColor: UIColor
|
||||||
if status.favourited ?? false {
|
if status.favourited ?? false {
|
||||||
favoriteTitle = "Unfavorite"
|
favoriteTitle = "Unfavorite"
|
||||||
favoriteAction = status.unfavourite
|
favoriteRequest = Status.unfavourite(status)
|
||||||
favoriteColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
|
favoriteColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
favoriteTitle = "Favorite"
|
favoriteTitle = "Favorite"
|
||||||
favoriteAction = status.favourite
|
favoriteRequest = Status.favourite(status)
|
||||||
favoriteColor = UIColor(displayP3Red: 1, green: 204/255, blue: 0, alpha: 1)
|
favoriteColor = UIColor(displayP3Red: 1, green: 204/255, blue: 0, alpha: 1)
|
||||||
}
|
}
|
||||||
let favorite = UIContextualAction(style: .normal, title: favoriteTitle) { (action, view, completion) in
|
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 {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
completion(true)
|
completion(true)
|
||||||
|
@ -293,25 +297,25 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
completion(false)
|
completion(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
favorite.image = StatusTableViewCell.favoriteActionImage
|
favorite.image = StatusTableViewCell.favoriteActionImage
|
||||||
favorite.backgroundColor = favoriteColor
|
favorite.backgroundColor = favoriteColor
|
||||||
|
|
||||||
let reblogTitle: String
|
let reblogTitle: String
|
||||||
let reblogAction: (@escaping Client.Callback<Status>) -> Void
|
let reblogRequest: Request<Status>
|
||||||
let reblogColor: UIColor
|
let reblogColor: UIColor
|
||||||
if status.reblogged ?? false {
|
if status.reblogged ?? false {
|
||||||
reblogTitle = "Unreblog"
|
reblogTitle = "Unreblog"
|
||||||
reblogAction = status.unreblog
|
reblogRequest = Status.unreblog(status)
|
||||||
reblogColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
|
reblogColor = UIColor(displayP3Red: 235/255, green: 77/255, blue: 62/255, alpha: 1)
|
||||||
} else {
|
} else {
|
||||||
reblogTitle = "Reblog"
|
reblogTitle = "Reblog"
|
||||||
reblogAction = status.reblog
|
reblogRequest = Status.reblog(status)
|
||||||
reblogColor = tintColor
|
reblogColor = tintColor
|
||||||
}
|
}
|
||||||
let reblog = UIContextualAction(style: .normal, title: reblogTitle) { (action, view, completion) in
|
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 {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
completion(true)
|
completion(true)
|
||||||
|
@ -320,7 +324,7 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
completion(false)
|
completion(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
reblog.image = StatusTableViewCell.reblogActionImage
|
reblog.image = StatusTableViewCell.reblogActionImage
|
||||||
reblog.backgroundColor = reblogColor
|
reblog.backgroundColor = reblogColor
|
||||||
|
|
Loading…
Reference in New Issue