Skip to content

feat: add configurable floating stats overlay - #138

Merged
debugtheworldbot merged 20 commits into
mainfrom
dev
Aug 23, 2026
Merged

feat: add configurable floating stats overlay#138
debugtheworldbot merged 20 commits into
mainfrom
dev

Conversation

@debugtheworldbot

@debugtheworldbot debugtheworldbot commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • add an always-on-top floating statistics window with configurable layout and font size
  • add settings and quick actions for showing, positioning, and customizing the overlay
  • hide the overlay during fullscreen playback, and add theme-aware materials plus localized strings

Testing

  • not run (PR creation only)
  • design QA notes are included in KeyStats.Windows/design-qa.md

Closes #137

@debugtheworldbot
debugtheworldbot marked this pull request as ready for review August 23, 2026 06:29
Copilot AI lite review requested due to automatic review settings August 23, 2026 06:29

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.

🟡 Changes recommended

The added design QA doc includes absolute local file paths that are not portable and should be replaced with repo-relative or PR-attachment references.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a Windows “floating stats” overlay window (always-on-top) that can be shown from the tray, configured in Settings (metrics/layout/font size/behavior), and automatically hidden while a fullscreen foreground window is detected (e.g., video playback/games). This fits into the Windows UI layer by extending the tray integration (App.xaml.cs), settings UI (SettingsWindow), and StatsManager UI projection APIs.

Changes:

  • Introduces a new FloatingStatsWindow + FloatingStatsViewModel to render two selected live metrics in single-row or double-row layouts.
  • Adds Settings UI controls and new persisted settings fields for overlay behavior (metrics, layout mode, font size, topmost, lock position, last position).
  • Implements fullscreen detection via Win32 APIs and a polling monitor to hide/show the overlay, plus theme resources and localized strings.
File summaries
File Description
KeyStats.Windows/KeyStats/Views/SettingsWindow.xaml.cs Loads/refreshes floating overlay controls and persists user selections (metrics/layout/font/behavior), with analytics events.
KeyStats.Windows/KeyStats/Views/SettingsWindow.xaml Adds a new “Floating Stats” settings card with ComboBoxes and CheckBoxes wired to new handlers.
KeyStats.Windows/KeyStats/Views/FloatingStatsWindow.xaml.cs New overlay window behavior: positioning/clamping, layout/font application, theme/backdrop handling, context menu, and analytics.
KeyStats.Windows/KeyStats/Views/FloatingStatsWindow.xaml New overlay UI markup for single-row and double-row metric display with tooltips and theme brushes.
KeyStats.Windows/KeyStats/ViewModels/FloatingStatsViewModel.cs New VM to project current stats into compact strings, manage metric selection validation, and refresh on stats/settings changes.
KeyStats.Windows/KeyStats/Services/StatsManager.cs Adds a lock-protected CurrentStatsSnapshot API for UI projection; makes FormatScrollDistance public for VM use.
KeyStats.Windows/KeyStats/Properties/Strings.zh-Hant.resx Adds Traditional Chinese strings for tray item, overlay, and settings card.
KeyStats.Windows/KeyStats/Properties/Strings.zh-Hans.resx Adds Simplified Chinese strings for tray item, overlay, and settings card.
KeyStats.Windows/KeyStats/Properties/Strings.resx Adds English strings for tray item, overlay, and settings card.
KeyStats.Windows/KeyStats/Properties/Strings.cs Exposes strongly-typed accessors for the new localized string keys.
KeyStats.Windows/KeyStats/Models/AppSettings.cs Adds persisted settings for enabling/configuring the floating overlay (metrics/layout/font/position/topmost/lock).
KeyStats.Windows/KeyStats/Helpers/ThemeManager.cs Adds theme tokens for FloatingStatsSurfaceColor/Brush in light/dark theme application.
KeyStats.Windows/KeyStats/Helpers/NativeInterop.cs Adds Win32 interop for monitor info + notification state queries to support fullscreen detection.
KeyStats.Windows/KeyStats/Helpers/FullscreenWindowDetector.cs New helper to determine if the foreground window is effectively fullscreen on its monitor.
KeyStats.Windows/KeyStats/App.xaml.cs Integrates tray toggle for overlay, creates/closes the floating window, and polls fullscreen state to hide/show.
KeyStats.Windows/KeyStats/App.xaml Adds default app resources for FloatingStatsSurfaceColor/Brush.
KeyStats.Windows/design-qa.md Adds design QA notes for the floating overlay visuals and sizing.
Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread KeyStats.Windows/design-qa.md Outdated
Comment on lines +3 to +6
- Source feedback capture: `C:\Users\t\AppData\Local\Temp\codex-clipboard-67a8ee63-df85-4c65-ab56-4e22ddc7dab7.png`
- Single-row implementation: `C:\Users\t\.codex\visualizations\2026\08\23\01a02c9c-fa5e-7dc3-af63-d32cab43e2a6\floating-stats-single-row-tight.png`
- Double-row implementation: `C:\Users\t\.codex\visualizations\2026\08\23\01a02c9c-fa5e-7dc3-af63-d32cab43e2a6\floating-stats-double-row.png`
- Combined comparison: `C:\Users\t\.codex\visualizations\2026\08\23\01a02c9c-fa5e-7dc3-af63-d32cab43e2a6\floating-stats-layout-comparison.png`

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42b49d605b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

