|
1 | 1 | import SwiftUI |
2 | | -import AppKit |
3 | 2 |
|
4 | 3 | import Libipf |
5 | 4 |
|
6 | | -class GlobalState: ObservableObject { |
7 | | - @Published var items: [ForwardedItem] = [] |
8 | | - @Published var errors: [Int8: [IpfError]] = [:] |
9 | | - @Published var isAddingNewItem: Bool = false |
10 | | - |
11 | | - public func clear() { |
12 | | - items = [] |
13 | | - errors = [:] |
14 | | - isAddingNewItem = false |
15 | | - } |
16 | | -} |
17 | | - |
18 | | -var globalState = GlobalState() |
19 | | - |
20 | | -// Disable tab |
21 | | -final class AppDelegate: NSObject, NSApplicationDelegate { |
22 | | - func applicationDidFinishLaunching(_ notification: Notification) { |
23 | | - NSWindow.allowsAutomaticWindowTabbing = false |
24 | | - } |
25 | | -} |
26 | | - |
27 | | -struct WindowAccessor: NSViewRepresentable { |
28 | | - @Binding var window: NSWindow? |
29 | | - |
30 | | - func makeNSView(context: Context) -> NSView { |
31 | | - let view = NSView() |
32 | | - DispatchQueue.main.async { |
33 | | - self.window = view.window |
34 | | - } |
35 | | - return view |
36 | | - } |
37 | | - |
38 | | - func updateNSView(_ nsView: NSView, context: Context) {} |
39 | | -} |
40 | | - |
41 | 5 | @main |
42 | 6 | struct iPortForwarderApp: App { |
43 | | - @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate |
44 | | - |
45 | | - @State private var window: NSWindow? |
46 | | - @State private var isMainWindowOpened = false |
47 | | - |
48 | 7 | init() { |
49 | | - try! Libipf.registerErrorHandler { id, ipfError in |
50 | | - DispatchQueue.main.async { |
51 | | - if var errors = globalState.errors[id] { |
52 | | - errors.append(ipfError) |
53 | | - } else { |
54 | | - globalState.errors[id] = [ipfError] |
55 | | - } |
56 | | - } |
57 | | - } |
| 8 | + initLibipfErrorHandler() |
58 | 9 | } |
59 | 10 |
|
60 | 11 | var body: some Scene { |
61 | 12 | WindowGroup { |
62 | 13 | ContentView() |
63 | | - .background(WindowAccessor(window: $window)) |
64 | 14 | .environmentObject(globalState) |
65 | | - .onAppear { |
66 | | - isMainWindowOpened = true |
67 | | - } |
68 | 15 | .onDisappear { |
69 | | - isMainWindowOpened = false |
70 | 16 | globalState.clear() |
71 | 17 | } |
72 | 18 | } |
73 | 19 | .commands { |
74 | | - CommandGroup(replacing: .newItem) { |
75 | | - if isMainWindowOpened { |
76 | | - Button("New Forward Item") { |
77 | | - withAnimation { |
78 | | - globalState.isAddingNewItem = true |
79 | | - } |
80 | | - } |
81 | | - .keyboardShortcut("n", modifiers: .command) |
82 | | - } |
83 | | - } |
84 | | - |
85 | | - CommandGroup(replacing: .saveItem) { |
86 | | - if isMainWindowOpened { |
87 | | - Button("Save Current Forwarding List") { |
88 | | - let listOfItemInfo = globalState.items.map { |
89 | | - ForwardedItemInfo(item: $0) |
90 | | - } |
91 | | - let jsonData = try! JSONEncoder().encode(listOfItemInfo) |
92 | | - let jsonString = String(data: jsonData, encoding: .utf8)! |
93 | | - |
94 | | - let savePanel = NSSavePanel() |
95 | | - savePanel.allowedContentTypes = [.json] |
96 | | - savePanel.canCreateDirectories = true |
97 | | - savePanel.isExtensionHidden = false |
98 | | - savePanel.title = "Save current forwarding list" |
99 | | - savePanel.message = "Choose a folder and a name to store the list." |
100 | | - savePanel.nameFieldLabel = "List name:" |
101 | | - savePanel.beginSheetModal(for: window!) { |
102 | | - if $0 == .OK { |
103 | | - if let saveUrl = savePanel.url { |
104 | | - do { |
105 | | - try jsonString.write(to: saveUrl, atomically: false, encoding: .utf8) |
106 | | - } catch { |
107 | | - showErrorDialog(error) |
108 | | - } |
109 | | - } |
110 | | - } |
111 | | - } |
112 | | - } |
113 | | - .keyboardShortcut("s", modifiers: .command) |
114 | | - } |
115 | | - } |
116 | | - |
117 | | - CommandGroup(after: .saveItem) { |
118 | | - if isMainWindowOpened { |
119 | | - Button("Import Forwarding List") { |
120 | | - let openPanel = NSOpenPanel() |
121 | | - openPanel.allowsMultipleSelection = false |
122 | | - openPanel.allowedContentTypes = [.json] |
123 | | - openPanel.allowsOtherFileTypes = false |
124 | | - openPanel.canChooseFiles = true |
125 | | - openPanel.canChooseDirectories = false |
126 | | - openPanel.canCreateDirectories = false |
127 | | - openPanel.isExtensionHidden = false |
128 | | - openPanel.title = "Import a forwarding list" |
129 | | - openPanel.message = "Choose a forwarding list to import." |
130 | | - openPanel.beginSheetModal(for: window!) { |
131 | | - if $0 == .OK { |
132 | | - if let openUrl = openPanel.url { |
133 | | - do { |
134 | | - var jsonString: String |
135 | | - if #available(macOS 13, *) { |
136 | | - jsonString = try String(contentsOfFile: openUrl.path(percentEncoded: false)) |
137 | | - } else { |
138 | | - jsonString = try String(contentsOfFile: openUrl.path) |
139 | | - } |
140 | | - |
141 | | - let list = try JSONDecoder().decode([ForwardedItemInfo].self, from: jsonString.data(using: .utf8)!) |
142 | | - |
143 | | - try withAnimation { |
144 | | - for item in list { |
145 | | - globalState.items.append(try ForwardedItem(item: item)) |
146 | | - } |
147 | | - } |
148 | | - } catch { |
149 | | - showErrorDialog(error) |
150 | | - } |
151 | | - } |
152 | | - } |
153 | | - } |
154 | | - } |
155 | | - .keyboardShortcut("o", modifiers: .command) |
156 | | - } |
157 | | - } |
| 20 | + iPortForwarderCommands() |
158 | 21 | } |
159 | 22 | } |
160 | 23 | } |
0 commit comments