Skip to content

Overlay floating control [More Improvements] #911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

plyght
Copy link
Contributor

@plyght plyght commented Jun 2, 2025

fixes #653

Summary by CodeRabbit

  • New Features

    • Improved persistence and recovery of window position, including smarter handling on focus and resize.
    • Enhanced accessibility with updated button labels and improved UI grouping for audio and recording controls.
    • Added user consent management and audio control hooks for microphone and speaker mute states.
  • Bug Fixes

    • Resolved issues with stale event handlers during drag operations.
    • Fixed error handling for microphone and speaker mute actions, as well as session pause, resume, and stop actions.
  • Style

    • Updated button styling for a darker theme and clearer separation of controls.
  • Chores

    • Improved error logging and removed debug statements.
    • Updated macOS dependencies for better platform support.
    • Refined internal state management and error handling for overlays and window operations.
    • Added controlled management of overlay asynchronous tasks to improve stability.

Copy link

coderabbitai bot commented Jun 2, 2025

## Walkthrough

This set of changes enhances error handling, state management, and UI clarity across several components. It introduces custom hooks for consent and audio mute state management with event subscriptions, refines window positioning and event handling in the desktop app, adds explicit loading and error states to session store actions, updates macOS dependencies, improves platform-specific window logic, and refines overlay event management with controlled async task handling.

## Changes

| File(s)                                                                                         | Change Summary                                                                                                                                                                                                                                  |
|------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| apps/desktop/src/components/editor-area/note-header/listen-button.tsx                          | Added new hooks `useConsentManagement` and `useAudioControls` for managing user consent and microphone/speaker mute states with Tauri event subscriptions and error-logging toggle mutations.                                                 |
| apps/desktop/src/routes/app.control.tsx                                                        | Improved position persistence, event handling, debounced bounds updates, user interaction tracking, UI grouping, accessibility, error handling, and removed debug code and screenshot button.                                                  |
| packages/utils/src/stores/ongoing-session.ts                                                   | Introduced explicit loading state and error handling for `stop`, `pause`, and `resume` session actions, using immutable state updates.                                                                                                       |
| plugins/windows/Cargo.toml                                                                     | Added `objc2`, `objc2-app-kit`, and `objc2-foundation` as macOS-specific dependencies; added `once_cell` to general dependencies.                                                                                                            |
| plugins/windows/src/commands.rs                                                                | Added missing newline at end of file; no code logic changes.                                                                                                                                                                                  |
| plugins/windows/src/ext.rs                                                                     | Refactored `close` and `show` methods for platform-specific handling, improved error handling, updated macOS window button manipulation using `objc2`, and managed overlay listener join handle.                                            |
| plugins/windows/src/overlay.rs                                                                 | Changed `spawn_overlay_listener` to return a join handle, improved error logging for cursor events, refined focus logic, and updated state reset conditions.                                                                                 |
| plugins/windows/src/lib.rs                                                                     | Added static global for overlay join handle management with functions to set and abort the stored join handle, enabling controlled cancellation and replacement of the overlay async task.                                                    |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant UI (app.control.tsx)
    participant Store (ongoing-session.ts)
    participant AudioControls (listen-button.tsx)
    participant Overlay (overlay.rs)
    participant WindowExt (ext.rs)

    User->>UI (app.control.tsx): Drag/Move/Interact with control
    UI (app.control.tsx)->>UI (app.control.tsx): Update position state, debounce bounds update
    UI (app.control.tsx)->>UI (app.control.tsx): Persist position to localStorage
    User->>AudioControls (listen-button.tsx): Toggle mic/speaker mute
    AudioControls (listen-button.tsx)->>AudioControls (listen-button.tsx): Call mutation with onError logging
    User->>Store (ongoing-session.ts): Stop/Pause/Resume session
    Store (ongoing-session.ts)->>Store (ongoing-session.ts): Set loading=true, call async command
    Store (ongoing-session.ts)->>Store (ongoing-session.ts): On success: update state, loading=false
    Store (ongoing-session.ts)->>Store (ongoing-session.ts): On error: log error, loading=false
    UI (app.control.tsx)->>WindowExt (ext.rs): Show/Close window
    WindowExt (ext.rs)->>Overlay (overlay.rs): Spawn overlay listener, handle join handle
    Overlay (overlay.rs)->>Overlay (overlay.rs): Manage cursor/focus, log errors

Possibly related PRs

Poem