</Grid>
</Border>

<Border Style="{DynamicResource CardBorder}" Margin="0,0,0,8" Padding="14,12">

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.

P1 Badge Make the enlarged settings window scrollable

Adding this approximately 200-DIP settings card to a window that uses SizeToContent="Height", ResizeMode="NoResize", and a root StackPanel without scrolling makes the window taller than the working area on common low-height or scaled displays (for example, 768px at 125% scaling). The lower calibration, language, and version controls then extend off-screen with no way to reach them; constrain the window height and place its contents in a ScrollViewer.

Useful? React with 👍 / 👎.

Comment on lines +344 to +345
var topLeft = fromDevice.Transform(new Point(screen.WorkingArea.Left, screen.WorkingArea.Top));
var bottomRight = fromDevice.Transform(new Point(screen.WorkingArea.Right, screen.WorkingArea.Bottom));

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.

P2 Badge Convert each monitor using its own DPI

On mixed-DPI multi-monitor systems, TransformFromDevice belongs to the monitor currently hosting this window, but it is applied here to the pixel coordinates of every Screen. A secondary monitor with a different scale therefore gets incorrect DIP bounds, causing restore and drag clamping to select the wrong area or move the overlay away from its saved position. Obtain the scale for each monitor—or use monitor-aware coordinate conversion—when constructing these working areas.

Useful? React with 👍 / 👎.

Comment thread KeyStats.Windows/design-qa.md Outdated
Comment on lines +7 to +8
- Viewports: single row 104 × 36 DIPs; double row 72 × 52 DIPs; both rendered at 96 DPI / 1× density
- Pixel dimensions: feedback capture 365 × 103; single-row implementation 104 × 36; double-row implementation 72 × 52; comparison canvas 790 × 150

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.

P2 Badge Correct the QA evidence to use the shipped dimensions

The QA report says the tested production layouts are 104×36 and 72×52 DIPs, but the committed window uses 72×28 for single-row and 32×38 for double-row. Consequently the referenced captures and the later claim that the exact production XAML was inspected do not validate the UI actually shipped by this commit, especially its much tighter clipping behavior. Regenerate the evidence from the committed dimensions or update the implementation to match the tested layouts.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: daa943592b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +24 to +28
return new Rect(
workingArea.Left / scaleFactor,
workingArea.Top / scaleFactor,
workingArea.Width / scaleFactor,
workingArea.Height / scaleFactor);

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.

P2 Badge Preserve virtual-desktop origins during DPI conversion

On mixed-DPI layouts, dividing the absolute virtual-desktop coordinates by each monitor's scale maps every monitor into a different coordinate space. For example, a 200%-scaled display beginning at physical X=1920 is reported here as starting at 960 DIPs, overlapping a 100%-scaled primary display spanning 0–1920 DIPs; restore, intersection selection, and clamping can consequently move the overlay to the wrong screen. Fresh evidence beyond the earlier review is that the replacement per-monitor helper now applies this division directly to the absolute WorkingArea origin rather than converting monitor-local dimensions while preserving a common virtual-desktop origin.

Useful? React with 👍 / 👎.

