Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e9d83bb
Add app utility pane regression tests
lawrencecchen Jul 14, 2026
f191907
Open Settings and iPhone pairing as panes
lawrencecchen Jul 14, 2026
3cba6c4
Fix Settings pane lifecycle and isolation
lawrencecchen Jul 14, 2026
a263248
Preserve settings pane presentation contracts
lawrencecchen Jul 14, 2026
1de6347
Preserve embedded Settings presentation behavior
lawrencecchen Jul 14, 2026
6eef43c
Merge remote-tracking branch 'origin/main' into task-ios-settings-panes
lawrencecchen Jul 15, 2026
1afe40b
Repair utility pane integration after main merge
lawrencecchen Jul 15, 2026
70ab0ba
Test app utilities open as split panes
lawrencecchen Jul 15, 2026
cd51812
Open app utilities in right-side panes
lawrencecchen Jul 15, 2026
d17aea1
Merge remote-tracking branch 'origin/main' into task-ios-settings-panes
lawrencecchen Jul 15, 2026
5edbbe3
Test utility tabs hide terminal portals
lawrencecchen Jul 15, 2026
d40fb4f
Unify pane portal visibility and settings chrome
lawrencecchen Jul 15, 2026
c3f5f09
Fix app utility test imports
lawrencecchen Jul 15, 2026
3b0895b
Scope utility split and portal reconciliation
lawrencecchen Jul 15, 2026
993ee0a
Preserve utility pane presentation contracts
lawrencecchen Jul 15, 2026
bb5eee9
Keep utility focus and portals pane-scoped
lawrencecchen Jul 15, 2026
12e6acc
Route mobile surface action through utility fallback
lawrencecchen Jul 15, 2026
c023508
Preserve nonactivating utility pane contract
lawrencecchen Jul 15, 2026
8971505
Align utility pane focus ownership
lawrencecchen Jul 15, 2026
a13f2e3
Preserve nonactivating window ordering
lawrencecchen Jul 15, 2026
1641fe4
Register utility panes in canvas layout
lawrencecchen Jul 15, 2026
6ddcccd
Improve pane settings search responsiveness
lawrencecchen Jul 15, 2026
1fb633d
Handle settings search clearing and text scaling
lawrencecchen Jul 15, 2026
24f28d4
Merge remote-tracking branch 'origin/main' into task-ios-settings-panes
lawrencecchen Jul 15, 2026
88d83f4
Resolve portal reconciliation merge
lawrencecchen Jul 15, 2026
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 @@ -13,15 +13,17 @@ struct SettingsSidebarEntryRow: View {
let title: String
let symbolName: String
let subtitle: String?
var isSelected = false

var body: some View {
HStack(spacing: 10) {
Image(systemName: symbolName)
.foregroundStyle(.secondary)
.foregroundStyle(isSelected ? Color.accentColor : Color.secondary)
.frame(width: 16)

VStack(alignment: .leading, spacing: 2) {
Text(title)
.foregroundStyle(isSelected ? Color.accentColor : Color.primary)
.lineLimit(1)

if let subtitle {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation
import Observation

/// Pane-local Settings navigation state.
///
/// Every Settings root owns one model. Search state therefore stays independent
/// when several Settings panes are open, while setting values continue to
/// converge through the shared stores in ``SettingsRuntime``.
@MainActor
@Observable
final class SettingsSidebarModel {
var searchText = "" {
didSet {
guard searchText != oldValue else { return }
visibleEntries = searchIndex.match(searchText)
searchEvaluationCount &+= 1
}
}

private(set) var visibleEntries: [SettingsSearchIndex.Entry]
private(set) var searchEvaluationCount = 1

@ObservationIgnored private let searchIndex: SettingsSearchIndex

init(searchIndex: SettingsSearchIndex) {
self.searchIndex = searchIndex
self.visibleEntries = searchIndex.match("")
}

var isSearching: Bool {
!searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation

struct SettingsInitialSelectionResolver {
let defaults: UserDefaults

func resolve(
initialNavigationSection: SettingsSectionID?
) -> (sectionRawValue: String, sidebarEntryID: String) {
if let initialNavigationSection {
return (
sectionRawValue: initialNavigationSection.rawValue,
sidebarEntryID: "section:\(initialNavigationSection.rawValue)"
)
}
let sectionRawValue = defaults.string(forKey: "selectedSettingsSection")
?? SettingsSectionID.account.rawValue
let section = SettingsSectionID(rawValue: sectionRawValue) ?? .account
let sidebarEntryID = defaults.string(forKey: "selectedSettingsSidebarEntry")
?? "section:\(section.rawValue)"
return (sectionRawValue: section.rawValue, sidebarEntryID: sidebarEntryID)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation

/// Routes Settings navigation notifications to one standalone window or pane.
@MainActor
struct SettingsNavigationNotificationRouter {
let scope: String?

func accepts(_ notification: Notification) -> Bool {
guard let scope else {
return notification.object == nil
}
return notification.object as? String == scope
}

/// Posts the same payload shape as the legacy Settings navigation request.
func post(target: SettingsSectionID, anchorID: String, highlight: Bool) {
NotificationCenter.default.post(
name: SettingsWindowRoot.navigationRequestName,
object: scope,
userInfo: [
"target": target.rawValue,
"anchor": anchorID,
"highlight": highlight
]
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// Controls sizing behavior for a standalone Settings window or an embedded pane.
public enum SettingsPresentationStyle: Sendable {
/// Preserve the standalone window's minimum content size.
case window
/// Adapt to the size of the containing workspace pane.
case pane
}
Loading
Loading