diff --git a/ApplicationLibrary/Views/Profile/ImportProfileView.swift b/ApplicationLibrary/Views/Profile/ImportProfileView.swift
index 2c1d22e..9755bea 100644
--- a/ApplicationLibrary/Views/Profile/ImportProfileView.swift
+++ b/ApplicationLibrary/Views/Profile/ImportProfileView.swift
@@ -7,20 +7,18 @@
@MainActor
public struct ImportProfileView: View {
+ @EnvironmentObject private var environments: ExtensionEnvironments
@Environment(\.dismiss) private var dismiss
@State private var isLoading = false
@State private var selected = false
@State private var alert: Alert?
- @State private var connection: NWSocket?
+ @State private var connection: NWConnection?
+ @State private var socket: NWSocket?
@State private var profiles: [LibboxProfilePreview]?
@State private var isImporting = false
- private let callback: () async -> Void
-
- public init(callback: @escaping () async -> Void) {
- self.callback = callback
- }
+ public init() {}
public var body: some View {
VStack(alignment: .center) {
if !selected {
@@ -73,17 +71,23 @@
}
private func reset() {
- selected = false
- profiles = nil
if let connection {
+ connection.stateUpdateHandler = nil
connection.cancel()
self.connection = nil
}
+ if let socket {
+ socket.cancel()
+ self.socket = nil
+ }
+ selected = false
+ profiles = nil
}
private func handleEndpoint(_ endpoint: NWEndpoint) async {
let connection = NWConnection(to: endpoint, using: NWParameters.applicationService)
- self.connection = NWSocket(connection)
+ self.connection = connection
+ socket = NWSocket(connection)
connection.stateUpdateHandler = { state in
switch state {
case let .failed(error):
@@ -104,13 +108,13 @@
}
private nonisolated func loopMessages() async throws {
- guard let connection = await connection else {
+ guard let socket = await socket else {
return
}
var message: Data
while true {
do {
- message = try connection.read()
+ message = try socket.read()
} catch {
throw NSError(domain: "read from connection: \(error.localizedDescription)", code: 0)
}
@@ -147,6 +151,7 @@
throw error
}
try await importProfile(content!)
+ return
default:
throw NSError(domain: "unknown message type \(message[0])", code: 0)
}
@@ -157,10 +162,14 @@
guard let connection else {
return
}
+ guard let socket else {
+ return
+ }
+ connection.stateUpdateHandler = nil
let request = LibboxProfileContentRequest()
request.profileID = profileID
do {
- try connection.write(request.encode())
+ try socket.write(request.encode())
isImporting = true
} catch {
alert = Alert(error)
@@ -191,8 +200,8 @@
}
try await ProfileManager.create(Profile(name: content.name, type: type, path: profileConfig.relativePath, remoteURL: content.remotePath, autoUpdate: content.autoUpdate, lastUpdated: lastUpdated))
await reset()
- await callback()
await MainActor.run {
+ environments.profileUpdate.send()
dismiss()
}
}
diff --git a/ApplicationLibrary/Views/Profile/ProfileView.swift b/ApplicationLibrary/Views/Profile/ProfileView.swift
index 2b3b0b1..dd32c2d 100644
--- a/ApplicationLibrary/Views/Profile/ProfileView.swift
+++ b/ApplicationLibrary/Views/Profile/ProfileView.swift
@@ -66,9 +66,7 @@ public struct ProfileView: View {
}
if ApplicationLibrary.inPreview || devicePickerSupports(.applicationService(name: "sing-box"), parameters: { .applicationService }) {
FormNavigationLink {
- ImportProfileView {
- await doReload()
- }
+ ImportProfileView()
} label: {
Text("Import Profile").foregroundColor(.accentColor)
}
@@ -188,15 +186,15 @@ public struct ProfileView: View {
}
private func doReload() async {
+ defer {
+ isLoading = false
+ }
if ApplicationLibrary.inPreview {
profileList = [
ProfilePreview(Profile(id: 0, name: "profile local", type: .local, path: "")),
ProfilePreview(Profile(id: 1, name: "profile remote", type: .remote, path: "", lastUpdated: Date(timeIntervalSince1970: 0))),
]
} else {
- defer {
- isLoading = false
- }
do {
profileList = try await ProfileManager.list().map { ProfilePreview($0) }
} catch {
diff --git a/ApplicationLibrary/Views/Setting/SettingView.swift b/ApplicationLibrary/Views/Setting/SettingView.swift
index 7c1fe37..1248be3 100644
--- a/ApplicationLibrary/Views/Setting/SettingView.swift
+++ b/ApplicationLibrary/Views/Setting/SettingView.swift
@@ -132,8 +132,16 @@ public struct SettingView: View {
Text("Loading...")
.onAppear {
Task.detached {
- taiwanFlagAvailable = !DeviceCensorship.isChinaDevice()
- isLoading = false
+ let available: Bool
+ if ApplicationLibrary.inPreview {
+ available = true
+ } else {
+ available = !DeviceCensorship.isChinaDevice()
+ }
+ await MainActor.run {
+ taiwanFlagAvailable = available
+ isLoading = false
+ }
}
}
} else {
diff --git a/MacLibrary/MainView.swift b/MacLibrary/MainView.swift
index c78d6cf..687d3c8 100644
--- a/MacLibrary/MainView.swift
+++ b/MacLibrary/MainView.swift
@@ -14,15 +14,8 @@ public struct MainView: View {
@State private var alert: Alert?
public init() {}
- public var body: some View {
- if ApplicationLibrary.inPreview {
- body1.frame(width: 1280, height: 750, alignment: .topLeading)
- } else {
- body1
- }
- }
- private var body1: some View {
+ public var body: some View {
NavigationSplitView {
SidebarView()
.navigationSplitViewColumnWidth(150)
@@ -31,9 +24,9 @@ public struct MainView: View {
selection.contentView
.navigationTitle(selection.title)
}
- .navigationSplitViewColumnWidth(600)
+ .navigationSplitViewColumnWidth(650)
}
- .frame(minHeight: 470)
+ .frame(minHeight: 500)
.onAppear {
environments.postReload()
#if !DEBUG
diff --git a/MacLibrary/SidebarView.swift b/MacLibrary/SidebarView.swift
index df83edf..7c4b33e 100644
--- a/MacLibrary/SidebarView.swift
+++ b/MacLibrary/SidebarView.swift
@@ -9,14 +9,16 @@ public struct SidebarView: View {
public init() {}
public var body: some View {
VStack {
- if environments.extensionProfileLoading {
+ if ApplicationLibrary.inPreview {
+ SidebarViewPreview()
+ } else if environments.extensionProfileLoading {
ProgressView()
} else if let profile = environments.extensionProfile {
SidebarView0().environmentObject(profile)
} else {
SidebarView1()
}
- }.frame(minWidth: 150)
+ }
}
struct SidebarView0: View {
@@ -69,4 +71,26 @@ public struct SidebarView: View {
}
}
}
+
+ struct SidebarViewPreview: View {
+ @Environment(\.selection) private var selection
+ var body: some View {
+ VStack {
+ List(selection: selection) {
+ Section(NavigationPage.dashboard.title) {
+ Label("Overview", systemImage: "text.and.command.macwindow")
+ .tint(.textColor)
+ .tag(NavigationPage.dashboard)
+ NavigationPage.groups.label.tag(NavigationPage.groups)
+ }
+ Divider()
+ ForEach(NavigationPage.macosDefaultPages, id: \.self) { it in
+ it.label
+ }
+ }
+ .listStyle(.sidebar)
+ .scrollDisabled(true)
+ }
+ }
+ }
}
diff --git a/SFM.System/Export.plist b/SFM.System/Export.plist
new file mode 100644
index 0000000..9f9bba4
--- /dev/null
+++ b/SFM.System/Export.plist
@@ -0,0 +1,17 @@
+
+
+
+
+ destination
+ export
+ method
+ developer-id
+ provisioningProfiles
+
+ io.nekohasekai.sfavt.standalone
+ XC io nekohasekai sfavt standalone
+ io.nekohasekai.sfavt.system
+ XC io nekohasekai sfavt system
+
+
+
diff --git a/sing-box.xcodeproj/project.pbxproj b/sing-box.xcodeproj/project.pbxproj
index 2f1a0f8..d6b2d97 100644
--- a/sing-box.xcodeproj/project.pbxproj
+++ b/sing-box.xcodeproj/project.pbxproj
@@ -24,6 +24,7 @@
3A27D9002A89BE230031EBCC /* CommandClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A27D8FF2A89BE230031EBCC /* CommandClient.swift */; };
3A27D9022A89C6870031EBCC /* ExtensionEnvironments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A27D9012A89C6870031EBCC /* ExtensionEnvironments.swift */; };
3A2EAEED2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */; };
+ 3A2F29EB2C998A5D007E024C /* Export.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3A2F29EA2C998A5D007E024C /* Export.plist */; };
3A3AA7FC2A4EFDAE002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
3A3AA7FF2A4EFDB3002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
3A3AB2A72B70C146001815AE /* CoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3AB2A62B70C146001815AE /* CoreView.swift */; };
@@ -454,6 +455,7 @@
3A27D8FF2A89BE230031EBCC /* CommandClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandClient.swift; sourceTree = ""; };
3A27D9012A89C6870031EBCC /* ExtensionEnvironments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionEnvironments.swift; sourceTree = ""; };
3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndependentApplicationDelegate.swift; sourceTree = ""; };
+ 3A2F29EA2C998A5D007E024C /* Export.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Export.plist; sourceTree = ""; };
3A3AB2A62B70C146001815AE /* CoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreView.swift; sourceTree = ""; };
3A3AB2A82B70C5F1001815AE /* RequestReviewButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestReviewButton.swift; sourceTree = ""; };
3A3DEBE12A4FFA1A00373BF4 /* ExtensionFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExtensionFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/System/Library/Frameworks/ExtensionFoundation.framework; sourceTree = DEVELOPER_DIR; };
@@ -966,6 +968,7 @@
3AEECC052A6DF9CA006A0E0C /* SFM.System */ = {
isa = PBXGroup;
children = (
+ 3A2F29EA2C998A5D007E024C /* Export.plist */,
3AEECC062A6DF9CA006A0E0C /* Application.swift */,
3AEECC502A6E0074006A0E0C /* SFM.entitlements */,
3A2223532A6E1B6700C50B23 /* Info.plist */,
@@ -1438,6 +1441,7 @@
3AABFD472A9CCC58005A24A4 /* Upload.plist in Resources */,
3A6CA5A82A713B340027933B /* AppIcon.icns in Resources */,
3AEC8A4F2A6E5E18003702E1 /* Assets.xcassets in Resources */,
+ 3A2F29EB2C998A5D007E024C /* Export.plist in Resources */,
3AEECC0B2A6DF9CA006A0E0C /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;