diff --git a/ScreenSound/Assets/kofi-button.png b/ScreenSound/Assets/kofi-button.png
new file mode 100644
index 0000000..8926e9e
Binary files /dev/null and b/ScreenSound/Assets/kofi-button.png differ
diff --git a/ScreenSound/ScreenSound.csproj b/ScreenSound/ScreenSound.csproj
index 90f1364..bd3bee2 100644
--- a/ScreenSound/ScreenSound.csproj
+++ b/ScreenSound/ScreenSound.csproj
@@ -52,6 +52,14 @@
-->
+
+
diff --git a/ScreenSound/Views/MainWindow.xaml b/ScreenSound/Views/MainWindow.xaml
index 4e8cbfe..717434c 100644
--- a/ScreenSound/Views/MainWindow.xaml
+++ b/ScreenSound/Views/MainWindow.xaml
@@ -89,6 +89,12 @@
+
@@ -100,6 +106,17 @@
+
+
+
+
+
+
+
@@ -598,6 +615,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScreenSound is a solo developer project built in spare time. If it's
+ made your multi-monitor setup a little nicer, a one-off tip helps
+ justify the hours spent on bug fixes and new features — the app
+ stays free either way.
+
+
+
+
+
+
+
+
+
+
diff --git a/ScreenSound/Views/MainWindow.xaml.cs b/ScreenSound/Views/MainWindow.xaml.cs
index b6e81a3..b277d84 100644
--- a/ScreenSound/Views/MainWindow.xaml.cs
+++ b/ScreenSound/Views/MainWindow.xaml.cs
@@ -31,8 +31,8 @@ public MainWindow()
DataContext = _viewModel;
// Order must match the Tag indices on the sidebar RadioButtons:
- // 0 = Home, 1 = Pinned, 2 = Settings, 3 = About.
- _pages = new[] { HomePage, PinnedPage, SettingsPage, AboutPage };
+ // 0 = Home, 1 = Pinned, 2 = Settings, 3 = About, 4 = Donate.
+ _pages = new[] { HomePage, PinnedPage, SettingsPage, AboutPage, DonatePage };
SetupTrayIcon();
@@ -363,6 +363,40 @@ private void RemovePinFromList_Click(object sender, RoutedEventArgs e)
}
}
+ // ── Donate page ───────────────────────────────────────────────────────
+
+ ///
+ /// Opens the Ko-fi donation page in the user's default browser. The
+ /// Donate tab's button is a bare image-button (no wpfui:Hyperlink)
+ /// so the ko-fi-yellow branded PNG renders pixel-perfect without any
+ /// Hyperlink chrome repainting over it — the trade-off is that URL
+ /// launching has to be wired here rather than inherited from NavigateUri.
+ ///
+ /// UseShellExecute=true is required for opening https:// URLs in
+ /// .NET 8 — without it
+ /// treats the URL as an executable path and throws Win32Exception. Any
+ /// failure (no default browser, shell error) is swallowed: the button
+ /// click is a best-effort nice-to-have, not something to crash the UI
+ /// over.
+ ///
+ private void KofiDonate_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = "https://ko-fi.com/twibster",
+ UseShellExecute = true,
+ });
+ }
+ catch
+ {
+ // Intentionally swallowed — a failed browser launch shouldn't
+ // crash the app or even surface an error dialog. The ToolTip
+ // already shows the URL so the user can copy/paste if needed.
+ }
+ }
+
protected override void OnClosing(CancelEventArgs e)
{
if (!_forceClose && _viewModel.MinimizeOnClose)