Prepare airdrop support
@@ -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<Alert?>) -> some View {
|
||||
alert(isPresented: Binding(get: {
|
||||
binding.wrappedValue != nil
|
||||
}, set: { newValue, _ in
|
||||
if !newValue {
|
||||
binding.wrappedValue = nil
|
||||
}
|
||||
})) {
|
||||
binding.wrappedValue!
|
||||
}
|
||||
}
|
||||
|
||||
func alertBinding(_ binding: Binding<Alert?>, _ isLoading: Binding<Bool>) -> some View {
|
||||
alert(isPresented: Binding(get: {
|
||||
binding.wrappedValue != nil
|
||||
}, set: { newValue, _ in
|
||||
if !newValue, !isLoading.wrappedValue {
|
||||
binding.wrappedValue = nil
|
||||
}
|
||||
})) {
|
||||
binding.wrappedValue!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -7,8 +7,7 @@ public struct ExtensionStatusView: View {
|
||||
@State private var message: LibboxStatusMessage?
|
||||
@State private var connectTask: Task<Void, Error>?
|
||||
@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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<LibboxImportRemoteProfile?> = .constant(nil)
|
||||
}
|
||||
|
||||
var importRemoteProfile: Binding<LibboxImportRemoteProfile?> {
|
||||
get {
|
||||
self[importRemoteProfileKey.self]
|
||||
}
|
||||
set {
|
||||
self[importRemoteProfileKey.self] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,13 @@ import Library
|
||||
import SwiftUI
|
||||
|
||||
public struct GroupView: View {
|
||||
private var expland: Binding<Bool>
|
||||
@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<Bool>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import Foundation
|
||||
import Libbox
|
||||
|
||||
public extension Profile {
|
||||
var shareLink: URL {
|
||||
URL(string: LibboxGenerateRemoteProfileImportLink(name, remoteURL!))!
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 278 KiB After Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 272 KiB |
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 340 KiB After Width: | Height: | Size: 340 KiB |
@@ -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
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
<array>
|
||||
<string>io.nekohasekai.sfa.update_profiles</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>AppIcon.icns</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>sing-box</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>sing-box</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSUbiquitousContainers</key>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -2,6 +2,23 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>AppIcon.icns</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>sing-box</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>sing-box</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSUbiquitousContainers</key>
|
||||
<dict>
|
||||
<key>iCloud.io.nekohasekai.sfa</key>
|
||||
@@ -14,7 +31,5 @@
|
||||
<string>Any</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"colors": [
|
||||
{
|
||||
"idiom": "universal"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"author": "xcode",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 272 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 340 KiB |
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,21 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>sing-box</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>sing-box</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSUbiquitousContainers</key>
|
||||
|
||||
@@ -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 = "<group>"; };
|
||||
3A57DF412A4D927A00690BC5 /* Profile+Hashable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Profile+Hashable.swift"; sourceTree = "<group>"; };
|
||||
3A648D2C2A4EEAA600D95A12 /* Library.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Library.swift; sourceTree = "<group>"; };
|
||||
3A6CA5A52A713AA10027933B /* AppIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon.icns; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
3A7701712A4E6B34008F031F /* Intents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Intents.swift; sourceTree = "<group>"; };
|
||||
@@ -388,11 +395,13 @@
|
||||
3AAB5E732A4BF90B009757F1 /* ServiceLogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLogView.swift; sourceTree = "<group>"; };
|
||||
3AAB5E752A4BFB0B009757F1 /* EditProfileContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileContentView.swift; sourceTree = "<group>"; };
|
||||
3AAB5E7A2A4C1446009757F1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
3AB1220A2A70FD500087CD55 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
|
||||
3AC194512A50303300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
|
||||
3AC5EC072A6417470077AF34 /* DeviceCensorship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceCensorship.swift; sourceTree = "<group>"; };
|
||||
3AD0953C2A70EB310052764E /* Profile+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Profile+Share.swift"; sourceTree = "<group>"; };
|
||||
3ADF8DF12A4AF59900900CC8 /* ActiveDashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveDashboardView.swift; sourceTree = "<group>"; };
|
||||
3ADF8DF32A4AF9B500900CC8 /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = "<group>"; };
|
||||
3ADF8DF62A4AFB2C00900CC8 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
|
||||
@@ -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 = "<group>"; };
|
||||
3AEC210D2A459B1900A63465 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||
3AEC210F2A459B1A00A63465 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
3AEC21142A459B1A00A63465 /* SFM.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SFM.entitlements; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
@@ -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 = "<group>";
|
||||
};
|
||||
3A6CA5A42A713A6C0027933B /* Icons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3A6CA5A52A713AA10027933B /* AppIcon.icns */,
|
||||
);
|
||||
path = Icons;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
@@ -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 = "<group>";
|
||||
@@ -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" */;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,52 +14,52 @@
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>15</integer>
|
||||
<integer>18</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>16</integer>
|
||||
<integer>19</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground) 3.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>27</integer>
|
||||
<integer>30</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground) 4.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>28</integer>
|
||||
<integer>31</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground) 5.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>29</integer>
|
||||
<integer>32</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>14</integer>
|
||||
<integer>17</integer>
|
||||
</dict>
|
||||
<key>ExtensionMac.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>22</integer>
|
||||
<integer>25</integer>
|
||||
</dict>
|
||||
<key>Launcher.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>18</integer>
|
||||
<integer>21</integer>
|
||||
</dict>
|
||||
<key>MacExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
@@ -69,59 +69,59 @@
|
||||
<key>MacLibrary.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>MessageExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>16</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>9</integer>
|
||||
<integer>11</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>10</integer>
|
||||
<integer>12</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground) 3.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>23</integer>
|
||||
<integer>26</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground) 4.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>24</integer>
|
||||
<integer>27</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground) 5.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>26</integer>
|
||||
<integer>29</integer>
|
||||
</dict>
|
||||
<key>MyPlayground (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>8</integer>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
<key>SFA.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
<integer>24</integer>
|
||||
</dict>
|
||||
<key>SFI.xcscheme</key>
|
||||
<dict>
|
||||
@@ -131,121 +131,121 @@
|
||||
<key>SFM.System.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>5</integer>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
<key>SFM.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>SystemExtension.xcscheme_^#shared#^_</key>
|
||||
<key>SFM.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>SystemExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>Test.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>10</integer>
|
||||
<integer>13</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>6</integer>
|
||||
<integer>8</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>7</integer>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground) 3.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>33</integer>
|
||||
<integer>36</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground) 4.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>34</integer>
|
||||
<integer>37</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground) 5.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>35</integer>
|
||||
<integer>38</integer>
|
||||
</dict>
|
||||
<key>Tour (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>5</integer>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>12</integer>
|
||||
<integer>15</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>13</integer>
|
||||
<integer>16</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground) 3.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>30</integer>
|
||||
<integer>33</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground) 4.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>31</integer>
|
||||
<integer>34</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground) 5.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>32</integer>
|
||||
<integer>35</integer>
|
||||
</dict>
|
||||
<key>TransactionObserver (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>11</integer>
|
||||
<integer>14</integer>
|
||||
</dict>
|
||||
<key>mactest.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>25</integer>
|
||||
<integer>28</integer>
|
||||
</dict>
|
||||
<key>sing-box.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>20</integer>
|
||||
<integer>23</integer>
|
||||
</dict>
|
||||
<key>test.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>19</integer>
|
||||
<integer>22</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
||||