diff --git a/Localization/ios-infoPlist.json b/Localization/ios-infoPlist.json
index f25dbcc0..c6db73de 100644
--- a/Localization/ios-infoPlist.json
+++ b/Localization/ios-infoPlist.json
@@ -1,4 +1,6 @@
{
"NSCameraUsageDescription": "Used to take photo for post status",
- "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library"
-}
\ No newline at end of file
+ "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library",
+ "NewPostShortcutItemTitle": "New Post",
+ "SearchShortcutItemTitle": "Search"
+}
diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - ASDK.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - ASDK.xcscheme
new file mode 100644
index 00000000..4ce52bd5
--- /dev/null
+++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - ASDK.xcscheme
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme
new file mode 100644
index 00000000..15ecdcbe
--- /dev/null
+++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme
new file mode 100644
index 00000000..70507b96
--- /dev/null
+++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme
new file mode 100644
index 00000000..b64bfc89
--- /dev/null
+++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index a5dbdb34..09d2afef 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,12 +7,12 @@
AppShared.xcscheme_^#shared#^_
orderHint
- 24
+ 21
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 22
+ 23
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -42,7 +42,7 @@
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 21
+ 22
SuppressBuildableAutocreation
diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift
index 5aac2b1b..04804dde 100644
--- a/Mastodon/Coordinator/SceneCoordinator.swift
+++ b/Mastodon/Coordinator/SceneCoordinator.swift
@@ -13,7 +13,7 @@ final public class SceneCoordinator {
private weak var scene: UIScene!
private weak var sceneDelegate: SceneDelegate!
private weak var appContext: AppContext!
- private weak var tabBarController: MainTabBarController!
+ private(set) weak var tabBarController: MainTabBarController!
let id = UUID().uuidString
diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist
index cbb93eab..6143fcdb 100644
--- a/Mastodon/Info.plist
+++ b/Mastodon/Info.plist
@@ -86,5 +86,24 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
+ UIApplicationShortcutItems
+
+
+ UIApplicationShortcutItemType
+ org.joinmastodon.app.new-post
+ UIApplicationShortcutItemIconSymbolName
+ square.and.pencil
+ UIApplicationShortcutItemTitle
+ NewPostShortcutItemTitle
+
+
+ UIApplicationShortcutItemType
+ org.joinmastodon.app.search
+ UIApplicationShortcutItemIconSymbolName
+ magnifyingglass
+ UIApplicationShortcutItemTitle
+ SearchShortcutItemTitle
+
+
diff --git a/Mastodon/Resources/ar.lproj/InfoPlist.strings b/Mastodon/Resources/ar.lproj/InfoPlist.strings
index 48566ae3..71086557 100644
--- a/Mastodon/Resources/ar.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/ar.lproj/InfoPlist.strings
@@ -1,2 +1,4 @@
"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
\ No newline at end of file
+"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
+"NewPostShortcutItemTitle" = "New Post";
+"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
diff --git a/Mastodon/Resources/en.lproj/InfoPlist.strings b/Mastodon/Resources/en.lproj/InfoPlist.strings
index 48566ae3..71086557 100644
--- a/Mastodon/Resources/en.lproj/InfoPlist.strings
+++ b/Mastodon/Resources/en.lproj/InfoPlist.strings
@@ -1,2 +1,4 @@
"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
\ No newline at end of file
+"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
+"NewPostShortcutItemTitle" = "New Post";
+"SearchShortcutItemTitle" = "Search";
\ No newline at end of file
diff --git a/Mastodon/Resources/en.lproj/infoPlist.strings b/Mastodon/Resources/en.lproj/infoPlist.strings
deleted file mode 100644
index 48566ae3..00000000
--- a/Mastodon/Resources/en.lproj/infoPlist.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-"NSCameraUsageDescription" = "Used to take photo for post status";
-"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library";
\ No newline at end of file
diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift
index 6964eef9..05ff8850 100644
--- a/Mastodon/Supporting Files/SceneDelegate.swift
+++ b/Mastodon/Supporting Files/SceneDelegate.swift
@@ -5,6 +5,7 @@
// Created by MainasuK Cirno on 2021/1/22.
//
+import os.log
import UIKit
import Combine
import CoreDataStack
@@ -25,6 +26,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var fpsIndicator: FPSIndicator?
#endif
+ var savedShortCutItem: UIApplicationShortcutItem?
+
+ let logger = Logger(subsystem: "SceneDelegate", category: "logic")
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
@@ -55,6 +59,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
sceneCoordinator.setup()
sceneCoordinator.setupOnboardingIfNeeds(animated: false)
window.makeKeyAndVisible()
+
+ if let shortcutItem = connectionOptions.shortcutItem {
+ // Save it off for later when we become active.
+ savedShortCutItem = shortcutItem
+ }
UserDefaults.shared.observe(\.customUserInterfaceStyle, options: [.initial, .new]) { [weak self] defaults, _ in
guard let self = self else { return }
@@ -84,6 +93,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// trigger status filter update
AppContext.shared.statusFilterService.filterUpdatePublisher.send()
+
+ if let shortcutItem = savedShortCutItem {
+ _ = handler(shortcutItem: shortcutItem)
+ savedShortCutItem = nil
+ }
}
func sceneWillResignActive(_ scene: UIScene) {
@@ -103,7 +117,40 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
AppContext.shared.audioPlaybackService.pauseIfNeed()
}
+}
+extension SceneDelegate {
+ func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
+ completionHandler(handler(shortcutItem: shortcutItem))
+ }
+
+ private func handler(shortcutItem: UIApplicationShortcutItem) -> Bool {
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(shortcutItem.type)")
+
+ switch shortcutItem.type {
+ case "org.joinmastodon.app.new-post":
+ if coordinator?.tabBarController.topMost is ComposeViewController {
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): composing…")
+ } else {
+ let composeViewModel = ComposeViewModel(context: AppContext.shared, composeKind: .post)
+ coordinator?.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil))
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): present compose scene")
+ }
+ case "org.joinmastodon.app.search":
+ coordinator?.switchToTabBar(tab: .search)
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select search tab")
+
+ if let searchViewController = coordinator?.tabBarController.topMost as? SearchViewController {
+ searchViewController.searchBarTapPublisher.send()
+ logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): trigger search")
+ }
+ default:
+ assertionFailure()
+ break
+ }
+
+ return true
+ }
}
#if DEBUG