Add App Shortcuts and improve IntentsExtension
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"sourceLanguage" : "en",
|
||||||
|
"strings" : {
|
||||||
|
"Start ${applicationName}" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "启动 ${applicationName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Stop ${applicationName}" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "停止 ${applicationName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Restart ${applicationName}" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "重启 ${applicationName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Toggle ${applicationName}" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "开关 ${applicationName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Update ${applicationName} profile" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "更新 ${applicationName} 配置"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version" : "1.0"
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ struct StartServiceIntent: AppIntent {
|
|||||||
@Parameter(title: "Profile", optionsProvider: ProfileProvider())
|
@Parameter(title: "Profile", optionsProvider: ProfileProvider())
|
||||||
var profile: String
|
var profile: String
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult {
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
||||||
throw NSError(domain: "NetworkExtension not installed", code: 0)
|
throw NSError(domain: "NetworkExtension not installed", code: 0)
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ struct StartServiceIntent: AppIntent {
|
|||||||
}
|
}
|
||||||
if extensionProfile.status == .connected {
|
if extensionProfile.status == .connected {
|
||||||
if !profileChanged {
|
if !profileChanged {
|
||||||
return .result()
|
return .result(dialog: "Service is already running")
|
||||||
}
|
}
|
||||||
try LibboxNewStandaloneCommandClient()!.serviceReload()
|
try LibboxNewStandaloneCommandClient()!.serviceReload()
|
||||||
} else if extensionProfile.status.isConnected {
|
} else if extensionProfile.status.isConnected {
|
||||||
@@ -42,7 +42,7 @@ struct StartServiceIntent: AppIntent {
|
|||||||
} else {
|
} else {
|
||||||
try await extensionProfile.start()
|
try await extensionProfile.start()
|
||||||
}
|
}
|
||||||
return .result()
|
return .result(dialog: "Service started")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,9 +56,9 @@ struct RestartServiceIntent: AppIntent {
|
|||||||
Summary("Restart sing-box service")
|
Summary("Restart sing-box service")
|
||||||
}
|
}
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult {
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
||||||
return .result()
|
return .result(dialog: "Service is not installed")
|
||||||
}
|
}
|
||||||
if extensionProfile.status == .connected {
|
if extensionProfile.status == .connected {
|
||||||
try LibboxNewStandaloneCommandClient()!.serviceReload()
|
try LibboxNewStandaloneCommandClient()!.serviceReload()
|
||||||
@@ -67,7 +67,7 @@ struct RestartServiceIntent: AppIntent {
|
|||||||
} else {
|
} else {
|
||||||
try await extensionProfile.start()
|
try await extensionProfile.start()
|
||||||
}
|
}
|
||||||
return .result()
|
return .result(dialog: "Service restarted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +81,12 @@ struct StopServiceIntent: AppIntent {
|
|||||||
Summary("Stop sing-box service")
|
Summary("Stop sing-box service")
|
||||||
}
|
}
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult {
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
guard let extensionProfile = try await (ExtensionProfile.load()) else {
|
||||||
return .result()
|
return .result(dialog: "Service is not installed")
|
||||||
}
|
}
|
||||||
try await extensionProfile.stop()
|
try await extensionProfile.stop()
|
||||||
return .result()
|
return .result(dialog: "Service stopped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ struct UpdateProfileIntent: AppIntent {
|
|||||||
var profile: String
|
var profile: String
|
||||||
|
|
||||||
init() {}
|
init() {}
|
||||||
func perform() async throws -> some IntentResult {
|
func perform() async throws -> some IntentResult & ProvidesDialog {
|
||||||
guard let profile = try await ProfileManager.get(by: profile) else {
|
guard let profile = try await ProfileManager.get(by: profile) else {
|
||||||
throw NSError(domain: "Specified profile not found: \(profile)", code: 0)
|
throw NSError(domain: "Specified profile not found: \(profile)", code: 0)
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ struct UpdateProfileIntent: AppIntent {
|
|||||||
throw NSError(domain: "Specified profile is not a remote profile", code: 0)
|
throw NSError(domain: "Specified profile is not a remote profile", code: 0)
|
||||||
}
|
}
|
||||||
try await profile.updateRemoteProfile()
|
try await profile.updateRemoteProfile()
|
||||||
return .result()
|
return .result(dialog: "Profile updated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,3 +192,38 @@ class RemoteProfileProvider: DynamicOptionsProvider {
|
|||||||
try await ProfileManager.listRemote().map(\.name)
|
try await ProfileManager.listRemote().map(\.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ServiceShortcuts: AppShortcutsProvider {
|
||||||
|
static var appShortcuts: [AppShortcut] {
|
||||||
|
AppShortcut(
|
||||||
|
intent: StartServiceIntent(),
|
||||||
|
phrases: ["Start \(.applicationName)"],
|
||||||
|
shortTitle: "Start",
|
||||||
|
systemImageName: "power"
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: StopServiceIntent(),
|
||||||
|
phrases: ["Stop \(.applicationName)"],
|
||||||
|
shortTitle: "Stop",
|
||||||
|
systemImageName: "stop.fill"
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: RestartServiceIntent(),
|
||||||
|
phrases: ["Restart \(.applicationName)"],
|
||||||
|
shortTitle: "Restart",
|
||||||
|
systemImageName: "arrow.clockwise"
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: ToggleServiceIntent(),
|
||||||
|
phrases: ["Toggle \(.applicationName)"],
|
||||||
|
shortTitle: "Toggle",
|
||||||
|
systemImageName: "arrow.triangle.2.circlepath"
|
||||||
|
)
|
||||||
|
AppShortcut(
|
||||||
|
intent: UpdateProfileIntent(),
|
||||||
|
phrases: ["Update \(.applicationName) profile"],
|
||||||
|
shortTitle: "Update Profile",
|
||||||
|
systemImageName: "arrow.down.circle"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct ServiceToggleControl: ControlWidget {
|
|||||||
action: ToggleServiceIntent()
|
action: ToggleServiceIntent()
|
||||||
) { isOn in
|
) { isOn in
|
||||||
Label(isOn ? "Running" : "Stopped", systemImage: "shippingbox.fill")
|
Label(isOn ? "Running" : "Stopped", systemImage: "shippingbox.fill")
|
||||||
|
.controlWidgetActionHint(isOn ? "Stop" : "Start")
|
||||||
}
|
}
|
||||||
.tint(.init(red: CGFloat(Double(69) / 255), green: CGFloat(Double(90) / 255), blue: CGFloat(Double(100) / 255)))
|
.tint(.init(red: CGFloat(Double(69) / 255), green: CGFloat(Double(90) / 255), blue: CGFloat(Double(100) / 255)))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user