mirror of
https://github.com/SagerNet/sing-box-for-apple.git
synced 2026-05-04 11:32:29 +00:00
207 lines
6.6 KiB
Swift
207 lines
6.6 KiB
Swift
import Library
|
|
import SwiftUI
|
|
|
|
#if os(macOS)
|
|
private struct SettingsNavigationPathKey: EnvironmentKey {
|
|
static let defaultValue: Binding<NavigationPath>? = nil
|
|
}
|
|
|
|
public extension EnvironmentValues {
|
|
var settingsNavigationPath: Binding<NavigationPath>? {
|
|
get { self[SettingsNavigationPathKey.self] }
|
|
set { self[SettingsNavigationPathKey.self] = newValue }
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if os(macOS)
|
|
public enum SettingsPage: Hashable {
|
|
case app
|
|
case core, packetTunnel, onDemandRules, profileOverride, sponsors
|
|
}
|
|
#endif
|
|
|
|
public struct SettingView: View {
|
|
private enum Tabs: Int, CaseIterable, Identifiable {
|
|
var id: Self {
|
|
self
|
|
}
|
|
|
|
case app, core, packetTunnel, onDemandRules, profileOverride, sponsors
|
|
|
|
#if os(macOS)
|
|
var page: SettingsPage {
|
|
switch self {
|
|
case .app:
|
|
return .app
|
|
case .core:
|
|
return .core
|
|
case .packetTunnel:
|
|
return .packetTunnel
|
|
case .onDemandRules:
|
|
return .onDemandRules
|
|
case .profileOverride:
|
|
return .profileOverride
|
|
case .sponsors:
|
|
return .sponsors
|
|
}
|
|
}
|
|
#endif
|
|
|
|
var label: some View {
|
|
Label(title, systemImage: iconImage)
|
|
}
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .app:
|
|
return String(localized: "App")
|
|
case .core:
|
|
return String(localized: "Core")
|
|
case .packetTunnel:
|
|
return String(localized: "Packet Tunnel")
|
|
case .onDemandRules:
|
|
return String(localized: "On Demand Rules")
|
|
case .profileOverride:
|
|
return String(localized: "Profile Override")
|
|
case .sponsors:
|
|
return String(localized: "Sponsors")
|
|
}
|
|
}
|
|
|
|
private var iconImage: String {
|
|
switch self {
|
|
case .app:
|
|
return "app.badge.fill"
|
|
case .core:
|
|
return "shippingbox.fill"
|
|
case .packetTunnel:
|
|
return "aspectratio.fill"
|
|
case .onDemandRules:
|
|
return "filemenu.and.selection"
|
|
case .profileOverride:
|
|
return "square.dashed.inset.filled"
|
|
case .sponsors:
|
|
return "heart.fill"
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
var contentView: some View {
|
|
Group {
|
|
switch self {
|
|
case .app:
|
|
AppView()
|
|
case .core:
|
|
CoreView()
|
|
case .packetTunnel:
|
|
PacketTunnelView()
|
|
case .onDemandRules:
|
|
OnDemandRulesView()
|
|
case .profileOverride:
|
|
ProfileOverrideView()
|
|
case .sponsors:
|
|
SponsorsView()
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
|
|
#if os(iOS)
|
|
.background(Color(uiColor: .systemGroupedBackground))
|
|
#endif
|
|
}
|
|
|
|
@MainActor
|
|
var navigationLink: some View {
|
|
#if os(macOS)
|
|
FormNavigationLink(value: page) {
|
|
label
|
|
}
|
|
#else
|
|
FormNavigationLink {
|
|
contentView
|
|
} label: {
|
|
label
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if os(macOS)
|
|
@MainActor
|
|
private static func destinationView(for page: SettingsPage) -> some View {
|
|
Group {
|
|
switch page {
|
|
case .app:
|
|
AppView()
|
|
case .core:
|
|
CoreView()
|
|
case .packetTunnel:
|
|
PacketTunnelView()
|
|
case .onDemandRules:
|
|
OnDemandRulesView()
|
|
case .profileOverride:
|
|
ProfileOverrideView()
|
|
case .sponsors:
|
|
SponsorsView()
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
|
|
}
|
|
#endif
|
|
|
|
public init() {}
|
|
public var body: some View {
|
|
FormView {
|
|
Section {
|
|
Tabs.app.navigationLink
|
|
Tabs.core.navigationLink
|
|
#if !os(tvOS)
|
|
Tabs.packetTunnel.navigationLink
|
|
#endif
|
|
Tabs.onDemandRules.navigationLink
|
|
Tabs.profileOverride.navigationLink
|
|
}
|
|
#if !os(tvOS)
|
|
Section("About") {
|
|
Link(destination: URL(string: String(localized: "https://sing-box.sagernet.org/"))!) {
|
|
Label("Documentation", systemImage: "doc.on.doc.fill")
|
|
}
|
|
.buttonStyle(.plain)
|
|
.foregroundColor(.accentColor)
|
|
.contextMenu {
|
|
Link(destination: URL(string: String(localized: "https://sing-box.sagernet.org/changelog/"))!) {
|
|
Text("Changelog")
|
|
}
|
|
Link(destination: URL(string: String(localized: "https://sing-box.sagernet.org/configuration/"))!) {
|
|
Text("Configuration")
|
|
}
|
|
}
|
|
Link(destination: URL(string: String("https://github.com/SagerNet/sing-box"))!) {
|
|
Label("Source Code", systemImage: "pills.fill")
|
|
}
|
|
.buttonStyle(.plain)
|
|
.foregroundColor(.accentColor)
|
|
.contextMenu {
|
|
Link(destination: URL(string: String("https://github.com/SagerNet/sing-box/releases"))!) {
|
|
Text("Releases")
|
|
}
|
|
}
|
|
RequestReviewButton {
|
|
Label("Rate on the App Store", systemImage: "text.bubble.fill")
|
|
}
|
|
#if os(macOS)
|
|
if Variant.useSystemExtension {
|
|
Tabs.sponsors.navigationLink
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
#if os(macOS)
|
|
.formNavigationDestination(for: SettingsPage.self) { page in
|
|
Self.destinationView(for: page)
|
|
}
|
|
#endif
|
|
}
|
|
}
|