Reuse modifier for navigation stacks with close button (#861)

Refactored:

- iOS
  - VPNProviderServerView
- macOS
  - AboutView
  - ProfileSplitView
- Both
  - ProfileCoordinator
  - VPNProviderServerCoordinator
This commit is contained in:
Davide 2024-11-13 19:17:00 +01:00 committed by GitHub
parent 1b9b9cbd5c
commit 2d698cabfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 59 additions and 69 deletions

View File

@ -20,7 +20,7 @@ concurrency:
jobs:
run_tests:
name: Run tests
runs-on: macos-14
runs-on: macos-15
timeout-minutes: 15
steps:
- uses: passepartoutvpn/action-prepare-xcode-build@master
@ -30,7 +30,7 @@ jobs:
bundle exec fastlane test
build_upload:
name: Upload to ASC
runs-on: macos-14
runs-on: macos-15
needs: run_tests
strategy:
fail-fast: true

View File

@ -17,7 +17,7 @@ concurrency:
jobs:
run_swift_tests:
name: Run SwiftPM tests
runs-on: macos-14
runs-on: macos-15
timeout-minutes: 10
steps:
- uses: passepartoutvpn/action-prepare-xcode-build@master

View File

@ -30,23 +30,13 @@ import SwiftUI
extension AboutRouterView {
var body: some View {
NavigationStack(path: $path) {
AboutView(
profileManager: profileManager,
navigationRoute: $navigationRoute
)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button {
dismiss()
} label: {
ThemeImage(.close)
}
}
}
.navigationDestination(for: NavigationRoute.self, destination: pushDestination)
.themeNavigationDetail()
}
AboutView(
profileManager: profileManager,
navigationRoute: $navigationRoute
)
.navigationDestination(for: NavigationRoute.self, destination: pushDestination)
.themeNavigationDetail()
.themeNavigationStack(closable: true, path: $path)
}
}

View File

@ -36,17 +36,16 @@ extension AboutRouterView {
navigationRoute: $navigationRoute
)
} detail: {
NavigationStack(path: $path) {
pushDestination(for: navigationRoute)
.navigationDestination(for: NavigationRoute.self, destination: pushDestination)
}
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button(Strings.Global.ok) {
dismiss()
pushDestination(for: navigationRoute)
.navigationDestination(for: NavigationRoute.self, destination: pushDestination)
.themeNavigationStack(closable: false, path: $path)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button(Strings.Global.ok) {
dismiss()
}
}
}
}
}
.onLoad {
navigationRoute = .links

View File

@ -55,7 +55,7 @@ struct ProfileSplitView: View, Routable {
flow: flow
)
} detail: {
NavigationStack(path: $detailPath) {
Group {
switch selectedModuleId {
case ModuleListView.generalModuleId:
detailView(for: .general)
@ -64,6 +64,7 @@ struct ProfileSplitView: View, Routable {
detailView(for: .module(id: selectedModuleId))
}
}
.themeNavigationStack(path: $detailPath)
.toolbar(content: toolbarContent)
.environment(\.navigationPath, $detailPath)
}

View File

@ -44,25 +44,15 @@ struct VPNProviderServerCoordinator<Configuration>: View where Configuration: Pr
let onSelect: (VPNEntity<Configuration>) async throws -> Void
var body: some View {
NavigationStack {
VPNProviderServerView(
moduleId: moduleId,
providerId: providerId,
configurationType: Configuration.self,
selectedEntity: selectedEntity,
filtersWithSelection: false,
onSelect: onSelect
)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button {
dismiss()
} label: {
ThemeCloseLabel()
}
}
}
}
VPNProviderServerView(
moduleId: moduleId,
providerId: providerId,
configurationType: Configuration.self,
selectedEntity: selectedEntity,
filtersWithSelection: false,
onSelect: onSelect
)
.themeNavigationStack(closable: true)
}
}

View File

@ -79,7 +79,7 @@ private extension VPNProviderServerView {
Button {
isPresented = false
} label: {
ThemeImage(.close)
ThemeCloseLabel()
}
}
}

View File

@ -44,7 +44,7 @@ public struct SettingsView: View {
.navigationTitle(Strings.Global.settings)
#if os(iOS)
.themeNavigationDetail()
.themeNavigationStack(if: true, closable: true, path: $path)
.themeNavigationStack(closable: true, path: $path)
#endif
}
}

View File

@ -75,8 +75,24 @@ extension View {
))
}
public func themeNavigationStack(if condition: Bool, closable: Bool = false, path: Binding<NavigationPath>) -> some View {
modifier(ThemeNavigationStackModifier(condition: condition, closable: closable, path: path))
public func themeNavigationStack(
closable: Bool = false,
path: Binding<NavigationPath> = .constant(NavigationPath())
) -> some View {
modifier(ThemeNavigationStackModifier(closable: closable, path: path))
}
@ViewBuilder
public func themeNavigationStack(
if condition: Bool,
closable: Bool = false,
path: Binding<NavigationPath> = .constant(NavigationPath())
) -> some View {
if condition {
modifier(ThemeNavigationStackModifier(closable: closable, path: path))
} else {
self
}
}
public func themeForm() -> some View {
@ -269,31 +285,25 @@ struct ThemeNavigationStackModifier: ViewModifier {
@Environment(\.dismiss)
private var dismiss
let condition: Bool
let closable: Bool
@Binding
var path: NavigationPath
func body(content: Content) -> some View {
if condition {
NavigationStack(path: $path) {
content
.toolbar {
if closable {
ToolbarItem(placement: .cancellationAction) {
Button {
dismiss()
} label: {
ThemeCloseLabel()
}
NavigationStack(path: $path) {
content
.toolbar {
if closable {
ToolbarItem(placement: .cancellationAction) {
Button {
dismiss()
} label: {
ThemeCloseLabel()
}
}
}
}
} else {
content
}
}
}
}