Start adding Siri Shortcuts
This commit is contained in:
parent
3a378a852f
commit
61f91eee4a
|
@ -60,6 +60,9 @@
|
||||||
D621544821682A9D0003D87D /* TabsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544721682A9D0003D87D /* TabsTableViewController.swift */; };
|
D621544821682A9D0003D87D /* TabsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544721682A9D0003D87D /* TabsTableViewController.swift */; };
|
||||||
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; };
|
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; };
|
||||||
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D621544C21682AD90003D87D /* TabTableViewCell.xib */; };
|
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 */; };
|
D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Trim.swift */; };
|
||||||
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.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 */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -483,6 +489,16 @@
|
||||||
path = Tab;
|
path = Tab;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D62D241E217AA46B005076CC /* Shortcuts */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D62D2425217ABF63005076CC /* UserActivityType.swift */,
|
||||||
|
D62D2421217AA7E1005076CC /* UserActivityManager.swift */,
|
||||||
|
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */,
|
||||||
|
);
|
||||||
|
path = Shortcuts;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D641C780213DD7C4004B4513 /* Screens */ = {
|
D641C780213DD7C4004B4513 /* Screens */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -747,6 +763,7 @@
|
||||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
||||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
||||||
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
||||||
|
D62D241E217AA46B005076CC /* Shortcuts */,
|
||||||
D663626021360A9600C9CBA2 /* Preferences */,
|
D663626021360A9600C9CBA2 /* Preferences */,
|
||||||
D667E5F62135C2ED0057A976 /* Extensions */,
|
D667E5F62135C2ED0057A976 /* Extensions */,
|
||||||
D6F953F121251A2F00CF0F2B /* Controllers */,
|
D6F953F121251A2F00CF0F2B /* Controllers */,
|
||||||
|
@ -1107,9 +1124,12 @@
|
||||||
D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */,
|
D6C693F92162E4DB007D6A6D /* StatusContentLabel.swift in Sources */,
|
||||||
D667E5F52135BCD50057A976 /* ConversationViewController.swift in Sources */,
|
D667E5F52135BCD50057A976 /* ConversationViewController.swift in Sources */,
|
||||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
||||||
|
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */,
|
||||||
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
|
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
|
||||||
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */,
|
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */,
|
||||||
D67E051521643C77000E0927 /* Tab.swift in Sources */,
|
D67E051521643C77000E0927 /* Tab.swift in Sources */,
|
||||||
|
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
|
||||||
|
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */,
|
||||||
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
|
|
|
@ -34,6 +34,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||||
|
return userActivity.handleResume()
|
||||||
|
}
|
||||||
|
|
||||||
func applicationWillResignActive(_ application: UIApplication) {
|
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.
|
// 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.
|
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<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>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
@ -36,7 +41,7 @@
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Post photos from the camera.</string>
|
<string>Post photos from the camera.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Save photos directly from other people's posts.</string>
|
<string>Save photos directly from other people's posts.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Post photos from the photo library.</string>
|
<string>Post photos from the photo library.</string>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
import Intents
|
||||||
|
|
||||||
class ComposeViewController: UIViewController {
|
class ComposeViewController: UIViewController {
|
||||||
|
|
||||||
|
@ -121,6 +122,20 @@ class ComposeViewController: UIViewController {
|
||||||
updatePlaceholder()
|
updatePlaceholder()
|
||||||
|
|
||||||
progressView.progress = 0
|
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() {
|
override func viewDidLayoutSubviews() {
|
||||||
|
|
|
@ -54,6 +54,8 @@ class NotificationsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerForPreviewing(with: self, sourceView: view)
|
registerForPreviewing(with: self, sourceView: view)
|
||||||
|
|
||||||
|
userActivity = UserActivityManager.checkNotificationsActivity()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,17 +13,17 @@ import SwiftSoup
|
||||||
struct XCBActions {
|
struct XCBActions {
|
||||||
|
|
||||||
// MARK: - Utils
|
// 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)
|
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 tabBarController = UIApplication.shared.keyWindow!.rootViewController! as! UITabBarController
|
||||||
let navController = tabBarController.selectedViewController as! UINavigationController
|
let navController = tabBarController.selectedViewController as! UINavigationController
|
||||||
navController.pushViewController(vc, animated: animated)
|
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"] {
|
if let id = request.arguments["statusID"] {
|
||||||
MastodonCache.status(for: id) { (status) in
|
MastodonCache.status(for: id) { (status) in
|
||||||
if let status = status {
|
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"] {
|
if let id = request.arguments["accountID"] {
|
||||||
MastodonCache.account(for: id) { (account) in
|
MastodonCache.account(for: id) { (account) in
|
||||||
if let account = account {
|
if let account = account {
|
||||||
|
|
Loading…
Reference in New Issue