Prepare airdrop support
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "apple-16 1x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-16 2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "16x16"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-32 1x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-32 2x 1.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "32x32"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-128 1x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-128 2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "128x128"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-256 1x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-256 2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "256x256"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-512 1x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "1x",
|
||||
"size" : "512x512"
|
||||
},
|
||||
{
|
||||
"filename" : "apple-512 2x.png",
|
||||
"idiom" : "mac",
|
||||
"scale" : "2x",
|
||||
"size" : "512x512"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 278 KiB |
|
After Width: | Height: | Size: 286 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 286 KiB |
|
After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 272 KiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 340 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public struct MacApplication: Scene {
|
||||
MainView()
|
||||
.onAppear {
|
||||
Task.detached {
|
||||
await initialize()
|
||||
initialize()
|
||||
}
|
||||
}
|
||||
.environment(\.showMenuBarExtra, $showMenuBarExtra)
|
||||
@@ -35,9 +35,9 @@ public struct MacApplication: Scene {
|
||||
SidebarCommands()
|
||||
}
|
||||
|
||||
Window("New Profile", id: NewProfileView.windowID) {
|
||||
NewProfileView()
|
||||
}
|
||||
WindowGroup("New Profile", id: NewProfileView.windowID, for: NewProfileView.ImportRequest.self) { importRequest in
|
||||
NewProfileView(importRequest.wrappedValue)
|
||||
}.commandsRemoved()
|
||||
|
||||
WindowGroup("Edit Profile", id: EditProfileWindowView.windowID, for: Int64.self) { profileID in
|
||||
EditProfileWindowView(profileID.wrappedValue)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ApplicationLibrary
|
||||
import Libbox
|
||||
import Library
|
||||
import SwiftUI
|
||||
|
||||
@@ -9,11 +10,8 @@ public struct MainView: View {
|
||||
@State private var extensionProfile: ExtensionProfile?
|
||||
@State private var profileLoading = true
|
||||
@State private var logClient: LogClient!
|
||||
|
||||
@State private var dialogTitle = ""
|
||||
@State private var dialogContent = ""
|
||||
@State private var dialogAction: (() -> Void)?
|
||||
@State private var dialogPresented = false
|
||||
@State private var alert: Alert?
|
||||
@State private var importRemoteProfile: LibboxImportRemoteProfile?
|
||||
|
||||
public init() {}
|
||||
public var body: some View {
|
||||
@@ -44,19 +42,10 @@ public struct MainView: View {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
.alert(isPresented: $dialogPresented, content: {
|
||||
Alert(
|
||||
title: Text(dialogTitle),
|
||||
message: Text(dialogContent),
|
||||
dismissButton: .default(Text("Ok"), action: dialogAction)
|
||||
)
|
||||
})
|
||||
.alertBinding($alert)
|
||||
.onAppear {
|
||||
ServiceNotification.setServiceNotificationListener { notification in
|
||||
dialogTitle = notification.title
|
||||
dialogContent = notification.body
|
||||
dialogAction = nil
|
||||
dialogPresented = true
|
||||
alert = Alert(title: Text(notification.title), message: Text(notification.body))
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
@@ -84,6 +73,22 @@ public struct MainView: View {
|
||||
.environment(\.selection, $selection)
|
||||
.environment(\.extensionProfile, $extensionProfile)
|
||||
.environment(\.logClient, $logClient)
|
||||
.environment(\.importRemoteProfile, $importRemoteProfile)
|
||||
.handlesExternalEvents(preferring: [], allowing: ["*"])
|
||||
.onOpenURL(perform: openURL)
|
||||
}
|
||||
|
||||
private func openURL(url: URL) {
|
||||
if url.host == "import-remote-profile" {
|
||||
var error: NSError?
|
||||
importRemoteProfile = LibboxParseRemoteProfileImportLink(url.absoluteString, &error)
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
if selection != .profiles {
|
||||
selection = .profiles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadProfile() async {
|
||||
@@ -115,13 +120,14 @@ public struct MainView: View {
|
||||
private func checkApplicationPath() {
|
||||
let directoryName = URL(filePath: Bundle.main.bundlePath).deletingLastPathComponent().pathComponents.last
|
||||
if directoryName != "Applications" {
|
||||
dialogTitle = "Wrong application location"
|
||||
dialogContent = "This app needs to be placed under ~/Applications to work."
|
||||
dialogAction = {
|
||||
NSWorkspace.shared.selectFile(Bundle.main.bundlePath, inFileViewerRootedAtPath: "")
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
dialogPresented = true
|
||||
alert = Alert(
|
||||
title: Text("Wrong application location"),
|
||||
message: Text("This app needs to be placed under ~/Applications to work."),
|
||||
dismissButton: .default(Text("Ok")) {
|
||||
NSWorkspace.shared.selectFile(Bundle.main.bundlePath, inFileViewerRootedAtPath: "")
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +71,7 @@ public struct MenuView: View {
|
||||
|
||||
private struct StatusSwitch: View {
|
||||
@ObservedObject private var profile: ExtensionProfile
|
||||
@State private var errorPresented = false
|
||||
@State private var errorMessage = ""
|
||||
@State private var alert: Alert?
|
||||
|
||||
init(_ profile: ExtensionProfile) {
|
||||
self.profile = profile
|
||||
@@ -88,13 +87,7 @@ public struct MenuView: View {
|
||||
})) {}
|
||||
.toggleStyle(.switch)
|
||||
.disabled(!profile.status.isEnabled)
|
||||
.alert(isPresented: $errorPresented) {
|
||||
Alert(
|
||||
title: Text("Error"),
|
||||
message: Text(errorMessage),
|
||||
dismissButton: .default(Text("Ok"))
|
||||
)
|
||||
}
|
||||
.alertBinding($alert)
|
||||
}
|
||||
|
||||
private func switchProfile(_ isEnabled: Bool) async {
|
||||
@@ -105,8 +98,7 @@ public struct MenuView: View {
|
||||
profile.stop()
|
||||
}
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
errorPresented = true
|
||||
alert = Alert(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -123,10 +115,8 @@ public struct MenuView: View {
|
||||
@State private var profileList: [Profile] = []
|
||||
@State private var selectedProfileID: Int64!
|
||||
@State private var reasserting = false
|
||||
|
||||
@State private var errorPresented = false
|
||||
@State private var errorMessage = ""
|
||||
@State private var observer: Any?
|
||||
@State private var alert: Alert?
|
||||
|
||||
var body: some View {
|
||||
viewBuilder {
|
||||
@@ -169,13 +159,7 @@ public struct MenuView: View {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $errorPresented) {
|
||||
Alert(
|
||||
title: Text("Error"),
|
||||
message: Text(errorMessage),
|
||||
dismissButton: .default(Text("Ok"))
|
||||
)
|
||||
}
|
||||
.alertBinding($alert)
|
||||
}
|
||||
|
||||
private func doReload() {
|
||||
@@ -185,8 +169,7 @@ public struct MenuView: View {
|
||||
do {
|
||||
profileList = try ProfileManager.list()
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
errorPresented = true
|
||||
alert = Alert(error)
|
||||
return
|
||||
}
|
||||
if profileList.isEmpty {
|
||||
@@ -210,8 +193,7 @@ public struct MenuView: View {
|
||||
do {
|
||||
try LibboxNewStandaloneCommandClient(FilePath.sharedDirectory.relativePath)?.serviceReload()
|
||||
} catch {
|
||||
errorMessage = error.localizedDescription
|
||||
errorPresented = true
|
||||
alert = Alert(error)
|
||||
}
|
||||
}
|
||||
reasserting = false
|
||||
|
||||