Skip to content

feat: add auto-start and minimize to tray feature#1301

Open
g-k-s-03 wants to merge 2 commits into
AOSSIE-Org:mainfrom
g-k-s-03:feature/auto-start-minimize-tray
Open

feat: add auto-start and minimize to tray feature#1301
g-k-s-03 wants to merge 2 commits into
AOSSIE-Org:mainfrom
g-k-s-03:feature/auto-start-minimize-tray

Conversation

@g-k-s-03
Copy link
Copy Markdown
Contributor

@g-k-s-03 g-k-s-03 commented Jun 1, 2026

Fixes #817
This PR implements two system integration features:

  1. Auto Start — uses tauri-plugin-autostart to register the app
    with the system startup manager. User can enable/disable via
    a toggle in Settings → General. When launched at boot, the app
    starts minimized to the system tray.

  2. Minimize to Tray — closing the window now hides the app to the
    system tray instead of exiting. A tray icon with a context menu
    (Show / Quit) allows the user to restore the window or fully
    exit the app.

Tested on Windows. The tauri-plugin-autostart plugin handles
macOS and Linux platform support internally.

Also fixed a duplicate core:tray:default entry in
capabilities/migrated.json.

Screenshot 2026-06-02 045312 Screenshot 2026-06-02 045409 Screenshot 2026-06-02 045420

Summary by CodeRabbit

  • New Features

    • App now minimizes to the system tray instead of closing
    • System tray menu added for quick access to show/quit the application
    • New "Launch at startup" toggle in system settings
  • Documentation

    • API docs clarified: POST /images/toggle-favourite now includes a description stating it toggles an image’s favorite status
  • Chores

    • Updated dependencies to support tray and autostart functionality

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b1b7f47-8461-47e9-b0dc-f429913721a5

📥 Commits

Reviewing files that changed from the base of the PR and between f689f4d and dcffffb.

📒 Files selected for processing (2)
  • frontend/src-tauri/src/main.rs
  • frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx
  • frontend/src-tauri/src/main.rs

Walkthrough

Adds autostart and minimize-to-tray behavior to the Tauri desktop app, including Tauri dependency/capability updates, tray UI and autostart commands, a Settings UI toggle for autostart, and a one-line OpenAPI operation description addition.

Changes

Application Behavior Settings

Layer / File(s) Summary
Tauri dependencies and capabilities
frontend/src-tauri/Cargo.toml, frontend/src-tauri/capabilities/migrated.json
Add tray-icon feature to tauri, add tauri-plugin-autostart = "2", and include autostart:default capability while adjusting tray capability ordering.
Window lifecycle, tray UI, and autostart commands
frontend/src-tauri/src/main.rs
Intercept CloseRequested to hide the window; add enable_autostart, disable_autostart, is_autostart_enabled Tauri commands; configure autostart plugin with --minimized; hide main window on minimized startup; build tray with Show/Quit and left-click handlers; register new invokes.
Frontend autostart toggle UI
frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx, frontend/src/pages/SettingsPage/Settings.tsx
New SystemSettingsCard component queries initial autostart status, renders an accessible switch-style toggle, invokes enable/disable commands, and is integrated into Settings page general tab.
OpenAPI documentation
docs/backend/backend_python/openapi.json
Add description field to POST /images/toggle-favourite operation.

Sequence Diagram

sequenceDiagram
  participant Frontend as Frontend (React)
  participant TauriCmds as Tauri Commands
  participant Autolaunch as Autolaunch Plugin
  participant Tray as System Tray
  participant Window as Main Window

  Frontend->>TauriCmds: is_autostart_enabled()
  TauriCmds->>Autolaunch: is_enabled()
  Autolaunch-->>TauriCmds: bool
  TauriCmds-->>Frontend: Result<bool, String>

  Frontend->>TauriCmds: enable_autostart() / disable_autostart()
  TauriCmds->>Autolaunch: enable() / disable()
  Autolaunch-->>TauriCmds: Ok / Err
  TauriCmds-->>Frontend: Result<(), String>

  Note over Window: User triggers CloseRequested
  Window->>Window: hide() (prevent close)
  Note over Tray,Window: User selects Show
  Tray->>Window: show() + set_focus()
  Note over Tray,App: User selects Quit
  Tray->>App: kill_process_tree() + exit(0)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Rust, TypeScript/JavaScript, Documentation

Poem

