355 lines
15 KiB
Swift
355 lines
15 KiB
Swift
//
|
|
// XCBActions.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 9/23/18.
|
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import Pachyderm
|
|
import SwiftSoup
|
|
|
|
struct XCBActions {
|
|
|
|
// MARK: - Utils
|
|
private static var mastodonController: MastodonController {
|
|
let scene = UIApplication.shared.activeOrBackgroundScene!
|
|
return scene.session.mastodonController!
|
|
}
|
|
|
|
private static func getMainTabBarController() -> MainTabBarViewController {
|
|
let scene = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first!
|
|
let window = scene.windows.first { $0.isKeyWindow }!
|
|
return window.rootViewController as! MainTabBarViewController
|
|
}
|
|
|
|
private static func show(_ vc: UIViewController) {
|
|
let tabBarController = getMainTabBarController()
|
|
if tabBarController.presentedViewController != nil {
|
|
tabBarController.presentedViewController?.dismiss(animated: false)
|
|
}
|
|
tabBarController.selectedViewController!.show(vc, sender: nil)
|
|
}
|
|
|
|
private static func present(_ vc: UIViewController, animated: Bool = true) {
|
|
getMainTabBarController().present(vc, animated: animated)
|
|
}
|
|
|
|
private static func getStatus(from request: XCBRequest, session: XCBSession, completion: @escaping (Status) -> Void) {
|
|
if let id = request.arguments["statusID"] {
|
|
let request = Client.getStatus(id: id)
|
|
mastodonController.run(request) { (response) in
|
|
guard case let .success(status, _) = response else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Could not get status with ID \(id)"
|
|
])
|
|
return
|
|
}
|
|
completion(status)
|
|
}
|
|
} else if let searchQuery = request.arguments["statusURL"] {
|
|
let request = Client.search(query: searchQuery)
|
|
mastodonController.run(request) { (response) in
|
|
if case let .success(results, _) = response,
|
|
let status = results.statuses.first {
|
|
completion(status)
|
|
} else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Could not find status by searching '\(searchQuery)'"
|
|
])
|
|
}
|
|
}
|
|
} else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "No status provided. Specify either instance-local statusID or remote statusURL."
|
|
])
|
|
}
|
|
}
|
|
|
|
private static func getAccount(from request: XCBRequest, session: XCBSession, completion: @escaping (Account) -> Void) {
|
|
if let id = request.arguments["accountID"] {
|
|
let request = Client.getAccount(id: id)
|
|
mastodonController.run(request) { (response) in
|
|
guard case let .success(account, _) = response else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Could not get account with ID \(id)"
|
|
])
|
|
return
|
|
}
|
|
completion(account)
|
|
}
|
|
} else if let searchQuery = request.arguments["accountURL"] {
|
|
let request = Client.search(query: searchQuery)
|
|
mastodonController.run(request) { (response) in
|
|
if case let .success(results, _) = response {
|
|
if let account = results.accounts.first {
|
|
completion(account)
|
|
} else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Could not find account by searching '\(searchQuery)'"
|
|
])
|
|
}
|
|
} else if case let .failure(error) = response {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
}
|
|
}
|
|
} else if let acct = request.arguments["acct"] {
|
|
let request = Client.searchForAccount(query: acct)
|
|
mastodonController.run(request) { (response) in
|
|
if case let .success(accounts, _) = response {
|
|
if let account = accounts.first {
|
|
completion(account)
|
|
} else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Could not find account \(acct)"
|
|
])
|
|
}
|
|
} else if case let .failure(error) = response {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
}
|
|
}
|
|
} else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "No status provided. Specify either instance-local ID, account URL, or qualified username."
|
|
])
|
|
}
|
|
}
|
|
|
|
// MARK: - Statuses
|
|
static func showStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
getStatus(from: request, session: session) { (status) in
|
|
DispatchQueue.main.async {
|
|
let vc = ConversationTableViewController(for: status.id, mastodonController: mastodonController)
|
|
show(vc)
|
|
}
|
|
}
|
|
}
|
|
|
|
static func postStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
let mentioning = request.arguments["mentioning"]
|
|
let text = request.arguments["text"]
|
|
|
|
if silent ?? false {
|
|
var status = ""
|
|
if let mentioning = mentioning { status += mentioning }
|
|
if let text = text { status += text }
|
|
guard CharacterCounter.count(text: status) <= mastodonController.instance.maxStatusCharacters ?? 500 else {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": "Too many characters. Instance maximum is \(mastodonController.instance.maxStatusCharacters ?? 500)"
|
|
])
|
|
return
|
|
}
|
|
let request = Client.createStatus(text: status, visibility: Preferences.shared.defaultPostVisibility)
|
|
mastodonController.run(request) { response in
|
|
if case let .success(status, _) = response {
|
|
session.complete(with: .success, additionalData: [
|
|
"statusURL": status.url?.absoluteString,
|
|
"statusURI": status.uri
|
|
])
|
|
} else if case let .failure(error) = response {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
}
|
|
}
|
|
} else {
|
|
// todo: use text param
|
|
let draft = mastodonController.createDraft(mentioningAcct: mentioning)
|
|
let compose = ComposeHostingController(draft: draft, mastodonController: mastodonController)
|
|
// compose.xcbSession = session
|
|
let vc = UINavigationController(rootViewController: compose)
|
|
present(vc)
|
|
}
|
|
}
|
|
|
|
static func getStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
getStatus(from: request, session: session) { (status) in
|
|
let html = Bool(request.arguments["html"] ?? "false") ?? false
|
|
let content: String
|
|
if html {
|
|
content = status.content
|
|
} else {
|
|
do {
|
|
let doc = try SwiftSoup.parse(status.content)
|
|
content = try doc.body()!.text()
|
|
} catch {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
return
|
|
}
|
|
}
|
|
session.complete(with: .success, additionalData: [
|
|
"url": status.url?.absoluteString,
|
|
"uri": status.uri,
|
|
"id": status.id,
|
|
"account": status.account.acct,
|
|
"inReplyTo": status.inReplyToID,
|
|
"posted": status.createdAt.timeIntervalSince1970.description,
|
|
"content": content,
|
|
"reblog": status.reblog?.id
|
|
])
|
|
}
|
|
}
|
|
|
|
static func favoriteStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
statusAction(request: Status.favourite, alertTitle: "Favorite status?", request, session, silent)
|
|
}
|
|
|
|
static func reblogStatus(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
statusAction(request: Status.reblog, alertTitle: "Reblog status?", request, session, silent)
|
|
}
|
|
|
|
static func statusAction(request: @escaping (String) -> Request<Status>, alertTitle: String, _ url: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
func performAction(status: Status, completion: ((Status) -> Void)?) {
|
|
mastodonController.run(request(status.id)) { (response) in
|
|
if case let .success(status, _) = response {
|
|
completion?(status)
|
|
session.complete(with: .success, additionalData: [
|
|
"statusURL": status.url?.absoluteString,
|
|
"statusURI": status.uri
|
|
])
|
|
} else if case let .failure(error) = response {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
}
|
|
}
|
|
}
|
|
|
|
func favorite(_ status: Status) {
|
|
if silent ?? false {
|
|
performAction(status: status, completion: nil)
|
|
} else {
|
|
let vc = ConversationTableViewController(for: status.id, mastodonController: mastodonController)
|
|
DispatchQueue.main.async {
|
|
show(vc)
|
|
}
|
|
let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .alert)
|
|
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
|
performAction(status: status, completion: { (status) in
|
|
DispatchQueue.main.async {
|
|
vc.tableView.reloadData()
|
|
}
|
|
})
|
|
}))
|
|
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
|
|
session.complete(with: .cancel)
|
|
}))
|
|
DispatchQueue.main.async {
|
|
present(alertController)
|
|
}
|
|
}
|
|
}
|
|
|
|
getStatus(from: url, session: session, completion: favorite)
|
|
}
|
|
|
|
// MARK: - Accounts
|
|
static func showAccount(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
getAccount(from: request, session: session) { (account) in
|
|
DispatchQueue.main.async {
|
|
let vc = ProfileViewController(accountID: account.id, mastodonController: mastodonController)
|
|
show(vc)
|
|
}
|
|
}
|
|
}
|
|
|
|
static func getAccount(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
getAccount(from: request, session: session) { (account) in
|
|
session.complete(with: .success, additionalData: [
|
|
"username": account.acct,
|
|
"displayName": account.displayName,
|
|
"locked": account.locked.description,
|
|
"followers": account.followersCount.description,
|
|
"following": account.followingCount.description,
|
|
"url": account.url.absoluteString,
|
|
"avatarURL": account.avatar.absoluteString,
|
|
"headerURL": account.header?.absoluteString
|
|
])
|
|
}
|
|
}
|
|
|
|
static func getCurrentUser(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
let account = mastodonController.account!
|
|
session.complete(with: .success, additionalData: [
|
|
"username": account.acct,
|
|
"displayName": account.displayName,
|
|
"locked": account.locked.description,
|
|
"followers": account.followersCount.description,
|
|
"following": account.followingCount.description,
|
|
"url": account.url.absoluteString,
|
|
"avatarURL": account.avatar.absoluteString,
|
|
"headerURL": account.header?.absoluteString
|
|
])
|
|
}
|
|
|
|
static func followUser(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
func performAction(_ account: Account) {
|
|
let request = Account.follow(account.id)
|
|
mastodonController.run(request) { (response) in
|
|
if case .success(_, _) = response {
|
|
session.complete(with: .success, additionalData: [
|
|
"url": account.url.absoluteString
|
|
])
|
|
} else if case let .failure(error) = response {
|
|
session.complete(with: .error, additionalData: [
|
|
"error": error.localizedDescription
|
|
])
|
|
}
|
|
}
|
|
}
|
|
|
|
func follow(_ account: Account) {
|
|
if silent ?? false {
|
|
performAction(account)
|
|
} else {
|
|
let vc = ProfileViewController(accountID: account.id, mastodonController: mastodonController)
|
|
DispatchQueue.main.async {
|
|
show(vc)
|
|
}
|
|
// todo: update to use managed objects
|
|
let alertController = UIAlertController(title: "Follow \(account.displayName)?", message: nil, preferredStyle: .alert)
|
|
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) in
|
|
performAction(account)
|
|
}))
|
|
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
|
|
session.complete(with: .cancel)
|
|
}))
|
|
DispatchQueue.main.async {
|
|
present(alertController)
|
|
}
|
|
}
|
|
}
|
|
|
|
getAccount(from: request, session: session, completion: follow)
|
|
}
|
|
|
|
// MARK: - Search
|
|
|
|
static func search(_ request: XCBRequest, _ session: XCBSession, _ silent: Bool?) {
|
|
let query = request.arguments["query"]!
|
|
|
|
let tabBarController = getMainTabBarController()
|
|
if let navigationController = tabBarController.getTabController(tab: .explore) as? UINavigationController,
|
|
let exploreController = navigationController.viewControllers.first as? ExploreViewController {
|
|
|
|
tabBarController.select(tab: .explore)
|
|
navigationController.popToRootViewController(animated: false)
|
|
|
|
exploreController.loadViewIfNeeded()
|
|
exploreController.searchController.isActive = true
|
|
|
|
exploreController.searchController.searchBar.text = query
|
|
exploreController.resultsController.performSearch(query: query)
|
|
} else {
|
|
session.complete(with: .error)
|
|
}
|
|
}
|
|
}
|