mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-23 07:36:48 +00:00
Add more shortcuts
This commit is contained in:
parent
4e4d903c44
commit
49a5c6a56a
12 changed files with 295 additions and 7 deletions
|
@ -44,6 +44,9 @@
|
|||
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4B2952005C00B3281A /* MessagesTab.swift */; };
|
||||
9F37BDDB2BE36E22007F28AD /* PostIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDA2BE36E22007F28AD /* PostIntent.swift */; };
|
||||
9F37BDDD2BE37193007F28AD /* AppIntentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDC2BE37193007F28AD /* AppIntentService.swift */; };
|
||||
9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDDE2BE37C35007F28AD /* TabIntent.swift */; };
|
||||
9F37BDE12BE38646007F28AD /* PostPhotoIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDE02BE38646007F28AD /* PostPhotoIntent.swift */; };
|
||||
9F37BDE32BE393A7007F28AD /* AppShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */; };
|
||||
9F38A7332ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
|
||||
9F38A7342ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
|
||||
9F38A7352ACEA26100DBCD66 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */; };
|
||||
|
@ -200,6 +203,9 @@
|
|||
9F35DB4B2952005C00B3281A /* MessagesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesTab.swift; sourceTree = "<group>"; };
|
||||
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostIntent.swift; sourceTree = "<group>"; };
|
||||
9F37BDDC2BE37193007F28AD /* AppIntentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentService.swift; sourceTree = "<group>"; };
|
||||
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabIntent.swift; sourceTree = "<group>"; };
|
||||
9F37BDE02BE38646007F28AD /* PostPhotoIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostPhotoIntent.swift; sourceTree = "<group>"; };
|
||||
9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcuts.swift; sourceTree = "<group>"; };
|
||||
9F38A7322ACEA26100DBCD66 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; };
|
||||
9F398AA52935FE8A00A889F2 /* AppRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRegistry.swift; sourceTree = "<group>"; };
|
||||
|
@ -358,6 +364,9 @@
|
|||
children = (
|
||||
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */,
|
||||
9F37BDDC2BE37193007F28AD /* AppIntentService.swift */,
|
||||
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */,
|
||||
9F37BDE02BE38646007F28AD /* PostPhotoIntent.swift */,
|
||||
9F37BDE22BE393A7007F28AD /* AppShortcuts.swift */,
|
||||
);
|
||||
path = IceCubesAppIntents;
|
||||
sourceTree = "<group>";
|
||||
|
@ -844,6 +853,8 @@
|
|||
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */,
|
||||
9F37BDDB2BE36E22007F28AD /* PostIntent.swift in Sources */,
|
||||
9F37BDDD2BE37193007F28AD /* AppIntentService.swift in Sources */,
|
||||
9F37BDE12BE38646007F28AD /* PostPhotoIntent.swift in Sources */,
|
||||
9F37BDDF2BE37C35007F28AD /* TabIntent.swift in Sources */,
|
||||
9FAD85CF2975B68900496AB1 /* SideBarView.swift in Sources */,
|
||||
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
|
||||
9FC14EF42B494D940006CEE1 /* RemoteTimelinesSettingView.swift in Sources */,
|
||||
|
@ -862,6 +873,7 @@
|
|||
9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */,
|
||||
639CDF9C296AC82F00C35E58 /* SafariRouter.swift in Sources */,
|
||||
9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */,
|
||||
9F37BDE32BE393A7007F28AD /* AppShortcuts.swift in Sources */,
|
||||
9F654BEF299AC45B00D27FA5 /* ReportView.swift in Sources */,
|
||||
D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */,
|
||||
9F7335F22967608F00AFF0BA /* AddRemoteTimelineView.swift in Sources */,
|
||||
|
|
|
@ -90,6 +90,9 @@ extension View {
|
|||
case let .prefilledStatusEditor(text, visibility):
|
||||
StatusEditor.MainView(mode: .new(text: text, visibility: visibility))
|
||||
.withEnvironments()
|
||||
case let .imageURL(urls, visibility):
|
||||
StatusEditor.MainView(mode: .imageURL(urls: urls, visibility: visibility))
|
||||
.withEnvironments()
|
||||
case let .editStatusEditor(status):
|
||||
StatusEditor.MainView(mode: .edit(status: status))
|
||||
.withEnvironments()
|
||||
|
|
|
@ -135,6 +135,12 @@ extension IceCubesApp {
|
|||
appRouterPath.presentedSheet = .prefilledStatusEditor(text: postIntent.content ?? "",
|
||||
visibility: userPreferences.postVisibility)
|
||||
#endif
|
||||
} else if let tabIntent = appIntentService.handledIntent?.intent as? TabIntent {
|
||||
selectedTab = tabIntent.tab.toAppTab
|
||||
} else if let imageIntent = appIntentService.handledIntent?.intent as? PostPhotoIntent,
|
||||
let urls = imageIntent.images?.compactMap({ $0.fileURL }) {
|
||||
appRouterPath.presentedSheet = .imageURL(urls: urls,
|
||||
visibility: userPreferences.postVisibility)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import Explore
|
|||
import Foundation
|
||||
import StatusKit
|
||||
import SwiftUI
|
||||
import AppIntents
|
||||
|
||||
@MainActor
|
||||
enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable {
|
||||
|
|
|
@ -20513,6 +20513,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bookmarks" : {
|
||||
|
||||
},
|
||||
"conversations.action.delete" : {
|
||||
"comment" : "MARK: Package: Conversations",
|
||||
|
@ -26422,6 +26425,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Explore & Trending" : {
|
||||
|
||||
},
|
||||
"explore.navigation-title" : {
|
||||
"comment" : "MARK: Package: Explore",
|
||||
|
@ -28446,6 +28452,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Favorites" : {
|
||||
|
||||
},
|
||||
"Federated Timeline" : {
|
||||
|
||||
},
|
||||
"filter.action.hide" : {
|
||||
"extractionState" : "manual",
|
||||
|
@ -30708,6 +30720,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Followed Tags" : {
|
||||
|
||||
},
|
||||
"Home Timeline" : {
|
||||
|
||||
},
|
||||
"Image" : {
|
||||
|
||||
},
|
||||
"Image to post on Mastodon" : {
|
||||
|
||||
},
|
||||
"instance.info.domains" : {
|
||||
"comment" : "MARK: Instances",
|
||||
|
@ -32957,6 +32981,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Lists" : {
|
||||
|
||||
},
|
||||
"lists.add-remove-%@" : {
|
||||
"comment" : "MARK: Package: Lists",
|
||||
|
@ -33910,6 +33937,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Local Timeline" : {
|
||||
|
||||
},
|
||||
"Mentions" : {
|
||||
|
||||
},
|
||||
"menu.font" : {
|
||||
"localizations" : {
|
||||
|
@ -34619,6 +34652,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"New post" : {
|
||||
|
||||
},
|
||||
"Notifications" : {
|
||||
|
||||
},
|
||||
"notifications-others-count %lld" : {
|
||||
"extractionState" : "manual",
|
||||
|
@ -39700,6 +39739,15 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Open Ice Cubes" : {
|
||||
|
||||
},
|
||||
"Open on a tab" : {
|
||||
|
||||
},
|
||||
"Open the app on a specific tab" : {
|
||||
|
||||
},
|
||||
"placeholder.loading.long" : {
|
||||
"localizations" : {
|
||||
|
@ -39936,11 +39984,26 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Post a status" : {
|
||||
|
||||
},
|
||||
"Post an image to Mastodon" : {
|
||||
|
||||
},
|
||||
"Post content" : {
|
||||
|
||||
},
|
||||
"Post to Mastodon" : {
|
||||
"Post images" : {
|
||||
|
||||
},
|
||||
"Post status to Mastodon" : {
|
||||
|
||||
},
|
||||
"Private Messages" : {
|
||||
|
||||
},
|
||||
"Profile" : {
|
||||
|
||||
},
|
||||
"report.action.send" : {
|
||||
|
@ -40416,6 +40479,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Selected tab" : {
|
||||
|
||||
},
|
||||
"Settings" : {
|
||||
|
||||
},
|
||||
"settings.about.built-with" : {
|
||||
"localizations" : {
|
||||
|
@ -74591,6 +74660,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Tab" : {
|
||||
|
||||
},
|
||||
"tab.explore" : {
|
||||
"comment" : "MARK: Tabs",
|
||||
|
@ -80113,6 +80185,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Trending Links" : {
|
||||
|
||||
},
|
||||
"Trending Timeline" : {
|
||||
|
||||
},
|
||||
"trending-tag-people-talking %lld" : {
|
||||
"extractionState" : "manual",
|
||||
|
@ -80473,7 +80551,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Use Ice Cubes to post text to Mastodon" : {
|
||||
"Use Ice Cubes to post a status to Mastodon" : {
|
||||
|
||||
},
|
||||
"Use Ice Cubes to post a status with an image to Mastodon" : {
|
||||
|
||||
}
|
||||
},
|
||||
|
|
34
IceCubesAppIntents/AppShortcuts.swift
Normal file
34
IceCubesAppIntents/AppShortcuts.swift
Normal file
|
@ -0,0 +1,34 @@
|
|||
import AppIntents
|
||||
|
||||
struct AppShortcuts: AppShortcutsProvider {
|
||||
static var appShortcuts: [AppShortcut] {
|
||||
AppShortcut(
|
||||
intent: PostIntent(),
|
||||
phrases: [
|
||||
"Post \(\.$content) in \(.applicationName)",
|
||||
"Post a status on Mastodon with \(.applicationName)",
|
||||
"Write a status in \(.applicationName)",
|
||||
],
|
||||
shortTitle: "Post a status",
|
||||
systemImageName: "square.and.pencil"
|
||||
)
|
||||
AppShortcut(
|
||||
intent: TabIntent(),
|
||||
phrases: [
|
||||
"Open \(\.$tab) in \(.applicationName)",
|
||||
"Open \(.applicationName)",
|
||||
],
|
||||
shortTitle: "Open Ice Cubes",
|
||||
systemImageName: "cube"
|
||||
)
|
||||
AppShortcut(
|
||||
intent: PostPhotoIntent(),
|
||||
phrases: [
|
||||
"Post images \(\.$images) in \(.applicationName)",
|
||||
"Send photos \(\.$images) with \(.applicationName)",
|
||||
],
|
||||
shortTitle: "Post images",
|
||||
systemImageName: "photo"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@ import Foundation
|
|||
import AppIntents
|
||||
|
||||
struct PostIntent: AppIntent {
|
||||
static let title: LocalizedStringResource = "Post to Mastodon"
|
||||
static let title: LocalizedStringResource = "Post status to Mastodon"
|
||||
static var description: IntentDescription {
|
||||
get {
|
||||
"Use Ice Cubes to post text to Mastodon"
|
||||
"Use Ice Cubes to post a status to Mastodon"
|
||||
}
|
||||
}
|
||||
static let openAppWhenRun: Bool = true
|
||||
|
|
23
IceCubesAppIntents/PostPhotoIntent.swift
Normal file
23
IceCubesAppIntents/PostPhotoIntent.swift
Normal file
|
@ -0,0 +1,23 @@
|
|||
import Foundation
|
||||
import AppIntents
|
||||
|
||||
struct PostPhotoIntent: AppIntent {
|
||||
static let title: LocalizedStringResource = "Post an image to Mastodon"
|
||||
static var description: IntentDescription {
|
||||
get {
|
||||
"Use Ice Cubes to post a status with an image to Mastodon"
|
||||
}
|
||||
}
|
||||
static let openAppWhenRun: Bool = true
|
||||
|
||||
@Parameter(title: "Image",
|
||||
description: "Image to post on Mastodon",
|
||||
supportedTypeIdentifiers: ["public.image"],
|
||||
inputConnectionBehavior: .connectToPreviousIntentResult)
|
||||
var images: [IntentFile]?
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
AppIntentService.shared.handledIntent = .init(intent: self)
|
||||
return .result()
|
||||
}
|
||||
}
|
96
IceCubesAppIntents/TabIntent.swift
Normal file
96
IceCubesAppIntents/TabIntent.swift
Normal file
|
@ -0,0 +1,96 @@
|
|||
import Foundation
|
||||
import AppIntents
|
||||
|
||||
enum TabEnum: String, AppEnum, Sendable {
|
||||
case timeline, notifications, mentions, explore, messages, settings
|
||||
case trending, federated, local
|
||||
case profile
|
||||
case bookmarks
|
||||
case favorites
|
||||
case post
|
||||
case followedTags
|
||||
case lists
|
||||
case links
|
||||
|
||||
static var typeDisplayName: LocalizedStringResource {
|
||||
get { "Tab" }
|
||||
}
|
||||
|
||||
static let typeDisplayRepresentation: TypeDisplayRepresentation = "Tab"
|
||||
|
||||
nonisolated static var caseDisplayRepresentations: [TabEnum : DisplayRepresentation] {
|
||||
[.timeline: .init(title: "Home Timeline"),
|
||||
.trending: .init(title: "Trending Timeline"),
|
||||
.federated: .init(title: "Federated Timeline"),
|
||||
.local: .init(title: "Local Timeline"),
|
||||
.notifications: .init(title: "Notifications"),
|
||||
.mentions: .init(title: "Mentions"),
|
||||
.explore: .init(title: "Explore & Trending"),
|
||||
.messages: .init(title: "Private Messages"),
|
||||
.settings: .init(title: "Settings"),
|
||||
.profile: .init(title: "Profile"),
|
||||
.bookmarks: .init(title: "Bookmarks"),
|
||||
.favorites: .init(title: "Favorites"),
|
||||
.followedTags: .init(title: "Followed Tags"),
|
||||
.lists: .init(title: "Lists"),
|
||||
.links: .init(title: "Trending Links"),
|
||||
.post: .init(title: "New post"),
|
||||
]
|
||||
}
|
||||
|
||||
var toAppTab: Tab {
|
||||
switch self {
|
||||
case .timeline:
|
||||
.timeline
|
||||
case .notifications:
|
||||
.notifications
|
||||
case .mentions:
|
||||
.mentions
|
||||
case .explore:
|
||||
.explore
|
||||
case .messages:
|
||||
.messages
|
||||
case .settings:
|
||||
.settings
|
||||
case .trending:
|
||||
.trending
|
||||
case .federated:
|
||||
.federated
|
||||
case .local:
|
||||
.local
|
||||
case .profile:
|
||||
.profile
|
||||
case .bookmarks:
|
||||
.bookmarks
|
||||
case .favorites:
|
||||
.favorites
|
||||
case .post:
|
||||
.post
|
||||
case .followedTags:
|
||||
.followedTags
|
||||
case .lists:
|
||||
.lists
|
||||
case .links:
|
||||
.links
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TabIntent: AppIntent {
|
||||
static let title: LocalizedStringResource = "Open on a tab"
|
||||
static var description: IntentDescription {
|
||||
get {
|
||||
"Open the app on a specific tab"
|
||||
}
|
||||
}
|
||||
static let openAppWhenRun: Bool = true
|
||||
|
||||
@Parameter(title: "Selected tab")
|
||||
var tab: TabEnum
|
||||
|
||||
@MainActor
|
||||
func perform() async throws -> some IntentResult {
|
||||
AppIntentService.shared.handledIntent = .init(intent: self)
|
||||
return .result()
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ public enum SheetDestination: Identifiable, Hashable {
|
|||
|
||||
case newStatusEditor(visibility: Models.Visibility)
|
||||
case prefilledStatusEditor(text: String, visibility: Models.Visibility)
|
||||
case imageURL(urls: [URL], visibility: Models.Visibility)
|
||||
case editStatusEditor(status: Status)
|
||||
case replyToStatusEditor(status: Status)
|
||||
case quoteStatusEditor(status: Status)
|
||||
|
@ -80,7 +81,7 @@ public enum SheetDestination: Identifiable, Hashable {
|
|||
public var id: String {
|
||||
switch self {
|
||||
case .editStatusEditor, .newStatusEditor, .replyToStatusEditor, .quoteStatusEditor,
|
||||
.mentionStatusEditor, .quoteLinkStatusEditor, .prefilledStatusEditor:
|
||||
.mentionStatusEditor, .quoteLinkStatusEditor, .prefilledStatusEditor, .imageURL:
|
||||
"statusEditor"
|
||||
case .listCreate:
|
||||
"listCreate"
|
||||
|
|
|
@ -11,6 +11,7 @@ public extension StatusEditor.ViewModel {
|
|||
case quoteLink(link: URL)
|
||||
case mention(account: Account, visibility: Models.Visibility)
|
||||
case shareExtension(items: [NSItemProvider])
|
||||
case imageURL(urls: [URL], visibility: Models.Visibility)
|
||||
|
||||
var isInShareExtension: Bool {
|
||||
switch self {
|
||||
|
@ -41,7 +42,7 @@ public extension StatusEditor.ViewModel {
|
|||
|
||||
var title: LocalizedStringKey {
|
||||
switch self {
|
||||
case .new, .mention, .shareExtension, .quoteLink:
|
||||
case .new, .mention, .shareExtension, .quoteLink, .imageURL:
|
||||
"status.editor.mode.new"
|
||||
case .edit:
|
||||
"status.editor.mode.edit"
|
||||
|
|
|
@ -234,7 +234,7 @@ public extension StatusEditor {
|
|||
language: selectedLanguage,
|
||||
mediaAttributes: mediaAttributes)
|
||||
switch mode {
|
||||
case .new, .replyTo, .quote, .mention, .shareExtension, .quoteLink:
|
||||
case .new, .replyTo, .quote, .mention, .shareExtension, .quoteLink, .imageURL:
|
||||
postStatus = try await client.post(endpoint: Statuses.postStatus(json: data))
|
||||
if let postStatus {
|
||||
StreamWatcher.shared.emmitPostEvent(for: postStatus)
|
||||
|
@ -311,6 +311,13 @@ public extension StatusEditor {
|
|||
itemsProvider = items
|
||||
visibility = .pub
|
||||
processItemsProvider(items: items)
|
||||
case let .imageURL(urls, visibility):
|
||||
Task {
|
||||
for container in await Self.makeImageContainer(from: urls) {
|
||||
prepareToPost(for: container)
|
||||
}
|
||||
}
|
||||
self.visibility = visibility
|
||||
case let .replyTo(status):
|
||||
var mentionString = ""
|
||||
if (status.reblog?.account.acct ?? status.account.acct) != currentAccount?.acct {
|
||||
|
@ -739,6 +746,29 @@ public extension StatusEditor {
|
|||
error: nil
|
||||
)
|
||||
}
|
||||
|
||||
private static func makeImageContainer(from urls: [URL]) async -> [MediaContainer] {
|
||||
var containers: [MediaContainer] = []
|
||||
|
||||
for url in urls {
|
||||
let compressor = Compressor()
|
||||
|
||||
if let compressedData = await compressor.compressImageFrom(url: url),
|
||||
let image = UIImage(data: compressedData) {
|
||||
|
||||
containers.append(MediaContainer(
|
||||
id: UUID().uuidString,
|
||||
image: image,
|
||||
movieTransferable: nil,
|
||||
gifTransferable: nil,
|
||||
mediaAttachment: nil,
|
||||
error: nil
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return containers
|
||||
}
|
||||
|
||||
func upload(container: MediaContainer) async {
|
||||
if let index = indexOf(container: container) {
|
||||
|
|
Loading…
Reference in a new issue