Skip to content

feat: extract settings into a separate native window#53

Merged
amemya merged 1 commit into
mainfrom
feat/separate-settings-window
Jun 10, 2026
Merged

feat: extract settings into a separate native window#53
amemya merged 1 commit into
mainfrom
feat/separate-settings-window

Conversation

@amemya

@amemya amemya commented Jun 10, 2026

Copy link
Copy Markdown
Owner
  • Added OpenSettingsWindow in the Go backend to handle spawning and focusing a dedicated settings window via Wails v3 WebviewWindow.
  • Modified the application menu (main.go) to trigger the new native window instead of emitting an IPC event.
  • Extracted the settings modal from App.tsx into a new standalone SettingsWindow.tsx component.
  • Implemented client-side routing in main.tsx to serve the settings view on the /settings path.
  • Updated App.tsx to synchronize watchFolder and exportFolder states via the settings_saved Wails event.
  • Added a draggable top bar to the settings window for better native UX.
  • Improved type safety and Promise error handling based on code review.

resolved #30

- Added `OpenSettingsWindow` in the Go backend to handle spawning and focusing a dedicated settings window via Wails v3 WebviewWindow.
- Modified the application menu (`main.go`) to trigger the new native window instead of emitting an IPC event.
- Extracted the settings modal from `App.tsx` into a new standalone `SettingsWindow.tsx` component.
- Implemented client-side routing in `main.tsx` to serve the settings view on the `/settings` path.
- Updated `App.tsx` to synchronize `watchFolder` and `exportFolder` states via the `settings_saved` Wails event.
- Added a draggable top bar to the settings window for better native UX.
- Improved type safety and Promise error handling based on code review.
@amemya amemya requested a review from Copilot June 10, 2026 13:54

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

リリースノート

  • New Features
    • 設定ウィンドウがメインアプリケーション内のモーダル表示から独立したウィンドウとして開くようになりました。設定の保存後に構成が自動で再読み込みされるようになります。

Walkthrough

Settings ウィンドウを App 内ローカルモーダルから独立 Wails ウィンドウに変更。バックエンド側で OpenSettingsWindow() メソッド追加、フロントエンドに新規 SettingsWindow コンポーネント実装、既存 App から設定モーダルと関連イベント処理削除、イベント駆動で設定変更後の再読み込み追加。

Changes

Settings Window の独立化

Layer / File(s) Summary
バックエンド:Settings Window 起動メソッド
app.go, main.go
Go 側に OpenSettingsWindow() メソッドを追加して既存ウィンドウの検索・再利用または新規作成を管理。メニュー「Preferences...」(macOS / その他)のハンドラを新メソッド呼び出しに統一。
フロントエンド:Settings Window コンポーネント
frontend/src/SettingsWindow.tsx
初期表示時に GetSettings() で watch/export フォルダ読み込み、ユーザーがフォルダ選択・保存操作時に SaveSettings() 実行、settings_saved イベント発行で他ウィンドウに通知。
フロントエンド:Settings Window ルーティング
frontend/src/main.tsx
root.render を /settings パスで分岐させ、Settings ウィンドウ起動時は SettingsWindow、メインウィンドウは App をレンダリング。
フロントエンド:App 設定UI の削除と新ウィンドウ統合
frontend/src/App.tsx
showSettings ローカルモーダル状態と open_settings イベント購読を削除、Settings ボタンを OpenSettingsWindow() 呼び出しに変更、settings_saved イベント購読追加で設定保存後に watch/export フォルダを再読み込み。UI 整形含む。

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • amemya/ExifFrame#11: 同じく frontend/src/App.tsx で設定 UI の表示方法を変更(このPRは App 内モーダルから独立 SettingsWindow に移行、PR #11 は UI/レイアウト全面改修で設定パネル削除)。
  • amemya/ExifFrame#42: 同じく「Preferences…」メニュー動作とそれに紐づく open_settings / showSettings UI 処理を調整(このPRは OpenSettingsWindow() / /settings ルーティングで再実装)。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed プルリクエストのタイトルは、変更の主要な内容である「設定画面を独立したネイティブウィンドウに分離する」ことを正確に反映している。