In windows and overlays, we hop and we bound,
With error logs ready when troubles are found.
The audio controls now whisper their woes,
And session states pause when the user says so.
A rabbit’s delight in a codebase so neat—
With every small fix, our software’s complete!
🐇✨


<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=fastrepl/hyprnote&utm_content=911):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@plyght
Copy link
Contributor Author

plyght commented Jun 2, 2025

@coderabbitai review

Copy link

coderabbitai bot commented Jun 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🔭 Outside diff range comments (1)
plugins/windows/src/ext.rs (1)

363-380: 🛠️ Refactor suggestion

Window created at full-screen size defeats the purpose of a “floating control”

inner_size(window_width, window_height) sets the Control window to the entire primary monitor.
On HiDPI displays the overlay will cover everything and prevent clicks, contradicting the “toolbar-sized” UX you achieve later with CSS.

-                    .inner_size(window_width, window_height)
+                    // Give the window just enough room for the toolbar
+                    .inner_size( /* ≈ 220 × 80 logical px is sufficient */ 220.0, 80.0)

If you really need the invisible full-screen window for hit-testing, consider using set_fake_window_bounds only and keep the real OS window minimal & click-through.

🧹 Nitpick comments (4)
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (1)

487-489: Good addition of error handling for speaker mute functionality.

The error callback provides useful debugging information when the speaker mute operation fails.

For production, consider enhancing error handling to provide user feedback:

 onError: (error) => {
   console.error('Failed to toggle speaker mute:', error);
+  // Consider showing user notification or toast message
 },
plugins/windows/src/ext.rs (1)

398-437: Unsafe Objective-C calls: missing null-checks & memory-safety guarantees

ns_window as *mut AnyObject is assumed non-null and subsequently dereferenced; if ns_window() returns 0 (can happen when window hasn’t finished initialisation) this will cause UB.

Add an early return:

