Add swiftlint & Minor fixes
This commit is contained in:
@@ -111,22 +111,25 @@ public struct ActiveDashboardView: View {
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
private func updateButtonVisibility() {
|
||||
buttonState.update(profile: profile, commandClient: environments.commandClient)
|
||||
buttonState.update(profile: profile, commandClient: environments.commandClient, requireAnyConnection: true)
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
private var isTabViewBottomAccessoryAvailable: Bool {
|
||||
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
#endif
|
||||
|
||||
@ToolbarContentBuilder
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItem(placement: .topBarLeading) {
|
||||
#if os(iOS)
|
||||
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
|
||||
EmptyView()
|
||||
} else {
|
||||
navigationButtons
|
||||
}
|
||||
#else
|
||||
#if os(tvOS)
|
||||
ToolbarItem(placement: .topBarLeading) {
|
||||
navigationButtons
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
if #available(iOS 16.0, tvOS 17.0, *) {
|
||||
cardManagementButton
|
||||
@@ -137,10 +140,7 @@ public struct ActiveDashboardView: View {
|
||||
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
|
||||
EmptyView()
|
||||
} else {
|
||||
HStack(spacing: 12) {
|
||||
Divider()
|
||||
StartStopButton()
|
||||
}
|
||||
StartStopButton()
|
||||
}
|
||||
#else
|
||||
HStack(spacing: 12) {
|
||||
@@ -151,16 +151,18 @@ public struct ActiveDashboardView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var navigationButtons: some View {
|
||||
NavigationButtonsView(
|
||||
showGroupsButton: buttonState.showGroupsButton,
|
||||
showConnectionsButton: buttonState.showConnectionsButton,
|
||||
groupsCount: buttonState.groupsCount,
|
||||
connectionsCount: buttonState.connectionsCount,
|
||||
onGroupsTap: { showGroups = true },
|
||||
onConnectionsTap: { showConnections = true }
|
||||
)
|
||||
}
|
||||
#if os(tvOS)
|
||||
private var navigationButtons: some View {
|
||||
NavigationButtonsView(
|
||||
showGroupsButton: buttonState.showGroupsButton,
|
||||
showConnectionsButton: buttonState.showConnectionsButton,
|
||||
groupsCount: buttonState.groupsCount,
|
||||
connectionsCount: buttonState.connectionsCount,
|
||||
onGroupsTap: { showGroups = true },
|
||||
onConnectionsTap: { showConnections = true }
|
||||
)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
@@ -176,19 +178,42 @@ public struct ActiveDashboardView: View {
|
||||
@ViewBuilder
|
||||
private var cardManagementButton: some View {
|
||||
Menu {
|
||||
#if os(iOS)
|
||||
if !isTabViewBottomAccessoryAvailable {
|
||||
if buttonState.showGroupsButton {
|
||||
Button {
|
||||
showGroups = true
|
||||
} label: {
|
||||
Label("Groups (\(buttonState.groupsCount))", systemImage: "rectangle.3.group.fill")
|
||||
}
|
||||
}
|
||||
if buttonState.showConnectionsButton {
|
||||
Button {
|
||||
showConnections = true
|
||||
} label: {
|
||||
Label("Connections (\(buttonState.connectionsCount))", systemImage: "list.bullet.rectangle.portrait.fill")
|
||||
}
|
||||
}
|
||||
if buttonState.showGroupsButton || buttonState.showConnectionsButton {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Button {
|
||||
showCardManagement = true
|
||||
} label: {
|
||||
Label("Dashboard Items", systemImage: "square.grid.2x2")
|
||||
}
|
||||
} label: {
|
||||
Label("Others", systemImage: "ellipsis.circle")
|
||||
Label("Others", systemImage: "line.3.horizontal.circle")
|
||||
}
|
||||
.sheet(isPresented: $showCardManagement) {
|
||||
CardManagementSheet(configurationVersion: $cardConfigurationVersion)
|
||||
.sheet(isPresented: $showCardManagement, onDismiss: {
|
||||
cardConfigurationVersion += 1
|
||||
}, content: {
|
||||
CardManagementSheet()
|
||||
.presentationDetents([.large])
|
||||
.presentationDragIndicator(.visible)
|
||||
}
|
||||
})
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,11 +4,8 @@ import SwiftUI
|
||||
@MainActor public struct CardManagementSheet: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@StateObject private var configuration = DashboardCardConfiguration()
|
||||
@Binding private var configurationVersion: Int
|
||||
|
||||
public init(configurationVersion: Binding<Int>) {
|
||||
_configurationVersion = configurationVersion
|
||||
}
|
||||
public init() {}
|
||||
|
||||
public var body: some View {
|
||||
#if os(macOS)
|
||||
@@ -41,7 +38,6 @@ import SwiftUI
|
||||
Button("Reset", role: .destructive) {
|
||||
Task {
|
||||
await configuration.resetToDefault()
|
||||
configurationVersion += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,11 +45,9 @@ import SwiftUI
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
.keyboardShortcut(.escape, modifiers: [])
|
||||
}
|
||||
}
|
||||
.onExitCommand {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
#else
|
||||
private var iOSBody: some View {
|
||||
@@ -74,7 +68,6 @@ import SwiftUI
|
||||
Button("Reset", role: .destructive) {
|
||||
Task {
|
||||
await configuration.resetToDefault()
|
||||
configurationVersion += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,13 +84,13 @@ import SwiftUI
|
||||
isEnabled: configuration.isEnabled(card),
|
||||
onToggle: {
|
||||
configuration.toggleCard(card)
|
||||
configurationVersion += 1
|
||||
}
|
||||
)
|
||||
}
|
||||
.onMove { source, destination in
|
||||
configuration.moveCard(from: source, to: destination)
|
||||
configurationVersion += 1
|
||||
Task {
|
||||
await configuration.moveCard(from: source, to: destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
.applyContentMargins()
|
||||
|
||||
@@ -40,13 +40,9 @@ public final class DashboardCardConfiguration: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
public func moveCard(from source: IndexSet, to destination: Int) {
|
||||
public func moveCard(from source: IndexSet, to destination: Int) async {
|
||||
cardOrder.move(fromOffsets: source, toOffset: destination)
|
||||
|
||||
// Save asynchronously in background
|
||||
Task {
|
||||
await saveCardOrder()
|
||||
}
|
||||
await saveCardOrder()
|
||||
}
|
||||
|
||||
public func resetToDefault() async {
|
||||
|
||||
@@ -19,12 +19,17 @@ public struct HTTPProxyCard: View {
|
||||
|
||||
public var body: some View {
|
||||
DashboardCardView(title: "", isHalfWidth: false) {
|
||||
Toggle("System HTTP Proxy", isOn: $systemProxyEnabled)
|
||||
.onChangeCompat(of: systemProxyEnabled) { newValue in
|
||||
Task {
|
||||
await onToggle(newValue)
|
||||
HStack {
|
||||
Text("System HTTP Proxy")
|
||||
Spacer()
|
||||
Toggle("", isOn: $systemProxyEnabled)
|
||||
.labelsHidden()
|
||||
.onChangeCompat(of: systemProxyEnabled) { newValue in
|
||||
Task {
|
||||
await onToggle(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ public struct ProfileCard: View {
|
||||
.disabled(viewModel.isUpdating)
|
||||
.sheet(isPresented: $viewModel.showNewProfile, onDismiss: {
|
||||
environments.profileUpdate.send()
|
||||
}) {
|
||||
}, content: {
|
||||
NewProfileNavigationView()
|
||||
.environmentObject(environments)
|
||||
}
|
||||
})
|
||||
.sheet(isPresented: $viewModel.showManageProfiles) {
|
||||
manageProfilesSheet
|
||||
}
|
||||
@@ -218,11 +218,12 @@ public struct ProfileCard: View {
|
||||
NavigationSheet(
|
||||
title: String(localized: "Manage profiles"),
|
||||
showDoneButton: true,
|
||||
onDismiss: { viewModel.showManageProfiles = false }
|
||||
) {
|
||||
ManageProfilesView()
|
||||
.environmentObject(environments)
|
||||
}
|
||||
onDismiss: { viewModel.showManageProfiles = false },
|
||||
content: {
|
||||
ManageProfilesView()
|
||||
.environmentObject(environments)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -390,6 +391,7 @@ extension ProfileCard {
|
||||
@ObservedObject private var viewModel: ProfileViewModel
|
||||
@State private var profile: ProfilePreview
|
||||
@State private var shareLinkPresented = false
|
||||
@State private var isUpdating = false
|
||||
|
||||
init(_ viewModel: ProfileViewModel, _ profile: ProfilePreview) {
|
||||
self.viewModel = viewModel
|
||||
@@ -416,25 +418,26 @@ extension ProfileCard {
|
||||
HStack(spacing: 8) {
|
||||
if profile.type == .remote {
|
||||
Button {
|
||||
viewModel.isUpdating = true
|
||||
isUpdating = true
|
||||
Task {
|
||||
await viewModel.updateProfile(profile.origin)
|
||||
profile = ProfilePreview(profile.origin)
|
||||
isUpdating = false
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
.font(.system(size: 16))
|
||||
.rotationEffect(.degrees(viewModel.isUpdating ? 360 : 0))
|
||||
.rotationEffect(.degrees(isUpdating ? 360 : 0))
|
||||
.animation(
|
||||
viewModel.isUpdating
|
||||
isUpdating
|
||||
? .linear(duration: 1).repeatForever(autoreverses: false)
|
||||
: .default,
|
||||
value: viewModel.isUpdating
|
||||
value: isUpdating
|
||||
)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.actionButtonStyle()
|
||||
.disabled(viewModel.isUpdating)
|
||||
.disabled(isUpdating)
|
||||
|
||||
Button {
|
||||
shareLinkPresented = true
|
||||
|
||||
@@ -83,10 +83,8 @@ struct ProfileSelectorButton: View {
|
||||
|
||||
private func updateButtonContent(_ button: MenuAttachmentButton) {
|
||||
// Remove existing subviews
|
||||
for subview in button.subviews {
|
||||
if subview is UIStackView {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
for subview in button.subviews where subview is UIStackView {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
|
||||
// Create content stack
|
||||
|
||||
@@ -42,35 +42,72 @@ public struct StartStopButton: View {
|
||||
await switchProfile(!profile.status.isConnected)
|
||||
}
|
||||
} label: {
|
||||
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 os(iOS)
|
||||
HStack(spacing: 8) {
|
||||
if showRuntimeDuration, profile.status.isConnectedStrict, let duration = runtimeDuration {
|
||||
Text(duration)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.monospacedDigit()
|
||||
.fixedSize()
|
||||
.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")
|
||||
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)
|
||||
.animation(.spring(response: 0.35, dampingFraction: 0.75), value: profile.status.isConnectedStrict)
|
||||
#else
|
||||
HStack(spacing: 8) {
|
||||
if profile.status.isConnectedStrict, let duration = runtimeDuration {
|
||||
Text(duration)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.monospacedDigit()
|
||||
.fixedSize()
|
||||
.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)
|
||||
#endif
|
||||
}
|
||||
.labelStyle(.iconOnly)
|
||||
.tint(.primary)
|
||||
.disabled(!profile.status.isEnabled)
|
||||
.alertBinding($alert)
|
||||
.onReceive(timer) { _ in
|
||||
currentTime = Date()
|
||||
}
|
||||
#if os(iOS)
|
||||
.modifier(PrimaryTintModifier())
|
||||
#else
|
||||
.tint(.primary)
|
||||
#endif
|
||||
.disabled(!profile.status.isEnabled)
|
||||
.alertBinding($alert)
|
||||
.onReceive(timer) { _ in
|
||||
currentTime = Date()
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
private var showRuntimeDuration: Bool {
|
||||
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
#endif
|
||||
|
||||
private var runtimeDuration: String? {
|
||||
guard let connectedDate = profile.connectedDate else { return nil }
|
||||
let interval = currentTime.timeIntervalSince(connectedDate)
|
||||
@@ -103,3 +140,15 @@ public struct StartStopButton: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
private struct PrimaryTintModifier: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
if #available(iOS 26.0, *), !Variant.debugNoIOS26 {
|
||||
content.tint(.primary)
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -85,10 +85,10 @@ public struct DashboardView: View {
|
||||
private func importRemoteProfileSheet(for request: NewProfileView.ImportRequest) -> some View {
|
||||
NavigationSheet(title: "Import Profile", onDismiss: {
|
||||
environments.profileUpdate.send()
|
||||
}) {
|
||||
}, content: {
|
||||
NewProfileView(request)
|
||||
.environmentObject(environments)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -111,11 +111,11 @@ public struct DashboardView: View {
|
||||
@ViewBuilder
|
||||
private var mainContent: some View {
|
||||
if ApplicationLibrary.inPreview {
|
||||
ActiveDashboardView(externalCardConfigurationVersion: cardConfigurationVersion)
|
||||
activeDashboardView
|
||||
} else if environments.extensionProfileLoading {
|
||||
ProgressView()
|
||||
} else if let profile = environments.extensionProfile {
|
||||
ActiveDashboardView(externalCardConfigurationVersion: cardConfigurationVersion)
|
||||
activeDashboardView
|
||||
.environmentObject(profile)
|
||||
.alertBinding($coordinator.alert)
|
||||
.onChangeCompat(of: profile.status) { status in
|
||||
@@ -129,4 +129,13 @@ public struct DashboardView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var activeDashboardView: some View {
|
||||
#if os(macOS)
|
||||
ActiveDashboardView(externalCardConfigurationVersion: cardConfigurationVersion)
|
||||
#else
|
||||
ActiveDashboardView()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user