diff --git a/ApplicationLibrary/Views/Abstract/Alert.swift b/ApplicationLibrary/Views/Abstract/Alert.swift new file mode 100644 index 0000000..02a4bd9 --- /dev/null +++ b/ApplicationLibrary/Views/Abstract/Alert.swift @@ -0,0 +1,47 @@ +import Foundation +import SwiftUI + +public extension Alert { + init(_ error: Error, _ dismissAction: (() -> Void)? = nil) { + self.init( + errorMessage: error.localizedDescription, + dismissAction + ) + } + + init(errorMessage: String, _ dismissAction: (() -> Void)? = nil) { + self.init( + title: Text("Error"), + message: Text(errorMessage), + dismissButton: .default(Text("Ok")) { + dismissAction?() + } + ) + } +} + +public extension View { + func alertBinding(_ binding: Binding) -> some View { + alert(isPresented: Binding(get: { + binding.wrappedValue != nil + }, set: { newValue, _ in + if !newValue { + binding.wrappedValue = nil + } + })) { + binding.wrappedValue! + } + } + + func alertBinding(_ binding: Binding, _ isLoading: Binding) -> some View { + alert(isPresented: Binding(get: { + binding.wrappedValue != nil + }, set: { newValue, _ in + if !newValue, !isLoading.wrappedValue { + binding.wrappedValue = nil + } + })) { + binding.wrappedValue! + } + } +} diff --git a/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift b/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift index 0624df0..531c934 100644 --- a/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift +++ b/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift @@ -16,9 +16,7 @@ public struct ActiveDashboardView: View { @State private var selectedProfileID: Int64! @State private var reasserting = false @State private var observer: Any? - - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? public init() {} @@ -78,43 +76,37 @@ public struct ActiveDashboardView: View { } } } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) #if os(iOS) - .onChange(of: scenePhase, perform: { newValue in - if newValue == .active { - Task.detached { - await doReload() - } - } - }) - .onChange(of: selection.wrappedValue, perform: { newValue in - if newValue == .dashboard { - Task.detached { - await doReload() - } - } - }) - #elseif os(macOS) - .onAppear { - if observer == nil { - observer = NotificationCenter.default.addObserver(forName: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { _ in + .onChange(of: scenePhase, perform: { newValue in + if newValue == .active { Task.detached { await doReload() } - }) + } + }) + .onChange(of: selection.wrappedValue, perform: { newValue in + if newValue == .dashboard { + Task.detached { + await doReload() + } + } + }) + #elseif os(macOS) + .onAppear { + if observer == nil { + observer = NotificationCenter.default.addObserver(forName: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { _ in + Task.detached { + await doReload() + } + }) + } } - } - .onDisappear { - if let observer { - NotificationCenter.default.removeObserver(observer) + .onDisappear { + if let observer { + NotificationCenter.default.removeObserver(observer) + } } - } #endif } @@ -132,8 +124,7 @@ public struct ActiveDashboardView: View { do { profileList = try ProfileManager.list() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } if profileList.isEmpty { @@ -158,8 +149,7 @@ public struct ActiveDashboardView: View { do { try LibboxNewStandaloneCommandClient(FilePath.sharedDirectory.relativePath)?.serviceReload() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } reasserting = false diff --git a/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift b/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift index 413ac79..fb5738b 100644 --- a/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift +++ b/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift @@ -7,8 +7,7 @@ public struct ExtensionStatusView: View { @State private var message: LibboxStatusMessage? @State private var connectTask: Task? @State private var columnCount: Int = 4 - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? private let infoFont = Font.system(.caption, design: .monospaced) @@ -67,13 +66,7 @@ public struct ExtensionStatusView: View { } commandClient = nil } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) } private func doReload() { @@ -125,8 +118,7 @@ public struct ExtensionStatusView: View { do { try LibboxNewStandaloneCommandClient(FilePath.sharedDirectory.relativePath)?.closeConnections() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } diff --git a/ApplicationLibrary/Views/Dashboard/InstallProfileButton.swift b/ApplicationLibrary/Views/Dashboard/InstallProfileButton.swift index 15bb915..e32952e 100644 --- a/ApplicationLibrary/Views/Dashboard/InstallProfileButton.swift +++ b/ApplicationLibrary/Views/Dashboard/InstallProfileButton.swift @@ -4,8 +4,7 @@ import SwiftUI public struct InstallProfileButton: View { @Environment(\.extensionProfile) private var extensionProfile - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? public init() {} @@ -15,21 +14,14 @@ public struct InstallProfileButton: View { await installProfile() } } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) } private func installProfile() async { do { try await ExtensionProfile.install() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } } diff --git a/ApplicationLibrary/Views/Dashboard/InstallSystemExtensionButton.swift b/ApplicationLibrary/Views/Dashboard/InstallSystemExtensionButton.swift index 9dc4bd7..75f6987 100644 --- a/ApplicationLibrary/Views/Dashboard/InstallSystemExtensionButton.swift +++ b/ApplicationLibrary/Views/Dashboard/InstallSystemExtensionButton.swift @@ -4,8 +4,7 @@ import SwiftUI public struct InstallSystemExtensionButton: View { - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? private let callback: () -> Void public init(_ callback: @escaping () -> Void) { self.callback = callback @@ -17,27 +16,19 @@ await installSystemExtension() } } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) } private func installSystemExtension() async { do { if let result = try await SystemExtension.install() { if result == .willCompleteAfterReboot { - errorMessage = "Need reboot" - errorPresented = true + alert = Alert(errorMessage: "Need Reboot") } } callback() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } } diff --git a/ApplicationLibrary/Views/Dashboard/StartStopButton.swift b/ApplicationLibrary/Views/Dashboard/StartStopButton.swift index 978d3a1..b6d792b 100644 --- a/ApplicationLibrary/Views/Dashboard/StartStopButton.swift +++ b/ApplicationLibrary/Views/Dashboard/StartStopButton.swift @@ -41,8 +41,7 @@ public struct StartStopButton: View { private struct Button0: View { @Environment(\.logClient) private var logClient @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 @@ -75,13 +74,7 @@ public struct StartStopButton: View { #endif } .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 { @@ -93,8 +86,7 @@ public struct StartStopButton: View { profile.stop() } } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } } diff --git a/ApplicationLibrary/Views/EnvironmentValues.swift b/ApplicationLibrary/Views/EnvironmentValues.swift index 19e8374..54e3970 100644 --- a/ApplicationLibrary/Views/EnvironmentValues.swift +++ b/ApplicationLibrary/Views/EnvironmentValues.swift @@ -1,4 +1,5 @@ import Foundation +import Libbox import Library import SwiftUI @@ -54,4 +55,17 @@ public extension EnvironmentValues { self[logClientKey.self] = newValue } } + + private struct importRemoteProfileKey: EnvironmentKey { + static var defaultValue: Binding = .constant(nil) + } + + var importRemoteProfile: Binding { + get { + self[importRemoteProfileKey.self] + } + set { + self[importRemoteProfileKey.self] = newValue + } + } } diff --git a/ApplicationLibrary/Views/Groups/GroupView.swift b/ApplicationLibrary/Views/Groups/GroupView.swift index 5423390..2da860e 100644 --- a/ApplicationLibrary/Views/Groups/GroupView.swift +++ b/ApplicationLibrary/Views/Groups/GroupView.swift @@ -3,16 +3,13 @@ import Library import SwiftUI public struct GroupView: View { - private var expland: Binding + @Binding private var expland: Bool @State private var group: OutboundGroup @State private var geometryWidth: CGFloat = 300 - @State private var errorPresented = false - @State private var errorMessage = "" - public init(_ group: OutboundGroup, _ expland: Binding) { self.group = group - self.expland = expland + _expland = expland } private var title: some View { @@ -28,9 +25,9 @@ public struct GroupView: View { .background(Color.gray.opacity(0.5)) .cornerRadius(4) Button { - expland.wrappedValue = !expland.wrappedValue + expland = !expland } label: { - if expland.wrappedValue { + if expland { Image(systemName: "arrow.down.to.line") } else { Image(systemName: "arrow.up.to.line") @@ -51,18 +48,11 @@ public struct GroupView: View { #endif Spacer(minLength: 6) } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } } public var body: some View { Section { - if expland.wrappedValue { + if expland { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: explandColumnCount())) { @@ -123,12 +113,7 @@ public struct GroupView: View { } private func doURLTest() { - do { - try LibboxNewStandaloneCommandClient(FilePath.sharedDirectory.relativePath)!.urlTest(group.tag) - } catch { - errorMessage = error.localizedDescription - errorPresented = true - } + try? LibboxNewStandaloneCommandClient(FilePath.sharedDirectory.relativePath)!.urlTest(group.tag) } } diff --git a/ApplicationLibrary/Views/Profile/EditProfileContentView.swift b/ApplicationLibrary/Views/Profile/EditProfileContentView.swift index ddece65..a5899a8 100644 --- a/ApplicationLibrary/Views/Profile/EditProfileContentView.swift +++ b/ApplicationLibrary/Views/Profile/EditProfileContentView.swift @@ -26,10 +26,7 @@ public struct EditProfileContentView: View { @State private var profile: Profile! @State private var profileContent: String = "" @State private var isChanged = false - - @State private var errorPresented = false - @State private var errorMessage = "" - @State private var fatalError = false + @State private var alert: Alert? public var body: some View { viewBuilder { @@ -60,17 +57,7 @@ public struct EditProfileContentView: View { } } } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok"), action: { - if fatalError { - dismiss() - } - }) - ) - } + .alertBinding($alert) .navigationTitle(navigationTitle) #if os(macOS) .toolbar { @@ -115,9 +102,7 @@ public struct EditProfileContentView: View { do { try loadContent0() } catch { - errorMessage = error.localizedDescription - fatalError = true - errorPresented = true + alert = Alert(error, dismiss.callAsFunction) } } @@ -140,8 +125,7 @@ public struct EditProfileContentView: View { do { try profile.write(profileContent) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } isChanged = false diff --git a/ApplicationLibrary/Views/Profile/EditProfileView.swift b/ApplicationLibrary/Views/Profile/EditProfileView.swift index 5f5c25f..9d1879d 100644 --- a/ApplicationLibrary/Views/Profile/EditProfileView.swift +++ b/ApplicationLibrary/Views/Profile/EditProfileView.swift @@ -10,8 +10,7 @@ public struct EditProfileView: View { @State private var isLoading = false @State private var isChanged = false - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? public init() {} @@ -69,6 +68,17 @@ public struct EditProfileView: View { } .disabled(isLoading) } + if #available(iOS 16.0, *) { + ShareLink(item: profile.shareLink) { + Text("Share") + } + } else { + Button("Share") { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + windowScene.keyWindow?.rootViewController?.present(UIActivityViewController(activityItems: [profile.shareLink], applicationActivities: nil), animated: true, completion: nil) + } + } + } } #endif } @@ -132,13 +142,7 @@ public struct EditProfileView: View { } } #endif - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) .navigationTitle("Edit Profile") } @@ -150,8 +154,7 @@ public struct EditProfileView: View { try await Task.sleep(nanoseconds: UInt64(100 * Double(NSEC_PER_MSEC))) try profile.updateRemoteProfile() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } @@ -159,8 +162,7 @@ public struct EditProfileView: View { do { _ = try ProfileManager.update(profile) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } isChanged = false diff --git a/ApplicationLibrary/Views/Profile/EditProfileWindowView.swift b/ApplicationLibrary/Views/Profile/EditProfileWindowView.swift index d82609d..da87285 100644 --- a/ApplicationLibrary/Views/Profile/EditProfileWindowView.swift +++ b/ApplicationLibrary/Views/Profile/EditProfileWindowView.swift @@ -1,4 +1,3 @@ - import Library import SwiftUI @@ -16,8 +15,7 @@ import SwiftUI @State private var isLoading = true @State private var profile: Profile! - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? public var body: some View { viewBuilder { @@ -27,19 +25,11 @@ import SwiftUI await doReload() } } - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok"), action: { - dismiss() - }) - ) - } } else { EditProfileView().environmentObject(profile!) } } + .alertBinding($alert) .onExitCommand { dismiss() } @@ -47,20 +37,17 @@ import SwiftUI private func doReload() async { guard let profileID else { - errorMessage = "Context destroyed" - errorPresented = true + alert = Alert(errorMessage: "Context destroyed") return } do { profile = try ProfileManager.get(profileID) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } if profile == nil { - errorMessage = "Profile deleted" - errorPresented = true + alert = Alert(errorMessage: "Profile deleted") return } isLoading = false diff --git a/ApplicationLibrary/Views/Profile/NewProfileView.swift b/ApplicationLibrary/Views/Profile/NewProfileView.swift index 24ca118..0702b26 100644 --- a/ApplicationLibrary/Views/Profile/NewProfileView.swift +++ b/ApplicationLibrary/Views/Profile/NewProfileView.swift @@ -17,12 +17,21 @@ public struct NewProfileView: View { @State private var fileURL: URL! @State private var remotePath = "" @State private var pickerPresented = false - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? + + public struct ImportRequest: Codable, Hashable { + public let name: String + public let url: String + } private let callback: (() -> Void)? - public init(_ callback: (() -> Void)? = nil) { + public init(_ importRequest: ImportRequest? = nil, _ callback: (() -> Void)? = nil) { self.callback = callback + if let importRequest { + _profileName = .init(initialValue: importRequest.name) + _profileType = .init(initialValue: .remote) + _remotePath = .init(initialValue: importRequest.url) + } } public var body: some View { @@ -88,13 +97,7 @@ public struct NewProfileView: View { } } .navigationTitle("New Profile") - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) .fileImporter( isPresented: $pickerPresented, allowedContentTypes: [.json], @@ -106,8 +109,7 @@ public struct NewProfileView: View { fileURL = urls[0] } } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } } @@ -118,26 +120,22 @@ public struct NewProfileView: View { isSaving = false } if profileName.isEmpty { - errorMessage = "Missing profile name" - errorPresented = true + alert = Alert(errorMessage: "Missing profile name") return } if remotePath.isEmpty { if profileType == .icloud { - errorMessage = "Missing path" - errorPresented = true + alert = Alert(errorMessage: "Missing path") return } else if profileType == .remote { - errorMessage = "Missing URL" - errorPresented = true + alert = Alert(errorMessage: "Missing URL") return } } do { try createProfile0() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } await MainActor.run { @@ -173,13 +171,11 @@ public struct NewProfileView: View { let profileConfig = profileConfigDirectory.appendingPathComponent("config_\(nextProfileID).json") if fileImport { guard let fileURL else { - errorMessage = "Missing file" - errorPresented = true + alert = Alert(errorMessage: "Missing file") return } if !fileURL.startAccessingSecurityScopedResource() { - errorMessage = "Missing access to selected file" - errorPresented = true + alert = Alert(errorMessage: "Missing access to selected file") return } defer { diff --git a/ApplicationLibrary/Views/Profile/ProfileView.swift b/ApplicationLibrary/Views/Profile/ProfileView.swift index bf9eb86..ffdedee 100644 --- a/ApplicationLibrary/Views/Profile/ProfileView.swift +++ b/ApplicationLibrary/Views/Profile/ProfileView.swift @@ -1,16 +1,19 @@ import Foundation +import Libbox import Library import SwiftUI public struct ProfileView: View { public static let notificationName = Notification.Name("\(FilePath.packageName).update-profile") + @Environment(\.importRemoteProfile) private var importRemoteProfile + @State private var importRemoteProfileRequest: NewProfileView.ImportRequest? + @State private var importRemoteProfilePresented = false + @State private var isLoading = true @State private var isUpdating = false - @State private var errorPresented = false - @State private var errorMessage = "" - + @State private var alert: Alert? @State private var profileList: [Profile] = [] #if os(iOS) @@ -33,36 +36,51 @@ public struct ProfileView: View { } } else { #if os(iOS) - FormView { - NavigationLink { - NewProfileView { - Task.detached { - doReload() + ZStack { + if let importRemoteProfileRequest { + NavigationLink( + destination: NewProfileView(importRemoteProfileRequest) { + Task.detached { + doReload() + } + }, + isActive: $importRemoteProfilePresented, + label: { + EmptyView() } - } - } label: { - Text("New Profile").foregroundColor(.accentColor) + ) } - .disabled(editMode.isEditing) - if profileList.isEmpty { - Text("Empty Profiles") - } else { - List { - ForEach(profileList, id: \.mustID) { profile in - viewBuilder { - if editMode.isEditing == true { - Text(profile.name) - } else { - NavigationLink { - EditProfileView().environmentObject(profile) - } label: { + FormView { + NavigationLink { + NewProfileView { + Task.detached { + doReload() + } + } + } label: { + Text("New Profile").foregroundColor(.accentColor) + } + .disabled(editMode.isEditing) + if profileList.isEmpty { + Text("Empty Profiles") + } else { + List { + ForEach(profileList, id: \.mustID) { profile in + viewBuilder { + if editMode.isEditing == true { Text(profile.name) + } else { + NavigationLink { + EditProfileView().environmentObject(profile) + } label: { + Text(profile.name) + } } } } + .onMove(perform: moveProfile) + .onDelete(perform: deleteProfile) } - .onMove(perform: moveProfile) - .onDelete(perform: deleteProfile) } } } @@ -92,6 +110,9 @@ public struct ProfileView: View { }, label: { Image(systemName: "arrow.clockwise") }) + ShareLink(item: profile.shareLink) { + Image(systemName: "square.and.arrow.up.fill") + } } Button(action: { openWindow(id: EditProfileWindowView.windowID, value: profile.mustID) @@ -119,8 +140,13 @@ public struct ProfileView: View { } .disabled(isUpdating) .navigationTitle("Profiles") - #if os(macOS) - .onAppear { + .alertBinding($alert, $isLoading) + .onAppear { + if let remoteProfile = importRemoteProfile.wrappedValue { + importRemoteProfile.wrappedValue = nil + createImportRemoteProfileDialog(remoteProfile) + } + #if os(macOS) if observer == nil { observer = NotificationCenter.default.addObserver(forName: ProfileView.notificationName, object: nil, queue: .main) { _ in Task.detached { @@ -128,40 +154,63 @@ public struct ProfileView: View { } } } + #endif + } + .onChange(of: importRemoteProfile.wrappedValue) { newValue in + if let newValue { + importRemoteProfile.wrappedValue = nil + createImportRemoteProfileDialog(newValue) } - .onDisappear { - if let observer { - NotificationCenter.default.removeObserver(observer) - } - observer = nil + } + #if os(macOS) + .onDisappear { + if let observer { + NotificationCenter.default.removeObserver(observer) } - .toolbar { - ToolbarItem { - Button(action: { - openWindow(id: NewProfileView.windowID) - }, label: { - Label("New Profile", systemImage: "plus.square.fill") - }) - } + observer = nil + } + .toolbar { + ToolbarItem { + Button(action: { + openWindow(id: NewProfileView.windowID) + }, label: { + Label("New Profile", systemImage: "plus.square.fill") + }) } + } #elseif os(iOS) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - EditButton().disabled(profileList.isEmpty) - } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + EditButton().disabled(profileList.isEmpty) } - .environment(\.editMode, $editMode) + } + .environment(\.editMode, $editMode) #endif } + private func createImportRemoteProfileDialog(_ newValue: LibboxImportRemoteProfile) { + importRemoteProfileRequest = .init(name: newValue.name, url: newValue.url) + alert = Alert( + title: Text("Import Remote Profile"), + message: Text("Are you sure to import remote configuration \(newValue.name)? You will connect to \(newValue.host) to download the configuration."), + primaryButton: .default(Text("Import")) { + #if os(iOS) + importRemoteProfilePresented = true + #elseif os(macOS) + openWindow(id: NewProfileView.windowID, value: importRemoteProfileRequest!) + #endif + }, + secondaryButton: .cancel() + ) + } + private func deleteSelectedProfiles(_ profileID: [Int64]) { do { if try ProfileManager.delete(by: profileID) > 0 { isLoading = true } } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } @@ -178,8 +227,7 @@ public struct ProfileView: View { do { profileList = try ProfileManager.list() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } } @@ -189,8 +237,7 @@ public struct ProfileView: View { do { _ = try profile.updateRemoteProfile() } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } isUpdating = false } @@ -200,8 +247,7 @@ public struct ProfileView: View { do { _ = try ProfileManager.delete(profile) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } isLoading = true @@ -216,8 +262,7 @@ public struct ProfileView: View { do { try ProfileManager.update(profileList) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) return } } @@ -231,8 +276,7 @@ public struct ProfileView: View { do { _ = try ProfileManager.delete(profileToDelete) } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } } diff --git a/ApplicationLibrary/Views/Setting/SettingView.swift b/ApplicationLibrary/Views/Setting/SettingView.swift index 6322e80..3a2f00d 100644 --- a/ApplicationLibrary/Views/Setting/SettingView.swift +++ b/ApplicationLibrary/Views/Setting/SettingView.swift @@ -24,9 +24,7 @@ public struct SettingView: View { @State private var version = "" @State private var dataSize = "" @State private var taiwanFlagAvailable = false - - @State private var errorPresented = false - @State private var errorMessage = "" + @State private var alert: Alert? public init() {} @@ -82,13 +80,11 @@ public struct SettingView: View { do { if let result = try await SystemExtension.install(forceUpdate: true) { if result == .willCompleteAfterReboot { - errorMessage = "Need reboot" - errorPresented = true + alert = Alert(errorMessage: "Need reboot") } } } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } } @@ -134,13 +130,7 @@ public struct SettingView: View { } } .navigationTitle("Settings") - .alert(isPresented: $errorPresented) { - Alert( - title: Text("Error"), - message: Text(errorMessage), - dismissButton: .default(Text("Ok")) - ) - } + .alertBinding($alert) } #if os(macOS) @@ -156,8 +146,7 @@ public struct SettingView: View { try SMAppService.mainApp.unregister() } } catch { - errorMessage = error.localizedDescription - errorPresented = true + alert = Alert(error) } } #endif diff --git a/Library/Database/Profile+Share.swift b/Library/Database/Profile+Share.swift new file mode 100644 index 0000000..e276b93 --- /dev/null +++ b/Library/Database/Profile+Share.swift @@ -0,0 +1,8 @@ +import Foundation +import Libbox + +public extension Profile { + var shareLink: URL { + URL(string: LibboxGenerateRemoteProfileImportLink(name, remoteURL!))! + } +} diff --git a/SFM.System/Assets.xcassets/AccentColor.colorset/Contents.json b/MacLibrary/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from SFM.System/Assets.xcassets/AccentColor.colorset/Contents.json rename to MacLibrary/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/Contents.json b/MacLibrary/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/Contents.json rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png diff --git a/SFM.System/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png b/MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png similarity index 100% rename from SFM.System/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png rename to MacLibrary/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png diff --git a/SFM.System/Assets.xcassets/Contents.json b/MacLibrary/Assets.xcassets/Contents.json similarity index 100% rename from SFM.System/Assets.xcassets/Contents.json rename to MacLibrary/Assets.xcassets/Contents.json diff --git a/MacLibrary/Icons/AppIcon.icns b/MacLibrary/Icons/AppIcon.icns new file mode 100644 index 0000000..c1b8ed0 Binary files /dev/null and b/MacLibrary/Icons/AppIcon.icns differ diff --git a/MacLibrary/MacApplication.swift b/MacLibrary/MacApplication.swift index 278c9c5..bdc5c4d 100644 --- a/MacLibrary/MacApplication.swift +++ b/MacLibrary/MacApplication.swift @@ -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) diff --git a/MacLibrary/MainView.swift b/MacLibrary/MainView.swift index c8ec743..cbb9b2b 100644 --- a/MacLibrary/MainView.swift +++ b/MacLibrary/MainView.swift @@ -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) + } + ) } } } diff --git a/MacLibrary/MenuView.swift b/MacLibrary/MenuView.swift index 8df7bc3..0717e21 100644 --- a/MacLibrary/MenuView.swift +++ b/MacLibrary/MenuView.swift @@ -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 diff --git a/SFI/Info.plist b/SFI/Info.plist index 374a712..8836d9a 100644 --- a/SFI/Info.plist +++ b/SFI/Info.plist @@ -6,6 +6,21 @@ io.nekohasekai.sfa.update_profiles + CFBundleURLTypes + + + CFBundleTypeRole + Viewer + CFBundleURLIconFile + AppIcon.icns + CFBundleURLName + sing-box + CFBundleURLSchemes + + sing-box + + + ITSAppUsesNonExemptEncryption NSUbiquitousContainers diff --git a/SFI/MainView.swift b/SFI/MainView.swift index 228b9d3..1f2c242 100644 --- a/SFI/MainView.swift +++ b/SFI/MainView.swift @@ -1,4 +1,5 @@ import ApplicationLibrary +import Libbox import Library import SwiftUI @@ -14,6 +15,8 @@ struct MainView: View { @State private var serviceNotificationContent = "" @State private var serviceNotificationPresented = false + @State private var importRemoteProfile: LibboxImportRemoteProfile? + var body: some View { viewBuilder { if profileLoading { @@ -54,7 +57,22 @@ struct MainView: View { .environment(\.selection, $selection) .environment(\.extensionProfile, $extensionProfile) .environment(\.logClient, $logClient) - .preferredColorScheme(.dark) + .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 { diff --git a/SFM.System/Info.plist b/SFM.System/Info.plist index fbc2dd1..43d3931 100644 --- a/SFM.System/Info.plist +++ b/SFM.System/Info.plist @@ -2,6 +2,23 @@ + CFBundleURLTypes + + + CFBundleTypeRole + Viewer + CFBundleURLIconFile + AppIcon.icns + CFBundleURLName + sing-box + CFBundleURLSchemes + + sing-box + + + + ITSAppUsesNonExemptEncryption + NSUbiquitousContainers iCloud.io.nekohasekai.sfa @@ -14,7 +31,5 @@ Any - ITSAppUsesNonExemptEncryption - diff --git a/SFM/Assets.xcassets/AccentColor.colorset/Contents.json b/SFM/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index 0afb3cf..0000000 --- a/SFM/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors": [ - { - "idiom": "universal" - } - ], - "info": { - "author": "xcode", - "version": 1 - } -} diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/Contents.json b/SFM/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index f4ac7bc..0000000 --- a/SFM/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "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 - } -} diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png deleted file mode 100644 index 9b10cd7..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 1x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png deleted file mode 100644 index 21693a6..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-128 2x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png deleted file mode 100644 index 28df597..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 1x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png deleted file mode 100644 index 6852edd..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-16 2x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png deleted file mode 100644 index db0a7f0..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 1x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png deleted file mode 100644 index 4449735..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-256 2x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png deleted file mode 100644 index 171cb5b..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 1x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png deleted file mode 100644 index 1654da9..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-32 2x 1.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png deleted file mode 100644 index 99e829a..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 1x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png b/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png deleted file mode 100644 index 88a80d6..0000000 Binary files a/SFM/Assets.xcassets/AppIcon.appiconset/apple-512 2x.png and /dev/null differ diff --git a/SFM/Assets.xcassets/Contents.json b/SFM/Assets.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/SFM/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/SFM/Info.plist b/SFM/Info.plist index 710b062..5e088a4 100644 --- a/SFM/Info.plist +++ b/SFM/Info.plist @@ -2,6 +2,21 @@ + CFBundleURLTypes + + + CFBundleTypeRole + Viewer + CFBundleURLIconFile + AppIcon + CFBundleURLName + sing-box + CFBundleURLSchemes + + sing-box + + + ITSAppUsesNonExemptEncryption NSUbiquitousContainers diff --git a/sing-box.xcodeproj/project.pbxproj b/sing-box.xcodeproj/project.pbxproj index 1bb443f..c97cb56 100644 --- a/sing-box.xcodeproj/project.pbxproj +++ b/sing-box.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 3A1CF2F62A50EE9C000A8289 /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F52A50EE9C000A8289 /* GroupView.swift */; }; 3A1CF2F82A50F0A5000A8289 /* GroupItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F72A50F0A5000A8289 /* GroupItemView.swift */; }; 3A1CF2FA2A50F0BD000A8289 /* OutboundGroupItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F92A50F0BD000A8289 /* OutboundGroupItem.swift */; }; - 3A2223542A6E1B6700C50B23 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3A2223532A6E1B6700C50B23 /* Info.plist */; }; 3A2223562A6E1BDE00C50B23 /* Variant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2223552A6E1BDE00C50B23 /* Variant.swift */; }; 3A2223582A6E1CC700C50B23 /* MacApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2223572A6E1CC700C50B23 /* MacApplication.swift */; }; 3A22235A2A6E212A00C50B23 /* SystemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2223592A6E212A00C50B23 /* SystemExtension.swift */; }; @@ -55,6 +54,12 @@ 3A5F26C92A503D4A00C27EDF /* Library.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 3A648D2D2A4EEAA600D95A12 /* Library.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A648D2C2A4EEAA600D95A12 /* Library.swift */; }; 3A648D542A4EF4C700D95A12 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF342B12A4AA520002B34AC /* NetworkExtension.framework */; }; + 3A6CA5A02A71317A0027933B /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 3A6CA59F2A71317A0027933B /* MarkdownUI */; }; + 3A6CA5A32A713A580027933B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AEECC0A2A6DF9CA006A0E0C /* Assets.xcassets */; }; + 3A6CA5A62A713AA10027933B /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3A6CA5A52A713AA10027933B /* AppIcon.icns */; }; + 3A6CA5A72A713ABA0027933B /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3A6CA5A52A713AA10027933B /* AppIcon.icns */; }; + 3A6CA5A82A713B340027933B /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3A6CA5A52A713AA10027933B /* AppIcon.icns */; }; + 3A6CA5A92A713C420027933B /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3A6CA5A52A713AA10027933B /* AppIcon.icns */; }; 3A76504C2A4F08BA003945C5 /* Libbox.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC20DB2A4599D000A63465 /* Libbox.xcframework */; }; 3A7701702A4E6B34008F031F /* IntentsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A77016F2A4E6B34008F031F /* IntentsExtension.swift */; }; 3A7701722A4E6B34008F031F /* Intents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7701712A4E6B34008F031F /* Intents.swift */; }; @@ -65,10 +70,12 @@ 3A9144D92A46AE370036E9AD /* ShadredPreferences+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */; }; 3A9759202A4EB69C00E4404B /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; }; 3A9759212A4EB69C00E4404B /* Library.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 3AB1220B2A70FD500087CD55 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB1220A2A70FD500087CD55 /* Alert.swift */; }; 3AC194492A50013F00BD8CB9 /* IntentsExtension.appex in Embed ExtensionKit Extensions */ = {isa = PBXBuildFile; fileRef = 3A77016D2A4E6B34008F031F /* IntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 3AC1944F2A50247300BD8CB9 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */; }; 3AC194502A502DFE00BD8CB9 /* ServiceNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC1944C2A50206C00BD8CB9 /* ServiceNotification.swift */; }; 3AC5EC082A6417470077AF34 /* DeviceCensorship.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC5EC072A6417470077AF34 /* DeviceCensorship.swift */; }; + 3AD0953D2A70EB310052764E /* Profile+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD0953C2A70EB310052764E /* Profile+Share.swift */; }; 3AE4D0B22A6E2B6A009FEA9E /* ExtensionPlatformInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF342A62A4AA0FF002B34AC /* ExtensionPlatformInterface.swift */; }; 3AE4D0B32A6E2B94009FEA9E /* Extension+RunBlocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF342A82A4AA155002B34AC /* Extension+RunBlocking.swift */; }; 3AE4D0B42A6E2BA3009FEA9E /* Extension+Iterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF342AA2A4AA173002B34AC /* Extension+Iterator.swift */; }; @@ -80,7 +87,6 @@ 3AEAEE992A4F16430059612D /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A096F862A4ED3DE00D4A2ED /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 3AEC20F62A459AB400A63465 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEC20F52A459AB400A63465 /* Application.swift */; }; 3AEC20FA2A459AB500A63465 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AEC20F92A459AB500A63465 /* Assets.xcassets */; }; - 3AEC21102A459B1A00A63465 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AEC210F2A459B1A00A63465 /* Assets.xcassets */; }; 3AEC212F2A459D5600A63465 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEC212E2A459D5600A63465 /* Profile.swift */; }; 3AEC213C2A459FDF00A63465 /* Databse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEC213B2A459FDF00A63465 /* Databse.swift */; }; 3AEC21402A45A28F00A63465 /* ProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEC213F2A45A28F00A63465 /* ProfileManager.swift */; }; @@ -373,6 +379,7 @@ 3A57DF3F2A4D70B600690BC5 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = ""; }; 3A57DF412A4D927A00690BC5 /* Profile+Hashable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Profile+Hashable.swift"; sourceTree = ""; }; 3A648D2C2A4EEAA600D95A12 /* Library.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Library.swift; sourceTree = ""; }; + 3A6CA5A52A713AA10027933B /* AppIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon.icns; sourceTree = ""; }; 3A77016D2A4E6B34008F031F /* IntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.extensionkit-extension"; includeInIndex = 0; path = IntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 3A77016F2A4E6B34008F031F /* IntentsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentsExtension.swift; sourceTree = ""; }; 3A7701712A4E6B34008F031F /* Intents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Intents.swift; sourceTree = ""; }; @@ -388,11 +395,13 @@ 3AAB5E732A4BF90B009757F1 /* ServiceLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLogView.swift; sourceTree = ""; }; 3AAB5E752A4BFB0B009757F1 /* EditProfileContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileContentView.swift; sourceTree = ""; }; 3AAB5E7A2A4C1446009757F1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 3AB1220A2A70FD500087CD55 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 3ABA46D22A6A32A100D8366B /* Messages.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Messages.framework; path = Library/Frameworks/Messages.framework; sourceTree = DEVELOPER_DIR; }; 3AC1944C2A50206C00BD8CB9 /* ServiceNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceNotification.swift; sourceTree = ""; }; 3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 3AC194512A50303300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 3AC5EC072A6417470077AF34 /* DeviceCensorship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceCensorship.swift; sourceTree = ""; }; + 3AD0953C2A70EB310052764E /* Profile+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Profile+Share.swift"; sourceTree = ""; }; 3ADF8DF12A4AF59900900CC8 /* ActiveDashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveDashboardView.swift; sourceTree = ""; }; 3ADF8DF32A4AF9B500900CC8 /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = ""; }; 3ADF8DF62A4AFB2C00900CC8 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; @@ -410,7 +419,6 @@ 3AEC21092A459B1900A63465 /* sing-box.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sing-box.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 3AEC210B2A459B1900A63465 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; 3AEC210D2A459B1900A63465 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; - 3AEC210F2A459B1A00A63465 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 3AEC21142A459B1A00A63465 /* SFM.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SFM.entitlements; sourceTree = ""; }; 3AEC211D2A459B4700A63465 /* Library.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Library.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3AEC212E2A459D5600A63465 /* Profile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = ""; }; @@ -460,6 +468,7 @@ buildActionMask = 2147483647; files = ( 3A4EAD1B2A4FEB02005435B3 /* Library.framework in Frameworks */, + 3A6CA5A02A71317A0027933B /* MarkdownUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -573,6 +582,14 @@ path = Service; sourceTree = ""; }; + 3A6CA5A42A713A6C0027933B /* Icons */ = { + isa = PBXGroup; + children = ( + 3A6CA5A52A713AA10027933B /* AppIcon.icns */, + ); + path = Icons; + sourceTree = ""; + }; 3A77016E2A4E6B34008F031F /* IntentsExtension */ = { isa = PBXGroup; children = ( @@ -677,7 +694,6 @@ isa = PBXGroup; children = ( 3AEC210B2A459B1900A63465 /* Application.swift */, - 3AEC210F2A459B1A00A63465 /* Assets.xcassets */, 3AEC21142A459B1A00A63465 /* SFM.entitlements */, 3AEAEE9C2A4F1A9D0059612D /* Info.plist */, ); @@ -707,6 +723,7 @@ 3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */, 3A57DF362A4D5D2600690BC5 /* Profile+Date.swift */, 3A57DF412A4D927A00690BC5 /* Profile+Hashable.swift */, + 3AD0953C2A70EB310052764E /* Profile+Share.swift */, ); path = Database; sourceTree = ""; @@ -767,7 +784,6 @@ isa = PBXGroup; children = ( 3AEECC062A6DF9CA006A0E0C /* Application.swift */, - 3AEECC0A2A6DF9CA006A0E0C /* Assets.xcassets */, 3AEECC502A6E0074006A0E0C /* SFM.entitlements */, 3A2223532A6E1B6700C50B23 /* Info.plist */, 3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */, @@ -778,6 +794,8 @@ 3AEECC302A6DFDAD006A0E0C /* MacLibrary */ = { isa = PBXGroup; children = ( + 3A6CA5A42A713A6C0027933B /* Icons */, + 3AEECC0A2A6DF9CA006A0E0C /* Assets.xcassets */, 3AEC210D2A459B1900A63465 /* MainView.swift */, 3A57DF3F2A4D70B600690BC5 /* MenuView.swift */, 3A1CF2F32A50E937000A8289 /* SidebarView.swift */, @@ -808,6 +826,7 @@ 3AF342D32A4AADB2002B34AC /* Formtem.swift */, 3ADF8E022A4B118700900CC8 /* Binding+Unwrap.swift */, 3AC5EC072A6417470077AF34 /* DeviceCensorship.swift */, + 3AB1220A2A70FD500087CD55 /* Alert.swift */, ); path = Abstract; sourceTree = ""; @@ -871,6 +890,9 @@ 3A4EAD1E2A4FEB02005435B3 /* PBXTargetDependency */, ); name = ApplicationLibrary; + packageProductDependencies = ( + 3A6CA59F2A71317A0027933B /* MarkdownUI */, + ); productName = ApplicationLibrary; productReference = 3A4EAD102A4FEAE6005435B3 /* ApplicationLibrary.framework */; productType = "com.apple.product-type.framework"; @@ -1090,6 +1112,7 @@ 3A7E90362A46778E00D53052 /* XCRemoteSwiftPackageReference "BinaryCodable" */, 3A017F902A4AB2E4009149FA /* XCRemoteSwiftPackageReference "GRDB" */, 3A57DF3A2A4D705000690BC5 /* XCRemoteSwiftPackageReference "MacControlCenterUI" */, + 3ADB2D832A71266E00A6517D /* XCRemoteSwiftPackageReference "swift-markdown-ui" */, ); productRefGroup = 3AEC20C72A45991900A63465 /* Products */; projectDirPath = ""; @@ -1120,6 +1143,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3A6CA5A92A713C420027933B /* AppIcon.icns in Resources */, 3AEC20FA2A459AB500A63465 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1128,8 +1152,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3A6CA5A72A713ABA0027933B /* AppIcon.icns in Resources */, + 3A6CA5A32A713A580027933B /* Assets.xcassets in Resources */, 3A251C122A52D09700651082 /* Assets.xcassets in Resources */, - 3AEC21102A459B1A00A63465 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1151,8 +1176,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3A6CA5A82A713B340027933B /* AppIcon.icns in Resources */, 3AEC8A4F2A6E5E18003702E1 /* Assets.xcassets in Resources */, - 3A2223542A6E1B6700C50B23 /* Info.plist in Resources */, 3AEECC0B2A6DF9CA006A0E0C /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1161,6 +1186,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3A6CA5A62A713AA10027933B /* AppIcon.icns in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1197,6 +1223,7 @@ 3A4EAD2F2A4FEB77005435B3 /* EditProfileContentView.swift in Sources */, 3A4EAD272A4FEB65005435B3 /* DashboardView.swift in Sources */, 3A4EAD342A4FEB7F005435B3 /* LogView.swift in Sources */, + 3AB1220B2A70FD500087CD55 /* Alert.swift in Sources */, 3A4EAD362A4FEB9C005435B3 /* ProfileUpdateTask.swift in Sources */, 3A1CF2F62A50EE9C000A8289 /* GroupView.swift in Sources */, 3A4EAD212A4FEB3C005435B3 /* ApplicationLibrary.swift in Sources */, @@ -1248,6 +1275,7 @@ 3AEC214A2A45AA5600A63465 /* Profile+RW.swift in Sources */, 3A57DF422A4D927A00690BC5 /* Profile+Hashable.swift in Sources */, 3A7E90352A46756300D53052 /* SharedPreferences.swift in Sources */, + 3AD0953D2A70EB310052764E /* Profile+Share.swift in Sources */, 3AE4D0B32A6E2B94009FEA9E /* Extension+RunBlocking.swift in Sources */, 3AEC21482A45A9DE00A63465 /* Bundle+Version.swift in Sources */, 3A57DF372A4D5D2600690BC5 /* Profile+Date.swift in Sources */, @@ -1418,6 +1446,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; OTHER_CODE_SIGN_FLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.extension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1457,6 +1486,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; OTHER_CODE_SIGN_FLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.extension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1574,6 +1604,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; OTHER_CODE_SIGN_FLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.intents; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1613,6 +1644,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; OTHER_CODE_SIGN_FLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.intents; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1764,7 +1796,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = SFI/SFI.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -1786,9 +1818,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; OTHER_CODE_SIGN_FLAGS = "--deep"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa; PRODUCT_NAME = "sing-box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1805,7 +1837,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = SFI/SFI.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -1827,9 +1859,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; OTHER_CODE_SIGN_FLAGS = "--deep"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa; PRODUCT_NAME = "sing-box"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1851,7 +1883,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 14; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = Z56Z6NYZN2; ENABLE_HARDENED_RUNTIME = YES; @@ -1867,7 +1899,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; OTHER_CODE_SIGN_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa; PRODUCT_NAME = "sing-box"; @@ -1889,7 +1921,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 12; + CURRENT_PROJECT_VERSION = 14; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = Z56Z6NYZN2; ENABLE_HARDENED_RUNTIME = YES; @@ -1905,7 +1937,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; OTHER_CODE_SIGN_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa; PRODUCT_NAME = "sing-box"; @@ -1952,7 +1984,7 @@ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; OTHER_CODE_SIGN_FLAGS = "--deep"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.library; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2004,7 +2036,7 @@ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; OTHER_CODE_SIGN_FLAGS = "--deep"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ld64"; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.library; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2117,7 +2149,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent; PRODUCT_NAME = SFM; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2156,7 +2188,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 13.0; - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.3.5; PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent; PRODUCT_NAME = SFM; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2367,6 +2399,14 @@ minimumVersion = 2.0.0; }; }; + 3ADB2D832A71266E00A6517D /* XCRemoteSwiftPackageReference "swift-markdown-ui" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/gonzalezreal/swift-markdown-ui"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -2375,6 +2415,11 @@ package = 3A017F902A4AB2E4009149FA /* XCRemoteSwiftPackageReference "GRDB" */; productName = GRDB; }; + 3A6CA59F2A71317A0027933B /* MarkdownUI */ = { + isa = XCSwiftPackageProductDependency; + package = 3ADB2D832A71266E00A6517D /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; + productName = MarkdownUI; + }; 3A7E90372A46778E00D53052 /* BinaryCodable */ = { isa = XCSwiftPackageProductDependency; package = 3A7E90362A46778E00D53052 /* XCRemoteSwiftPackageReference "BinaryCodable" */; diff --git a/sing-box.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/sing-box.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 36c6a71..19f1da3 100644 --- a/sing-box.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/sing-box.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -35,6 +35,15 @@ "revision" : "8757eb7c2cd708320df92e6ad6572efe90e58f16", "version" : "1.0.4" } + }, + { + "identity" : "swift-markdown-ui", + "kind" : "remoteSourceControl", + "location" : "https://github.com/gonzalezreal/swift-markdown-ui", + "state" : { + "revision" : "12b351a75201a8124c2f2e1f9fc6ef5cd812c0b9", + "version" : "2.1.0" + } } ], "version" : 2 diff --git a/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist b/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist index d0607a1..5f857fe 100644 --- a/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist @@ -14,52 +14,52 @@ isShown orderHint - 15 + 18 Associations (Playground) 2.xcscheme isShown orderHint - 16 + 19 Associations (Playground) 3.xcscheme isShown orderHint - 27 + 30 Associations (Playground) 4.xcscheme isShown orderHint - 28 + 31 Associations (Playground) 5.xcscheme isShown orderHint - 29 + 32 Associations (Playground).xcscheme isShown orderHint - 14 + 17 ExtensionMac.xcscheme_^#shared#^_ orderHint - 22 + 25 Launcher.xcscheme_^#shared#^_ orderHint - 18 + 21 MacExtension.xcscheme_^#shared#^_ @@ -69,59 +69,59 @@ MacLibrary.xcscheme_^#shared#^_ orderHint - 4 + 5 MessageExtension.xcscheme_^#shared#^_ orderHint - 16 + 20 MyPlayground (Playground) 1.xcscheme isShown orderHint - 9 + 11 MyPlayground (Playground) 2.xcscheme isShown orderHint - 10 + 12 MyPlayground (Playground) 3.xcscheme isShown orderHint - 23 + 26 MyPlayground (Playground) 4.xcscheme isShown orderHint - 24 + 27 MyPlayground (Playground) 5.xcscheme isShown orderHint - 26 + 29 MyPlayground (Playground).xcscheme isShown orderHint - 8 + 10 SFA.xcscheme_^#shared#^_ orderHint - 21 + 24 SFI.xcscheme @@ -131,121 +131,121 @@ SFM.System.xcscheme_^#shared#^_ orderHint - 5 + 4 - SFM.xcscheme_^#shared#^_ - - orderHint - 2 - - SystemExtension.xcscheme_^#shared#^_ + SFM.xcscheme orderHint 1 + SystemExtension.xcscheme_^#shared#^_ + + orderHint + 2 + Test.xcscheme_^#shared#^_ orderHint - 10 + 13 Tour (Playground) 1.xcscheme isShown orderHint - 6 + 8 Tour (Playground) 2.xcscheme isShown orderHint - 7 + 9 Tour (Playground) 3.xcscheme isShown orderHint - 33 + 36 Tour (Playground) 4.xcscheme isShown orderHint - 34 + 37 Tour (Playground) 5.xcscheme isShown orderHint - 35 + 38 Tour (Playground).xcscheme isShown orderHint - 5 + 7 TransactionObserver (Playground) 1.xcscheme isShown orderHint - 12 + 15 TransactionObserver (Playground) 2.xcscheme isShown orderHint - 13 + 16 TransactionObserver (Playground) 3.xcscheme isShown orderHint - 30 + 33 TransactionObserver (Playground) 4.xcscheme isShown orderHint - 31 + 34 TransactionObserver (Playground) 5.xcscheme isShown orderHint - 32 + 35 TransactionObserver (Playground).xcscheme isShown orderHint - 11 + 14 mactest.xcscheme_^#shared#^_ orderHint - 25 + 28 sing-box.xcscheme_^#shared#^_ orderHint - 20 + 23 test.xcscheme_^#shared#^_ orderHint - 19 + 22 SuppressBuildableAutocreation