Comment on lines +171 to +180
settings.FloatingStatsPrimaryMetric = metricId;
}
else
{
if (string.Equals(settings.FloatingStatsSecondaryMetric, metricId, StringComparison.Ordinal))
{
return false;
}

settings.FloatingStatsSecondaryMetric = metricId;

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.

P1 Badge Mutate floating settings under StatsManager's lock

The new setters mutate the shared Settings object directly on the Dispatcher while SaveSettings() can concurrently serialize that same object from its System.Timers.Timer callback. If a flush overlaps metric, behavior, or position changes, settings.json can contain properties observed from different UI states—for example, a duplicate primary/secondary metric combination—despite the in-memory transitions being valid. Route these mutations through lock-protected StatsManager APIs and serialize a snapshot under the same lock.

AGENTS.md reference: KeyStats.Windows/AGENTS.md:L64-L68

Useful? React with 👍 / 👎.

Comment on lines +325 to +327
_floatingStatsWindow = new FloatingStatsWindow();
_floatingStatsWindow.Closed += (_, _) => _floatingStatsWindow = null;
_floatingStatsWindow.ShowWindow();

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.

P2 Badge Reconcile independent overlay closes with enabled state

When the overlay is closed independently—for example, with Alt+F4 after interacting with this focusable borderless window—the handler only clears _floatingStatsWindow; FloatingStatsEnabled remains true and the tray item remains checked. The visibility timer also never recreates it because its non-fullscreen path returns while _isFloatingStatsHiddenForFullscreen is false, leaving the feature apparently enabled but absent until the user toggles it off and on.

Useful? React with 👍 / 👎.

Comment on lines +396 to +397
var shouldHideForFullscreen = FullscreenWindowDetector.IsForegroundWindowFullscreen();
if (shouldHideForFullscreen)

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.

P2 Badge Scope fullscreen hiding to the overlay's monitor

On multi-monitor systems this global boolean hides the overlay whenever the foreground window covers any monitor, without checking which monitor contains the overlay. A fullscreen video on monitor B therefore hides an overlay positioned on monitor A even though they do not overlap; conversely, focusing a normal window on A makes the detector return false and can re-show a topmost overlay over fullscreen playback that remains on B. Return the fullscreen monitor identity and compare it with the overlay's monitor before changing visibility.

Useful? React with 👍 / 👎.

Comment on lines +289 to +290
settings.FloatingStatsTopmost = FloatingTopmostCheckBox.IsChecked == true;
settings.FloatingStatsPositionLocked = FloatingLockPositionCheckBox.IsChecked == true;

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.

P2 Badge Avoid overwriting lock state from a stale checkbox

If Settings is already open and the user changes position locking from the overlay's context menu, FloatingLockPositionCheckBox is not refreshed. Changing the unrelated Always on Top checkbox afterward enters this handler and writes both properties, so the stale checkbox value silently reverses the context-menu lock change. Update only the property represented by sender, or synchronize the Settings controls when the context-menu action changes shared state.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a29bdee3d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Width="35"
Height="41"
WindowStyle="None"
AllowsTransparency="True"

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.

P2 Badge Use the shared backdrop for the floating window

On Windows 11, AllowsTransparency="True" makes this a layered WPF window, while ApplySurface() only applies a translucent solid brush and never calls WindowBackdropHelper. The overlay therefore lacks the TransientWindow DWM backdrop used by the tray popup and appears as flat alpha compositing rather than the intended Acrylic-like material; use the shared backdrop path with transparency disabled.

AGENTS.md reference: KeyStats.Windows/AGENTS.md:L184-L186

Useful? React with 👍 / 👎.

AllowsTransparency="True"
Background="Transparent"
ShowInTaskbar="False"
ShowActivated="False"

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.

P2 Badge Prevent overlay clicks from stealing application focus

ShowActivated="False" only prevents activation when the window is initially shown; this otherwise focusable window is still activated when the user clicks its drag surface, context menu, or double-click action. Consequently, repositioning or interacting with the always-visible overlay takes keyboard focus away from the application the user was working in, and subsequent typing is routed to KeyStats until that application is selected again. Apply no-activate window behavior while retaining the required mouse interactions.

Useful? React with 👍 / 👎.

@debugtheworldbot
debugtheworldbot merged commit cb56bc1 into main Aug 23, 2026
1 check passed
@debugtheworldbot
debugtheworldbot deleted the dev branch August 23, 2026 12:24
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.

window版本能加这种流量小控件吗?

2 participants