🐰 A tray beneath moonlight, apps tucked in tight,
Autostart whispers softly at the rise of light,
A toggle clicks, the rabbit hums a tiny tune,
The window hides, the tray keeps watch till noon,
Hoppity happy, PictoPy sleeps and wakes in bloom.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding auto-start and minimize-to-tray features, which are the primary objectives of the PR.
Linked Issues check ✅ Passed All coding requirements from issue #817 are implemented: auto-start with platform support via tauri-plugin-autostart and toggle in Settings, minimize-to-tray with system tray icon and context menu.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing auto-start and minimize-to-tray features; the OpenAPI description addition supports the backend integration, and the capabilities.json fix addresses a noted duplicate.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added enhancement New feature or request frontend labels Jun 1, 2026
Copy link
Copy Markdown
Contributor

@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: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/backend/backend_python/openapi.json`:
- Line 896: The OpenAPI description uses American spelling "favorite" but the
endpoint and schema use British spelling; update the description string for the
"/toggle-favourite" operation to use "favourite" (e.g., "Toggle the favourite
status of an image.") and check the related schema name ToggleFavouriteRequest
and any other description fields for the same consistency to ensure all
user-facing docs use "favourite".

In `@frontend/src-tauri/src/main.rs`:
- Line 243: The .icon call uses app.default_window_icon().unwrap().clone() which
can panic; instead convert the Option to a Result and propagate the error from
the setup closure. Replace the unwrap usage in the .icon invocation (around
default_window_icon) with a safe conversion (e.g., call .ok_or / ok_or_else to
produce an error value and use ? to return it) so setup returns Err when no
default icon is present rather than panicking.
- Around line 242-273: The tray left-click handler (inside TrayIconBuilder
.on_tray_icon_event using TrayIconEvent::Click and MouseButton::Left) will
conflict with Tauri v2's default menu_on_left_click behavior; update the
TrayIconBuilder chain to call .menu_on_left_click(false) so left-click only
triggers your restore logic (show/set_focus in the on_tray_icon_event) and the
context menu remains on right-click.

In `@frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx`:
- Around line 17-25: The handler handleToggle can fire multiple invoke(...)
calls concurrently causing out-of-order resolution and stale UI; add a local
pending boolean state (e.g., isToggling) and short-circuit if isToggling is
true, set isToggling = true before calling invoke and set it false in finally,
disable the switch control while isToggling is true, compute the intended new
value from the current autostart at the moment of click (const next =
!autostart) and only call setAutostart(next) after a successful invoke (and
consider reading the confirmed value from the response if available) to ensure
the toggle reflects the last user action; update both occurrences of
handleToggle (lines shown) accordingly.
- Around line 6-70: Add a React Testing Library test suite for
SystemSettingsCard that mocks the invoke bridge to cover mount-time fetch,
toggle success, and error paths: mock invoke('is_autostart_enabled') to return
true/false and assert initial switch state and loading behavior (verify disabled
while loading and role="switch" aria-checked updates), mock invoke for
'enable_autostart'/'disable_autostart' to resolve and assert the UI flips state
when the button is clicked, and mock invoke to reject to assert the error path
leaves state unchanged and optionally logs; use render, waitFor (or findBy*),
and fireEvent/click to drive the component and restore/reset mocks between tests
so the mount effect and handleToggle flows are fully covered.
- Around line 33-64: The switch control in SystemSettingsCard is missing an
accessible name and description; add IDs for the visible label ("Launch at
startup") and its helper text then reference them from the button via
aria-labelledby and aria-describedby (keeping existing role="switch",
aria-checked={autostart}, disabled={loading}, and onClick={handleToggle});
ensure the IDs are unique within the component and used where the label and
helper text are rendered so assistive tech announces both the name and the
description.
- Around line 11-14: The current promise chain calling
invoke<boolean>('is_autostart_enabled') swallows errors and unconditionally
calls setAutostart(false) on failure; instead preserve an explicit unknown/error
state and keep the control disabled until a successful read. Change the state
used by SystemSettingsCard (the state set by setAutostart) to allow a tri-state
(true | false | null or an explicit error flag), update the promise catch to set
the state to null/error rather than false, ensure setLoading still flips off in
finally, and update any toggle/handler logic to no-op or stay disabled when
autostart is null so the UI does not falsely show disabled and avoid calling
enable_autostart when the real status is unknown; locate this logic around the
invoke call and the setAutostart usage (and the toggle handler) to implement the
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7e50fbb4-03f3-49a1-8b39-a72d45b0ef81

📥 Commits

Reviewing files that changed from the base of the PR and between ffd438a and f689f4d.

⛔ Files ignored due to path filters (2)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • frontend/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • docs/backend/backend_python/openapi.json
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/capabilities/migrated.json
  • frontend/src-tauri/src/main.rs
  • frontend/src/pages/SettingsPage/Settings.tsx
  • frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx

"Images"
],
"summary": "Toggle Favourite",
"description": "Toggle the favorite status of an image.",
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Spelling inconsistency: use "favourite" to match the endpoint naming.

The description uses American spelling ("favorite") while the endpoint path and request schema use British spelling ("/toggle-favourite", "ToggleFavouriteRequest"). For consistency in user-facing API documentation, the description should match the endpoint's spelling convention.

📝 Suggested fix
-        "description": "Toggle the favorite status of an image.",
+        "description": "Toggle the favourite status of an image.",
📝 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
"description": "Toggle the favorite status of an image.",
"description": "Toggle the favourite status of an image.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/backend/backend_python/openapi.json` at line 896, The OpenAPI
description uses American spelling "favorite" but the endpoint and schema use
British spelling; update the description string for the "/toggle-favourite"
operation to use "favourite" (e.g., "Toggle the favourite status of an image.")
and check the related schema name ToggleFavouriteRequest and any other
description fields for the same consistency to ensure all user-facing docs use
"favourite".

