Skip to content

Refine desktop shortcuts and dashboard widgets#6107

Merged
kodjima33 merged 1 commit into
mainfrom
codex/dashboard-widget-cleanup
Mar 28, 2026
Merged

Refine desktop shortcuts and dashboard widgets#6107
kodjima33 merged 1 commit into
mainfrom
codex/dashboard-widget-cleanup

Conversation

@kodjima33
Copy link
Copy Markdown
Collaborator

Summary

  • center the dashboard tasks widget and remove the extra dashboard header controls
  • split keyboard shortcuts into a dedicated Settings section and remove model/transcription choices from that UI
  • add disable states for Ask omi and Push to Talk shortcuts while preserving custom shortcut support

Verification

  • rebuilt and launched /Applications/onboarding-v14.app from this branch
  • connected to the running app with agent-swift and verified the new Shortcuts settings section is present
  • confirmed the old AI Model and Transcription Mode settings are no longer exposed in the shortcuts UI

@kodjima33 kodjima33 merged commit db7da05 into main Mar 28, 2026
3 checks passed
@kodjima33 kodjima33 deleted the codex/dashboard-widget-cleanup branch March 28, 2026 05:50
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 28, 2026

Greptile Summary

This PR refines the desktop app's Settings UI by splitting keyboard shortcuts into a dedicated Shortcuts section, moving floating-bar appearance controls (background style, draggable bar) into the existing Floating Bar section, and simplifying the dashboard by centering the tasks widget and removing the Daily task creation button and AI goal-generation header controls. It also adds proper enable/disable states for the Ask Omi and Push-to-Talk shortcuts backed by UserDefaults persistence.

Key changes:

  • ShortcutSettings gains askOmiEnabled and pttEnabled @Published booleans, both defaulting to true for backward compatibility.
  • GlobalShortcutManager guards hot-key registration behind askOmiEnabled, reading both properties atomically via MainActor.assumeIsolated.
  • PushToTalkManager short-circuits handleShortcutEvent when pttEnabled == false.
  • ShortcutsSettingsSection is stripped of AI Model, background style, draggable bar, and transcription mode cards; a new disableShortcutButton widget provides the enabled/disabled radio-button UX and dependent cards (double-tap, PTT sounds) dim when PTT is off.
  • SettingsPage wires up the new .shortcuts case and inlines the moved Floating Bar sub-settings.
  • Dashboard widgets (TodaysTasksWidget, GoalsWidget) receive layout and header simplification.

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style/UX suggestions with no correctness or data-integrity impact.

The enable/disable logic is correct end-to-end: settings are persisted, GlobalShortcutManager re-reads them on each registration call, and PushToTalkManager gates events properly. The three findings are limited to a misleading button label, a redundant double-notification on preset selection, and an idempotent re-fire when Disable is clicked while already disabled — none affect data integrity or the primary user path.

desktop/Desktop/Sources/MainWindow/Pages/ShortcutsSettingsSection.swift — "Save" label regression and double-notification pattern are worth a quick follow-up.

Important Files Changed

