import AppKit import ApplicationLibrary import Libbox import Library import SwiftUI @MainActor public class MainViewModel: BaseViewModel { @Published public var selection: NavigationPage @Published public var importProfile: LibboxProfileContent? @Published public var importRemoteProfile: LibboxImportRemoteProfile? public init(selection: NavigationPage = .dashboard) { self.selection = selection super.init() } public func onAppear(environments: ExtensionEnvironments) { environments.postReload() #if !DEBUG if Variant.useSystemExtension { checkApplicationPath() } #endif } public func onControlActiveStateChange(_ newValue: ControlActiveState, environments: ExtensionEnvironments) { if newValue != .inactive { environments.postReload() } } public func onSelectionChange(_ newValue: NavigationPage, environments: ExtensionEnvironments) { if newValue == .logs { environments.connect() } } public func openSettings() { selection = .settings } public func openURL(_ url: URL) { if url.host == "import-remote-profile" { var error: NSError? importRemoteProfile = LibboxParseRemoteProfileImportLink(url.absoluteString, &error) if let error { alert = AlertState(error: error) } } else if url.pathExtension == "bpf" { Task { await importURLProfile(url) } } else { alert = AlertState(errorMessage: String(localized: "Handled unknown URL \(url.absoluteString)")) } } private func importURLProfile(_ url: URL) async { do { importProfile = try await url.withSecurityScopedAccess { try await .from(readURL(url)) } } catch { alert = AlertState(error: error) } } private nonisolated func readURL(_ url: URL) async throws -> Data { try Data(contentsOf: url) } private func checkApplicationPath() { let directoryName = URL(filePath: Bundle.main.bundlePath).deletingLastPathComponent().pathComponents.last if directoryName != "Applications" { alert = AlertState( title: String(localized: "Wrong application location"), message: String(localized: "This app needs to be placed under the Applications folder to work."), primaryButton: .default(String(localized: "Move to Applications")) { [self] in moveToApplications() }, secondaryButton: .cancel(String(localized: "Quit")) { NSWorkspace.shared.selectFile(Bundle.main.bundlePath, inFileViewerRootedAtPath: "") NSApp.terminate(nil) } ) } } private func moveToApplications() { let source = Bundle.main.bundlePath let appName = URL(filePath: source).lastPathComponent let dest = "/Applications/\(appName)" let script = """ do shell script "rm -rf '\(dest)'; mv '\(source)' '\(dest)'" with administrator privileges """ var error: NSDictionary? guard let appleScript = NSAppleScript(source: script) else { return } appleScript.executeAndReturnError(&error) if let error { let msg = error[NSAppleScript.errorMessage] as? String ?? "Unknown error" alert = AlertState(errorMessage: msg) return } let url = URL(filePath: dest) NSWorkspace.shared.openApplication(at: url, configuration: .init()) NSApp.terminate(nil) } }