Comment thread frontend/src-tauri/src/main.rs
Comment thread frontend/src-tauri/src/main.rs Outdated
Comment on lines +6 to +70
const SystemSettingsCard: React.FC = () => {
const [autostart, setAutostart] = useState(false);
const [loading, setLoading] = useState(true);

useEffect(() => {
invoke<boolean>('is_autostart_enabled')
.then(setAutostart)
.catch(() => setAutostart(false))
.finally(() => setLoading(false));
}, []);

const handleToggle = async () => {
const next = !autostart;
try {
await invoke(next ? 'enable_autostart' : 'disable_autostart');
setAutostart(next);
} catch (err) {
console.error('Failed to toggle autostart:', err);
}
};

return (
<SettingsCard
icon={Monitor}
title="System"
description="System integration and startup behavior"
>
<div className="flex items-center justify-between py-1">
<div>
<div className="font-medium">Launch at startup</div>
<div className="text-muted-foreground text-sm">
Automatically start PictoPy when you log in. The window starts
minimized to the system tray.
</div>
</div>

<button
role="switch"
aria-checked={autostart}
disabled={loading}
onClick={handleToggle}
className={[
'relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full',
'transition-colors duration-200 ease-in-out',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
autostart
? 'bg-primary focus-visible:ring-primary'
: 'bg-gray-200 focus-visible:ring-gray-500 dark:bg-gray-700',
].join(' ')}
>
<span
className={[
'inline-block h-4 w-4 rounded-full bg-white shadow-md',
'transition-transform duration-200 ease-in-out',
autostart ? 'translate-x-6' : 'translate-x-1',
].join(' ')}
/>
</button>
</div>
</SettingsCard>
);
};

export default SystemSettingsCard;
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add automated coverage for the new autostart flow.

This is core PR functionality, but no test coverage is shown for the mount-time status fetch, the toggle command dispatch, or the failure paths. A small React Testing Library suite with invoke mocked would catch the regressions above before they ship. As per coding guidelines, "Ensure that test code is automated, comprehensive, and follows testing best practices" and "Verify that all critical functionality is covered by tests".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx` around
lines 6 - 70, Add a React Testing Library test suite for SystemSettingsCard that
mocks the invoke bridge to cover mount-time fetch, toggle success, and error
paths: mock invoke('is_autostart_enabled') to return true/false and assert
initial switch state and loading behavior (verify disabled while loading and
role="switch" aria-checked updates), mock invoke for
'enable_autostart'/'disable_autostart' to resolve and assert the UI flips state
when the button is clicked, and mock invoke to reject to assert the error path
leaves state unchanged and optionally logs; use render, waitFor (or findBy*),
and fireEvent/click to drive the component and restore/reset mocks between tests
so the mount effect and handleToggle flows are fully covered.

Comment thread frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx
Comment thread frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx
Comment thread frontend/src/pages/SettingsPage/components/SystemSettingsCard.tsx
@rohan-pandeyy
Copy link
Copy Markdown
Contributor

@g-k-s-03 please fix the lint errors and address the frontend failures

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Implement Application Behavior Settings

2 participants