Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor modal size to be a modifer parameter #877

Merged
merged 5 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ public struct AppCoordinator: View, AppCoordinatorConforming {
}
.themeModal(
item: $modalRoute,
isRoot: true,
size: modalRoute?.size ?? .large,
isFixedWidth: modalRoute?.isFixedWidth ?? false,
isFixedHeight: modalRoute?.isFixedHeight ?? false,
isInteractive: modalRoute?.isInteractive ?? true,
content: modalDestination
)
Expand Down Expand Up @@ -105,6 +107,36 @@ extension AppCoordinator {
}
}

var size: ThemeModalSize {
switch self {
case .migrateProfiles:
return .custom(width: 700, height: 400)

default:
return .large
}
}

var isFixedWidth: Bool {
switch self {
case .migrateProfiles:
return true

default:
return false
}
}

var isFixedHeight: Bool {
switch self {
case .migrateProfiles:
return true

default:
return false
}
}

var isInteractive: Bool {
switch self {
case .editProfile:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ private extension VPNProviderServerView {
} label: {
ThemeImage(.filters)
}
.themePopover(isPresented: $isPresented) {
.themePopover(
isPresented: $isPresented,
size: .custom(width: 400, height: 400)
) {
filtersContent
.modifier(FiltersViewModifier(isPresented: $isPresented))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ extension Theme {
public convenience init() {
self.init(dummy: ())
animationCategories = [.diagnostics, .modules, .profiles, .providers]
popoverSize = .init(width: 400.0, height: 400.0)
}
}

Expand All @@ -41,10 +40,12 @@ extension Theme {
extension View {
public func themePopover<Content>(
isPresented: Binding<Bool>,
size: ThemeModalSize = .medium,
content: @escaping () -> Content
) -> some View where Content: View {
modifier(ThemeBooleanPopoverModifier(
isPresented: isPresented,
size: size,
popover: content
))
}
Expand All @@ -70,15 +71,18 @@ struct ThemeBooleanPopoverModifier<Popover>: ViewModifier, SizeClassProviding wh
@Binding
var isPresented: Bool

let size: ThemeModalSize

@ViewBuilder
let popover: Popover

func body(content: Content) -> some View {
let modalSize = theme.modalSize(size)
if isBigDevice {
content
.popover(isPresented: $isPresented) {
popover
.frame(minWidth: theme.popoverSize?.width, minHeight: theme.popoverSize?.height)
.frame(minWidth: modalSize.width, minHeight: modalSize.height)
.themeLockScreen()
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import SwiftUI
extension Theme {
public convenience init() {
self.init(dummy: Void())
rootModalSize = CGSize(width: 750, height: 500)
secondaryModalSize = CGSize(width: 500.0, height: 200.0)
animationCategories = [.diagnostics, .profiles, .providers]
}
}
Expand Down
10 changes: 4 additions & 6 deletions Passepartout/Library/Sources/UILibrary/Theme/Theme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ public final class Theme: ObservableObject {

public internal(set) var animationCategories: Set<ThemeAnimationCategory> = Set(ThemeAnimationCategory.allCases)

public internal(set) var rootModalSize: CGSize?

public internal(set) var secondaryModalSize: CGSize?

public internal(set) var popoverSize: CGSize?

public internal(set) var relevantWeight: Font.Weight = .semibold

public internal(set) var titleColor: Color = .primary
Expand Down Expand Up @@ -70,6 +64,10 @@ public final class Theme: ObservableObject {

public internal(set) var logoImage = "Logo"

public internal(set) var modalSize: (ThemeModalSize) -> CGSize = {
$0.defaultSize
}

public internal(set) var systemImageName: (ImageName) -> String = Theme.ImageName.defaultSystemName

public internal(set) var menuImageName: (MenuImageName) -> String = Theme.MenuImageName.defaultImageName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,48 @@ import SwiftUI

// MARK: Shortcuts

public enum ThemeModalSize {
case small

case medium

case large

case custom(width: CGFloat, height: CGFloat)
}

extension View {
public func themeModal<Content>(
isPresented: Binding<Bool>,
isRoot: Bool = false,
size: ThemeModalSize = .medium,
isFixedWidth: Bool = false,
isFixedHeight: Bool = false,
isInteractive: Bool = true,
content: @escaping () -> Content
) -> some View where Content: View {
modifier(ThemeBooleanModalModifier(
isPresented: isPresented,
isRoot: isRoot,
size: size,
isFixedWidth: isFixedWidth,
isFixedHeight: isFixedHeight,
isInteractive: isInteractive,
modal: content
))
}

public func themeModal<Content, T>(
item: Binding<T?>,
isRoot: Bool = false,
size: ThemeModalSize = .medium,
isFixedWidth: Bool = false,
isFixedHeight: Bool = false,
isInteractive: Bool = true,
content: @escaping (T) -> Content
) -> some View where Content: View, T: Identifiable {
modifier(ThemeItemModalModifier(
item: item,
isRoot: isRoot,
size: size,
isFixedWidth: isFixedWidth,
isFixedHeight: isFixedHeight,
isInteractive: isInteractive,
modal: content
))
Expand Down Expand Up @@ -200,6 +218,24 @@ extension View {

// MARK: - Presentation modifiers

extension ThemeModalSize {
var defaultSize: CGSize {
switch self {
case .small:
return CGSize(width: 300, height: 300)

case .medium:
return CGSize(width: 550, height: 350)

case .large:
return CGSize(width: 800, height: 500)

case .custom(let width, let height):
return CGSize(width: width, height: height)
}
}
}

struct ThemeBooleanModalModifier<Modal>: ViewModifier where Modal: View {

@EnvironmentObject
Expand All @@ -208,25 +244,34 @@ struct ThemeBooleanModalModifier<Modal>: ViewModifier where Modal: View {
@Binding
var isPresented: Bool

let isRoot: Bool
let size: ThemeModalSize

let isFixedWidth: Bool

let isFixedHeight: Bool

let isInteractive: Bool

let modal: () -> Modal

func body(content: Content) -> some View {
content
let modalSize = theme.modalSize(size)
_ = modalSize
return content
.sheet(isPresented: $isPresented) {
modal()
.frame(minWidth: modalSize?.width, minHeight: modalSize?.height)
#if os(macOS)
.frame(
minWidth: modalSize.width,
maxWidth: isFixedWidth ? modalSize.width : nil,
minHeight: modalSize.height,
maxHeight: isFixedHeight ? modalSize.height : nil
)
#endif
.interactiveDismissDisabled(!isInteractive)
.themeLockScreen()
}
}

private var modalSize: CGSize? {
isRoot ? theme.rootModalSize : theme.secondaryModalSize
}
}

struct ThemeItemModalModifier<Modal, T>: ViewModifier where Modal: View, T: Identifiable {
Expand All @@ -237,25 +282,34 @@ struct ThemeItemModalModifier<Modal, T>: ViewModifier where Modal: View, T: Iden
@Binding
var item: T?

let isRoot: Bool
let size: ThemeModalSize

let isFixedWidth: Bool

let isFixedHeight: Bool

let isInteractive: Bool

let modal: (T) -> Modal

func body(content: Content) -> some View {
content
let modalSize = theme.modalSize(size)
_ = modalSize
return content
.sheet(item: $item) {
modal($0)
.frame(minWidth: modalSize?.width, minHeight: modalSize?.height)
#if os(macOS)
.frame(
minWidth: modalSize.width,
maxWidth: isFixedWidth ? modalSize.width : nil,
minHeight: modalSize.height,
maxHeight: isFixedHeight ? modalSize.height : nil
)
#endif
.interactiveDismissDisabled(!isInteractive)
.themeLockScreen()
}
}

private var modalSize: CGSize? {
isRoot ? theme.rootModalSize : theme.secondaryModalSize
}
}

struct ThemeConfirmationModifier: ViewModifier {
Expand Down