Skip to content

feat: taskbar media controls, startup performance, and UI polish#56

Merged
hoobio merged 28 commits into
mainfrom
perf/startup-improvements
Jun 6, 2026
Merged

feat: taskbar media controls, startup performance, and UI polish#56
hoobio merged 28 commits into
mainfrom
perf/startup-improvements

Conversation

@hoobio

@hoobio hoobio commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Summary

A batch of startup-performance work and UI polish across the home, now-playing, quick-controls, and taskbar surfaces. No rule-engine or schema changes.

Changes

  • Faster startup, data relocated to %APPDATA%, lighter Mica
  • Taskbar thumbnail media controls, playback badge, and auto-hide after 30s paused
  • WinUI TitleBar control with working back navigation; collapsible nav pane
  • Theme-aware card surfaces, unified dividers, Mica uniformity, tighter margins
  • Per-device display overrides; device card menu on right-click
  • Now-playing polish: artwork cross-fade, leniency grace window, band layout, title/artist cleanup ('- Topic', redundant prefix, Official tags)
  • Quick-controls polish: slide-in animation, scrollbar gutter, smooth scroll, click-away/Escape dismiss, black-flash mask on open
  • Session icons resolved via IconPath fallback; faint audio keeps app chips lit
  • Dropped Win2D: taskbar icons now render via System.Drawing
  • Stopped persisting/restoring window size

Testing

  • Manual testing on a Windows 11 host
  • Existing tests pass (dotnet test -p:Platform=x64)

Checklist

  • PR title follows Conventional Commits
  • Code builds without warnings
  • No emoji / gitmoji in commit messages or PR title
  • Architecture boundary respected

feat: add per-device display overrides

feat: hide taskbar playback indicator after 30s paused

feat: resolve session icons from the IconPath fallback

feat: add taskbar thumbnail media controls and playback badge

feat: adopt WinUI TitleBar control with working back navigation

feat: refresh rule summaries during in-place session reconcile

feat: collapse nav pane on backdrop tap

feat: theme-aware card surfaces, Mica uniformity, and tighter page margins

feat: slide-in animation for quick controls windows

feat: now-playing leniency grace window and artwork cross-fade

feat: strip '- Topic' suffix from now playing artist

feat: strip redundant artist prefix from now playing titles

perf!: snappier startup, relocate data to %APPDATA%, lighter Mica

fix: strip Official tags from now-playing title and artist

fix: show device card menu on right-click, not backdrop menu

fix: refine now-playing band layout in strip and fill modes

fix: lower audible threshold so faint audio keeps app chips lit

fix: animate page transitions on every nav, not just first load

fix: keep card at row height as a floor when rules expand

fix: mask black flash on quick controls open with backdrop-matched reveal cover

fix: quick controls scrollbar gutter, disconnected dimming, scroll whitespace, native smooth scroll, click-away/Escape dismiss

refactor: render now-playing backdrop with in-app acrylic

refactor: unify card section dividers and modernise now-playing slider

refactor: stop persisting and restoring window size

refactor: remove unused volume-controls toggle from DeviceCard

build: drop Win2D, render taskbar icons via System.Drawing

BREAKING-CHANGE: settings and rules now live under %APPDATA%\Earmark. Config saved by a pre-1.0 build under the old location is not migrated and must be recreated after upgrading.

hoobio added 28 commits June 6, 2026 13:21
Many sources (YouTube music videos especially) title tracks
"Artist - Song" while reporting the artist separately, so the strip
showed the artist twice. Drop the leading "Artist - " when the head
matches the session artist, with normalised matching so channel noise
(VEVO, - Topic, spacing) still lines up. Non-matching titles untouched.
Startup:
- Defer notification register, Quick Controls hotkey window, and update check to a post-first-paint low-priority dispatch; move StartupSettingsApplier (WaveLink connect) onto the background init thread.
- Gate the first navigation only on audio singletons + rules; seeding and the routing applier's first apply run ungated after.
- Add an instant loading skeleton in MainWindow; make HomePage's loading state full-bleed/transparent (no inset card).