if let Ok(ns_window) = window.ns_window() {
-    unsafe {
-        let ns_window = ns_window as *mut AnyObject;
-        let ns_window = &*ns_window;
+    unsafe {
+        if ns_window.is_null() {
+            return;
+        }
+        let ns_window: &AnyObject = &*ns_window.cast::<AnyObject>();

Also prefer objc2::rc::Id::<objc2_app_kit::NSButton>::retain_autoreleased() helpers instead of raw pointers.

apps/desktop/src/routes/app.control.tsx (2)

461-475: Repeated setTimeout inside ref callback can cause layout jank

Every remount schedules a timer even when position hasn’t changed.
Prefer reading the DOM rect synchronously and compare before scheduling bounds updates, or throttle with requestAnimationFrame.


498-509: Minor accessibility nit – buttons visually red but no ARIA state

Mute buttons change colour but do not expose aria-pressed.
Add aria-pressed={micMuted} / aria-pressed={speakerMuted} to help screen-reader users.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 15f5278 and b65a386.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • apps/desktop/src/components/editor-area/note-header/listen-button.tsx (2 hunks)
  • apps/desktop/src/routes/app.control.tsx (8 hunks)
  • packages/utils/src/stores/ongoing-session.ts (3 hunks)
  • plugins/windows/Cargo.toml (1 hunks)
  • plugins/windows/src/commands.rs (0 hunks)
  • plugins/windows/src/ext.rs (5 hunks)
  • plugins/windows/src/overlay.rs (3 hunks)
💤 Files with no reviewable changes (1)
  • plugins/windows/src/commands.rs
🔇 Additional comments (15)
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (1)

473-475: Good addition of error handling for microphone mute functionality.

The error callback provides useful debugging information when the microphone mute operation fails.

plugins/windows/src/overlay.rs (5)

26-26: Excellent improvement to return JoinHandle for task lifecycle management.

Returning the JoinHandle allows the caller to properly manage the spawned task, including cleanup and cancellation when needed.


62-64: Good improvement replacing silent error handling with explicit logging.

The explicit error handling with warning logs is much better than the previous .ok() approach that silently ignored failures.


93-95: Consistent error handling pattern applied.

Good consistency in replacing silent error handling with explicit warning logs.


100-110: Enhanced focus management logic with proper state tracking.

The refined focus management prevents redundant focus calls and provides better state tracking for hover interactions.


112-112: Correct return of JoinHandle.

The function now properly returns the spawned task handle instead of discarding it.

packages/utils/src/stores/ongoing-session.ts (8)

133-137: Good addition of loading state management for stop operation.

Setting the loading state before the async operation provides the UI with feedback capability.


150-156: Excellent error handling for stop operation.

The error handling properly logs failures and resets the loading state to prevent UI from being stuck in a loading state.


162-166: Good loading state management for pause operation.

Consistent with the stop operation's loading state pattern.


169-174: Improved state management using mutate for pause operation.

The use of mutate function for immutable state updates is more consistent with the store's pattern.


184-190: Proper error handling for pause operation.

Consistent error handling pattern with logging and loading state reset.


194-198: Loading state management for resume operation.

Consistent pattern applied to resume operation.


201-206: Consistent state management for resume operation.

Good use of mutate function for immutable updates.


207-213: Complete error handling pattern for resume operation.

All session control operations now have consistent error handling with proper loading state management.

plugins/windows/src/ext.rs (1)

439-447: Race-condition between listener abort and window destruction

join_handle.abort() executes after the CloseRequested event fires; if the window is destroyed without firing that event (see first comment) the handle survives.
Tie the lifetime to WindowEvent::Destroyed or move the abort logic into close() for robustness.

@fastrepl fastrepl deleted a comment from coderabbitai bot Jun 2, 2025
@yujonglee
Copy link
Contributor

@plyght Also please resolve the merge conflict! I think w're almost there.

@plyght
Copy link
Contributor Author

plyght commented Jun 3, 2025

@coderabbitai review

Copy link

coderabbitai bot commented Jun 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
plugins/windows/src/lib.rs (1)

21-21: Consider alternatives to global state.

While the global static variable achieves the goal of managing overlay task lifecycle, global state can make testing and reasoning about code more difficult. Consider if this could be managed through the existing state management system or dependency injection.

However, given this appears to be a plugin system where lifecycle management across modules is needed, this approach may be justified.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b65a386 and c0da74f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • apps/desktop/src/routes/app.control.tsx (8 hunks)
  • plugins/windows/Cargo.toml (2 hunks)
  • plugins/windows/src/ext.rs (5 hunks)
  • plugins/windows/src/lib.rs (1 hunks)
  • plugins/windows/src/overlay.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • plugins/windows/Cargo.toml
  • plugins/windows/src/overlay.rs
  • plugins/windows/src/ext.rs
  • apps/desktop/src/routes/app.control.tsx
🔇 Additional comments (1)
plugins/windows/src/lib.rs (1)

16-17: LGTM! Necessary imports for synchronization.

The added imports for Mutex and Lazy are appropriate for the new global state management functionality.

Comment on lines +32 to +38
pub fn abort_overlay_join_handle() {
if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
if let Some(handle) = guard.take() {
handle.abort();
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add documentation and improve error handling.

Similar to set_overlay_join_handle, this function needs documentation and better error handling.

Apply this improvement:

+/// Aborts the current overlay join handle if one exists.
+/// 
+/// # Errors
+/// 
+/// Logs an error if the mutex lock fails.
 pub fn abort_overlay_join_handle() {
-    if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
+    match OVERLAY_JOIN_HANDLE.lock() {
+        Ok(mut guard) => {
             if let Some(handle) = guard.take() {
                 handle.abort();
             }
+        }
+        Err(e) => {
+            eprintln!("Failed to acquire overlay join handle lock: {}", e);
+        }
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn abort_overlay_join_handle() {
if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
if let Some(handle) = guard.take() {
handle.abort();
}
}
}
/// Aborts the current overlay join handle if one exists.
///
/// # Errors
///
/// Logs an error if the mutex lock fails.
pub fn abort_overlay_join_handle() {
match OVERLAY_JOIN_HANDLE.lock() {
Ok(mut guard) => {
if let Some(handle) = guard.take() {
handle.abort();
}
}
Err(e) => {
eprintln!("Failed to acquire overlay join handle lock: {}", e);
}
}
}
🤖 Prompt for AI Agents
In plugins/windows/src/lib.rs around lines 32 to 38, the function
abort_overlay_join_handle lacks documentation and does not handle errors when
locking the OVERLAY_JOIN_HANDLE mutex. Add a doc comment explaining the
function's purpose and behavior. Improve error handling by logging or otherwise
handling the case when the mutex lock fails, instead of silently ignoring it.

Comment on lines +23 to +30
pub fn set_overlay_join_handle(handle: tokio::task::JoinHandle<()>) {
if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
if let Some(old_handle) = guard.take() {
old_handle.abort();
}
*guard = Some(handle);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and add documentation.

The function logic for replacing overlay handles is sound, but there are opportunities for improvement:

  1. Silent error handling: Lock failures are silently ignored, which could mask threading issues or deadlocks.
  2. Missing documentation: As a public API function, it should be documented.

Consider this improvement:

+/// Sets a new overlay join handle, aborting any existing handle.
+/// 
+/// # Errors
+/// 
+/// Logs an error if the mutex lock fails.
 pub fn set_overlay_join_handle(handle: tokio::task::JoinHandle<()>) {
-    if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
+    match OVERLAY_JOIN_HANDLE.lock() {
+        Ok(mut guard) => {
             if let Some(old_handle) = guard.take() {
                 old_handle.abort();
             }
             *guard = Some(handle);
+        }
+        Err(e) => {
+            eprintln!("Failed to acquire overlay join handle lock: {}", e);
+        }
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn set_overlay_join_handle(handle: tokio::task::JoinHandle<()>) {
if let Ok(mut guard) = OVERLAY_JOIN_HANDLE.lock() {
if let Some(old_handle) = guard.take() {
old_handle.abort();
}
*guard = Some(handle);
}
}
/// Sets a new overlay join handle, aborting any existing handle.
///
/// # Errors
///
/// Logs an error if the mutex lock fails.
pub fn set_overlay_join_handle(handle: tokio::task::JoinHandle<()>) {
match OVERLAY_JOIN_HANDLE.lock() {
Ok(mut guard) => {
if let Some(old_handle) = guard.take() {
old_handle.abort();
}
*guard = Some(handle);
}
Err(e) => {
eprintln!("Failed to acquire overlay join handle lock: {}", e);
}
}
}
🤖 Prompt for AI Agents
In plugins/windows/src/lib.rs around lines 23 to 30, the function
set_overlay_join_handle silently ignores errors when locking the mutex, which
can hide potential threading issues. Modify the code to handle the lock error
explicitly, such as logging or returning a Result to indicate failure.
Additionally, add proper Rust doc comments above the function to describe its
purpose, parameters, and behavior as it is part of the public API.

@plyght plyght force-pushed the overlay-floating-control branch from 917598f to c0da74f Compare June 3, 2025 18:36
@plyght
Copy link
Contributor Author

plyght commented Jun 3, 2025

@coderabbitai review

Copy link

coderabbitai bot commented Jun 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (1)

326-339: useConsentManagement hook implementation is correct but appears unused.

The hook logic correctly manages consent state based on onboarding status, but it's not being used anywhere in the component. This could indicate incomplete implementation or dead code.

Is this hook intended for future use, or should it be integrated with the existing component logic? I can help implement the integration if needed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0da74f and 0b4b2e2.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • apps/desktop/src/components/editor-area/note-header/listen-button.tsx (3 hunks)
  • apps/desktop/src/routes/app.control.tsx (8 hunks)
  • packages/utils/src/stores/ongoing-session.ts (3 hunks)
  • plugins/windows/Cargo.toml (2 hunks)
  • plugins/windows/src/commands.rs (1 hunks)
  • plugins/windows/src/ext.rs (5 hunks)
  • plugins/windows/src/lib.rs (2 hunks)
  • plugins/windows/src/overlay.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • plugins/windows/src/commands.rs
  • plugins/windows/Cargo.toml
  • plugins/windows/src/overlay.rs
  • plugins/windows/src/lib.rs
  • packages/utils/src/stores/ongoing-session.ts
  • plugins/windows/src/ext.rs
  • apps/desktop/src/routes/app.control.tsx
🔇 Additional comments (1)
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (1)

4-4: Import additions look appropriate.

The new imports for useState, useEffect and Tauri's listen, emit are correctly added to support the new hooks functionality.

Also applies to: 17-17

Comment on lines +326 to +403
function useConsentManagement(isOnboarding: boolean) {
const ongoingSessionStore = useOngoingSession((s) => ({
hasShownConsent: s.hasShownConsent,
setHasShownConsent: s.setHasShownConsent,
}));

const effectiveHasShownConsent = isOnboarding ? true : ongoingSessionStore.hasShownConsent;
const showConsent = !effectiveHasShownConsent && !isOnboarding;

return {
showConsent,
setHasShownConsent: ongoingSessionStore.setHasShownConsent,
};
}

function useAudioControls() {
const { data: isMicMuted, refetch: refetchMicMuted } = useQuery({
queryKey: ["mic-muted"],
queryFn: () => listenerCommands.getMicMuted(),
});

const { data: isSpeakerMuted, refetch: refetchSpeakerMuted } = useQuery({
queryKey: ["speaker-muted"],
queryFn: () => listenerCommands.getSpeakerMuted(),
});

useEffect(() => {
const unsubscribeMicState = listen<{ muted: boolean }>("audio-mic-state-changed", ({ payload }) => {
console.log(`[Main Window] Received mic state change:`, payload);
refetchMicMuted();
});

const unsubscribeSpeakerState = listen<{ muted: boolean }>("audio-speaker-state-changed", ({ payload }) => {
console.log(`[Main Window] Received speaker state change:`, payload);
refetchSpeakerMuted();
});

return () => {
unsubscribeMicState.then(unlisten => unlisten());
unsubscribeSpeakerState.then(unlisten => unlisten());
};
}, [refetchMicMuted, refetchSpeakerMuted]);

const toggleMicMuted = useMutation({
mutationFn: async () => {
const newMuted = !isMicMuted;
await listenerCommands.setMicMuted(newMuted);
await emit("audio-mic-state-changed", { muted: newMuted });
return newMuted;
},
onSuccess: () => refetchMicMuted(),
onError: (error) => {
console.error('Failed to toggle microphone mute:', error);
},
});

const toggleSpeakerMuted = useMutation({
mutationFn: async () => {
const newMuted = !isSpeakerMuted;
await listenerCommands.setSpeakerMuted(newMuted);
await emit("audio-speaker-state-changed", { muted: newMuted });
return newMuted;
},
onSuccess: () => refetchSpeakerMuted(),
onError: (error) => {
console.error('Failed to toggle speaker mute:', error);
},
});

return {
isMicMuted,
isSpeakerMuted,
toggleMicMuted,
toggleSpeakerMuted,
refetchSpeakerMuted,
refetchMicMuted,
};
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider integration with existing functionality or removal.

Both hooks provide functionality that either duplicates existing code or isn't being used. The useAudioControls hook overlaps with the audio control logic in the RecordingControls component (lines 243-254). Consider either:

  1. Integrating these hooks with the existing component
  2. Removing them if they're not needed
  3. Documenting their intended future use

Let me check if these hooks are used elsewhere in the codebase:


🏁 Script executed:

#!/bin/bash
# Search for usage of the new hooks across the codebase
echo "Searching for useConsentManagement usage..."
rg "useConsentManagement" --type tsx --type ts

echo "Searching for useAudioControls usage..."
rg "useAudioControls" --type tsx --type ts

Length of output: 331


Let’s retry the search across all TypeScript/TSX files with glob patterns:


🏁 Script executed:

#!/bin/bash
# Search across .ts and .tsx files for hook usage
rg "useConsentManagement" -g '*.ts' -g '*.tsx' -n
rg "useAudioControls" -g '*.ts' -g '*.tsx' -n

Length of output: 328


Review and consolidate unused hooks in listen-button.tsx

The useConsentManagement and useAudioControls hooks in
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (lines 326–403) are never referenced elsewhere in the codebase. At the same time, the RecordingControls component in
apps/desktop/src/components/editor-area/note-header/recording-controls.tsx (around lines 243–254) already implements similar mic/speaker mute logic.

Consider one of the following actions:

  • Integrate the new hooks into the existing RecordingControls component so that the shared logic lives in one place.
  • Remove useConsentManagement and useAudioControls if they’re not needed today.
  • Document their intended future use if you plan to expose this functionality elsewhere.
🤖 Prompt for AI Agents
In apps/desktop/src/components/editor-area/note-header/listen-button.tsx around
lines 326 to 403, the hooks useConsentManagement and useAudioControls are
defined but never used anywhere else in the codebase, and their functionality
overlaps with existing logic in the RecordingControls component in
apps/desktop/src/components/editor-area/note-header/recording-controls.tsx
around lines 243 to 254. To fix this, either integrate these hooks into the
RecordingControls component to consolidate audio control logic, or remove these
hooks entirely if they are not currently needed, or add clear documentation
about their intended future use if you plan to keep them for upcoming features.

@yujonglee yujonglee merged commit 8daaf72 into fastrepl:overlay-floating-control Jun 3, 2025
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jun 3, 2025
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.

2 participants