Improve Start/Stop button
This commit is contained in:
@@ -2,7 +2,7 @@ import SwiftUI
|
||||
|
||||
public func NavigationStackCompat(@ViewBuilder content: () -> some View) -> some View {
|
||||
viewBuilder {
|
||||
if #available(iOS 17.0, *) {
|
||||
if #available(iOS 17.0, macOS 13.0, tvOS 17.0, *) {
|
||||
// view not updating in iOS 16, but why?
|
||||
NavigationStack {
|
||||
content()
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user