Skip to content

Commit

Permalink
Implement app-wide navigation state
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanbaird committed Jul 8, 2024
1 parent 1efa9e6 commit 2fb6c6d
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 96 deletions.
40 changes: 36 additions & 4 deletions Ice.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
7133ED5E2A853FCF000A7E1B /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7133ED5D2A853FCF000A7E1B /* Constants.swift */; };
7133ED652A85811C000A7E1B /* NSApplication+windowWithIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7133ED642A85811C000A7E1B /* NSApplication+windowWithIdentifier.swift */; };
7133ED6A2A85870E000A7E1B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7133ED692A85870E000A7E1B /* SettingsView.swift */; };
7133ED712A85AE6A000A7E1B /* SettingsNavigationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7133ED702A85AE6A000A7E1B /* SettingsNavigationItem.swift */; };
7150A7AD2AA4265F0045EA68 /* KeyCombination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7150A7AC2AA4265F0045EA68 /* KeyCombination.swift */; };
7150A7AF2AA426C60045EA68 /* HotkeyRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7150A7AE2AA426C60045EA68 /* HotkeyRegistry.swift */; };
7150A7B12AA427F80045EA68 /* KeyCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7150A7B02AA427F80045EA68 /* KeyCode.swift */; };
Expand All @@ -128,6 +127,11 @@
71C400322AAD76A8006FDB1C /* ReadWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71C400312AAD76A8006FDB1C /* ReadWindow.swift */; };
71D2B02E2AAFDD5C0002B6C8 /* Bundle+versionString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D2B02D2AAFDD5C0002B6C8 /* Bundle+versionString.swift */; };
71D36C4F2A88FE4900D89CD5 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71D36C4E2A88FE4900D89CD5 /* SettingsWindow.swift */; };
71F4280F2C3B5C870025706C /* SettingsNavigationIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F4280E2C3B5C870025706C /* SettingsNavigationIdentifier.swift */; };
71F428112C3B5CE90025706C /* NavigationIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F428102C3B5CE90025706C /* NavigationIdentifier.swift */; };
71F428132C3B5E030025706C /* IconResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F428122C3B5E030025706C /* IconResource.swift */; };
71F428152C3B5F3D0025706C /* AppNavigationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F428142C3B5F3D0025706C /* AppNavigationState.swift */; };
71F428172C3B60070025706C /* AppNavigationIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71F428162C3B60070025706C /* AppNavigationIdentifier.swift */; };
71FEA2542A8D701B0048341A /* LocalEventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FEA2532A8D701B0048341A /* LocalEventMonitor.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -230,7 +234,6 @@
7133ED5D2A853FCF000A7E1B /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
7133ED642A85811C000A7E1B /* NSApplication+windowWithIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSApplication+windowWithIdentifier.swift"; sourceTree = "<group>"; };
7133ED692A85870E000A7E1B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
7133ED702A85AE6A000A7E1B /* SettingsNavigationItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigationItem.swift; sourceTree = "<group>"; };
7150A7AC2AA4265F0045EA68 /* KeyCombination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyCombination.swift; sourceTree = "<group>"; };
7150A7AE2AA426C60045EA68 /* HotkeyRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotkeyRegistry.swift; sourceTree = "<group>"; };
7150A7B02AA427F80045EA68 /* KeyCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyCode.swift; sourceTree = "<group>"; };
Expand All @@ -253,6 +256,11 @@
71C400312AAD76A8006FDB1C /* ReadWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadWindow.swift; sourceTree = "<group>"; };
71D2B02D2AAFDD5C0002B6C8 /* Bundle+versionString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+versionString.swift"; sourceTree = "<group>"; };
71D36C4E2A88FE4900D89CD5 /* SettingsWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindow.swift; sourceTree = "<group>"; };
71F4280E2C3B5C870025706C /* SettingsNavigationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigationIdentifier.swift; sourceTree = "<group>"; };
71F428102C3B5CE90025706C /* NavigationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationIdentifier.swift; sourceTree = "<group>"; };
71F428122C3B5E030025706C /* IconResource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconResource.swift; sourceTree = "<group>"; };
71F428142C3B5F3D0025706C /* AppNavigationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppNavigationState.swift; sourceTree = "<group>"; };
71F428162C3B60070025706C /* AppNavigationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppNavigationIdentifier.swift; sourceTree = "<group>"; };
71FEA2532A8D701B0048341A /* LocalEventMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalEventMonitor.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -595,7 +603,6 @@
7133ED662A858230000A7E1B /* Settings */ = {
isa = PBXGroup;
children = (
7133ED702A85AE6A000A7E1B /* SettingsNavigationItem.swift */,
7133ED692A85870E000A7E1B /* SettingsView.swift */,
71D36C4E2A88FE4900D89CD5 /* SettingsWindow.swift */,
17B331D12B991D180084EBB0 /* SettingsManagers */,
Expand Down Expand Up @@ -662,6 +669,7 @@
17C261E72B5AEB7A0076F129 /* Main */,
7166834E2A768190006ABF84 /* MenuBar */,
179F13BC2B91E7F700EC6B52 /* MenuBarAppearance */,
71F4280B2C3B5BF00025706C /* Navigation */,
1787C42A2B16ADF2002F50DF /* Permissions */,
7133ED662A858230000A7E1B /* Settings */,
71D36C522A89443800D89CD5 /* UI */,
Expand All @@ -683,6 +691,7 @@
17DFF4BF2AD8DBC500B5177A /* CodableColor.swift */,
7133ED5D2A853FCF000A7E1B /* Constants.swift */,
17928F192AC5DF9C0016C615 /* Defaults.swift */,
71F428122C3B5E030025706C /* IconResource.swift */,
17F998452C16C78000D75EC0 /* Injection.swift */,
17C303772BA62CD20079755B /* MigrationManager.swift */,
17F998312C15C91400D75EC0 /* MouseCursor.swift */,
Expand Down Expand Up @@ -767,6 +776,25 @@
path = UI;
sourceTree = "<group>";
};
71F4280B2C3B5BF00025706C /* Navigation */ = {
isa = PBXGroup;
children = (
71F428142C3B5F3D0025706C /* AppNavigationState.swift */,
71F428182C3B605B0025706C /* NavigationIdentifiers */,
);
path = Navigation;
sourceTree = "<group>";
};
71F428182C3B605B0025706C /* NavigationIdentifiers */ = {
isa = PBXGroup;
children = (
71F428162C3B60070025706C /* AppNavigationIdentifier.swift */,
71F428102C3B5CE90025706C /* NavigationIdentifier.swift */,
71F4280E2C3B5C870025706C /* SettingsNavigationIdentifier.swift */,
);
path = NavigationIdentifiers;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -894,13 +922,15 @@
17F9983E2C16562300D75EC0 /* LayoutBarItemView.swift in Sources */,
17F998322C15C91400D75EC0 /* MouseCursor.swift in Sources */,
171C6FC92C0659340097A5C8 /* Task+timeout.swift in Sources */,
71F428132C3B5E030025706C /* IconResource.swift in Sources */,
17F71BB22B87E37800905CBA /* RehideStrategy.swift in Sources */,
17F9984F2C16CF8600D75EC0 /* LayoutBarPaddingView.swift in Sources */,
17B380F32ADCBC8A0002C9C3 /* OnKeyDown.swift in Sources */,
1736F77C2ADBBF340073428E /* CustomGradientPicker.swift in Sources */,
17543EB12C2C7A100052711E /* RunLoopLocalEventMonitor.swift in Sources */,
17BE3DD02C1A45B3008B98EF /* IceBar.swift in Sources */,
17C303782BA62CD20079755B /* MigrationManager.swift in Sources */,
71F4280F2C3B5C870025706C /* SettingsNavigationIdentifier.swift in Sources */,
17CDCACD2C2E6F6A000B1CFF /* Deprecated.swift in Sources */,
17CC22B52B8A55E7001A0582 /* WindowInfo.swift in Sources */,
17CC22B02B8A0CA6001A0582 /* HotkeysSettingsPane.swift in Sources */,
Expand Down Expand Up @@ -931,11 +961,13 @@
179AC2FC2C1146EF0051E7B0 /* RemoveSidebarToggle.swift in Sources */,
17B7F32B2B264C1800CDCF49 /* MenuBarAppearanceManager.swift in Sources */,
17F9984D2C16CD8E00D75EC0 /* MenuBarItemsSettingsPane.swift in Sources */,
71F428152C3B5F3D0025706C /* AppNavigationState.swift in Sources */,
17D1AC8D2B97BB5900726180 /* MenuBarItem.swift in Sources */,
71553E372C378BF50083F5BE /* Notifications.swift in Sources */,
173C248C2B8E821C0096F7A1 /* UpdatesSettingsPane.swift in Sources */,
171C6F9C2C0356BC0097A5C8 /* GeneralSettingsPane.swift in Sources */,
7150A7B12AA427F80045EA68 /* KeyCode.swift in Sources */,
71F428172C3B60070025706C /* AppNavigationIdentifier.swift in Sources */,
71829E0A2C2FDCC200503604 /* NSScreen+getMenuBarHeight.swift in Sources */,
17B331D02B9916E70084EBB0 /* SettingsManager.swift in Sources */,
17B331D32B991D290084EBB0 /* GeneralSettingsManager.swift in Sources */,
Expand Down Expand Up @@ -963,10 +995,10 @@
718152C32C34E595005564AA /* NSScreen+screenWithMouse.swift in Sources */,
17F998532C16EFCD00D75EC0 /* CGImage+averageColor.swift in Sources */,
71287C602C3189AC0028706E /* IceBarColorManager.swift in Sources */,
71F428112C3B5CE90025706C /* NavigationIdentifier.swift in Sources */,
17DFF4C02AD8DBC500B5177A /* CodableColor.swift in Sources */,
17CC22BC2B8CDE6F001A0582 /* EventManager.swift in Sources */,
1737E3E52BA3C4AA009F0EFA /* HotkeyAction.swift in Sources */,
7133ED712A85AE6A000A7E1B /* SettingsNavigationItem.swift in Sources */,
17EE69682C277B4E00F778A7 /* Publisher+mapToVoid.swift in Sources */,
17EE69652C27777C00F778A7 /* MenuBarItemImageCache.swift in Sources */,
174AA5D62B71D97100E3FE74 /* MenuBarOverlayPanel.swift in Sources */,
Expand Down
12 changes: 12 additions & 0 deletions Ice/Main/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ final class AppState: ObservableObject {
/// Manager for app updates.
let updatesManager = UpdatesManager()

/// Model for app-wide navigation.
let navigationState = AppNavigationState()

/// The app's delegate.
private(set) weak var appDelegate: AppDelegate?

Expand Down Expand Up @@ -101,6 +104,15 @@ final class AppState: ObservableObject {
}
.store(in: &c)

if let settingsWindow {
settingsWindow.publisher(for: \.isVisible)
.receive(on: DispatchQueue.main)
.sink { [weak self] isVisible in
self?.navigationState.appNavigationIdentifier = if isVisible { .settings } else { .idle }
}
.store(in: &c)
}

menuBarManager.objectWillChange
.sink { [weak self] in
self?.objectWillChange.send()
Expand Down
13 changes: 13 additions & 0 deletions Ice/Navigation/AppNavigationState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// AppNavigationState.swift
// Ice
//

import Combine

/// The model for app-wide navigation.
@MainActor
final class AppNavigationState: ObservableObject {
@Published var appNavigationIdentifier: AppNavigationIdentifier = .idle
@Published var settingsNavigationIdentifier: SettingsNavigationIdentifier = .general
}
10 changes: 10 additions & 0 deletions Ice/Navigation/NavigationIdentifiers/AppNavigationIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// AppNavigationIdentifier.swift
// Ice
//

/// An identifier used for app-wide navigation.
enum AppNavigationIdentifier: String, NavigationIdentifier {
case idle
case settings
}
20 changes: 20 additions & 0 deletions Ice/Navigation/NavigationIdentifiers/NavigationIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// NavigationIdentifier.swift
// Ice
//

import SwiftUI

/// A type that represents an identifier used for navigation in a user interface.
protocol NavigationIdentifier: CaseIterable, Hashable, Identifiable, RawRepresentable {
/// A localized description of the identifier that can be presented to the user.
var localized: LocalizedStringKey { get }
}

extension NavigationIdentifier where ID == Int {
var id: Int { hashValue }
}

extension NavigationIdentifier where RawValue == String {
var localized: LocalizedStringKey { LocalizedStringKey(rawValue) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// SettingsNavigationIdentifier.swift
// Ice
//

/// An identifier used for navigation in the settings interface.
enum SettingsNavigationIdentifier: String, NavigationIdentifier {
case general = "General"
case menuBarItems = "Menu Bar Items"
case menuBarAppearance = "Menu Bar Appearance"
case hotkeys = "Hotkeys"
case advanced = "Advanced"
case updates = "Updates"
case about = "About"
}
48 changes: 0 additions & 48 deletions Ice/Settings/SettingsNavigationItem.swift

This file was deleted.

64 changes: 20 additions & 44 deletions Ice/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,23 @@
import SwiftUI

struct SettingsView: View {
private static let items: [SettingsNavigationItem] = [
SettingsNavigationItem(
name: .general,
icon: .systemSymbol("gearshape")
),
SettingsNavigationItem(
name: .menuBarItems,
icon: .systemSymbol("menubar.rectangle")
),
SettingsNavigationItem(
name: .menuBarAppearance,
icon: .systemSymbol("paintpalette")
),
SettingsNavigationItem(
name: .hotkeys,
icon: .systemSymbol("keyboard")
),
SettingsNavigationItem(
name: .advanced,
icon: .systemSymbol("gearshape.2")
),
SettingsNavigationItem(
name: .updates,
icon: .systemSymbol("arrow.triangle.2.circlepath.circle")
),
SettingsNavigationItem(
name: .about,
icon: .assetCatalog(.iceCubeStroke)
),
]

@State private var selection = Self.items[0]
@EnvironmentObject var navigationState: AppNavigationState

var body: some View {
NavigationSplitView {
sidebar
} detail: {
detailView
}
.navigationTitle(selection.name.localized)
.navigationTitle(navigationState.settingsNavigationIdentifier.localized)
}

@ViewBuilder
private var sidebar: some View {
List(selection: $selection) {
List(selection: $navigationState.settingsNavigationIdentifier) {
Section {
ForEach(Self.items, id: \.self) { item in
sidebarItem(item: item)
ForEach(SettingsNavigationIdentifier.allCases, id: \.self) { identifier in
sidebarItem(for: identifier)
}
} header: {
HStack {
Expand All @@ -76,7 +45,7 @@ struct SettingsView: View {

@ViewBuilder
private var detailView: some View {
switch selection.name {
switch navigationState.settingsNavigationIdentifier {
case .general:
GeneralSettingsPane()
case .menuBarItems:
Expand All @@ -95,20 +64,27 @@ struct SettingsView: View {
}

@ViewBuilder
private func sidebarItem(item: SettingsNavigationItem) -> some View {
private func sidebarItem(for identifier: SettingsNavigationIdentifier) -> some View {
Label {
Text(item.name.localized)
Text(identifier.localized)
.font(.title3)
.padding(.leading, 2)
} icon: {
item.icon.view
icon(for: identifier).view
.foregroundStyle(.primary)
}
.frame(height: 30)
}
}

#Preview {
SettingsView()
.environmentObject(AppState())
private func icon(for identifier: SettingsNavigationIdentifier) -> IconResource {
switch identifier {
case .general: .systemSymbol("gearshape")
case .menuBarItems: .systemSymbol("menubar.rectangle")
case .menuBarAppearance: .systemSymbol("paintpalette")
case .hotkeys: .systemSymbol("keyboard")
case .advanced: .systemSymbol("gearshape.2")
case .updates: .systemSymbol("arrow.triangle.2.circlepath.circle")
case .about: .assetCatalog(.iceCubeStroke)
}
}
}
1 change: 1 addition & 0 deletions Ice/Settings/SettingsWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct SettingsWindow: Scene {
.frame(minWidth: 825, minHeight: 500)
.onAppear(perform: onAppear)
.environmentObject(appState)
.environmentObject(appState.navigationState)
}
.commandsRemoved()
.windowResizability(.contentSize)
Expand Down
Loading

0 comments on commit 2fb6c6d

Please sign in to comment.