Add clash mode selector & always on

This commit is contained in:
世界
2023-08-28 11:42:47 +08:00
parent d3b2040fe1
commit b5a89fddec
11 changed files with 169 additions and 13 deletions
@@ -0,0 +1,58 @@
import Libbox
import Library
import SwiftUI
public struct ClashModeView: View {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var commandClient = CommandClient(.clashMode)
@State private var clashMode = ""
@State private var alert: Alert?
public init() {}
public var body: some View {
VStack {
if commandClient.clashModeList.count > 1 {
Picker("", selection: Binding(get: {
clashMode
}, set: { newMode in
clashMode = newMode
Task.detached {
await setMode(newMode)
}
}), content: {
ForEach(commandClient.clashModeList, id: \.self) { it in
Text(it)
}
})
.pickerStyle(.segmented)
.padding([.top], 8)
}
}
.onReceive(commandClient.$clashMode) { newMode in
clashMode = newMode
}
.padding([.leading, .trailing])
.onAppear {
commandClient.connect()
}
.onDisappear {
commandClient.disconnect()
}
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
commandClient.connect()
} else {
commandClient.disconnect()
}
}
.alertBinding($alert)
}
private func setMode(_ newMode: String) {
do {
try LibboxNewStandaloneCommandClient()!.setClashMode(newMode)
} catch {
alert = Alert(error)
}
}
}
@@ -3,6 +3,7 @@ import Library
import SwiftUI
public struct ExtensionStatusView: View {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var commandClient = CommandClient(.status)
@State private var columnCount: Int = 4
@State private var alert: Alert?
@@ -83,6 +84,13 @@ public struct ExtensionStatusView: View {
.onDisappear {
commandClient.disconnect()
}
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
commandClient.connect()
} else {
commandClient.disconnect()
}
}
.alertBinding($alert)
}
@@ -6,7 +6,6 @@ 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]
@@ -24,6 +23,7 @@ public struct OverviewView: View {
VStack {
if ApplicationLibrary.inPreview || profile.status.isConnected {
ExtensionStatusView()
ClashModeView()
}
if profileList.isEmpty {
Text("Empty profiles")
@@ -3,6 +3,7 @@ import Library
import SwiftUI
public struct GroupListView: View {
@Environment(\.scenePhase) private var scenePhase
@State private var isLoading = true
@StateObject private var commandClient = CommandClient(.groups)
@State private var groups: [OutboundGroup] = []
@@ -31,6 +32,13 @@ public struct GroupListView: View {
.onDisappear {
commandClient.disconnect()
}
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
commandClient.connect()
} else {
commandClient.disconnect()
}
}
.onReceive(commandClient.$groups, perform: { groups in
if let groups {
setGroups(groups)
@@ -20,6 +20,7 @@ public struct SettingView: View {
@State private var keepMenuBarInBackground = false
#endif
@State private var alwaysOn = false
@State private var disableMemoryLimit = false
@State private var version = ""
@State private var dataSize = ""
@@ -66,6 +67,13 @@ public struct SettingView: View {
}
#endif
Section("Packet Tunnel") {
Toggle("Always On", isOn: $alwaysOn)
.onChangeCompat(of: alwaysOn) { newValue in
Task.detached {
SharedPreferences.alwaysOn = newValue
await updateAlwaysOn(newValue)
}
}
Toggle("Disable Memory Limit", isOn: $disableMemoryLimit)
.onChangeCompat(of: disableMemoryLimit) { newValue in
Task.detached {
@@ -155,6 +163,7 @@ public struct SettingView: View {
startAtLogin = SMAppService.mainApp.status == .enabled
keepMenuBarInBackground = SharedPreferences.menuBarExtraInBackground
#endif
alwaysOn = SharedPreferences.alwaysOn
disableMemoryLimit = SharedPreferences.disableMemoryLimit
version = LibboxVersion()
if ApplicationLibrary.inPreview {
@@ -173,6 +182,17 @@ public struct SettingView: View {
try? FileManager.default.removeItem(at: FilePath.workingDirectory)
isLoading = true
}
private func updateAlwaysOn(_ newState: Bool) async {
guard let profile = try? await ExtensionProfile.load() else {
return
}
do {
try await profile.updateAlwaysOn(newState)
} catch {
alert = Alert(error)
}
}
}
private extension URL {