From adc520cfe420fa74b264602de2598c05cc188601 Mon Sep 17 00:00:00 2001
From: EdnLove <138235519+EdnLove@users.noreply.github.com>
Date: Sat, 11 Jul 2026 18:30:50 +0800
Subject: [PATCH 1/4] Fix responsive window layout and controls
---
FluentCleaner/App.xaml.cs | 236 ++++++++++++++++++++++----------------
1 file changed, 134 insertions(+), 102 deletions(-)
diff --git a/FluentCleaner/App.xaml.cs b/FluentCleaner/App.xaml.cs
index 5f3122a..f1666fb 100644
--- a/FluentCleaner/App.xaml.cs
+++ b/FluentCleaner/App.xaml.cs
@@ -1,117 +1,149 @@
-using FluentCleaner.Services;
-using Microsoft.UI;
-using Microsoft.UI.Windowing;
-using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Media;
-using Windows.Graphics;
-
-namespace FluentCleaner;
-
-public partial class App : Application
-{
- public MainWindow? MainWindow { get; private set; }
-
- public App()
- {
- InitializeComponent();
- }
-
- //Entry point;load settings, build the window, wire everything up.
- protected override void OnLaunched(LaunchActivatedEventArgs args)
- {
-
- AppSettings.Reload();
-
- // SilentRunner headless clean, no window; /SHUTDOWN shuts down after
- var cmdArgs = Environment.GetCommandLineArgs();
- bool isAuto = cmdArgs.Any(a => a.Equals("/AUTO", StringComparison.OrdinalIgnoreCase));
- bool isShutdown = cmdArgs.Any(a => a.Equals("/SHUTDOWN", StringComparison.OrdinalIgnoreCase));
-
- if (isAuto)
- {
- _ = SilentRunner.RunAsync(isShutdown);
- return;
- }
-
- MainWindow = new MainWindow();
- SetupTitleBar();
- RestoreWindowSize();
- ApplyBackdrop(AppSettings.Instance.Backdrop);
- ApplyTheme(AppSettings.Instance.Theme);
- MainWindow.Activate();
-
- //Remember size for next launch
+using FluentCleaner.Services;
+using Microsoft.UI;
+using Microsoft.UI.Windowing;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Media;
+using Windows.Graphics;
+
+namespace FluentCleaner;
+
+public partial class App : Application
+{
+ public MainWindow? MainWindow { get; private set; }
+
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ //Entry point;load settings, build the window, wire everything up.
+ protected override void OnLaunched(LaunchActivatedEventArgs args)
+ {
+
+ AppSettings.Reload();
+
+ // SilentRunner headless clean, no window; /SHUTDOWN shuts down after
+ var cmdArgs = Environment.GetCommandLineArgs();
+ bool isAuto = cmdArgs.Any(a => a.Equals("/AUTO", StringComparison.OrdinalIgnoreCase));
+ bool isShutdown = cmdArgs.Any(a => a.Equals("/SHUTDOWN", StringComparison.OrdinalIgnoreCase));
+
+ if (isAuto)
+ {
+ _ = SilentRunner.RunAsync(isShutdown);
+ return;
+ }
+
+ MainWindow = new MainWindow();
+ SetupTitleBar();
+ RestoreWindowSize();
+ ApplyBackdrop(AppSettings.Instance.Backdrop);
+ ApplyTheme(AppSettings.Instance.Theme);
+ MainWindow.Activate();
+
+ //Remember size for next launch
MainWindow.Closed += (_, _) =>
{
+ // Do not persist the maximized work-area size as a normal window
+ // size; restoring it on a different DPI/display can crop content.
+ if (MainWindow.AppWindow.Presenter is OverlappedPresenter presenter &&
+ presenter.State == OverlappedPresenterState.Maximized)
+ return;
+
var size = MainWindow.AppWindow.Size;
AppSettings.Instance.WindowWidth = size.Width;
AppSettings.Instance.WindowHeight = size.Height;
- AppSettings.Instance.Save();
- };
- }
- // idea from John Gage Faulkner's WinUI3SampleStarterApp
- // https://github.com/johngagefaulkner/WinUI3SampleStarterApp
- // remove idle background only;so it lets TitleBar blend with Mica
- // don't touch hover/pressed, PreferredTheme handles it
- // overriding all states breaks hover (learned that the hard way)
- private void SetupTitleBar()
- {
- if (AppWindowTitleBar.IsCustomizationSupported())
- {
- var bar = MainWindow!.AppWindow.TitleBar;
- bar.ButtonBackgroundColor = Colors.Transparent;
- bar.ButtonInactiveBackgroundColor = Colors.Transparent;
- }
- }
-
- //Picks up the saved size from settings, falls back to 960x620 on first run
+ AppSettings.Instance.Save();
+ };
+ }
+ // idea from John Gage Faulkner's WinUI3SampleStarterApp
+ // https://github.com/johngagefaulkner/WinUI3SampleStarterApp
+ // remove idle background only;so it lets TitleBar blend with Mica
+ // don't touch hover/pressed, PreferredTheme handles it
+ // overriding all states breaks hover (learned that the hard way)
+ private void SetupTitleBar()
+ {
+ if (AppWindowTitleBar.IsCustomizationSupported())
+ {
+ var bar = MainWindow!.AppWindow.TitleBar;
+ bar.ButtonBackgroundColor = Colors.Transparent;
+ bar.ButtonInactiveBackgroundColor = Colors.Transparent;
+ }
+ }
+
+ //Picks up the saved size from settings, falls back to 960x620 on first run
private void RestoreWindowSize()
{
- var w = AppSettings.Instance.WindowWidth;
- var h = AppSettings.Instance.WindowHeight;
- MainWindow!.AppWindow.Resize(new SizeInt32(w, h));
-
- if (DisplayArea.GetFromWindowId(MainWindow.AppWindow.Id, DisplayAreaFallback.Primary) is { } display)
+ if (DisplayArea.GetFromWindowId(MainWindow!.AppWindow.Id, DisplayAreaFallback.Primary) is { } display)
{
var area = display.WorkArea;
+
+ // AppWindow sizes are restored from the previous session, but the
+ // saved size may belong to a different monitor or DPI scale. Clamp
+ // it to the current work area so the bottom/right edge never lands
+ // outside the visible screen.
+ const int minWidth = 760;
+ const int minHeight = 520;
+ var maxWidth = Math.Max(minWidth, area.Width - 32);
+ var maxHeight = Math.Max(minHeight, area.Height - 48);
+ var savedWidth = AppSettings.Instance.WindowWidth;
+ var savedHeight = AppSettings.Instance.WindowHeight;
+
+ // A previous build could persist a maximized/near-maximized size.
+ // Treat that as stale and start with the intended compact default.
+ if (savedWidth >= area.Width - 64 && savedHeight >= area.Height - 80)
+ {
+ savedWidth = 960;
+ savedHeight = 620;
+ }
+
+ var w = Math.Clamp(savedWidth, minWidth, maxWidth);
+ var h = Math.Clamp(savedHeight, minHeight, maxHeight);
+
+ MainWindow.AppWindow.Resize(new SizeInt32(w, h));
MainWindow.AppWindow.Move(new PointInt32(
area.X + (area.Width - w) / 2,
area.Y + (area.Height - h) / 2));
- }
- }
-
- // Switches light/dark/system
- public void ApplyTheme(string? theme)
- {
- var elementTheme = theme switch
- {
- "Light" => ElementTheme.Light,
- "Dark" => ElementTheme.Dark,
- _ => ElementTheme.Default
- };
- if (MainWindow?.Content is FrameworkElement root)
- root.RequestedTheme = elementTheme;
-
- if (MainWindow is not { } win) return;
-
- win.AppWindow.TitleBar.PreferredTheme = elementTheme switch
- {
- ElementTheme.Light => TitleBarTheme.Light,
- ElementTheme.Dark => TitleBarTheme.Dark,
- _ => TitleBarTheme.UseDefaultAppMode
- };
- }
-
- // Mica by default, acrylic if the user set it via terminal. No Settings UI for this on purpose
- public void ApplyBackdrop(string? backdrop)
- {
- if (MainWindow is null) return;
+ return;
+ }
- MainWindow.SystemBackdrop = backdrop?.ToLowerInvariant() switch
- {
- "acrylic" => new DesktopAcrylicBackdrop(),
- _ => new MicaBackdrop()
- };
+ MainWindow.AppWindow.Resize(new SizeInt32(
+ Math.Max(760, AppSettings.Instance.WindowWidth),
+ Math.Max(520, AppSettings.Instance.WindowHeight)));
}
-}
+
+ // Switches light/dark/system
+ public void ApplyTheme(string? theme)
+ {
+ var elementTheme = theme switch
+ {
+ "Light" => ElementTheme.Light,
+ "Dark" => ElementTheme.Dark,
+ _ => ElementTheme.Default
+ };
+
+ if (MainWindow?.Content is FrameworkElement root)
+ root.RequestedTheme = elementTheme;
+
+ if (MainWindow is not { } win) return;
+
+ win.AppWindow.TitleBar.PreferredTheme = elementTheme switch
+ {
+ ElementTheme.Light => TitleBarTheme.Light,
+ ElementTheme.Dark => TitleBarTheme.Dark,
+ _ => TitleBarTheme.UseDefaultAppMode
+ };
+ }
+
+ // Mica by default, acrylic if the user set it via terminal. No Settings UI for this on purpose
+ public void ApplyBackdrop(string? backdrop)
+ {
+ if (MainWindow is null) return;
+
+ MainWindow.SystemBackdrop = backdrop?.ToLowerInvariant() switch
+ {
+ "acrylic" => new DesktopAcrylicBackdrop(),
+ _ => new MicaBackdrop()
+ };
+ }
+}
From ef5cb9b9e5d67cf5f92ad61355bec6768846f2d1 Mon Sep 17 00:00:00 2001
From: EdnLove <138235519+EdnLove@users.noreply.github.com>
Date: Sat, 11 Jul 2026 18:30:53 +0800
Subject: [PATCH 2/4] Fix responsive window layout and controls
---
FluentCleaner/MainWindow.xaml | 276 +++++++++++++++++-----------------
1 file changed, 140 insertions(+), 136 deletions(-)
diff --git a/FluentCleaner/MainWindow.xaml b/FluentCleaner/MainWindow.xaml
index ecb5011..86d3c44 100644
--- a/FluentCleaner/MainWindow.xaml
+++ b/FluentCleaner/MainWindow.xaml
@@ -1,140 +1,144 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ IsBackButtonVisible="Collapsed"
+ IsPaneToggleButtonVisible="False"
+ CompactPaneLength="48"
+ OpenPaneLength="240"
+ SelectionChanged="NavView_SelectionChanged">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 7c3b24f1fd48497b8ecbf020aaea9f8c3d1c1911 Mon Sep 17 00:00:00 2001
From: EdnLove <138235519+EdnLove@users.noreply.github.com>
Date: Sat, 11 Jul 2026 18:30:57 +0800
Subject: [PATCH 3/4] Fix responsive window layout and controls
---
FluentCleaner/Views/CleanerPage.xaml | 844 ++++++++++++++-------------
1 file changed, 426 insertions(+), 418 deletions(-)
diff --git a/FluentCleaner/Views/CleanerPage.xaml b/FluentCleaner/Views/CleanerPage.xaml
index 4d71537..ba694b5 100644
--- a/FluentCleaner/Views/CleanerPage.xaml
+++ b/FluentCleaner/Views/CleanerPage.xaml
@@ -1,436 +1,444 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Visibility="{x:Bind ViewModel.IsNotEmpty, Mode=OneWay,
+ Converter={StaticResource BoolToVisibilityConverter}}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ MinHeight="0"
+ ItemsSource="{x:Bind ViewModel.ResultLines, Mode=OneWay}"
+ SelectionMode="None"
+ IsItemClickEnabled="True"
+ ItemClick="ResultsListView_ItemClick"
+ Padding="0,2"
+ Visibility="{x:Bind ViewModel.IsShowingList, Mode=OneWay,
+ Converter={StaticResource BoolToVisibilityConverter}}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ MinHeight="0"
+ SelectionMode="None"
+ IsItemClickEnabled="True"
+ ItemClick="DetailList_ItemClick"
+ Padding="0,2"
+ Visibility="{x:Bind ViewModel.IsShowingDetail, Mode=OneWay,
+ Converter={StaticResource BoolToVisibilityConverter}}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ MinHeight="40"
+ Padding="18,8" />
+
+
+
+
From 53d8102b1c22bd269b144b44565dda5e21683fdb Mon Sep 17 00:00:00 2001
From: EdnLove <138235519+EdnLove@users.noreply.github.com>
Date: Sat, 11 Jul 2026 18:31:37 +0800
Subject: [PATCH 4/4] Add missing tools model definitions
---
FluentCleaner/Tools/ToolsDefinition.cs | 56 ++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 FluentCleaner/Tools/ToolsDefinition.cs
diff --git a/FluentCleaner/Tools/ToolsDefinition.cs b/FluentCleaner/Tools/ToolsDefinition.cs
new file mode 100644
index 0000000..a2cde73
--- /dev/null
+++ b/FluentCleaner/Tools/ToolsDefinition.cs
@@ -0,0 +1,56 @@
+namespace FluentCleaner.Tools;
+
+public enum ToolsCategory
+{
+ All,
+ System,
+ Privacy,
+ Network,
+ Apps,
+ Debloat
+}
+
+public sealed class ScriptMeta
+{
+ public string Description { get; init; } = "No description available.";
+ public List Options { get; init; } = [];
+ public ToolsCategory Category { get; init; } = ToolsCategory.All;
+ public bool UseConsole { get; init; }
+ public bool UseLog { get; init; }
+ public bool SupportsInput { get; init; }
+ public string InputPlaceholder { get; init; } = "";
+ public string PoweredByText { get; init; } = "";
+ public string PoweredByUrl { get; init; } = "";
+}
+
+public sealed class ToolsDefinition
+{
+ public ToolsDefinition(string title, string icon, string scriptPath, ScriptMeta meta)
+ {
+ Title = title;
+ Icon = icon;
+ ScriptPath = scriptPath;
+ Description = meta.Description;
+ Options = meta.Options;
+ Category = meta.Category;
+ UseConsole = meta.UseConsole;
+ UseLog = meta.UseLog;
+ SupportsInput = meta.SupportsInput;
+ InputPlaceholder = meta.InputPlaceholder;
+ PoweredByText = meta.PoweredByText;
+ PoweredByUrl = meta.PoweredByUrl;
+ }
+
+ public string Title { get; }
+ public string Icon { get; }
+ public string ScriptPath { get; }
+ public string Description { get; }
+ public IReadOnlyList Options { get; }
+ public ToolsCategory Category { get; }
+ public bool UseConsole { get; }
+ public bool UseLog { get; }
+ public bool SupportsInput { get; }
+ public string InputPlaceholder { get; }
+ public string PoweredByText { get; }
+ public string PoweredByUrl { get; }
+}