Perf:
- FileLogger holds one StreamWriter (AutoFlush) instead of open/close per line.
- AudioEndpointService caches endpoints whose AudioEndpointVolume activation fails, so it stops re-throwing a COMException per dead endpoint each refresh.
- Reuse the 20Hz TickAppMeters dictionary + per-card hash set instead of reallocating them.

Storage:
- Persisted data moves to %APPDATA%\Hoobi\Earmark, logs to %LOCALAPPDATA%\Earmark, both segregated per build channel (Dev/Prerelease subfolder; Release at base) via AppInfo.ChannelFolder.

Installer:
- Per-channel ARP name, install folder, registry key, and UpgradeCode so Dev/Prerelease/Release coexist as separate Add/Remove Programs entries; component GUIDs switched to auto; Manufacturer set to 'Hoobi' to match the MSIX PublisherDisplayName. Workflow exports EARMARK_CHANNEL for WiX.

UI:
- Mica Base (was BaseAlt) on MainWindow and QuickControlsWindow so the backdrop bleeds the wallpaper and matches Windows Settings.

Also carries in-progress Now Playing divider edits from concurrent work in the shared tree (DeviceCardView, DeviceCard, AppSettings, PeakMeterOptions).
YouTube Music's auto-generated channels report the artist as
"<Artist> - Topic". Drop that suffix from the displayed artist line.
VEVO is left alone (no separator, so stripping yields "KanyeWest").
…whitespace, native smooth scroll, click-away/Escape dismiss
Replace the hand-built title-bar grid with the WinUI TitleBar control
(matching WinUI Gallery): Tall height with caption buttons filling it, a
built-in animated pane toggle, icon-less title/subtitle, and the update
pill in the RightHeader slot (drops the manual caption-inset math).

Add a back/forward history stack to NavigationService since pages are
swapped as DI singletons (Frame.CanGoBack is never set). The back button
stays visible and disables when there's nowhere to go; mouse XButton1/2
drive back/forward. Disabled back button no longer paints a square fill.

Align each page's H1 title with the top of the first nav-rail item by
zeroing the page content top inset.
Adds prev / play-pause / next buttons to the taskbar thumbnail toolbar
(shown on hover) plus a playback badge on the taskbar icon, both driving
the primary SMTC session via INowPlayingService.GetPrimary. The badge is
the OS BadgeNotificationManager glyph on packaged builds and a
SetOverlayIcon corner overlay on unpackaged builds (where the former
throws). Only shown while the main window has a taskbar button.
A device card stretched up to match a taller sibling in its row shrank to its own content when its rules block expanded, instead of holding that height and growing past it. Both wrap layouts now remember the row baseline each card is arranged at (not its own collapsed desired height) and use it as the floor for a card that opts out of the baseline, so it grows for the expanded rules but never drops below its pre-expansion height.
NavigationService swaps DI-singleton pages via Content=, so NavigationThemeTransition never fired and the passed transition info was dead. Element Transitions (EntranceThemeTransition) only play on first realisation, so cached pages didn't animate on re-show. Drive an explicit fade + slide-up storyboard per swap instead, and add an ADR on the singleton-vs-Frame.Navigate decision.
Falls back to IAudioSessionControl::GetIconPath (parsing the @file,-id
shell reference, env-expanded, negative index = resource ID) when neither
the exe nor the process window yields an icon. Fixes the blank System
Sounds chip, which is hosted by taskhostw.exe (no icon) but reports
AudioSrv.Dll,-203.
Replace the Win2D Gaussian blur for the now-playing strip's low-res
artwork with an in-app AcrylicBrush overlay, so the compositor does the
blur. High-res art still fills sharp; only frosted (low-res) art gets the
acrylic, whose theme-aware tint/luminosity darkens in dark mode and
lightens in light. The scrim is dropped over frosted art to avoid
double-darkening.