Description check ✅ Passed プルリクエストの説明は、バックエンド・フロントエンドの複数の変更について関連した詳細な記述があり、変更セットに関連している。
Linked Issues check ✅ Passed プルリクエストは、リンクされたIssue #30の要件(設定画面をウィンドウ内ポップアップから独立したネイティブウィンドウへ変更する)を完全に満たしている。
Out of Scope Changes check ✅ Passed すべての変更は、Issue #30で定義された設定画面をネイティブウィンドウに分離するという要件に直接関連しており、範囲外の変更は見当たらない。

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/separate-settings-window

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 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 `@frontend/src/SettingsWindow.tsx`:
- Around line 37-66: The settings_saved event emitted by handleSave triggers
this component's own settings_saved listener and causes an unnecessary
GetSettings() reload; modify Events.Emit("settings_saved") to include an
identifier (e.g., { source: myWindowId } or { skipSelf: true }) and update the
local listener (the settings_saved handler in this component that calls
GetSettings()) to ignore events coming from the same source (compare
payload.source to a currentWindowId) or payload.skipSelf === true, while leaving
other windows to continue reacting normally; reference handleSave, Events.Emit,
the settings_saved listener, GetSettings, and
setFullSettings/setWatchFolder/setExportFolder when making 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 80010365-e7e0-4f1e-9c1e-80b11481002f

📥 Commits

Reviewing files that changed from the base of the PR and between ac3d8b5 and 3508295.

📒 Files selected for processing (5)
  • app.go
  • frontend/src/App.tsx
  • frontend/src/SettingsWindow.tsx
  • frontend/src/main.tsx
  • main.go

Comment on lines +37 to +66
const handleSave = async (newWatch: string, newExport: string) => {
if (!fullSettings) return;

const s = new Settings();
// Copy existing settings
Object.assign(s, fullSettings);

// Update folders
s.watchFolder = newWatch;
s.exportFolder = newExport;

try {
const errStr = await AppAPI.SaveSettings(s);
if (errStr && errStr !== "") {
console.error(errStr);
alert(errStr);
return;
}

// Update local state
setWatchFolder(newWatch);
setExportFolder(newExport);
setFullSettings(s);

// Notify other windows
Events.Emit("settings_saved");
} catch (e: any) {
console.error("Error saving settings", e);
}
};

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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

保存後に自身のイベントを受信して設定を再読み込みしています。

handleSaveEvents.Emit("settings_saved") を呼び出すと、同じコンポーネント内の settings_saved リスナー(24-30行目)がトリガーされ、保存したばかりの設定を再度 GetSettings() で取得します。

クロスウィンドウ同期のためにリスナーは必要ですが、自身の保存操作による再読み込みは冗長です。パフォーマンスへの影響は軽微ですが、最適化する場合は保存元ウィンドウを識別するフラグをイベントペイロードに含めることを検討してください。

🤖 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/SettingsWindow.tsx` around lines 37 - 66, The settings_saved
event emitted by handleSave triggers this component's own settings_saved
listener and causes an unnecessary GetSettings() reload; modify
Events.Emit("settings_saved") to include an identifier (e.g., { source:
myWindowId } or { skipSelf: true }) and update the local listener (the
settings_saved handler in this component that calls GetSettings()) to ignore
events coming from the same source (compare payload.source to a currentWindowId)
or payload.skipSelf === true, while leaving other windows to continue reacting
normally; reference handleSave, Events.Emit, the settings_saved listener,
GetSettings, and setFullSettings/setWatchFolder/setExportFolder when making the
change.

@amemya amemya merged commit e7ec176 into main Jun 10, 2026
1 check passed
@amemya amemya deleted the feat/separate-settings-window branch June 10, 2026 14:10
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