From 68451dafb5ef986acc1a8ca4c58e6394664776b4 Mon Sep 17 00:00:00 2001 From: KnifeLemon Date: Sun, 18 Oct 2026 16:18:34 +0900 Subject: [PATCH] Closing the window can quit Filee: asked once, or set in Settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the main window used to always keep Filee in the tray. Now the first close asks "Keep in tray / Quit" with "Don't ask again", and Settings → General has "When I close the window": ask every time, keep running in the tray, or quit. A value from a newer Filee reads as Ask. Close() from code still only hides the window. Closes #111. Co-Authored-By: Claude Opus 5.5 --- src/Filee.App/Assets/i18n/en.json | 9 ++ src/Filee.App/Assets/i18n/ko.json | 9 ++ src/Filee.App/Assets/i18n/zh-CN.json | 9 ++ .../ViewModels/Pages/GeneralPageViewModel.cs | 25 ++- src/Filee.App/Views/CloseAskWindow.axaml | 27 ++++ src/Filee.App/Views/CloseAskWindow.axaml.cs | 28 ++++ src/Filee.App/Views/MainWindow.axaml.cs | 67 +++++++- src/Filee.App/Views/Pages/GeneralPage.axaml | 4 + src/Filee.Core/Settings/AppSettings.cs | 18 +++ tests/Filee.App.Tests/CloseActionTests.cs | 148 ++++++++++++++++++ tests/Filee.App.Tests/RenderTests.cs | 14 ++ tests/Filee.Core.Tests/UserDataStoreTests.cs | 24 +++ 12 files changed, 377 insertions(+), 5 deletions(-) create mode 100644 src/Filee.App/Views/CloseAskWindow.axaml create mode 100644 src/Filee.App/Views/CloseAskWindow.axaml.cs create mode 100644 tests/Filee.App.Tests/CloseActionTests.cs diff --git a/src/Filee.App/Assets/i18n/en.json b/src/Filee.App/Assets/i18n/en.json index df514816..5881a259 100644 --- a/src/Filee.App/Assets/i18n/en.json +++ b/src/Filee.App/Assets/i18n/en.json @@ -18,6 +18,11 @@ "tray.quit": "Quit", "tray.update": "Update to {0}", "tray.tooltip": "Filee: hold {0} and drag files", + "close.title": "Keep Filee running?", + "close.text": "In the tray, the donut toolbar and watch folders keep working.\nYou can change this later in Settings → General.", + "close.tray": "Keep in tray", + "close.quit": "Quit", + "close.dont_ask": "Don't ask again", "home.title": "Home", "home.drop_title": "Drop files here", @@ -178,6 +183,10 @@ "general.keep_dates": "Keep the original file dates for every conversion", "general.keep_dates_hint": "Converted files keep the original's created and modified dates, with every preset.\nOff: only presets with \"Keep the original file dates\" do it.", "general.check_updates": "Check for updates automatically", + "general.close_action": "When I close the window", + "general.close.Ask": "Ask every time", + "general.close.Tray": "Keep Filee running in the tray", + "general.close.Quit": "Quit Filee", "general.history": "Conversion history", "general.no_history": "Don't keep a history of recent conversions", "general.clear_history": "Clear history", diff --git a/src/Filee.App/Assets/i18n/ko.json b/src/Filee.App/Assets/i18n/ko.json index 911d0f3b..9d529c14 100644 --- a/src/Filee.App/Assets/i18n/ko.json +++ b/src/Filee.App/Assets/i18n/ko.json @@ -18,6 +18,11 @@ "tray.quit": "종료", "tray.update": "{0} 버전으로 업데이트", "tray.tooltip": "Filee: {0} 누른 채 파일 드래그", + "close.title": "Filee를 계속 실행할까요?", + "close.text": "트레이에 두면 원형 툴바와 자동 변환 폴더가 계속 동작해요.\n나중에 설정 → 일반에서 바꿀 수 있어요.", + "close.tray": "트레이에 유지", + "close.quit": "종료", + "close.dont_ask": "다시 묻지 않기", "home.title": "홈", "home.drop_title": "여기에 파일을 놓으세요", @@ -178,6 +183,10 @@ "general.keep_dates": "모든 변환에서 원본 파일 날짜 유지", "general.keep_dates_hint": "어떤 프리셋이든 원본의 만든 날짜·수정한 날짜를 그대로 써요.\n끄면 \"원본 파일 날짜 유지\"를 켠 프리셋만 그렇게 해요.", "general.check_updates": "자동으로 업데이트 확인", + "general.close_action": "창을 닫을 때", + "general.close.Ask": "매번 묻기", + "general.close.Tray": "트레이에서 계속 실행", + "general.close.Quit": "Filee 종료", "general.history": "변환 기록", "general.no_history": "최근 변환 기록 남기지 않기", "general.clear_history": "기록 지우기", diff --git a/src/Filee.App/Assets/i18n/zh-CN.json b/src/Filee.App/Assets/i18n/zh-CN.json index d6f4f5b8..1a9ce163 100644 --- a/src/Filee.App/Assets/i18n/zh-CN.json +++ b/src/Filee.App/Assets/i18n/zh-CN.json @@ -18,6 +18,11 @@ "tray.quit": "退出", "tray.update": "更新到 {0}", "tray.tooltip": "Filee:按住 {0} 拖动文件", + "close.title": "让 Filee 继续运行吗?", + "close.text": "保留在托盘中时,环形工具栏和自动转换文件夹会继续工作。\n之后可以在 设置 → 常规 中更改。", + "close.tray": "保留在托盘", + "close.quit": "退出", + "close.dont_ask": "不再询问", "home.title": "首页", "home.drop_title": "将文件拖放到这里", @@ -178,6 +183,10 @@ "general.keep_dates": "所有转换都保留原文件日期", "general.keep_dates_hint": "无论使用哪个预设,转换后的文件都沿用原文件的创建和修改日期。\n关闭后,只有打开“保留原文件日期”的预设会这样做。", "general.check_updates": "自动检查更新", + "general.close_action": "关闭窗口时", + "general.close.Ask": "每次询问", + "general.close.Tray": "在托盘中继续运行", + "general.close.Quit": "退出 Filee", "general.history": "转换记录", "general.no_history": "不保留最近的转换记录", "general.clear_history": "清除记录", diff --git a/src/Filee.App/ViewModels/Pages/GeneralPageViewModel.cs b/src/Filee.App/ViewModels/Pages/GeneralPageViewModel.cs index cd03b1fe..55fc8d73 100644 --- a/src/Filee.App/ViewModels/Pages/GeneralPageViewModel.cs +++ b/src/Filee.App/ViewModels/Pages/GeneralPageViewModel.cs @@ -10,7 +10,7 @@ namespace Filee.App.ViewModels.Pages; -public sealed partial class GeneralPageViewModel : ObservableObject +public sealed partial class GeneralPageViewModel : ObservableObject, IDisposable { private readonly UserDataStore _store; private readonly ILocalizer _loc; @@ -40,6 +40,9 @@ public GeneralPageViewModel(UserDataStore store, ILocalizer loc, IPlatformServic _defaultSubfolder = output.SubfolderName; _defaultFolder = output.CustomFolder; _keepFileDates = store.Settings.KeepFileDates; + CloseChoices = Enum.GetValues().Select(v => new Choice(v, loc[$"general.close.{v}"])).ToList(); + _closeChoice = CloseChoices.First(c => c.Value == store.Settings.CloseAction); + store.SettingsChanged += OnSettingsChanged; _historyCount = store.History.Count; RefreshModernMenu(); } @@ -74,6 +77,26 @@ partial void OnDefaultSubfolderChanged(string value) => [ObservableProperty] private bool _keepFileDates; + /// What closing the main window does; its "Don't ask again" also sets it. + public IReadOnlyList> CloseChoices { get; } + + [ObservableProperty] private Choice _closeChoice; + + partial void OnCloseChoiceChanged(Choice value) + { + if (_store.Settings.CloseAction != value.Value) + Save(s => s.CloseAction = value.Value); + } + + // The close dialog may answer "Don't ask again" while this page stays open behind the hidden window. + private void OnSettingsChanged(object? sender, EventArgs e) + { + if (CloseChoice.Value != _store.Settings.CloseAction) + CloseChoice = CloseChoices.First(c => c.Value == _store.Settings.CloseAction); + } + + public void Dispose() => _store.SettingsChanged -= OnSettingsChanged; + partial void OnKeepFileDatesChanged(bool value) => Save(s => s.KeepFileDates = value); [ObservableProperty] private Choice _language; diff --git a/src/Filee.App/Views/CloseAskWindow.axaml b/src/Filee.App/Views/CloseAskWindow.axaml new file mode 100644 index 00000000..2f84eabb --- /dev/null +++ b/src/Filee.App/Views/CloseAskWindow.axaml @@ -0,0 +1,27 @@ + + + + + + + + + +