diff --git a/ApplicationLibrary/Assets.xcassets/Contents.json b/ApplicationLibrary/Assets.xcassets/Contents.json
index 74d6a72..73c0059 100644
--- a/ApplicationLibrary/Assets.xcassets/Contents.json
+++ b/ApplicationLibrary/Assets.xcassets/Contents.json
@@ -1,6 +1,6 @@
{
- "info": {
- "author": "xcode",
- "version": 1
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
}
}
diff --git a/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/Contents.json b/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/Contents.json
new file mode 100644
index 0000000..ce9c51a
--- /dev/null
+++ b/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "symbol-rendering-intent" : "template"
+ },
+ "symbols" : [
+ {
+ "filename" : "singbox-menubar.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/singbox-menubar.svg b/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/singbox-menubar.svg
new file mode 100644
index 0000000..af59e8f
--- /dev/null
+++ b/ApplicationLibrary/Assets.xcassets/MenuIcon.symbolset/singbox-menubar.svg
@@ -0,0 +1,194 @@
+
+
+
diff --git a/ApplicationLibrary/Views/Abstract/NavigationStackCompat.swift b/ApplicationLibrary/Views/Abstract/NavigationStackCompat.swift
index aed7cb8..3822d5b 100644
--- a/ApplicationLibrary/Views/Abstract/NavigationStackCompat.swift
+++ b/ApplicationLibrary/Views/Abstract/NavigationStackCompat.swift
@@ -1,6 +1,6 @@
import SwiftUI
-public func NavigationStackCompat(@ViewBuilder content: () -> T) -> some View where T: View{
+public func NavigationStackCompat(@ViewBuilder content: () -> some View) -> some View {
viewBuilder {
if #available(iOS 17.0, *) {
// view not updating in iOS 16, but why?
diff --git a/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift b/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift
index 69d8d08..76bb1be 100644
--- a/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift
+++ b/ApplicationLibrary/Views/Dashboard/ActiveDashboardView.swift
@@ -4,82 +4,53 @@ import Library
import SwiftUI
public struct ActiveDashboardView: View {
- public static let NotificationUpdateSelectedProfile = Notification.Name("update-selected-profile")
-
@Environment(\.scenePhase) var scenePhase
- @Environment(\.selection) private var selection
-
+ @Environment(\.selection) private var parentSelection
@EnvironmentObject private var profile: ExtensionProfile
-
@State private var isLoading = true
@State private var profileList: [Profile] = []
@State private var selectedProfileID: Int64!
- @State private var reasserting = false
- @State private var observer: Any?
@State private var alert: Alert?
+ @State private var selection = DashboardPage.overview
public init() {}
-
public var body: some View {
- viewBuilder {
- if isLoading {
- ProgressView().onAppear {
- Task.detached {
- await doReload()
- }
- }
- } else {
- if profileList.isEmpty {
- Text("Empty profiles")
- } else {
- VStack {
- #if os(iOS) || os(tvOS)
- if ApplicationLibrary.inPreview || profile.status.isConnected {
- ExtensionStatusView()
- .listStyle(.automatic)
- #if os(iOS)
- .navigationBarTitleDisplayMode(.inline)
- #endif
- }
- FormView {
- StartStopButton()
- Section("Profile") {
- Picker(selection: $selectedProfileID) {
- ForEach(profileList, id: \.id) { profile in
- Text(profile.name).tag(profile.id)
- }
- } label: {}
- .pickerStyle(.inline)
- }
- }
- #elseif os(macOS)
- if ApplicationLibrary.inPreview || profile.status.isConnected {
- ExtensionStatusView()
- }
- FormView {
- Section("Profile") {
- ForEach(profileList, id: \.id) { profile in
- Picker(profile.name, selection: $selectedProfileID) {
- Text("").tag(profile.id)
- }
- }
- .pickerStyle(.radioGroup)
- }
- }
- #endif
- }
- .onChangeCompat(of: selectedProfileID) {
- reasserting = true
- Task.detached {
- await switchProfile(selectedProfileID!)
- }
- }
- .disabled(!ApplicationLibrary.inPreview && (!profile.status.isSwitchable || reasserting))
+ if isLoading {
+ ProgressView().onAppear {
+ Task.detached {
+ await doReload()
}
}
- }
- .alertBinding($alert)
- #if os(iOS) || os(tvOS)
+ } else {
+ viewBuilder {
+ #if os(iOS) || os(tvOS)
+ if ApplicationLibrary.inPreview || profile.status.isConnectedStrict {
+ Picker("Page", selection: $selection) {
+ ForEach(DashboardPage.allCases) { page in
+ page.label
+ }
+ }
+ .pickerStyle(.segmented)
+ #if os(iOS)
+
+ .padding([.leading, .trailing])
+ .navigationBarTitleDisplayMode(.inline)
+ #endif
+ TabView(selection: $selection) {
+ ForEach(DashboardPage.allCases) { page in
+ page.contentView($profileList, $selectedProfileID)
+ .tag(page)
+ }
+ }
+ .tabViewStyle(.page(indexDisplayMode: .always))
+ } else {
+ OverviewView($profileList, $selectedProfileID)
+ }
+ #elseif os(macOS)
+ OverviewView($profileList, $selectedProfileID)
+ #endif
+ }
+ #if os(iOS) || os(tvOS)
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
Task.detached {
@@ -87,29 +58,16 @@ public struct ActiveDashboardView: View {
}
}
}
- .onChangeCompat(of: selection.wrappedValue) { newValue in
+ .onChangeCompat(of: parentSelection.wrappedValue) { 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)
- }
- }
- #endif
+ #endif
+ .alertBinding($alert)
+ }
}
private func doReload() {
@@ -143,28 +101,4 @@ public struct ActiveDashboardView: View {
}
}
}
-
- private func switchProfile(_ newProfileID: Int64) {
- SharedPreferences.selectedProfileID = newProfileID
- NotificationCenter.default.post(name: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil)
- if profile.status.isConnected {
- do {
- try LibboxNewStandaloneCommandClient()!.serviceReload()
- } catch {
- alert = Alert(error)
- }
- }
- reasserting = false
- }
-
- private struct ServiceErrorReporter: View {
- private let parent: ActiveDashboardView
- init(_ parent: ActiveDashboardView) {
- self.parent = parent
- }
-
- var body: some View {
- EmptyView()
- }
- }
}
diff --git a/ApplicationLibrary/Views/Dashboard/DashboardPage.swift b/ApplicationLibrary/Views/Dashboard/DashboardPage.swift
new file mode 100644
index 0000000..2d500fb
--- /dev/null
+++ b/ApplicationLibrary/Views/Dashboard/DashboardPage.swift
@@ -0,0 +1,43 @@
+import Foundation
+import Library
+import SwiftUI
+
+public enum DashboardPage: Int, CaseIterable, Identifiable {
+ public var id: Self {
+ self
+ }
+
+ case overview
+ case groups
+}
+
+public extension DashboardPage {
+ var title: String {
+ switch self {
+ case .overview:
+ return NSLocalizedString("Overview", comment: "")
+ case .groups:
+ return NSLocalizedString("Groups", comment: "")
+ }
+ }
+
+ var label: some View {
+ switch self {
+ case .overview:
+ return Label("Overview", systemImage: "text.and.command.macwindow")
+ case .groups:
+ return Label("Groups", systemImage: "rectangle.3.group.fill")
+ }
+ }
+
+ func contentView(_ profileList: Binding<[Profile]>, _ selectedProfileID: Binding) -> some View {
+ viewBuilder {
+ switch self {
+ case .overview:
+ OverviewView(profileList, selectedProfileID)
+ case .groups:
+ GroupListView()
+ }
+ }
+ }
+}
diff --git a/ApplicationLibrary/Views/Dashboard/DashboardView.swift b/ApplicationLibrary/Views/Dashboard/DashboardView.swift
index 4a7bf17..74d1b86 100644
--- a/ApplicationLibrary/Views/Dashboard/DashboardView.swift
+++ b/ApplicationLibrary/Views/Dashboard/DashboardView.swift
@@ -40,7 +40,6 @@ public struct DashboardView: View {
}
}
#endif
- .navigationTitle("Dashboard")
}
#if os(macOS)
diff --git a/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift b/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift
index 4adc655..784d22b 100644
--- a/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift
+++ b/ApplicationLibrary/Views/Dashboard/ExtensionStatusView.swift
@@ -18,28 +18,50 @@ public struct ExtensionStatusView: View {
VStack {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: columnCount), alignment: .leading) {
if ApplicationLibrary.inPreview {
- StatusItem("Memory", "6.4 MiB")
- StatusItem("Goroutines", "89")
- StatusItem("Inbound Connections", "34")
- StatusItem("Outbound Connections", "28")
- StatusItem("Uplink", "38 B/s")
- StatusItem("Downlink", "249 MiB/s")
- StatusItem("Uplink Total", "52 MiB")
- StatusItem("Downlink Total", "5.6 GiB")
+ StatusItem("Status") {
+ StatusLine("Memory", "6.4 MiB")
+ StatusLine("Goroutines", "89")
+ }
+ StatusItem("Connections") {
+ StatusLine("Inbound", "34")
+ StatusLine("Outbound", "28")
+ }
+ StatusItem("Traffic") {
+ StatusLine("Uplink", "38 B/s")
+ StatusLine("Downlink", "249 MiB/s")
+ }
+ StatusItem("TrafficTotal") {
+ StatusLine("Uplink", "52 MiB")
+ StatusLine("Downlink", "5.6 GiB")
+ }
} else if let message {
- StatusItem("Memory", LibboxFormatBytes(message.memory))
- StatusItem("Goroutines", "\(message.goroutines)")
+ StatusItem("Status") {
+ StatusLine("Memory", LibboxFormatBytes(message.memory))
+ StatusLine("Goroutines", "\(message.goroutines)")
+ }
+ StatusItem("Connections") {
+ StatusLine("Inbound", "\(message.connectionsIn)")
+ StatusLine("Outbound", "\(message.connectionsOut)")
+ }
if message.trafficAvailable {
- StatusItem("Inbound Connections", "\(message.connectionsIn)")
- StatusItem("Outbound Connections", "\(message.connectionsOut)")
- StatusItem("Uplink", LibboxFormatBytes(message.uplink) + "/s")
- StatusItem("Downlink", LibboxFormatBytes(message.downlink) + "/s")
- StatusItem("Uplink Total", LibboxFormatBytes(message.uplinkTotal))
- StatusItem("Downlink Total", LibboxFormatBytes(message.downlinkTotal))
+ StatusItem("Traffic") {
+ StatusLine("Uplink", "\(LibboxFormatBytes(message.uplink))/s")
+ StatusLine("Downlink", "\(LibboxFormatBytes(message.downlink))/s")
+ }
+ StatusItem("TrafficTotal") {
+ StatusLine("Uplink", LibboxFormatBytes(message.uplinkTotal))
+ StatusLine("Downlink", LibboxFormatBytes(message.downlinkTotal))
+ }
}
} else {
- StatusItem("Memory", "Loading...")
- StatusItem("Goroutines", "Loading...")
+ StatusItem("Status") {
+ StatusLine("Memory", "...")
+ StatusLine("Goroutines", "...")
+ }
+ StatusItem("Connections") {
+ StatusLine("Inbound", "...")
+ StatusLine("Outbound", "...")
+ }
}
}.background {
GeometryReader { geometry in
@@ -142,26 +164,25 @@ public struct ExtensionStatusView: View {
func writeGroups(_: LibboxOutboundGroupIteratorProtocol?) {}
}
- private struct StatusItem: View {
- private let name: String
- private let value: String
- init(_ name: String, _ value: String) {
- self.name = name
- self.value = value
+ private struct StatusItem: View where T: View {
+ private let title: String
+ @ViewBuilder private let content: () -> T
+
+ init(_ title: String, @ViewBuilder content: @escaping () -> T) {
+ self.title = title
+ self.content = content
}
var body: some View {
- VStack(alignment: .leading, spacing: 8) {
+ VStack(alignment: .leading) {
HStack {
- Text(name)
- .font(.subheadline)
- .foregroundColor(.secondary)
+ Text(title)
+ .font(.headline)
Spacer()
- }
- Text(value)
- .font(.system(size: 16))
+ }.padding(.bottom, 8)
+ content()
}
- .frame(minWidth: 125)
+ .frame(minWidth: 125, alignment: .topLeading)
#if os(tvOS)
.padding(EdgeInsets(top: 20, leading: 26, bottom: 20, trailing: 26))
#else
@@ -181,4 +202,25 @@ public struct ExtensionStatusView: View {
#endif
}
}
+
+ private struct StatusLine: View {
+ private let name: String
+ private let value: String
+
+ init(_ name: String, _ value: String) {
+ self.name = name
+ self.value = value
+ }
+
+ var body: some View {
+ HStack {
+ Text(name)
+ .font(.subheadline)
+ .foregroundColor(.secondary)
+ Spacer()
+ Text(value)
+ .font(.subheadline)
+ }
+ }
+ }
}
diff --git a/ApplicationLibrary/Views/Dashboard/OverviewView.swift b/ApplicationLibrary/Views/Dashboard/OverviewView.swift
new file mode 100644
index 0000000..dd8ca67
--- /dev/null
+++ b/ApplicationLibrary/Views/Dashboard/OverviewView.swift
@@ -0,0 +1,87 @@
+import Foundation
+import Libbox
+import Library
+import SwiftUI
+
+public struct OverviewView: View {
+ public static let NotificationUpdateSelectedProfile = Notification.Name("update-selected-profile")
+
+ @Environment(\.scenePhase) var scenePhase
+ @Environment(\.selection) private var selection
+ @EnvironmentObject private var profile: ExtensionProfile
+ @Binding private var profileList: [Profile]
+ @Binding private var selectedProfileID: Int64!
+ @State private var alert: Alert?
+ @State private var reasserting = false
+ @State private var observer: Any?
+
+ public init(_ profileList: Binding<[Profile]>, _ selectedProfileID: Binding) {
+ _profileList = profileList
+ _selectedProfileID = selectedProfileID
+ }
+
+ public var body: some View {
+ VStack {
+ if ApplicationLibrary.inPreview || profile.status.isConnected {
+ ExtensionStatusView()
+ }
+ FormView {
+ #if os(iOS) || os(tvOS)
+ StartStopButton()
+ Section("Profile") {
+ Picker(selection: $selectedProfileID) {
+ ForEach(profileList, id: \.id) { profile in
+ Text(profile.name).tag(profile.id)
+ }
+ } label: {}
+ .pickerStyle(.inline)
+ }
+ #elseif os(macOS)
+ Section("Profile") {
+ ForEach(profileList, id: \.id) { profile in
+ Picker(profile.name, selection: $selectedProfileID) {
+ Text("").tag(profile.id)
+ }
+ }
+ .pickerStyle(.radioGroup)
+ }
+ #endif
+ }
+ }
+ .alertBinding($alert)
+ .onChangeCompat(of: selectedProfileID) {
+ reasserting = true
+ Task.detached {
+ await switchProfile(selectedProfileID!)
+ }
+ }
+ .disabled(!ApplicationLibrary.inPreview && (!profile.status.isSwitchable || reasserting))
+ #if os(macOS)
+ .onAppear {
+ if observer == nil {
+ observer = NotificationCenter.default.addObserver(forName: OverviewView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { newProfileID in
+ selectedProfileID = newProfileID.object as! Int64
+ })
+ }
+ }
+ .onDisappear {
+ if let observer {
+ NotificationCenter.default.removeObserver(observer)
+ }
+ }
+ #endif
+ }
+
+ private func switchProfile(_ newProfileID: Int64) {
+ SharedPreferences.selectedProfileID = newProfileID
+ NotificationCenter.default.post(name: OverviewView.NotificationUpdateSelectedProfile, object: newProfileID)
+ if profile.status.isConnected {
+ do {
+ try LibboxNewStandaloneCommandClient()!.serviceReload()
+ } catch {
+ alert = Alert(error)
+ }
+ }
+ reasserting = false
+ }
+}
diff --git a/ApplicationLibrary/Views/Groups/GroupItemView.swift b/ApplicationLibrary/Views/Groups/GroupItemView.swift
index cb379d0..5a25b2d 100644
--- a/ApplicationLibrary/Views/Groups/GroupItemView.swift
+++ b/ApplicationLibrary/Views/Groups/GroupItemView.swift
@@ -17,48 +17,54 @@ public struct GroupItemView: View {
@State private var alert: Alert?
public var body: some View {
- HStack {
- if group.selected == item.tag {
- Rectangle()
- .fill(Color.accentColor)
- .frame(width: 6)
- } else {
- Rectangle()
- .fill(.clear)
- .frame(width: 6)
- }
- VStack {
- HStack {
- Text(item.tag)
- .truncationMode(.tail)
- .lineLimit(1)
- .font(.system(size: 14))
- Spacer(minLength: 6)
- }
- Spacer(minLength: 6)
- HStack(alignment: .center) {
- Text(item.type)
- .foregroundColor(.secondary)
- .font(.system(size: 12))
- Spacer(minLength: 6)
- if item.urlTestDelay > 0 {
- Text(item.delayString)
- .foregroundColor(item.delayColor)
- .font(.system(size: 11))
- }
- }
- }
- .frame(height: 36)
- .padding([.top, .bottom, .trailing], 12)
- }
- .background(backgroundColor)
- .onTapGesture {
+ Button(action: {
if group.selectable, group.selected != item.tag {
Task.detached {
selectOutbound()
}
}
- }
+ }, label: {
+ HStack {
+ VStack {
+ HStack {
+ Text(item.tag)
+ .font(.caption)
+ .foregroundStyle(.foreground)
+ .lineLimit(1)
+ .truncationMode(.tail)
+ Spacer(minLength: 0)
+
+ }
+ Spacer(minLength: 8)
+ HStack {
+ Text(item.type)
+ .font(.caption)
+ .foregroundColor(.secondary)
+ Spacer(minLength: 0)
+
+ }
+ }
+ Spacer(minLength: 0)
+ VStack {
+ if group.selected == item.tag {
+ Image(systemName: "checkmark.circle.fill")
+ .foregroundStyle(Color.accentColor)
+ }
+ Spacer(minLength: 0)
+ if item.urlTestDelay > 0 {
+ Text(item.delayString)
+ .font(.caption)
+ .foregroundColor(item.delayColor)
+ }
+ }
+ }
+ })
+ #if !os(tvOS)
+ .buttonStyle(.borderless)
+ .padding(EdgeInsets(top: 10, leading: 13, bottom: 10, trailing: 13))
+ .background(backgroundColor)
+ .cornerRadius(10)
+ #endif
.alertBinding($alert)
}
diff --git a/ApplicationLibrary/Views/Groups/GroupListView.swift b/ApplicationLibrary/Views/Groups/GroupListView.swift
index 7d0ed44..09937c8 100644
--- a/ApplicationLibrary/Views/Groups/GroupListView.swift
+++ b/ApplicationLibrary/Views/Groups/GroupListView.swift
@@ -23,7 +23,6 @@ public struct GroupListView: View {
}, set: { newValue in
groupExpand[it.tag] = newValue
}))
- Spacer()
}
}.padding()
}
@@ -40,7 +39,6 @@ public struct GroupListView: View {
}
commandClient = nil
}
- .navigationTitle("Groups")
}
private func doReload() {
@@ -51,7 +49,7 @@ public struct GroupListView: View {
OutboundGroupItem(tag: "server2", type: "WireGuard", urlTestTime: .now, urlTestDelay: 34),
OutboundGroupItem(tag: "auto", type: "URLTest", urlTestTime: .now, urlTestDelay: 100),
]),
- OutboundGroup(tag: "group2", type: "urltest", selected: "client", selectable: false, items:
+ OutboundGroup(tag: "group2", type: "urltest", selected: "client", selectable: true, items:
(0 ..< 234).map { index in
OutboundGroupItem(tag: "client\(index)", type: "Shadowsocks", urlTestTime: .now, urlTestDelay: UInt16(100 + index * 10))
}),
diff --git a/ApplicationLibrary/Views/Groups/GroupView.swift b/ApplicationLibrary/Views/Groups/GroupView.swift
index c3b68a5..9da8e40 100644
--- a/ApplicationLibrary/Views/Groups/GroupView.swift
+++ b/ApplicationLibrary/Views/Groups/GroupView.swift
@@ -15,12 +15,12 @@ public struct GroupView: View {
private var title: some View {
HStack {
Text(group.tag)
- .font(.system(size: 17))
+ .font(.headline)
Text(group.displayType)
- .font(.system(size: 13))
+ .font(.subheadline)
.foregroundColor(.secondary)
Text("\(group.items.count)")
- .font(.system(size: 11))
+ .font(.subheadline)
.padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4))
.background(Color.gray.opacity(0.5))
.cornerRadius(4)
@@ -33,7 +33,7 @@ public struct GroupView: View {
Image(systemName: "arrow.up.to.line")
}
}
- #if os(macOS)
+ #if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
Button {
@@ -43,11 +43,10 @@ public struct GroupView: View {
} label: {
Image(systemName: "bolt.fill")
}
- #if os(macOS)
+ #if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
- Spacer(minLength: 6)
- }
+ }.padding([.top, .bottom], 8)
}
public var body: some View {
@@ -61,13 +60,17 @@ public struct GroupView: View {
}
}
} else {
- VStack {
+ VStack(spacing: 5) {
ForEach(Array(itemGroups.enumerated()), id: \.offset) { items in
- HStack {
+ HStack(spacing: 5) {
ForEach(items.element, id: \.tag) { it in
Rectangle()
.fill(it.delayColor)
+ #if !os(tvOS)
.frame(width: 10, height: 10)
+ #else
+ .frame(width: 30, height: 30)
+ #endif
}
}.frame(maxWidth: .infinity, alignment: .topLeading)
}
@@ -93,7 +96,12 @@ public struct GroupView: View {
}
private var itemGroups: [[OutboundGroupItem]] {
- let count = Int(Int(geometryWidth) / 20)
+ let count: Int
+ #if os(tvOS)
+ count = Int(Int(geometryWidth) / 40)
+ #else
+ count = Int(Int(geometryWidth) / 20)
+ #endif
if count == 0 {
return [group.items]
} else {
@@ -104,11 +112,13 @@ public struct GroupView: View {
}
private func explandColumnCount() -> Int {
- let count = Int(Int(geometryWidth) / 180)
+ let standardCount = Int(Int(geometryWidth) / 180)
#if os(iOS)
- return count < 2 ? 2 : count
+ return standardCount < 2 ? 2 : standardCount
+ #elseif os(tvOS)
+ return Int(Int(geometryWidth) / 400)
#else
- return count < 1 ? 1 : count
+ return standardCount < 1 ? 1 : standardCount
#endif
}
diff --git a/ApplicationLibrary/Views/Log/LogView.swift b/ApplicationLibrary/Views/Log/LogView.swift
index a62e502..ffb99af 100644
--- a/ApplicationLibrary/Views/Log/LogView.swift
+++ b/ApplicationLibrary/Views/Log/LogView.swift
@@ -13,7 +13,6 @@ public struct LogView: View {
Text("Service not started")
}
}
- .navigationTitle("Logs")
}
private struct LogView0: View {
@@ -43,7 +42,7 @@ public struct LogView: View {
#if os(tvOS)
.focusable()
#endif
- Spacer(minLength: 5)
+ Spacer(minLength: 8)
}
.onChangeCompat(of: logClient.logList.count) { newCount in
diff --git a/ApplicationLibrary/Views/NavigationPage.swift b/ApplicationLibrary/Views/NavigationPage.swift
index 7f4e8f5..8ee0f5f 100644
--- a/ApplicationLibrary/Views/NavigationPage.swift
+++ b/ApplicationLibrary/Views/NavigationPage.swift
@@ -8,13 +8,19 @@ public enum NavigationPage: Int, CaseIterable, Identifiable {
}
case dashboard
- case groups
+ #if os(macOS)
+ case groups
+ #endif
case logs
case profiles
case settings
}
public extension NavigationPage {
+ static var macosDefaultPages: [NavigationPage] {
+ [.logs, .profiles, .settings]
+ }
+
var label: some View {
Label(title, systemImage: iconImage)
}
@@ -23,8 +29,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
return NSLocalizedString("Dashboard", comment: "")
- case .groups:
- return NSLocalizedString("Groups", comment: "")
+ #if os(macOS)
+ case .groups:
+ return NSLocalizedString("Groups", comment: "")
+ #endif
case .logs:
return NSLocalizedString("Logs", comment: "")
case .profiles:
@@ -38,8 +46,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
return "text.and.command.macwindow"
- case .groups:
- return "rectangle.3.group.fill"
+ #if os(macOS)
+ case .groups:
+ return "rectangle.3.group.fill"
+ #endif
case .logs:
return "doc.text.fill"
case .profiles:
@@ -54,9 +64,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
DashboardView()
-
- case .groups:
- GroupListView()
+ #if os(macOS)
+ case .groups:
+ GroupListView()
+ #endif
case .logs:
LogView()
case .profiles:
@@ -70,20 +81,14 @@ public extension NavigationPage {
#endif
}
- func visible(_ profile: ExtensionProfile?) -> Bool {
- switch self {
- case .groups:
- #if os(tvOS)
- // TODO: fix groups ui
- return false
- #else
- if ApplicationLibrary.inPreview {
- return true
- }
+ #if os(macOS)
+ func visible(_ profile: ExtensionProfile?) -> Bool {
+ switch self {
+ case .groups:
return profile?.status.isConnectedStrict == true
- #endif
- default:
- return true
+ default:
+ return true
+ }
}
- }
+ #endif
}
diff --git a/ApplicationLibrary/Views/Profile/ProfileView.swift b/ApplicationLibrary/Views/Profile/ProfileView.swift
index 552bfb8..5de8b99 100644
--- a/ApplicationLibrary/Views/Profile/ProfileView.swift
+++ b/ApplicationLibrary/Views/Profile/ProfileView.swift
@@ -115,7 +115,6 @@ public struct ProfileView: View {
}
}
.disabled(isUpdating)
- .navigationTitle("Profiles")
.alertBinding($alert, $isLoading)
.onAppear {
if let profile = importProfile.wrappedValue {
diff --git a/ApplicationLibrary/Views/Setting/SettingView.swift b/ApplicationLibrary/Views/Setting/SettingView.swift
index 95806d5..edcce66 100644
--- a/ApplicationLibrary/Views/Setting/SettingView.swift
+++ b/ApplicationLibrary/Views/Setting/SettingView.swift
@@ -129,7 +129,6 @@ public struct SettingView: View {
}
}
}
- .navigationTitle("Settings")
.alertBinding($alert)
}
diff --git a/MacLibrary/MacApplication.swift b/MacLibrary/MacApplication.swift
index bdc5c4d..6de43e6 100644
--- a/MacLibrary/MacApplication.swift
+++ b/MacLibrary/MacApplication.swift
@@ -53,7 +53,7 @@ public struct MacApplication: Scene {
MenuBarExtra(isInserted: $showMenuBarExtra) {
MenuView(isMenuPresented: $isMenuPresented)
} label: {
- Image(systemName: "network.badge.shield.half.filled")
+ Image("MenuIcon")
}
.menuBarExtraStyle(.window)
.menuBarExtraAccess(isPresented: $isMenuPresented)
diff --git a/MacLibrary/MainView.swift b/MacLibrary/MainView.swift
index 97118f5..0530178 100644
--- a/MacLibrary/MainView.swift
+++ b/MacLibrary/MainView.swift
@@ -17,11 +17,7 @@ public struct MainView: View {
public init() {}
public var body: some View {
NavigationSplitView {
- VStack {
- SidebarView()
- }
-
- .frame(minWidth: 150)
+ SidebarView()
} detail: {
if profileLoading {
ProgressView().onAppear {
@@ -32,6 +28,7 @@ public struct MainView: View {
}
} else {
selection.contentView
+ .navigationTitle(selection.title)
}
}
#if !DEBUG
diff --git a/MacLibrary/MenuView.swift b/MacLibrary/MenuView.swift
index 9f09b12..63b8fcd 100644
--- a/MacLibrary/MenuView.swift
+++ b/MacLibrary/MenuView.swift
@@ -149,8 +149,8 @@ public struct MenuView: View {
}
.onAppear {
if observer == nil {
- observer = NotificationCenter.default.addObserver(forName: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { _ in
- doReload()
+ observer = NotificationCenter.default.addObserver(forName: OverviewView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { notification in
+ selectedProfileID = notification.object as! Int64
})
}
}
@@ -188,7 +188,7 @@ public struct MenuView: View {
private func switchProfile(_ newProfileID: Int64) {
SharedPreferences.selectedProfileID = newProfileID
- NotificationCenter.default.post(name: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil)
+ NotificationCenter.default.post(name: OverviewView.NotificationUpdateSelectedProfile, object: newProfileID)
if profile.status.isConnected {
do {
try LibboxNewStandaloneCommandClient()?.serviceReload()
diff --git a/MacLibrary/SidebarView.swift b/MacLibrary/SidebarView.swift
index 4596dde..262ca42 100644
--- a/MacLibrary/SidebarView.swift
+++ b/MacLibrary/SidebarView.swift
@@ -8,13 +8,13 @@ public struct SidebarView: View {
public init() {}
public var body: some View {
- viewBuilder {
+ VStack {
if let profile = extensionProfile.wrappedValue {
SidebarView0().environmentObject(profile)
} else {
SidebarView1()
}
- }
+ }.frame(minWidth: 150)
}
struct SidebarView0: View {
@@ -22,11 +22,27 @@ public struct SidebarView: View {
@EnvironmentObject private var extensionProfile: ExtensionProfile
var body: some View {
- List(NavigationPage.allCases.filter { it in
- it.visible(extensionProfile)
- }, selection: selection) { it in
- it.label
- }.onChangeCompat(of: extensionProfile.status) {
+ VStack {
+ if extensionProfile.status.isConnectedStrict {
+ List(selection: selection) {
+ Section(NavigationPage.dashboard.title) {
+ Label("Overview", systemImage: "text.and.command.macwindow").tag(NavigationPage.dashboard)
+ NavigationPage.groups.label.tag(NavigationPage.groups)
+ }
+ Divider()
+ ForEach(NavigationPage.macosDefaultPages, id: \.self) { it in
+ it.label
+ }
+ }
+ } else {
+ List(NavigationPage.allCases.filter { it in
+ it.visible(extensionProfile)
+ }, selection: selection) { it in
+ it.label
+ }
+ }
+ }
+ .onChangeCompat(of: extensionProfile.status) {
if !selection.wrappedValue.visible(extensionProfile) {
selection.wrappedValue = NavigationPage.dashboard
}
diff --git a/SFI/MainView.swift b/SFI/MainView.swift
index e66a2ee..c844c0b 100644
--- a/SFI/MainView.swift
+++ b/SFI/MainView.swift
@@ -24,7 +24,16 @@ struct MainView: View {
}
}
} else {
- ContentView()
+ TabView(selection: $selection) {
+ ForEach(NavigationPage.allCases, id: \.self) { page in
+ NavigationStackCompat {
+ page.contentView
+ .navigationTitle(page.title)
+ }
+ .tag(page)
+ .tabItem { page.label }
+ }
+ }
}
}
.alertBinding($alert)
diff --git a/SFT/MainView.swift b/SFT/MainView.swift
index 73df2cb..35bb820 100644
--- a/SFT/MainView.swift
+++ b/SFT/MainView.swift
@@ -22,7 +22,17 @@ struct MainView: View {
}
}
} else {
- ContentView()
+ TabView(selection: $selection) {
+ ForEach(NavigationPage.allCases, id: \.self) { page in
+ NavigationStackCompat {
+ page.contentView
+ .navigationTitle(page.title)
+ .focusSection()
+ }
+ .tag(page)
+ .tabItem { page.label }
+ }
+ }
}
}
.onChangeCompat(of: scenePhase) { newValue in
diff --git a/sing-box.xcodeproj/project.pbxproj b/sing-box.xcodeproj/project.pbxproj
index 7677432..25a7f94 100644
--- a/sing-box.xcodeproj/project.pbxproj
+++ b/sing-box.xcodeproj/project.pbxproj
@@ -9,6 +9,8 @@
/* Begin PBXBuildFile section */
3A017F922A4AB2E4009149FA /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 3A017F912A4AB2E4009149FA /* GRDB */; };
3A096F8F2A4ED3DE00D4A2ED /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A096F862A4ED3DE00D4A2ED /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ 3A0C6D3C2A79D46500A4DF2B /* OverviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */; };
+ 3A0C6D3E2A79D6A600A4DF2B /* DashboardPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */; };
3A1CF2F02A50E5EE000A8289 /* GroupListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2EF2A50E5EE000A8289 /* GroupListView.swift */; };
3A1CF2F22A50E613000A8289 /* OutboundGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F12A50E613000A8289 /* OutboundGroup.swift */; };
3A1CF2F62A50EE9C000A8289 /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F52A50EE9C000A8289 /* GroupView.swift */; };
@@ -72,7 +74,6 @@
3A7E90352A46756300D53052 /* SharedPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7E90342A46756300D53052 /* SharedPreferences.swift */; };
3A7E90382A46778E00D53052 /* BinaryCodable in Frameworks */ = {isa = PBXBuildFile; productRef = 3A7E90372A46778E00D53052 /* BinaryCodable */; };
3A8655142A4FA26600B7181F /* IntentsExtension.appex in Embed ExtensionKit Extensions */ = {isa = PBXBuildFile; fileRef = 3A77016D2A4E6B34008F031F /* IntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
- 3A9108E42A511AE70088B196 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9108E32A511AE70088B196 /* ContentView.swift */; };
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, ); }; };
@@ -81,7 +82,6 @@
3A99B42E2A752ABB0010D4B0 /* NavigationDestinationCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99B42D2A752ABB0010D4B0 /* NavigationDestinationCompat.swift */; };
3AB1220B2A70FD500087CD55 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB1220A2A70FD500087CD55 /* Alert.swift */; };
3AC03B992A72BF3300B7946F /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC03B982A72BF3300B7946F /* Application.swift */; };
- 3AC03B9B2A72BF3300B7946F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC03B9A2A72BF3300B7946F /* ContentView.swift */; };
3AC03B9D2A72BF3500B7946F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AC03B9C2A72BF3500B7946F /* Assets.xcassets */; };
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 */; };
@@ -413,6 +413,8 @@
3A096F892A4ED3DE00D4A2ED /* ExtensionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionProvider.swift; sourceTree = ""; };
3A096F8B2A4ED3DE00D4A2ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
3A096F8C2A4ED3DE00D4A2ED /* Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Extension.entitlements; sourceTree = ""; };
+ 3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewView.swift; sourceTree = ""; };
+ 3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPage.swift; sourceTree = ""; };
3A1CF2EF2A50E5EE000A8289 /* GroupListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupListView.swift; sourceTree = ""; };
3A1CF2F12A50E613000A8289 /* OutboundGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutboundGroup.swift; sourceTree = ""; };
3A1CF2F32A50E937000A8289 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = ""; };
@@ -450,7 +452,6 @@
3A7701802A4E71F5008F031F /* IntentsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IntentsExtension.entitlements; sourceTree = ""; };
3A7E90302A46745A00D53052 /* ViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewBuilder.swift; sourceTree = ""; };
3A7E90342A46756300D53052 /* SharedPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedPreferences.swift; sourceTree = ""; };
- 3A9108E32A511AE70088B196 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShadredPreferences+Database.swift"; sourceTree = ""; };
3A99B4292A7526990010D4B0 /* NavigationStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationStackCompat.swift; sourceTree = ""; };
3A99B42B2A75288C0010D4B0 /* ViewCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewCompat.swift; sourceTree = ""; };
@@ -465,7 +466,6 @@
3ABA46D22A6A32A100D8366B /* Messages.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Messages.framework; path = Library/Frameworks/Messages.framework; sourceTree = DEVELOPER_DIR; };
3AC03B962A72BF3300B7946F /* sing-box.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sing-box.app"; sourceTree = BUILT_PRODUCTS_DIR; };
3AC03B982A72BF3300B7946F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; };
- 3AC03B9A2A72BF3300B7946F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
3AC03B9C2A72BF3500B7946F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; 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 = ""; };
@@ -707,7 +707,6 @@
children = (
3A4FB1642A73568E007012B9 /* SFT.entitlements */,
3AC03B982A72BF3300B7946F /* Application.swift */,
- 3AC03B9A2A72BF3300B7946F /* ContentView.swift */,
3AC03B9C2A72BF3500B7946F /* Assets.xcassets */,
3A4FB1652A73574B007012B9 /* Info.plist */,
3A4FB1672A7358C9007012B9 /* ApplicationDelegate.swift */,
@@ -783,7 +782,6 @@
3AEC20F92A459AB500A63465 /* Assets.xcassets */,
3A44BB812A4DC28700E4C9F8 /* MainView.swift */,
3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */,
- 3A9108E32A511AE70088B196 /* ContentView.swift */,
);
path = SFI;
sourceTree = "";
@@ -925,6 +923,8 @@
3AF342CC2A4AA88C002B34AC /* StartStopButton.swift */,
3ADF8DF32A4AF9B500900CC8 /* DashboardView.swift */,
3AE4D0C02A6E4852009FEA9E /* InstallSystemExtensionButton.swift */,
+ 3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */,
+ 3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */,
);
path = Dashboard;
sourceTree = "";
@@ -1384,10 +1384,12 @@
3A99B42E2A752ABB0010D4B0 /* NavigationDestinationCompat.swift in Sources */,
3A4EAD332A4FEB7F005435B3 /* LogClient.swift in Sources */,
3AC729F22A76088E00FE8EC1 /* ShareButton.swift in Sources */,
+ 3A0C6D3C2A79D46500A4DF2B /* OverviewView.swift in Sources */,
3A4EAD262A4FEB65005435B3 /* ExtensionStatusView.swift in Sources */,
3A4EAD252A4FEB65005435B3 /* StartStopButton.swift in Sources */,
3A4EAD2B2A4FEB6D005435B3 /* ViewBuilder.swift in Sources */,
3AC5EC082A6417470077AF34 /* DeviceCensorship.swift in Sources */,
+ 3A0C6D3E2A79D6A600A4DF2B /* DashboardPage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1406,7 +1408,6 @@
files = (
3A4FB1682A7358C9007012B9 /* ApplicationDelegate.swift in Sources */,
3A4FB16A2A735AC9007012B9 /* MainView.swift in Sources */,
- 3AC03B9B2A72BF3300B7946F /* ContentView.swift in Sources */,
3AC03B992A72BF3300B7946F /* Application.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1417,7 +1418,6 @@
files = (
3AC1944F2A50247300BD8CB9 /* ApplicationDelegate.swift in Sources */,
3AEC20F62A459AB400A63465 /* Application.swift in Sources */,
- 3A9108E42A511AE70088B196 /* ContentView.swift in Sources */,
3A44BB822A4DC28700E4C9F8 /* MainView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -2074,7 +2074,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.3.5;
+ MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2115,7 +2115,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.3.5;
+ MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2139,7 +2139,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 14;
+ CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = Z56Z6NYZN2;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2155,7 +2155,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.3.5;
+ MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2178,7 +2178,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 14;
+ CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = Z56Z6NYZN2;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2194,7 +2194,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
- MARKETING_VERSION = 1.3.5;
+ MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
diff --git a/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist b/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist
index 4f58539..3cb7054 100644
--- a/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/sing-box.xcodeproj/xcuserdata/sekai.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
ApplicationLibrary.xcscheme_^#shared#^_
orderHint
- 8
+ 2
Associations (Playground) 1.xcscheme
@@ -141,7 +141,7 @@
SFT.xcscheme_^#shared#^_
orderHint
- 7
+ 5
ShareExtension.xcscheme_^#shared#^_
@@ -151,7 +151,7 @@
SystemExtension.xcscheme_^#shared#^_
orderHint
- 5
+ 4
Test.xcscheme_^#shared#^_