Filename Overview
desktop/Desktop/Sources/FloatingControlBar/GlobalShortcutManager.swift Adds askOmiEnabled check before registering the global hot key; correctly reads both properties in a single MainActor.assumeIsolated block and returns early when disabled.
desktop/Desktop/Sources/FloatingControlBar/PushToTalkManager.swift Adds a single guard pttEnabled else { return } gate at the top of handleShortcutEvent; consistent with the existing pattern of accessing ShortcutSettings.shared properties directly from this handler.
desktop/Desktop/Sources/FloatingControlBar/ShortcutSettings.swift Adds askOmiEnabled and pttEnabled @Published properties with UserDefaults persistence; defaults to true for both, preserving existing behavior for users without the new key stored.
desktop/Desktop/Sources/MainWindow/Pages/ShortcutsSettingsSection.swift Strips AI Model, background style, draggable bar, and transcription mode cards (moved elsewhere); adds disableShortcutButton and enable-state guards throughout. Minor label regression ("Save" vs "Change") and redundant double-notification when selecting presets.
desktop/Desktop/Sources/MainWindow/Pages/SettingsPage.swift Promotes ShortcutsSettingsSection to a dedicated settings section and moves background style / draggable bar cards inline into floatingBarSection; also fixes a brace indentation bug in the show/hide toggle.
desktop/Desktop/Sources/MainWindow/SettingsSidebar.swift Updates search index entries to point shortcut-related items to the new .shortcuts section; adds a keyboard icon for the section.
desktop/Desktop/Sources/MainWindow/Components/TodaysTasksWidget.swift Removes the Daily task creation button/sheet and the spacer layout, replacing them with centered content using Spacer(minLength: 0) wrappers; straightforward UI simplification.
desktop/Desktop/Sources/MainWindow/Components/GoalsWidget.swift Removes goal history and AI goal-generation header buttons; only the manual "Add goal" button remains.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([User selects shortcut option]) --> B{Which option?}

    B -->|Preset key button| C[stopShortcutCapture\naskOmiEnabled = true\naskOmiShortcut = preset]
    B -->|Custom button| D[askOmiEnabled = true\nstartShortcutCapture]
    B -->|Disable button| E[stopShortcutCapture\naskOmiEnabled = false]

    C --> F[didSet: post askOmiShortcutChanged x2]
    D --> G[Local key monitor active\nUser presses key combo]
    E --> H[didSet: post askOmiShortcutChanged]

    G --> I{Valid shortcut?}
    I -->|Yes| J[askOmiEnabled = true\naskOmiShortcut = captured\nstopShortcutCapture]
    I -->|No| K[captureError shown]

    J --> F
    F --> L[GlobalShortcutManager\n.registerAskOmi]
    H --> L

    L --> M{askOmiEnabled?}
    M -->|false| N[UnregisterEventHotKey\nreturn early]
    M -->|true| O[UnregisterEventHotKey\nRegisterEventHotKey with new key]

    P([PTT key event]) --> Q{pttEnabled?}
    Q -->|false| R[return — event ignored]
    Q -->|true| S[Process push-to-talk logic]
Loading

Reviews (1): Last reviewed commit: "Refine desktop shortcuts and dashboard w..." | Re-trigger Greptile


Button(action: action) {
Text(recordingTarget != nil ? "Listening..." : "Change")
Text(isRecording ? "Listening..." : "Save")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 "Save" label is misleading when not actively recording

When the shortcut recorder card is shown because askOmiUsesCustomShortcut (or pttUsesCustomShortcut) is true and no recording is in progress, isRecording is false and the button renders "Save". However, clicking "Save" does not commit the currently-displayed shortcut — it calls startShortcutCapture(target), which begins a new recording session. The old label "Change" accurately described this intent.

Suggested change
Text(isRecording ? "Listening..." : "Save")
Text(isRecording ? "Listening..." : "Change")

This applies equally to the PTT shortcutRecorderCard call at line 109.

Comment on lines 75 to 78
return Button {
stopShortcutCapture()
settings.askOmiEnabled = true
settings.askOmiShortcut = shortcut
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Double notification fired when selecting a preset shortcut

Both askOmiKeyButton and pttKeyButton now set two @Published properties sequentially:

settings.askOmiEnabled = true   // didSet → posts askOmiShortcutChanged → GlobalShortcutManager.registerAskOmi() with OLD shortcut
settings.askOmiShortcut = shortcut  // didSet → posts askOmiShortcutChanged → GlobalShortcutManager.registerAskOmi() with NEW shortcut

registerAskOmi() first calls UnregisterEventHotKey, then re-registers, so it runs twice: once binding the old shortcut key to the new handler, and once more with the correct new key. In practice this is harmless because the second call immediately corrects it, but the same double-notification pattern also occurs in handleShortcutCapture. Consider batching the two mutations to avoid the redundant registration call.

Comment on lines +253 to +271
private func disableShortcutButton(isDisabled: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text("Disable")
.scaledFont(size: 13, weight: .medium)
.foregroundColor(OmiColors.textPrimary)
.padding(.horizontal, 14)
.padding(.vertical, 10)
.background(
RoundedRectangle(cornerRadius: 10)
.fill(isDisabled
? OmiColors.purplePrimary.opacity(0.3)
: OmiColors.backgroundTertiary.opacity(0.5))
)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isDisabled ? OmiColors.purplePrimary : Color.clear, lineWidth: 1.5)
)
}
.buttonStyle(.plain)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Clicking "Disable" when already disabled re-fires the notification

The disableShortcutButton action unconditionally calls settings.askOmiEnabled = false (or pttEnabled = false). When the shortcut is already disabled (isDisabled == true), pressing the button again triggers didSet, which posts askOmiShortcutChanged and writes to UserDefaults unnecessarily. A simple guard prevents the redundant side-effects:

disableShortcutButton(isDisabled: !settings.askOmiEnabled) {
    guard settings.askOmiEnabled else { return }  // already disabled, no-op
    stopShortcutCapture()
    settings.askOmiEnabled = false
}

The same applies to the PTT disable button.

Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant