Skip to content

Commit

Permalink
Implements autounhide when screen is wider than set width
Browse files Browse the repository at this point in the history
  • Loading branch information
michyprima committed Oct 21, 2024
1 parent d89de0f commit 733f140
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Ice/Main/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ final class AppState: ObservableObject {

/// Global cache for menu bar item images.
private(set) lazy var imageCache = MenuBarItemImageCache(appState: self)

Check warning on line 41 in Ice/Main/AppState.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
/// Global observer for auto expanding the bar based on the screens width
private(set) lazy var autoExpander = MenuBarAutoExpander(appState: self)

/// Manager for menu bar item spacing.
let spacingManager = MenuBarItemSpacingManager()
Expand Down Expand Up @@ -187,6 +190,7 @@ final class AppState: ObservableObject {
imageCache.performSetup()
updatesManager.performSetup()
userNotificationManager.performSetup()
autoExpander.performSetup()
}

/// Assigns the app delegate to the app state.
Expand Down
76 changes: 76 additions & 0 deletions Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// MenuBarAutoExpander.swift
// Ice
//
// Created by Michele Primavera on 21/10/24.
//

import Cocoa
import Combine

final class MenuBarAutoExpander : ObservableObject {

Check warning on line 11 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Colon Spacing Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon)
/// The shared app state.
private weak var appState: AppState?

Check warning on line 14 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
/// Storage for internal observers.
private var cancellables = Set<AnyCancellable>()

/// Creates a cache with the given app state.
init(appState: AppState) {
self.appState = appState
}

/// Sets up the cache.
@MainActor
func performSetup() {
configureCancellables()
}

/// Configures the internal observers for the cache.
@MainActor
private func configureCancellables() {
var c = Set<AnyCancellable>()

if let appState {
Publishers.Merge(
NotificationCenter.default.publisher(for: NSApplication.didChangeScreenParametersNotification).mapToVoid(),
Just(())
)
.throttle(for: 10.0, scheduler: DispatchQueue.main, latest: false)
.sink {
let advancedSettingsManager = appState.settingsManager.advancedSettingsManager

Check warning on line 42 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
if(advancedSettingsManager.showHiddenSectionWhenWidthGreaterThanEnabled) {

Check warning on line 43 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Control Statement Violation: `if`, `for`, `guard`, `switch`, `while`, and `catch` statements shouldn't unnecessarily wrap their conditionals or arguments in parentheses (control_statement)
Task.detached {
let mainScreen = NSScreen.main
if mainScreen != nil {
let mainScreenWidth = mainScreen!.frame.width

Check warning on line 47 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Force Unwrapping Violation: Force unwrapping should be avoided (force_unwrapping)

Check warning on line 48 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
guard let section = await appState.menuBarManager.section(withName: .hidden) else {
return
}

Check warning on line 52 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
let setting = await advancedSettingsManager.showHiddenSectionWhenWidthGreaterThan

Check warning on line 54 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
if (mainScreenWidth >= setting) {

Check warning on line 55 in Ice/MenuBar/MenuBarManagement/MenuBarAutoExpander.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Control Statement Violation: `if`, `for`, `guard`, `switch`, `while`, and `catch` statements shouldn't unnecessarily wrap their conditionals or arguments in parentheses (control_statement)
Logger.autoExpander.info("Showing hidden section because mainScreenWidth (\(mainScreenWidth)) >= showHiddenSectionWhenWidthGreaterThan (\(setting)")
await section.show()
} else {
Logger.autoExpander.info("Hiding hidden section because mainScreenWidth (\(mainScreenWidth)) < showHiddenSectionWhenWidthGreaterThan (\(setting)")
await section.hide()
}
}
}
}
}
.store(in: &c)
}

cancellables = c
}
}

