Skip to content

Commit

Permalink
Add ability to preview dynamic menu bar appearance
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanbaird committed Oct 14, 2024
1 parent 0529a7a commit b6528c6
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,25 @@ struct MenuBarAppearanceEditor: View {
}
if appearanceManager.configuration.isDynamic {
VStack(alignment: .leading) {
Text("Light Appearance")
.font(.headline)
HStack {
Text("Light Appearance")
.font(.headline)
if case .dark = SystemAppearance.current {
PreviewButton(configuration: appearanceManager.configuration.lightModeConfiguration)
}
}
.frame(height: 16)
MenuBarPartialAppearanceEditor(configuration: appearanceManager.bindings.configuration.lightModeConfiguration)
}
VStack(alignment: .leading) {
Text("Dark Appearance")
.font(.headline)
HStack {
Text("Dark Appearance")
.font(.headline)
if case .light = SystemAppearance.current {
PreviewButton(configuration: appearanceManager.configuration.darkModeConfiguration)
}
}
.frame(height: 16)
MenuBarPartialAppearanceEditor(configuration: appearanceManager.bindings.configuration.darkModeConfiguration)
}
} else {
Expand Down Expand Up @@ -137,7 +149,7 @@ struct MenuBarAppearanceEditor: View {
}
}

struct MenuBarPartialAppearanceEditor: View {
private struct MenuBarPartialAppearanceEditor: View {
@Binding var configuration: MenuBarAppearancePartialConfiguration

var body: some View {
Expand Down Expand Up @@ -222,3 +234,51 @@ struct MenuBarPartialAppearanceEditor: View {
}
}
}

private struct PreviewButton: View {
@EnvironmentObject var appearanceManager: MenuBarAppearanceManager

@State private var frame = CGRect.zero
@State private var isPressed = false

let configuration: MenuBarAppearancePartialConfiguration

var body: some View {
ZStack {
DummyButton(isPressed: $isPressed)
.allowsHitTesting(false)
Text("Hold to Preview")
.baselineOffset(1.5)
.padding(.horizontal, 10)
.contentShape(Rectangle())
}
.fixedSize()
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
isPressed = frame.contains(value.location)
}
.onEnded { _ in
isPressed = false
}
)
.onChange(of: isPressed) { _, newValue in
appearanceManager.previewConfiguration = newValue ? configuration : nil
}
.onFrameChange(update: $frame)
}
}

private struct DummyButton: NSViewRepresentable {
@Binding var isPressed: Bool

func makeNSView(context: Context) -> NSButton {
let button = NSButton()
button.title = ""
return button
}

func updateNSView(_ nsView: NSButton, context: Context) {
nsView.isHighlighted = isPressed
}
}
3 changes: 3 additions & 0 deletions Ice/MenuBar/Appearance/MenuBarAppearanceManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ final class MenuBarAppearanceManager: ObservableObject {
/// The current menu bar appearance configuration.
@Published var configuration: MenuBarAppearanceConfigurationV2 = .defaultConfiguration

/// The currently previewed partial configuration.
@Published var previewConfiguration: MenuBarAppearancePartialConfiguration?

/// The shared app state.
private weak var appState: AppState?

Expand Down
18 changes: 14 additions & 4 deletions Ice/MenuBar/Appearance/MenuBarOverlayPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,13 +360,20 @@ final class MenuBarOverlayPanel: NSPanel {
private final class MenuBarOverlayPanelContentView: NSView {
@Published private var fullConfiguration: MenuBarAppearanceConfigurationV2 = .defaultConfiguration

@Published private var previewConfiguration: MenuBarAppearancePartialConfiguration?

private var cancellables = Set<AnyCancellable>()

/// The overlay panel that contains the content view.
private var overlayPanel: MenuBarOverlayPanel? {
window as? MenuBarOverlayPanel
}

/// The currently displayed configuration.
private var configuration: MenuBarAppearancePartialConfiguration {
previewConfiguration ?? fullConfiguration.current
}

override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
configureCancellables()
Expand All @@ -381,6 +388,10 @@ private final class MenuBarOverlayPanelContentView: NSView {
.removeDuplicates()
.assign(to: &$fullConfiguration)

appState.appearanceManager.$previewConfiguration
.removeDuplicates()
.assign(to: &$previewConfiguration)

for section in appState.menuBarManager.sections {
// Redraw whenever the window frame of a control item changes.
//
Expand Down Expand Up @@ -436,8 +447,9 @@ private final class MenuBarOverlayPanelContentView: NSView {
.store(in: &c)
}

// Redraw whenever the full configuration changes.
$fullConfiguration
// Redraw whenever the configurations change.
$fullConfiguration.mapToVoid()
.merge(with: $previewConfiguration.mapToVoid())
.sink { [weak self] _ in
self?.needsDisplay = true
}
Expand Down Expand Up @@ -616,7 +628,6 @@ private final class MenuBarOverlayPanelContentView: NSView {

/// Draws the tint defined by the given configuration in the given rectangle.
private func drawTint(in rect: CGRect) {
let configuration = fullConfiguration.current
switch configuration.tintKind {
case .none:
break
Expand All @@ -641,7 +652,6 @@ private final class MenuBarOverlayPanelContentView: NSView {
}

let drawableBounds = getDrawableBounds()
let configuration = fullConfiguration.current

let shapePath = switch fullConfiguration.shapeKind {
case .none:
Expand Down

0 comments on commit b6528c6

Please sign in to comment.