Improve Start/Stop button

This commit is contained in:
世界
2025-11-26 22:25:52 +08:00
parent 32f5bf1f3b
commit 4f0d1098e6
10 changed files with 176 additions and 45 deletions
@@ -144,7 +144,11 @@ public struct ActiveDashboardView: View {
}
}
ToolbarItem(placement: .topBarTrailing) {
StartStopButton()
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
EmptyView()
} else {
StartStopButton()
}
}
}
#endif
@@ -2,6 +2,7 @@ import Library
import SwiftUI
@MainActor public struct CardManagementSheet: View {
@Environment(\.dismiss) private var dismiss
@StateObject private var configuration = DashboardCardConfiguration()
@Binding private var configurationVersion: Int
@@ -33,7 +34,7 @@ import SwiftUI
}
}
#else
ToolbarItem(placement: .automatic) {
ToolbarItem(placement: .cancellationAction) {
Button("Reset", role: .destructive) {
Task {
await configuration.resetToDefault()
@@ -41,6 +42,11 @@ import SwiftUI
}
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Done") {
dismiss()
}
}
#endif
}
}
@@ -78,18 +84,11 @@ private struct CardRow: View {
.foregroundColor(.secondary)
.imageScale(.small)
if isProfileCard {
Toggle(isOn: isToggleEnabled) {
Label(card.title, systemImage: card.systemImage)
Spacer()
Text("Required")
.font(.footnote)
.foregroundColor(.secondary)
} else {
Toggle(isOn: isToggleEnabled) {
Label(card.title, systemImage: card.systemImage)
}
.opacity(isEnabled ? 1.0 : 0.5)
}
.disabled(isProfileCard)
.opacity(isEnabled ? 1.0 : 0.5)
}
}
@@ -32,6 +32,9 @@ public struct StartStopButton: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@EnvironmentObject private var profile: ExtensionProfile
@State private var alert: Alert?
@State private var currentTime = Date()
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
Button {
@@ -39,15 +42,49 @@ public struct StartStopButton: View {
await switchProfile(!profile.status.isConnected)
}
} label: {
if !profile.status.isConnected {
Label("Start", systemImage: "play.fill")
} else {
Label("Stop", systemImage: "stop.fill")
HStack(spacing: 8) {
if profile.status.isConnectedStrict, let duration = runtimeDuration {
Text(duration)
.font(.caption)
.foregroundStyle(.secondary)
.monospacedDigit()
.transition(.asymmetric(
insertion: .move(edge: .trailing).combined(with: .opacity),
removal: .move(edge: .trailing).combined(with: .opacity)
))
}
if !profile.status.isConnected {
Label("Start", systemImage: "play.fill")
} else {
Label("Stop", systemImage: "stop.fill")
}
}
.animation(.spring(response: 0.35, dampingFraction: 0.75), value: profile.status.isConnectedStrict)
}
.labelStyle(.iconOnly)
.tint(.primary)
.disabled(!profile.status.isEnabled)
.alertBinding($alert)
.onReceive(timer) { _ in
currentTime = Date()
}
}
private var runtimeDuration: String? {
guard let connectedDate = profile.connectedDate else { return nil }
let interval = currentTime.timeIntervalSince(connectedDate)
guard interval >= 0 else { return nil }
let hours = Int(interval) / 3600
let minutes = Int(interval) / 60 % 60
let seconds = Int(interval) % 60
if hours > 0 {
return String(format: "%d:%02d:%02d", hours, minutes, seconds)
} else {
return String(format: "%d:%02d", minutes, seconds)
}
}
private nonisolated func switchProfile(_ isEnabled: Bool) async {
@@ -32,7 +32,9 @@ public struct OverviewView: View {
public var body: some View {
Group {
if profileList.isEmpty {
if configuration.isLoading {
ProgressView()
} else if profileList.isEmpty {
VStack {
Spacer()
Text("Empty profiles")