// MARK: - Logger
private extension Logger {
static let autoExpander = Logger(category: "MenuBarAutoExpander")
}
23 changes: 23 additions & 0 deletions Ice/Settings/SettingsManagers/AdvancedSettingsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ final class AdvancedSettingsManager: ObservableObject {
/// A Boolean value that indicates whether to show all sections when
/// the user is dragging items in the menu bar.
@Published var showAllSectionsOnUserDrag = true

/// A Boolean value that indicates whether to show all sections when
/// the screen width is greater than showHiddenSectionWhenWidthGreaterThan
@Published var showHiddenSectionWhenWidthGreaterThanEnabled = false

/// The minimum screen size showAllSectionOnScreenSize reacts to
@Published var showHiddenSectionWhenWidthGreaterThan: CGFloat = 3000

/// Storage for internal observers.
private var cancellables = Set<AnyCancellable>()
Expand All @@ -57,6 +64,8 @@ final class AdvancedSettingsManager: ObservableObject {
Defaults.ifPresent(key: .showOnHoverDelay, assign: &showOnHoverDelay)
Defaults.ifPresent(key: .tempShowInterval, assign: &tempShowInterval)
Defaults.ifPresent(key: .showAllSectionsOnUserDrag, assign: &showAllSectionsOnUserDrag)
Defaults.ifPresent(key: .showHiddenSectionWhenWidthGreaterThanEnabled, assign: &showHiddenSectionWhenWidthGreaterThanEnabled)
Defaults.ifPresent(key: .showHiddenSectionWhenWidthGreaterThan, assign: &showHiddenSectionWhenWidthGreaterThan)
}

private func configureCancellables() {
Expand Down Expand Up @@ -110,6 +119,20 @@ final class AdvancedSettingsManager: ObservableObject {
Defaults.set(showAll, forKey: .showAllSectionsOnUserDrag)
}
.store(in: &c)

$showHiddenSectionWhenWidthGreaterThanEnabled
.receive(on: DispatchQueue.main)
.sink { showAll in
Defaults.set(showAll, forKey: .showHiddenSectionWhenWidthGreaterThanEnabled)
}
.store(in: &c)

$showHiddenSectionWhenWidthGreaterThan
.receive(on: DispatchQueue.main)
.sink { width in
Defaults.set(width, forKey: .showHiddenSectionWhenWidthGreaterThan)
}
.store(in: &c)

cancellables = c
}
Expand Down
36 changes: 36 additions & 0 deletions Ice/Settings/SettingsPanes/AdvancedSettingsPane.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ struct AdvancedSettingsPane: View {
LocalizedStringKey(formatted + " seconds")
}
}

private func formattedToPx(_ px: CGFloat) -> LocalizedStringKey {
let formatted = px.formatted()
return LocalizedStringKey(formatted + " px")
}

var body: some View {
IceForm {
Expand All @@ -41,6 +46,10 @@ struct AdvancedSettingsPane: View {
showOnHoverDelaySlider
tempShowIntervalSlider
}
IceSection {
activeScreenWidthToggle
activeScreenWidthSlider
}
}
}

Expand Down Expand Up @@ -134,6 +143,33 @@ struct AdvancedSettingsPane: View {
private var showAllSectionsOnUserDrag: some View {
Toggle("Show all sections when Command + dragging menu bar items", isOn: manager.bindings.showAllSectionsOnUserDrag)
}

@ViewBuilder
private var activeScreenWidthToggle: some View {
Toggle("Automatically unhide when active screen width is higher than the value below", isOn: manager.bindings.showHiddenSectionWhenWidthGreaterThanEnabled)
}

@ViewBuilder
private var activeScreenWidthSlider: some View {
if manager.showHiddenSectionWhenWidthGreaterThanEnabled {
IceLabeledContent {
IceSlider(
formattedToPx(manager.showHiddenSectionWhenWidthGreaterThan),
value: manager.bindings.showHiddenSectionWhenWidthGreaterThan,
in: 1000...6000,
step: 10
)
} label: {
Text("Active screen width in pixels")
.frame(minHeight: .compactSliderMinHeight)
.frame(minWidth: maxSliderLabelWidth, alignment: .leading)
.onFrameChange { frame in
maxSliderLabelWidth = max(maxSliderLabelWidth, frame.width)
}
}
.annotation("You may want to disable automatically rehide in General.")
}
}
}

#Preview {
Expand Down
2 changes: 2 additions & 0 deletions Ice/Utilities/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ extension Defaults {
case showOnHoverDelay = "ShowOnHoverDelay"
case tempShowInterval = "TempShowInterval"
case showAllSectionsOnUserDrag = "ShowAllSectionsOnUserDrag"
case showHiddenSectionWhenWidthGreaterThanEnabled = "ShowHiddenSectionWhenWidthGreaterThanEnabled"
case showHiddenSectionWhenWidthGreaterThan = "ShowHiddenSectionWhenWidthGreaterThan"

// MARK: Menu Bar Appearance Settings

Expand Down

0 comments on commit 733f140

Please sign in to comment.