Start adding Siri Shortcuts

This commit is contained in:
Shadowfacts 2018-10-20 10:54:59 -04:00
parent fda4ca4d11
commit 9e7e16b3fc
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
9 changed files with 162 additions and 5 deletions

View File

@ -60,6 +60,9 @@
D621544821682A9D0003D87D /* TabsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544721682A9D0003D87D /* TabsTableViewController.swift */; };
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; };
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D621544C21682AD90003D87D /* TabTableViewCell.xib */; };
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; };
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; };
D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Trim.swift */; };
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; };
D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; };
@ -249,6 +252,9 @@
D621544721682A9D0003D87D /* TabsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewController.swift; sourceTree = "<group>"; };
D621544A21682AD30003D87D /* TabTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTableViewCell.swift; sourceTree = "<group>"; };
D621544C21682AD90003D87D /* TabTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TabTableViewCell.xib; sourceTree = "<group>"; };
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; };
D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = "<group>"; };
D6333B362137838300CE884A /* AttributedString+Trim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Trim.swift"; sourceTree = "<group>"; };
D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = "<group>"; };
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
@ -483,6 +489,16 @@
path = Tab;
sourceTree = "<group>";
};
D62D241E217AA46B005076CC /* Shortcuts */ = {
isa = PBXGroup;
children = (
D62D2425217ABF63005076CC /* UserActivityType.swift */,
D62D2421217AA7E1005076CC /* UserActivityManager.swift */,
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */,
);
path = Shortcuts;
sourceTree = "<group>";
};
D641C780213DD7C4004B4513 /* Screens */ = {
isa = PBXGroup;
children = (
@ -747,6 +763,7 @@
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
D6757A7A2157E00100721E32 /* XCallbackURL */,
D62D241E217AA46B005076CC /* Shortcuts */,
D663626021360A9600C9CBA2 /* Preferences */,
D667E5F62135C2ED0057A976 /* Extensions */,
D6F953F121251A2F00CF0F2B /* Controllers */,
@ -1107,9 +1124,12 @@
D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */,
D667E5F52135BCD50057A976 /* ConversationViewController.swift in Sources */,
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */,
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */,
D67E051521643C77000E0927 /* Tab.swift in Sources */,
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */,
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,

View File

@ -34,6 +34,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return false
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return userActivity.handleResume()
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.

View File

@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSUserActivityTypes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.check-notifications</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.new-post</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
@ -36,7 +41,7 @@
<key>NSCameraUsageDescription</key>
<string>Post photos from the camera.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save photos directly from other people's posts.</string>
<string>Save photos directly from other people&apos;s posts.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Post photos from the photo library.</string>
<key>UILaunchStoryboardName</key>

View File

@ -8,6 +8,7 @@
import UIKit
import Pachyderm
import Intents
class ComposeViewController: UIViewController {
@ -121,6 +122,20 @@ class ComposeViewController: UIViewController {
updatePlaceholder()
progressView.progress = 0
if let mentioningAcct = mentioningAcct {
let req = MastodonController.client.searchForAccount(query: mentioningAcct)
MastodonController.client.run(req) { [weak self] (response) in
if case let .success(accounts, _) = response {
self?.userActivity = UserActivityManager.newPostActivity(mentioning: accounts.first)
} else {
self?.userActivity = UserActivityManager.newPostActivity()
}
}
} else {
self.userActivity = UserActivityManager.newPostActivity()
}
}
override func viewDidLayoutSubviews() {

View File

@ -54,6 +54,8 @@ class NotificationsTableViewController: UITableViewController {
}
registerForPreviewing(with: self, sourceView: view)
userActivity = UserActivityManager.checkNotificationsActivity()
}
override func viewWillAppear(_ animated: Bool) {

View File

@ -0,0 +1,23 @@
//
// NSUserActivity+Extensions.swift
// Tusker
//
// Created by Shadowfacts on 10/19/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import Foundation
extension NSUserActivity {
convenience init(type: UserActivityType) {
self.init(activityType: type.rawValue)
}
func handleResume() -> Bool {
guard let type = UserActivityType(rawValue: activityType) else { return false }
type.handle(self)
return true
}
}

View File

@ -0,0 +1,63 @@
//
// UserActivityManager.swift
// Tusker
//
// Created by Shadowfacts on 10/19/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
class UserActivityManager {
// MARK: - Utils
private static func presentModally(_ vc: UIViewController, animated: Bool, completion: (() -> Void)? = nil) {
UIApplication.shared.keyWindow!.rootViewController!.present(vc, animated: animated, completion: completion)
}
private static func presentNav(_ vc: UIViewController, animated: Bool) {
let tabBarController = UIApplication.shared.keyWindow!.rootViewController! as! UITabBarController
let navController = tabBarController.selectedViewController as! UINavigationController
navController.pushViewController(vc, animated: animated)
}
// MARK: - New Post
static func newPostActivity(mentioning: Account? = nil) -> NSUserActivity {
let activity = NSUserActivity(type: .newPost)
activity.isEligibleForPrediction = true
if let mentioning = mentioning {
activity.userInfo = ["mentioning": mentioning.acct]
activity.title = "Send a message to \(mentioning.realDisplayName)"
activity.suggestedInvocationPhrase = "Send a message to \(mentioning.realDisplayName)"
} else {
activity.userInfo = [:]
activity.title = "New Post"
activity.suggestedInvocationPhrase = "Post in Tusker"
}
return activity
}
static func handleNewPost(activity: NSUserActivity) {
// TODO: check not currently showing compose screen
let mentioning = activity.userInfo?["mentioning"] as? String
presentModally(ComposeViewController.create(mentioning: mentioning), animated: true)
}
// MARK: - Check Notifications
static func checkNotificationsActivity() -> NSUserActivity {
let activity = NSUserActivity(type: .checkNotifications)
activity.isEligibleForPrediction = true
activity.title = "Check Notifications"
activity.suggestedInvocationPhrase = "Check my Tusker notifications"
return activity
}
static func handleCheckNotifications(activity: NSUserActivity) {
let index = Preferences.shared.tabs[.notifications] ?? -1
guard index > 0 else { return }
let tabBarController = UIApplication.shared.keyWindow!.rootViewController! as! UITabBarController
tabBarController.selectedIndex = index
}
}

View File

@ -0,0 +1,25 @@
//
// UserActivityType.swift
// Tusker
//
// Created by Shadowfacts on 10/19/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import Foundation
enum UserActivityType: String {
case newPost = "net.shadowfacts.tusker.activity.new-post"
case checkNotifications = "net.shadowfacts.tusker.activity.check-notifications"
}
extension UserActivityType {
var handle: (NSUserActivity) -> Void {
switch self {
case .newPost:
return UserActivityManager.handleNewPost
case .checkNotifications:
return UserActivityManager.handleCheckNotifications
}
}
}

View File

@ -13,17 +13,17 @@ import SwiftSoup
struct XCBActions {
// MARK: - Utils
static func presentModally(_ vc: UIViewController, animated: Bool, completion: (() -> Void)? = nil) {
private static func presentModally(_ vc: UIViewController, animated: Bool, completion: (() -> Void)? = nil) {
UIApplication.shared.keyWindow!.rootViewController!.present(vc, animated: animated, completion: completion)
}
static func presentNav(_ vc: UIViewController, animated: Bool) {
private static func presentNav(_ vc: UIViewController, animated: Bool) {
let tabBarController = UIApplication.shared.keyWindow!.rootViewController! as! UITabBarController
let navController = tabBarController.selectedViewController as! UINavigationController
navController.pushViewController(vc, animated: animated)
}
static func getStatus(from request: XCBRequest, session: XCBSession, completion: @escaping (Status) -> Void) {
private static func getStatus(from request: XCBRequest, session: XCBSession, completion: @escaping (Status) -> Void) {
if let id = request.arguments["statusID"] {
MastodonCache.status(for: id) { (status) in
if let status = status {
@ -54,7 +54,7 @@ struct XCBActions {
}
}
static func getAccount(from request: XCBRequest, session: XCBSession, completion: @escaping (Account) -> Void) {
private static func getAccount(from request: XCBRequest, session: XCBSession, completion: @escaping (Account) -> Void) {
if let id = request.arguments["accountID"] {
MastodonCache.account(for: id) { (account) in
if let account = account {