Refactor task usage and profile auto update
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user