Refactor task usage and profile auto update

This commit is contained in:
世界
2023-09-22 11:32:51 +08:00
parent 390e063f20
commit 3374f8e727
49 changed files with 823 additions and 636 deletions
@@ -3,6 +3,7 @@ import Libbox
import Library
import SwiftUI
@MainActor
public struct ActiveDashboardView: View {
@Environment(\.scenePhase) var scenePhase
@Environment(\.selection) private var parentSelection
@@ -19,7 +20,7 @@ public struct ActiveDashboardView: View {
public var body: some View {
if isLoading {
ProgressView().onAppear {
Task.detached {
Task {
await doReload()
}
}
@@ -28,9 +29,14 @@ public struct ActiveDashboardView: View {
body1
} else {
body1
.onAppear {
Task {
await doReloadSystemProxy()
}
}
.onChangeCompat(of: profile.status) { newStatus in
if newStatus == .connected {
Task.detached {
Task {
await doReloadSystemProxy()
}
}
@@ -70,14 +76,14 @@ public struct ActiveDashboardView: View {
#if os(iOS) || os(tvOS)
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
Task.detached {
Task {
await doReload()
}
}
}
.onChangeCompat(of: parentSelection.wrappedValue) { newValue in
if newValue == .dashboard {
Task.detached {
Task {
await doReload()
}
}
@@ -86,7 +92,7 @@ public struct ActiveDashboardView: View {
.alertBinding($alert)
}
private func doReload() {
private func doReload() async {
defer {
isLoading = false
}
@@ -98,35 +104,39 @@ public struct ActiveDashboardView: View {
systemProxyAvailable = true
systemProxyEnabled = true
selectedProfileID = 0
} else {
do {
profileList = try ProfileManager.list()
profileList = try await ProfileManager.list()
if profileList.isEmpty {
return
}
selectedProfileID = await SharedPreferences.selectedProfileID.get()
if profileList.filter({ profile in
profile.id == selectedProfileID
})
.isEmpty {
selectedProfileID = profileList[0].id!
await SharedPreferences.selectedProfileID.set(selectedProfileID)
}
} catch {
alert = Alert(error)
return
}
if profileList.isEmpty {
return
}
selectedProfileID = SharedPreferences.selectedProfileID
if profileList.filter({ profile in
profile.id == selectedProfileID
})
.isEmpty {
selectedProfileID = profileList[0].id!
SharedPreferences.selectedProfileID = selectedProfileID
}
}
}
private func doReloadSystemProxy() {
private nonisolated func doReloadSystemProxy() async {
do {
let status = try LibboxNewStandaloneCommandClient()!.getSystemProxyStatus()
systemProxyAvailable = status.available
systemProxyEnabled = status.enabled
await MainActor.run {
systemProxyAvailable = status.available
systemProxyEnabled = status.enabled
}
} catch {
alert = Alert(error)
await MainActor.run {
alert = Alert(error)
}
}
}
}
@@ -2,6 +2,7 @@ import Libbox
import Library
import SwiftUI
@MainActor
public struct ClashModeView: View {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var commandClient = CommandClient(.clashMode)
@@ -16,8 +17,8 @@ public struct ClashModeView: View {
clashMode
}, set: { newMode in
clashMode = newMode
Task.detached {
await setMode(newMode)
Task {
await setClashMode(newMode)
}
}), content: {
ForEach(commandClient.clashModeList, id: \.self) { it in
@@ -48,11 +49,13 @@ public struct ClashModeView: View {
.alertBinding($alert)
}
private func setMode(_ newMode: String) {
private nonisolated func setClashMode(_ newMode: String) async {
do {
try LibboxNewStandaloneCommandClient()!.setClashMode(newMode)
} catch {
alert = Alert(error)
await MainActor.run {
alert = Alert(error)
}
}
}
}
@@ -30,6 +30,7 @@ public extension DashboardPage {
}
}
@MainActor
func contentView(_ profileList: Binding<[Profile]>, _ selectedProfileID: Binding<Int64?>, _ systemProxyAvailable: Binding<Bool>, _ systemProxyEnabled: Binding<Bool>) -> some View {
viewBuilder {
switch self {
@@ -1,6 +1,7 @@
import Library
import SwiftUI
@MainActor
public struct DashboardView: View {
#if os(macOS)
@Environment(\.controlActiveState) private var controlActiveState
@@ -16,12 +17,18 @@ public struct DashboardView: View {
viewBuilder {
if !systemExtensionInstalled {
FormView {
InstallSystemExtensionButton(reload)
InstallSystemExtensionButton {
await reload()
}
}
} else {
DashboardView0()
}
}.onAppear(perform: reload)
}.onAppear {
Task {
await reload()
}
}
} else {
DashboardView0()
}
@@ -34,7 +41,9 @@ public struct DashboardView: View {
if newValue != .inactive {
if Variant.useSystemExtension {
if !isLoading {
reload()
Task {
await reload()
}
}
}
}
@@ -43,9 +52,10 @@ public struct DashboardView: View {
}
#if os(macOS)
private func reload() {
Task {
systemExtensionInstalled = await SystemExtension.isInstalled()
private nonisolated func reload() async {
let systemExtensionInstalled = await SystemExtension.isInstalled()
await MainActor.run {
self.systemExtensionInstalled = systemExtensionInstalled
isLoading = false
}
}
@@ -81,16 +91,20 @@ public struct DashboardView: View {
.alertBinding($alert)
.onChangeCompat(of: profile.status) { newValue in
if newValue == .disconnecting || newValue == .connected {
Task.detached {
if let serviceError = try? String(contentsOf: ExtensionProvider.errorFile) {
DispatchQueue.main.async {
alert = Alert(title: Text("Service Error"), message: Text(serviceError))
}
try? FileManager.default.removeItem(at: ExtensionProvider.errorFile)
}
Task {
await checkServiceError()
}
}
}
}
private nonisolated func checkServiceError() async {
if let serviceError = try? String(contentsOf: ExtensionProvider.errorFile) {
await MainActor.run {
alert = Alert(title: Text("Service Error"), message: Text(serviceError))
}
try? FileManager.default.removeItem(at: ExtensionProvider.errorFile)
}
}
}
}
@@ -113,14 +113,6 @@ public struct ExtensionStatusView: View {
}
}
private func closeConnections() {
do {
try LibboxNewStandaloneCommandClient()!.closeConnections()
} catch {
alert = Alert(error)
}
}
private struct StatusItem<T>: View where T: View {
private let title: String
@ViewBuilder private let content: () -> T
@@ -1,6 +1,7 @@
import Library
import SwiftUI
@MainActor
public struct InstallProfileButton: View {
@State private var alert: Alert?
@@ -3,10 +3,11 @@
import Library
import SwiftUI
@MainActor
public struct InstallSystemExtensionButton: View {
@State private var alert: Alert?
private let callback: () -> Void
public init(_ callback: @escaping () -> Void) {
private let callback: () async -> Void
public init(_ callback: @escaping () async -> Void) {
self.callback = callback
}
@@ -26,7 +27,7 @@
alert = Alert(errorMessage: "Need Reboot")
}
}
callback()
await callback()
} catch {
alert = Alert(error)
}
@@ -3,6 +3,7 @@ import Libbox
import Library
import SwiftUI
@MainActor
public struct OverviewView: View {
public static let NotificationUpdateSelectedProfile = Notification.Name("update-selected-profile")
@@ -38,7 +39,7 @@ public struct OverviewView: View {
if ApplicationLibrary.inPreview || profile.status.isConnectedStrict, systemProxyAvailable {
Toggle("HTTP Proxy", isOn: $systemProxyEnabled)
.onChangeCompat(of: systemProxyEnabled) { newValue in
Task.detached {
Task {
await setSystemProxyEnabled(newValue)
}
}
@@ -55,7 +56,7 @@ public struct OverviewView: View {
if ApplicationLibrary.inPreview || profile.status.isConnectedStrict, systemProxyAvailable {
Toggle("HTTP Proxy", isOn: $systemProxyEnabled)
.onChangeCompat(of: systemProxyEnabled) { newValue in
Task.detached {
Task {
await setSystemProxyEnabled(newValue)
}
}
@@ -75,7 +76,7 @@ public struct OverviewView: View {
.alertBinding($alert)
.onChangeCompat(of: selectedProfileID) {
reasserting = true
Task.detached {
Task {
await switchProfile(selectedProfileID!)
}
}
@@ -96,25 +97,31 @@ public struct OverviewView: View {
#endif
}
private func switchProfile(_ newProfileID: Int64) {
SharedPreferences.selectedProfileID = newProfileID
private nonisolated func switchProfile(_ newProfileID: Int64) async {
await SharedPreferences.selectedProfileID.set(newProfileID)
NotificationCenter.default.post(name: OverviewView.NotificationUpdateSelectedProfile, object: newProfileID)
if profile.status.isConnected {
if await profile.status.isConnected {
do {
try LibboxNewStandaloneCommandClient()!.serviceReload()
} catch {
await MainActor.run {
alert = Alert(error)
}
}
}
await MainActor.run {
reasserting = false
}
}
private nonisolated func setSystemProxyEnabled(_ isEnabled: Bool) async {
do {
try LibboxNewStandaloneCommandClient()!.setSystemProxyEnabled(isEnabled)
await SharedPreferences.systemProxyEnabled.set(isEnabled)
} catch {
await MainActor.run {
alert = Alert(error)
}
}
reasserting = false
}
private func setSystemProxyEnabled(_ isEnabled: Bool) {
do {
try LibboxNewStandaloneCommandClient()!.setSystemProxyEnabled(isEnabled)
SharedPreferences.systemProxyEnabled = isEnabled
} catch {
alert = Alert(error)
}
}
}
@@ -2,6 +2,7 @@ import Library
import NetworkExtension
import SwiftUI
@MainActor
public struct StartStopButton: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@@ -15,9 +16,9 @@ public struct StartStopButton: View {
Text("Enabled")
}
#elseif os(macOS)
Button(action: {}, label: {
Button {} label: {
Label("Stop", systemImage: "stop.fill")
})
}
#endif
} else if let profile = environments.extensionProfile {
@@ -28,10 +29,9 @@ public struct StartStopButton: View {
Text("Enabled")
}
#elseif os(macOS)
Button(action: {}, label: {
Button {} label: {
Label("Start", systemImage: "play.fill")
})
}
.disabled(true)
#endif
}
@@ -49,41 +49,42 @@ public struct StartStopButton: View {
Toggle(isOn: Binding(get: {
profile.status.isConnected
}, set: { newValue, _ in
Task.detached {
Task {
await switchProfile(newValue)
}
})) {
Text("Enabled")
}
#elseif os(macOS)
Button(action: {
Task.detached {
Button {
Task {
await switchProfile(!profile.status.isConnected)
}
}, label: {
} label: {
if !profile.status.isConnected {
Label("Start", systemImage: "play.fill")
} else {
Label("Stop", systemImage: "stop.fill")
}
})
}
#endif
}
.disabled(!profile.status.isEnabled)
.alertBinding($alert)
}
private func switchProfile(_ isEnabled: Bool) async {
private nonisolated func switchProfile(_ isEnabled: Bool) async {
do {
if isEnabled {
try await profile.start()
environments.logClient.connect()
await environments.logClient.connect()
} else {
profile.stop()
await profile.stop()
}
} catch {
alert = Alert(error)
return
await MainActor.run {
alert = Alert(error)
}
}
}
}