- Decode, black-bar trim and crop now run on BitmapDecoder (no Win2D).
- Drop the redundant now-playing blur-mode setting end to end.
- Fix section dividers staying dark in light mode: use {ThemeResource}
  borders instead of a converter that snapshotted the app default theme
  (the app themes per-element via RootGrid.RequestedTheme).
The now-playing backdrop no longer needs Win2D, leaving the taskbar
transport-button glyph -> HICON renderer as its only user. Port that to
GDI+ (System.Drawing.Common 10.0.0, already pulled transitively by
H.NotifyIcon) and remove the Win2D package plus its winmd WACK-workaround
target. GDI+ Format32bppArgb is straight alpha, so the un-premultiply
step is gone too.
The context-menu show/hide volume toggle moved into the Customise panel; its label/glyph/command and the host callback chain were the only consumers and are now dead.
Strip mode: the band has no bracketing hairlines (its filled edges are
the separator) and keeps the natural section spacing instead of butting
the rows above and below. Fill-card-background mode keeps the lighter
over-art dividers around it like every other section.

- Clip the fill-mode art + frost/scrim stack with one rounded Border so
  the corners no longer leak bright artwork pixels (per-layer rounding
  left the acrylic's corner short of the art's).
- Trim the seek-bar bottom padding by 6px so it matches the top inset.
Per-device tri-state overrides (follow global / on / off) for the now-playing strip, fill-card-background, app chips, app-chip metering, volume meter, peak-hold indicator, and rules section. Each device card resolves its own effective options (override ?? global), so chips, strips, meter, and rules honour them with no binding rewrites; build and tick passes gate per card.

Edited from the card Customise dialog under a collapsed Overrides section; each global toggle in Settings shows an InfoBar with the override count, affected device names, and a clear-all button.
The card's root Grid had no Background, so right-clicks in the gaps between child elements fell through to the host Border and bubbled ContextRequested to the page's backdrop flyout. A Transparent background captures the whole card surface in the Grid's subtree.
CleanTitle/CleanArtist now drop any ()/[] group containing "Official" (e.g. "(Official Video)", "[Official Music Video]"), so SMTC titles read cleanly. Title cleaning no longer requires a non-empty artist.
@hoobio hoobio changed the title perf: performance and polish feat: taskbar media controls, startup performance, and UI polish Jun 6, 2026
@hoobio hoobio enabled auto-merge (squash) June 6, 2026 09:43
@hoobio hoobio merged commit cb4efd1 into main Jun 6, 2026
14 checks passed
@hoobio hoobio deleted the perf/startup-improvements branch June 6, 2026 09:45
hoobio added a commit that referenced this pull request Jun 6, 2026
## Summary

