Fix interfaces for tvOS

This commit is contained in:
世界
2024-02-23 23:37:42 +08:00
parent be67111425
commit 45b4e58b3f
8 changed files with 95 additions and 47 deletions
@@ -0,0 +1,14 @@
import Foundation
import SwiftUI
public struct BackButton: View {
@Environment(\.dismiss) private var dismiss
public var body: some View {
Button {
dismiss()
} label: {
Image(systemName: "chevron.backward")
}
}
}
@@ -83,3 +83,18 @@ public func FormButton(role: ButtonRole?, action: @escaping () -> Void, @ViewBui
.foregroundColor(.accentColor)
#endif
}
public func FormNavigationLink(@ViewBuilder destination: () -> some View, @ViewBuilder label: () -> some View) -> some View {
#if !os(tvOS)
return NavigationLink(destination: destination, label: label)
#else
return NavigationLink(destination: {
destination()
.toolbar {
ToolbarItemGroup(placement: .topBarLeading) {
BackButton()
}
}
}, label: label)
#endif
}
@@ -57,7 +57,7 @@ public struct EditProfileView: View {
Section("Action") {
if profile.type != .remote {
#if os(iOS) || os(macOS)
NavigationLink {
FormNavigationLink {
EditProfileContentView(EditProfileContentView.Context(profileID: profile.id!, readOnly: false))
} label: {
Label("Edit Content", systemImage: "pencil")
@@ -66,7 +66,7 @@ public struct EditProfileView: View {
#endif
} else {
#if os(iOS) || os(macOS)
NavigationLink {
FormNavigationLink {
EditProfileContentView(EditProfileContentView.Context(profileID: profile.id!, readOnly: true))
} label: {
Label("View Content", systemImage: "doc.fill")
@@ -22,25 +22,37 @@
}
public var body: some View {
VStack {
VStack(alignment: .center) {
if !selected {
DevicePicker(
.applicationService(name: "sing-box:profile"))
{ endpoint in
selected = true
Task {
await handleEndpoint(endpoint)
Form {
Section {
EmptyView()
} footer: {
Text("To import configurations from your iPhone or iPad, make sure sing-box is the **same version** on both devices and **VPN is disabled**.")
}
DevicePicker(
.applicationService(name: "sing-box:profile"))
{ endpoint in
selected = true
Task {
await handleEndpoint(endpoint)
}
} label: {
Text("Select Device")
} fallback: {
EmptyView()
} parameters: {
.applicationService
}
} label: {
Text("Select Device")
} fallback: {
EmptyView()
} parameters: {
.applicationService
}
} else if let profiles {
Form {
Text("\(profiles.count) Profiles")
Section {
EmptyView()
} footer: {
Text("\(profiles.count) Profiles")
}
ForEach(profiles, id: \.profileID) { profile in
Button(profile.name) {
isLoading = true
@@ -45,27 +45,27 @@ public struct ProfileView: View {
}
FormView {
#if os(iOS)
NavigationLink {
FormNavigationLink {
NewProfileView()
} label: {
Text("New Profile").foregroundColor(.accentColor)
}
.disabled(editMode.isEditing)
#elseif os(macOS)
NavigationLink {
FormNavigationLink {
NewProfileView()
} label: {
Text("New Profile")
}
#elseif os(tvOS)
Section {
NavigationLink {
FormNavigationLink {
NewProfileView()
} label: {
Text("New Profile").foregroundColor(.accentColor)
}
if ApplicationLibrary.inPreview || devicePickerSupports(.applicationService(name: "sing-box"), parameters: { .applicationService }) {
NavigationLink {
FormNavigationLink {
ImportProfileView {
await doReload()
}
@@ -291,7 +291,7 @@ public struct ProfileView: View {
private var body0: some View {
viewBuilder {
#if !os(macOS)
NavigationLink {
FormNavigationLink {
EditProfileView().environmentObject(profile.origin)
} label: {
Text(profile.name)
@@ -329,7 +329,7 @@ public struct ProfileView: View {
}
}
#else
NavigationLink {
FormNavigationLink {
EditProfileView().environmentObject(profile.origin)
} label: {
HStack {
@@ -35,24 +35,28 @@ public struct ServiceLogView: View {
}
}
}
#if !os(tvOS)
.toolbar {
if !content.isEmpty {
ShareButtonCompat($alert) {
Label("Export", systemImage: "square.and.arrow.up.fill")
} itemURL: {
try content.generateShareFile(name: "service.log")
}
#if !os(tvOS)
ShareButtonCompat($alert) {
Label("Export", systemImage: "square.and.arrow.up.fill")
} itemURL: {
try content.generateShareFile(name: "service.log")
}
#endif
Button(role: .destructive) {
Task {
await deleteContent()
}
} label: {
Label("Delete", systemImage: "trash.fill")
#if !os(tvOS)
Label("Delete", systemImage: "trash.fill")
#else
Image(systemName: "trash.fill")
#endif
}
}
}
#endif
.alertBinding($alert)
.navigationTitle("Service Log")
#if os(tvOS)
@@ -78,7 +78,7 @@ public struct SettingView: View {
@MainActor
var navigationLink: some View {
NavigationLink {
FormNavigationLink {
contentView
} label: {
label
@@ -98,25 +98,25 @@ public struct SettingView: View {
ForEach([Tabs.core, Tabs.packetTunnel, Tabs.profileOverride]) { it in
it.navigationLink
}
Section("About") {
Link(destination: URL(string: "https://sing-box.sagernet.org/")!) {
Label("Documentation", systemImage: "doc.on.doc.fill")
}
.buttonStyle(.plain)
.foregroundColor(.accentColor)
#if !os(tvOS)
#if !os(tvOS)
Section("About") {
Link(destination: URL(string: "https://sing-box.sagernet.org/")!) {
Label("Documentation", systemImage: "doc.on.doc.fill")
}
.buttonStyle(.plain)
.foregroundColor(.accentColor)
RequestReviewButton {
Label("Rate on the App Store", systemImage: "text.bubble.fill")
}
#endif
#if os(macOS)
if Variant.useSystemExtension {
Tabs.sponsors.navigationLink
}
#endif
}
#if os(macOS)
if Variant.useSystemExtension {
Tabs.sponsors.navigationLink
}
#endif
}
#endif
Section("Debug") {
NavigationLink {
FormNavigationLink {
ServiceLogView()
} label: {
Label("Service Log", systemImage: "doc.on.clipboard")
@@ -136,6 +136,5 @@ public struct SettingView: View {
}
}
}
.navigationTitle("Settings")
}
}