228 lines
9.2 KiB
Swift
228 lines
9.2 KiB
Swift
import Library
|
|
import SwiftUI
|
|
|
|
#if os(macOS)
|
|
import AppKit
|
|
import ServiceManagement
|
|
#endif
|
|
|
|
public struct AppView: View {
|
|
@State private var isLoading = true
|
|
|
|
@State private var startAtLogin = false
|
|
@Environment(\.showMenuBarExtra) private var showMenuBarExtra
|
|
@State private var menuBarExtraInBackground = false
|
|
#if os(macOS)
|
|
|
|
@State private var rootHelperRegistrationStatus: SMAppService.Status = .notRegistered
|
|
|
|
#endif
|
|
|
|
@State private var alert: AlertState?
|
|
|
|
public init() {}
|
|
public var body: some View {
|
|
Group {
|
|
if isLoading {
|
|
ProgressView().onAppear {
|
|
Task {
|
|
await loadSettings()
|
|
}
|
|
}
|
|
} else {
|
|
FormView {
|
|
#if os(macOS)
|
|
FormToggle("Start At Login", "Launch the application when the system is logged in. If enabled at the same time as `Show in Menu Bar` and `Keep Menu Bar in Background`, the application interface will not be opened automatically.", $startAtLogin) { newValue in
|
|
updateLoginItems(newValue)
|
|
}
|
|
|
|
Toggle("Show in Menu Bar", isOn: showMenuBarExtra)
|
|
.onChangeCompat(of: showMenuBarExtra.wrappedValue) { newValue in
|
|
Task {
|
|
await SharedPreferences.showMenuBarExtra.set(newValue)
|
|
if !newValue {
|
|
menuBarExtraInBackground = false
|
|
}
|
|
}
|
|
}
|
|
|
|
if showMenuBarExtra.wrappedValue {
|
|
Toggle("Keep Menu Bar in Background", isOn: $menuBarExtraInBackground)
|
|
.onChangeCompat(of: menuBarExtraInBackground) { newValue in
|
|
Task {
|
|
await SharedPreferences.menuBarExtraInBackground.set(newValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
if Variant.useSystemExtension {
|
|
Section("System Extension") {
|
|
FormButton {
|
|
Task {
|
|
await updateSystemExtension()
|
|
}
|
|
} label: {
|
|
Label("Update", systemImage: "arrow.down.doc.fill")
|
|
}
|
|
FormButton(role: .destructive) {
|
|
Task {
|
|
await uninstallSystemExtension()
|
|
}
|
|
} label: {
|
|
Label("Uninstall", systemImage: "trash.fill").foregroundColor(.red)
|
|
}
|
|
}
|
|
|
|
Section {
|
|
if rootHelperRegistrationStatus == .enabled {
|
|
FormButton {
|
|
performHelperAction {
|
|
try HelperServiceManager.unregisterRootHelper()
|
|
try HelperServiceManager.registerRootHelper()
|
|
}
|
|
} label: {
|
|
Label("Update", systemImage: "arrow.down.doc.fill")
|
|
}
|
|
FormButton(role: .destructive) {
|
|
performHelperAction {
|
|
try HelperServiceManager.unregisterRootHelper()
|
|
}
|
|
} label: {
|
|
Label("Uninstall", systemImage: "trash.fill").foregroundColor(.red)
|
|
}
|
|
} else if rootHelperRegistrationStatus == .requiresApproval {
|
|
FormButton {
|
|
openHelperSettings()
|
|
} label: {
|
|
Label("Enable", systemImage: "switch.2")
|
|
}
|
|
} else {
|
|
FormButton {
|
|
performHelperAction {
|
|
try HelperServiceManager.registerRootHelper()
|
|
}
|
|
} label: {
|
|
Label("Install", systemImage: "square.and.arrow.down.fill")
|
|
}
|
|
}
|
|
} header: {
|
|
VStack(alignment: .leading, spacing: 4) {
|
|
Text("Helper Service")
|
|
Text("This helper service provides process lookup for `process_name` and `process_path` routing rules, and manages the working directory.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
.textCase(nil)
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
.alert($alert)
|
|
.navigationTitle("App")
|
|
#if os(iOS)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
#endif
|
|
}
|
|
|
|
private func loadSettings() async {
|
|
#if os(macOS)
|
|
startAtLogin = SMAppService.mainApp.status == .enabled
|
|
menuBarExtraInBackground = await SharedPreferences.menuBarExtraInBackground.get()
|
|
if Variant.useSystemExtension {
|
|
refreshHelperStatus()
|
|
}
|
|
#endif
|
|
isLoading = false
|
|
}
|
|
|
|
#if os(macOS)
|
|
|
|
private func updateLoginItems(_ startAtLogin: Bool) {
|
|
do {
|
|
if startAtLogin {
|
|
if SMAppService.mainApp.status == .enabled {
|
|
try? SMAppService.mainApp.unregister()
|
|
}
|
|
|
|
try SMAppService.mainApp.register()
|
|
} else {
|
|
try SMAppService.mainApp.unregister()
|
|
}
|
|
} catch {
|
|
alert = AlertState(error: error)
|
|
}
|
|
}
|
|
|
|
private func updateSystemExtension() async {
|
|
do {
|
|
if let result = try await SystemExtension.install(forceUpdate: true) {
|
|
switch result {
|
|
case .completed:
|
|
alert = AlertState(
|
|
title: String(localized: "Update"),
|
|
message: String(localized: "System Extension updated.")
|
|
)
|
|
case .willCompleteAfterReboot:
|
|
alert = AlertState(
|
|
title: String(localized: "Update"),
|
|
message: String(localized: "Reboot required.")
|
|
)
|
|
}
|
|
}
|
|
} catch {
|
|
alert = AlertState(error: error)
|
|
}
|
|
}
|
|
|
|
private func uninstallSystemExtension() async {
|
|
do {
|
|
if let result = try await SystemExtension.uninstall() {
|
|
switch result {
|
|
case .completed:
|
|
alert = AlertState(
|
|
title: String(localized: "Uninstall"),
|
|
message: String(localized: "System Extension removed.")
|
|
)
|
|
case .willCompleteAfterReboot:
|
|
alert = AlertState(
|
|
title: String(localized: "Uninstall"),
|
|
message: String(localized: "Reboot required.")
|
|
)
|
|
}
|
|
}
|
|
} catch {
|
|
alert = AlertState(error: error)
|
|
}
|
|
}
|
|
|
|
private func performHelperAction(_ action: () throws -> Void) {
|
|
do {
|
|
try action()
|
|
refreshHelperStatus()
|
|
} catch {
|
|
alert = AlertState(error: error)
|
|
}
|
|
}
|
|
|
|
private func refreshHelperStatus() {
|
|
rootHelperRegistrationStatus = HelperServiceManager.rootHelperStatus
|
|
}
|
|
|
|
private func openHelperSettings() {
|
|
if #available(macOS 13.0, *) {
|
|
SMAppService.openSystemSettingsLoginItems()
|
|
return
|
|
}
|
|
if let url = URL(string: "x-apple.systempreferences:com.apple.preference.users?LoginItems"),
|
|
NSWorkspace.shared.open(url)
|
|
{
|
|
return
|
|
}
|
|
NSWorkspace.shared.open(URL(fileURLWithPath: "/System/Applications/System Preferences.app"))
|
|
}
|
|
|
|
#endif
|
|
}
|