Updates the README to match Earmark's broadened scope after the
perf/polish release (#56). The tool grew from per-app routing into a
fuller audio companion (live mixer, now-playing with media controls,
taskbar controls, quick controls), and the data location moved to
%AppData%.

## Changes

- Reframe the intro: audio companion built around the rules engine, not
just per-app routing.
- Regroup Features into Routing rules / Devices dashboard / Now playing
& media / App.
- Correct "Where state lives": data now lives in %AppData%\Hoobi\Earmark
(was Documents), with a note on channel subfolders.

## Testing

- [x] Docs only; rendered markdown reviewed.
hoobio pushed a commit that referenced this pull request Jun 6, 2026
🤖 I have created a release *beep* *boop*
---


## [1.0.0](v0.2.0...v1.0.0)
(2026-06-06)


### ⚠ BREAKING CHANGES

* snappier startup, relocate data to %APPDATA%, lighter Mica
* settings and rules now live under %APPDATA%\Earmark. Config saved by a
pre-1.0 build under the old location is not migrated and must be
recreated after upgrading.

### Features

* ✨ add Now Playing media strip to device cards
([#55](#55))
([94ec4f2](94ec4f2))
* add per-device display overrides
([cb4efd1](cb4efd1))
* add Quick Controls overlay
([#52](#52))
([b6dd130](b6dd130))
* add taskbar thumbnail media controls and playback badge
([cb4efd1](cb4efd1))
* adopt WinUI TitleBar control with working back navigation
([cb4efd1](cb4efd1))
* channel-aware MSIX identity and DisplayName per build channel
([5bd1957](5bd1957))
* collapse nav pane on backdrop tap
([cb4efd1](cb4efd1))
* hide taskbar playback indicator after 30s paused
([cb4efd1](cb4efd1))
* now-playing leniency grace window and artwork cross-fade
([cb4efd1](cb4efd1))
* refresh rule summaries during in-place session reconcile
([cb4efd1](cb4efd1))
* resolve session icons from the IconPath fallback
([cb4efd1](cb4efd1))
* slide-in animation for quick controls windows
([cb4efd1](cb4efd1))
* strip '- Topic' suffix from now playing artist
([cb4efd1](cb4efd1))
* strip redundant artist prefix from now playing titles
([cb4efd1](cb4efd1))
* taskbar media controls, startup performance, and UI polish
([#56](#56))
([cb4efd1](cb4efd1))
* theme-aware card surfaces, Mica uniformity, and tighter page
([cb4efd1](cb4efd1))


### Bug Fixes

* animate page transitions on every nav, not just first load
([cb4efd1](cb4efd1))
* keep card at row height as a floor when rules expand
([cb4efd1](cb4efd1))
* lower audible threshold so faint audio keeps app chips lit
([cb4efd1](cb4efd1))
* mask black flash on quick controls open with backdrop-matched
([cb4efd1](cb4efd1))
* MSIX Store-readiness - brand icons, identity, and Quick Controls
polish ([#58](#58))
([5bd1957](5bd1957))
* quick controls scrollbar gutter, disconnected dimming, scroll
([cb4efd1](cb4efd1))
* refine now-playing band layout in strip and fill modes
([cb4efd1](cb4efd1))
* render real brand icons for the Start tile, taskbar, and tray in
([5bd1957](5bd1957))
* roll up hosted webview sessions to owner apps
([#50](#50))
([8d162b6](8d162b6))
* show device card menu on right-click, not backdrop menu
([cb4efd1](cb4efd1))
* stop replaying the Quick Controls slide-in on device state changes
([5bd1957](5bd1957))
* strip Official tags from now-playing title and artist
([cb4efd1](cb4efd1))
* suppress the Quick Controls right-click context menu
([5bd1957](5bd1957))


### Performance Improvements

* snappier startup, relocate data to %APPDATA%, lighter Mica
([cb4efd1](cb4efd1))


### Documentation

* remove shipped customization panel feature doc
([8d162b6](8d162b6))
* rewrite README for the audio companion scope
([#57](#57))
([89343fb](89343fb))


### Miscellaneous Chores

* remove custom smooth-scroll and update AGENTS.md
([#53](#53))
([82b639f](82b639f))


### Code Refactoring

* ♻️ slim down the Quick Controls overlay
([#54](#54))
([9ad54c6](9ad54c6))
* remove unused volume-controls toggle from DeviceCard
([cb4efd1](cb4efd1))
* render now-playing backdrop with in-app acrylic
([cb4efd1](cb4efd1))
* stop persisting and restoring window size
([cb4efd1](cb4efd1))
* unify card section dividers and modernise now-playing slider
([cb4efd1](cb4efd1))


### Build System

* drop Win2D, render taskbar icons via System.Drawing
([cb4efd1](cb4efd1))


### Continuous Integration

* emit an unsigned-namespace test MSIX for sideload testing
([5bd1957](5bd1957))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please-hoobi[bot] <279189756+release-please-hoobi[bot]@users.noreply.github.com>
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.

1 participant