Finish add support for tvOS

This commit is contained in:
世界
2023-07-29 19:40:38 +08:00
parent bb0385f53c
commit 27ffee06e2
28 changed files with 104 additions and 26 deletions
@@ -0,0 +1,15 @@
import SwiftUI
func NavigationDestinationCompat(isPresented: Binding<Bool>, @ViewBuilder destination: () -> some View) -> some View {
if #unavailable(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0) {
return NavigationLink(
destination: destination(),
isActive: isPresented,
label: {
EmptyView()
}
)
} else {
return EmptyView().navigationDestination(isPresented: isPresented, destination: destination)
}
}
@@ -0,0 +1,14 @@
import SwiftUI
public func NavigationStackCompat(@ViewBuilder content: () -> some View) -> some View {
viewBuilder {
if #available(iOS 16.0, macOS 13.0, tvOS 16.0, *) {
NavigationStack(root: content)
} else {
NavigationView(content: content)
#if !os(macOS)
.navigationViewStyle(.stack)
#endif
}
}
}
@@ -0,0 +1,23 @@
import SwiftUI
public extension View {
func onChangeCompat(of value: some Equatable, _ action: @escaping () -> Void) -> some View {
if #available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) {
return onChange(of: value, action)
} else {
return onChange(of: value) { _ in
action()
}
}
}
func onChangeCompat<V>(of value: V, _ action: @escaping (_ newValue: V) -> Void) -> some View where V: Equatable {
if #available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *) {
return onChange(of: value) { _, newValue in
action(newValue)
}
} else {
return onChange(of: value, perform: action)
}
}
}
@@ -68,7 +68,7 @@ public struct ActiveDashboardView: View {
}
#endif
}
.onChange(of: selectedProfileID) { _ in
.onChangeCompat(of: selectedProfileID) {
reasserting = true
Task.detached {
await switchProfile(selectedProfileID!)
@@ -46,7 +46,7 @@ public struct ExtensionStatusView: View {
Rectangle()
.fill(.clear)
.frame(height: 1)
.onChange(of: geometry.size.width) { newValue in
.onChangeCompat(of: geometry.size.width) { newValue in
updateColumnCount(newValue)
}
.onAppear {
@@ -82,7 +82,7 @@ public struct GroupView: View {
Rectangle()
.fill(.clear)
.frame(height: 1)
.onChange(of: geometry.size.width) { newValue in
.onChangeCompat(of: geometry.size.width) { newValue in
geometryWidth = newValue
}
.onAppear {
+1 -1
View File
@@ -46,7 +46,7 @@ public struct LogView: View {
Spacer(minLength: 5)
}
.onChange(of: logClient.logList.count) { newCount in
.onChangeCompat(of: logClient.logList.count) { newCount in
withAnimation {
reader.scrollTo(newCount - 1)
}
@@ -54,6 +54,7 @@ public extension NavigationPage {
switch self {
case .dashboard:
DashboardView()
case .groups:
GroupListView()
case .logs:
@@ -78,8 +79,9 @@ public extension NavigationPage {
#if os(tvOS)
// TODO: fix groups ui
return false
#endif
#else
return profile?.status.isConnectedStrict == true
#endif
default:
return true
}
@@ -43,17 +43,13 @@ public struct ProfileView: View {
#if os(iOS) || os(tvOS)
ZStack {
if let importRemoteProfileRequest {
NavigationLink(
destination: NewProfileView(importRemoteProfileRequest) {
NavigationDestinationCompat(isPresented: $importRemoteProfilePresented) {
NewProfileView(importRemoteProfileRequest) {
Task.detached {
doReload()
}
},
isActive: $importRemoteProfilePresented,
label: {
EmptyView()
}
)
}
}
FormView {
#if os(iOS) || os(tvOS)
@@ -67,7 +67,7 @@ public struct SettingView: View {
#endif
Section("Packet Tunnel") {
Toggle("Disable Memory Limit", isOn: $disableMemoryLimit)
.onChange(of: disableMemoryLimit) { newValue in
.onChangeCompat(of: disableMemoryLimit) { newValue in
Task.detached {
SharedPreferences.disableMemoryLimit = newValue
}
+2 -4
View File
@@ -25,10 +25,9 @@ struct ContentView: View {
ForEach(NavigationPage.allCases.filter { it in
it.visible(extensionProfile)
}, id: \.self) { page in
NavigationView {
NavigationStackCompat {
page.contentView
}
.navigationViewStyle(.stack)
.tag(page)
.tabItem { page.label }
}
@@ -48,10 +47,9 @@ struct ContentView: View {
ForEach(NavigationPage.allCases.filter { it in
it.visible(nil)
}, id: \.self) { page in
NavigationView {
NavigationStackCompat {
page.contentView
}
.navigationViewStyle(.stack)
.tag(page)
.tabItem { page.label }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 54 KiB

@@ -6,6 +6,7 @@
"scale" : "1x"
},
{
"filename" : "tv - App Icon Small - Back - 400 x 240 pt@2x.png",
"idiom" : "tv",
"scale" : "2x"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

@@ -6,6 +6,7 @@
"scale" : "1x"
},
{
"filename" : "tv - App Icon Small - Front - 400 x 240 pt@2x.png",
"idiom" : "tv",
"scale" : "2x"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@@ -1,10 +1,12 @@
{
"images" : [
{
"filename" : "tv - Top Shelf - Wide - 2320 x 720 pt.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "tv - Top Shelf - Wide - 2320 x 720 pt@2x.png",
"idiom" : "tv",
"scale" : "2x"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 725 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

@@ -1,10 +1,12 @@
{
"images" : [
{
"filename" : "1920 x 720 pt.png",
"idiom" : "tv",
"scale" : "1x"
},
{
"filename" : "1920 x 720 pt@2x.png",
"idiom" : "tv",
"scale" : "2x"
}
+2 -4
View File
@@ -25,11 +25,10 @@ struct ContentView: View {
ForEach(NavigationPage.allCases.filter { it in
it.visible(extensionProfile)
}, id: \.self) { page in
NavigationView {
NavigationStackCompat {
page.contentView
.focusSection()
}
.navigationViewStyle(.stack)
.tag(page)
.tabItem { page.label }
}
@@ -49,11 +48,10 @@ struct ContentView: View {
ForEach(NavigationPage.allCases.filter { it in
it.visible(nil)
}, id: \.self) { page in
NavigationView {
NavigationStackCompat {
page.contentView
.focusSection()
}
.navigationViewStyle(.stack)
.tag(page)
.tabItem { page.label }
}
+26
View File
@@ -76,6 +76,9 @@
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, ); }; };
3A99B42A2A7526990010D4B0 /* NavigationStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99B4292A7526990010D4B0 /* NavigationStackCompat.swift */; };
3A99B42C2A75288C0010D4B0 /* ViewCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99B42B2A75288C0010D4B0 /* ViewCompat.swift */; };
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 */; };
@@ -447,6 +450,9 @@
3A7E90342A46756300D53052 /* SharedPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedPreferences.swift; sourceTree = "<group>"; };
3A9108E32A511AE70088B196 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShadredPreferences+Database.swift"; sourceTree = "<group>"; };
3A99B4292A7526990010D4B0 /* NavigationStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationStackCompat.swift; sourceTree = "<group>"; };
3A99B42B2A75288C0010D4B0 /* ViewCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewCompat.swift; sourceTree = "<group>"; };
3A99B42D2A752ABB0010D4B0 /* NavigationDestinationCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationDestinationCompat.swift; sourceTree = "<group>"; };
3AA1ABB92A4C4054000FD4BA /* LogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogView.swift; sourceTree = "<group>"; };
3AA1ABBB2A4C4107000FD4BA /* LogClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogClient.swift; sourceTree = "<group>"; };
3AAB5E712A4BF6F6009757F1 /* SettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingView.swift; sourceTree = "<group>"; };
@@ -926,6 +932,9 @@
3ADF8E022A4B118700900CC8 /* Binding+Unwrap.swift */,
3AC5EC072A6417470077AF34 /* DeviceCensorship.swift */,
3AB1220A2A70FD500087CD55 /* Alert.swift */,
3A99B4292A7526990010D4B0 /* NavigationStackCompat.swift */,
3A99B42B2A75288C0010D4B0 /* ViewCompat.swift */,
3A99B42D2A752ABB0010D4B0 /* NavigationDestinationCompat.swift */,
);
path = Abstract;
sourceTree = "<group>";
@@ -1338,6 +1347,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3A99B42A2A7526990010D4B0 /* NavigationStackCompat.swift in Sources */,
3A4EAD2E2A4FEB77005435B3 /* EditProfileView.swift in Sources */,
3A4EAD2A2A4FEB6D005435B3 /* Binding+Unwrap.swift in Sources */,
3A4EAD2D2A4FEB77005435B3 /* ProfileView.swift in Sources */,
@@ -1357,6 +1367,7 @@
3A4EAD2F2A4FEB77005435B3 /* EditProfileContentView.swift in Sources */,
3A4EAD272A4FEB65005435B3 /* DashboardView.swift in Sources */,
3A4EAD342A4FEB7F005435B3 /* LogView.swift in Sources */,
3A99B42C2A75288C0010D4B0 /* ViewCompat.swift in Sources */,
3AB1220B2A70FD500087CD55 /* Alert.swift in Sources */,
3A4EAD362A4FEB9C005435B3 /* ProfileUpdateTask.swift in Sources */,
3A1CF2F62A50EE9C000A8289 /* GroupView.swift in Sources */,
@@ -1364,6 +1375,7 @@
3A1CF2F22A50E613000A8289 /* OutboundGroup.swift in Sources */,
3A4EAD2C2A4FEB77005435B3 /* EditProfileWindowView.swift in Sources */,
3A1CF2FA2A50F0BD000A8289 /* OutboundGroupItem.swift in Sources */,
3A99B42E2A752ABB0010D4B0 /* NavigationDestinationCompat.swift in Sources */,
3A4EAD332A4FEB7F005435B3 /* LogClient.swift in Sources */,
3A4EAD262A4FEB65005435B3 /* ExtensionStatusView.swift in Sources */,
3A4EAD252A4FEB65005435B3 /* StartStopButton.swift in Sources */,
@@ -1607,6 +1619,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.extension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1646,6 +1659,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.extension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1769,6 +1783,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.intents;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1808,6 +1823,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.intents;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2052,6 +2068,7 @@
);
MARKETING_VERSION = 1.3.5;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
PRODUCT_NAME = "sing-box";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2092,6 +2109,7 @@
);
MARKETING_VERSION = 1.3.5;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
PRODUCT_NAME = "sing-box";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2131,6 +2149,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
PRODUCT_NAME = "sing-box";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2169,6 +2188,7 @@
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
PRODUCT_NAME = "sing-box";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2216,6 +2236,7 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.library;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2270,6 +2291,7 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.library;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2309,6 +2331,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.4;
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.system;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2344,6 +2367,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.4;
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.system;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2384,6 +2408,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent;
PRODUCT_NAME = SFM;
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2423,6 +2448,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent;
PRODUCT_NAME = SFM;
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -7,7 +7,7 @@
<key>ApplicationLibrary.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
<integer>6</integer>
</dict>
<key>Associations (Playground) 1.xcscheme</key>
<dict>
@@ -69,7 +69,7 @@
<key>MacLibrary.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
<integer>4</integer>
</dict>
<key>MessageExtension.xcscheme_^#shared#^_</key>
<dict>
@@ -131,7 +131,7 @@
<key>SFM.System.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>5</integer>
</dict>
<key>SFM.xcscheme</key>
<dict>
@@ -141,12 +141,12 @@
<key>SFT.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
<integer>2</integer>
</dict>
<key>SystemExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
<integer>3</integer>
</dict>
<key>Test.xcscheme_^#shared#^_</key>
<dict>