Repository navigation
feat: Devices app chips, close/terminate, undo, and card options - #44
Merged
Merged
Conversation
- Windows App SDK 1.8.260416003 -> 2.1.3 (Microsoft.Windows.SDK.BuildTools 10.0.26100.4948 -> 10.0.28000.1839) - CommunityToolkit.WinUI.* 8.2.250402 -> 8.2.251219 - Microsoft.Extensions.* 10.0.0 -> 10.0.8 - NAudio.Wasapi 2.2.1 -> 2.3.0 - Microsoft.NET.Test.Sdk 17.13.0 -> 18.6.0, xunit.v3 1.0.1 -> 3.2.2, xunit.runner.visualstudio 3.0.2 -> 3.1.5 - replace FluentAssertions 7.1.0 with AwesomeAssertions 9.4.0 (FA v8 needs a commercial licence) - pin Microsoft.WindowsAppSDK.Runtime 2.1.3 as the path source for the #6071 notification workaround (wired up in the follow-up commit)
WinAppSDK 2.x unpackaged self-contained builds omit Microsoft.WindowsAppRuntime.Insights.Resource.dll, so AppNotificationManager.Register throws 0x8007007E (MOD_NOT_FOUND) even though IsSupported() returns true (microsoft/WindowsAppSDK#6071). - _EarmarkLayoutInsightsResource extracts that DLL from the runtime MSIX into build and publish output - reference Microsoft.WindowsAppSDK.Runtime with GeneratePathProperty to locate the MSIX - gate Register() on AppNotificationManager.IsSupported() per the self-contained deployment guide
Record what _EarmarkLayoutInsightsResource is for and how to verify whether a future WindowsAppSDK bump fixes #6071 so the workaround can be removed.
Card height (Balanced / Match row / Dynamic) controls how cards size within a row; card dividers draw Settings-style hairlines between a card's sections (default on). Both are shared through PeakMeterOptions and exposed under Settings > Devices. SettingsPage.xaml and HomeViewModel.cs also carry minor concurrent edits from another change (a section-header margin and a doc-comment rename).
The scroll region runs full-width so its scrollbar rides the window edge (Settings-style), content inset via padding; the page title gets matching top breathing room. App chips now use Composition implicit animations (slide on re-sort, fade out on prune, instant appearance so there's no blank gap as the card grows), and the opt-in section divider lines render. HomePage.xaml also carries a concurrent context-menu rework from another change (Delete group + critical-red styling), committed whole rather than split per the file's mixed state.
The app-chip Composition setup used an implicit opacity hide animation; on a card container recycled by the block ItemsRepeater it came back stuck at opacity 0, so a chip placed on a recycled card rendered invisible (its divider and reserved space showed, but no chip). Drop the opacity animation and keep the Offset slide only. Also remove the scroll region's bottom padding so cards scroll to the window's bottom edge instead of stopping short.
The apps row attached a Composition implicit Offset animation per chip, but re-sorting via ObservableCollection.Move made the ItemsControl recreate the moved chip's container - it landed fresh at its destination with no slide, so only the chips that stayed animated. Keep the collection in arrival order and have the WrapPanel arrange chips by a per-chip WrapOrder rank instead; a re-sort now re-positions the same containers, so every moved chip glides.
…argin The list's trailing space lived on the ScrollViewer padding, which reserved a dead band at the viewport bottom that clipped cards short mid-scroll. Move it onto the list itself (DevicesRepeater.Margin) so cards scroll flush to the window's bottom edge and only the last card clears it - by 28px, matching the side inset. Also centralise the page's content insets into named Thickness tokens in App.xaml (Padding/Margin can't take the x:Double Spacing tokens). HomePage.xaml also carries a concurrent context-menu rework from another change, committed whole rather than split per the file's mixed state.
…ches Restore NavView.IsPaneOpen from AppSettings on launch (in NavView.Loaded, so Auto display-mode init doesn't clobber it) and save it when the user toggles the pane, so the left sidebar's collapsed/expanded state survives a restart. Defaults to expanded.
- Right-click an app chip to Close it gracefully (posts WM_CLOSE to its windows); Shift+right-click reveals a red Terminate that force-kills it. - Elevated apps are pre-detected by integrity level: when a medium Earmark can't message an elevated target, Close is disabled and relabelled "Cannot close elevated app", while Terminate stays available where the OS permits it. - Elevated app chips show a shield badge. - Close/terminate feedback uses a bottom-centred in-app toast; Windows notifications stay reserved for background events like rule-driven device corrections. - A deliberate, successful close/terminate prunes the chip after a short 3s linger instead of the full configurable window.
A multi-process app (a browser's GPU / renderer / audio children all run the same exe) only owns its main window on the browser process, which is rarely the pid holding the audio session the chip stands for - so closing that one pid did nothing and terminating it left the rest running. Gather every running pid that shares the app's identity (lowercase exe path) and act on the whole set: WM_CLOSE to any of their top-level windows, TerminateProcess on each.
Extends the Devices-page undo stack beyond hide/show and volume/mute to cover the structural actions: hiding an app chip, reordering blocks or group members, and creating / joining / leaving / deleting a group. Each captures a snapshot of the layout state (block order, groups, hidden apps) before it mutates, and Ctrl+Z restores that snapshot wholesale and resyncs - simpler than reversing each op and uniform across all of them. Group rename is not covered.
When a card's apps row appears/disappears the cards below now slide to their new spots instead of snapping. The prior pass armed the block Offset animation then detached it on the next LayoutUpdated, which fired at/before the reflow arrange, so the slide never ran. Arm it on the apps-row change and leave it attached so back-to-back reflows glide; drop it on the ScrollViewer's ViewChanging (before a scroll re-arranges realised blocks, so the scroll stays crisp) and re-arm on the next change. No 'still scrolling' flag - the scroll's final ViewChanged isn't a reliable signal and a stuck flag killed the animation for the rest of the session.
In Balanced card-height mode, expanding one card's rules made it opt out of the row baseline, which then dropped to the shortest remaining card - so a no-rules sibling visibly shrank the moment you expanded a neighbour. Each layout now remembers a card's last stretch-eligible (collapsed) height and keeps counting it toward the baseline while the card is custom-sized, so the expanded card grows on its own and its row-mates hold their height.
The slide was disarmed on the ScrollViewer's ViewChanging, but a reflow grows the content and itself raises ViewChanging once the list has been scrolled - so it stripped the implicit mid-reflow and killed the slide for the rest of the session (it only worked before the first scroll, while the content still fit). Disarm on a short one-shot timer instead: attached for the reflow's arrange, gone before any later scroll. Also arm on Blocks.CollectionChanged so a device connecting or disconnecting (and showing/hiding a card, or forming/disbanding a group) slides the surrounding cards into place instead of snapping.
The slide was gated (arm on change, disarm via timer / ViewChanging, settle flag), which made it unreliable: maximizing the window didn't animate, and once the list had been scrolled the reflow stopped firing at all. Drop all of it. Every realised block now carries the implicit Offset slide, attached AFTER its arrange so it snaps into place on first realise / recycle and animates every later move - a reflow, a device added/removed, a window resize, a show/hide, a group change, or a drag. Detaching on (re)prepare keeps scrolling crisp (a recycled card is repositioned without the implicit). One mechanism, same as the app chips, no gating to misfire.
hoobio
pushed a commit
that referenced
this pull request
Jun 1, 2026
This PR was generated automatically by [release-please](https://github.com/googleapis/release-please). --- ## [0.2.0](v0.1.9...v0.2.0) (2026-06-01) ### ⚠ BREAKING CHANGES * **rules:** pinned/one-shot actions, drag-and-drop, consolidated schema ([#49](#49)) * **devices:** rules.json schema replaced - actions and conditions now use a Kind plus orthogonal mode fields (direction / membership / muted) and a Pinned flag; the old type-per-row enum no longer deserialises. ### Features * add "always show pinned apps" setting for rule-pinned chips ([dd387a6](dd387a6)) * add appearance backdrop setting (Mica, Acrylic, Solid) ([#39](#39)) ([7f2769a](7f2769a)) * add Devices-page reset to default and new-install seeding ([baffea1](baffea1)) * card-height and card-divider options for the Devices page ([dd387a6](dd387a6)) * close and terminate an app from its chip menu, across all the ([dd387a6](dd387a6)) * device customisation panel (glyph + accent colour) ([#46](#46)) ([34956eb](34956eb)) * Devices app chips, close/terminate, undo, and card options ([#44](#44)) ([dd387a6](dd387a6)) * Devices page options menu (show title bar / show hidden / lock ([288d13a](288d13a)) * **devices:** add a Bluetooth connect/disconnect button on Bluetooth ([c6feb57](c6feb57)) * **devices:** add persisted device-card display toggles ([1ea0d9e](1ea0d9e)) * hide an app's chip on a single device from its chip context menu ([34956eb](34956eb)) * hide app chips via a context menu, manage from settings ([#41](#41)) ([8e62187](8e62187)) * per-device accents, customise dialog, and Devices page options ([#47](#47)) ([288d13a](288d13a)) * per-device app-chip indicators with drag-to-reroute on the Devices ([dd387a6](dd387a6)) * per-device deterministic accent colours, reworked customise ([288d13a](288d13a)) * persist disconnected devices and add the Show disconnected filter ([#48](#48)) ([c6feb57](c6feb57)) * persist the navigation pane expand/collapse state across ([dd387a6](dd387a6)) * **rules:** flag matched-but-disconnected devices in the match chip ([1ea0d9e](1ea0d9e)) * **rules:** per-field match modes (regex / wildcard / exact) with a ([1ea0d9e](1ea0d9e)) * **rules:** pinned/one-shot actions, drag-and-drop, consolidated schema ([#49](#49)) ([1ea0d9e](1ea0d9e)) * **rules:** warn when an action is superseded by a higher-priority rule ([1ea0d9e](1ea0d9e)) * undo app-chip hide, reorder, and group changes with Ctrl+Z ([dd387a6](dd387a6)) ### Bug Fixes * allow click-to-mute on the device icon when volume controls are ([34956eb](34956eb)) * always animate the Devices card reflow (apps row, device ([dd387a6](dd387a6)) * expanding a card's rules no longer shrinks a shorter sibling card ([dd387a6](dd387a6)) * glide app chips on re-sort by ranking, not collection Move ([dd387a6](dd387a6)) * keep the device accent tile coloured while a mute rule is active ([288d13a](288d13a)) * lay out Insights.Resource.dll for self-contained app notifications ([dd387a6](dd387a6)) * move a device directly from one group into another in one drag ([dd387a6](dd387a6)) ### Documentation * note the backdrop setting in the design-language section ([7f2769a](7f2769a)) * rewrite the rule schema reference for the consolidated model ([1ea0d9e](1ea0d9e)) * spec loopback / listening chip suppression heuristic ([#45](#45)) ([16b4aad](16b4aad)) ### Code Refactoring * **devices:** split oversized DeviceCard and HomeViewModel into ([c6feb57](c6feb57)) ### Tests * cover rule matcher, device-rule resolver, and shadow analyzer ([1ea0d9e](1ea0d9e)) * **devices:** cover device-key identity, list filter, and store re-key ([c6feb57](c6feb57)) ### Build System * update dependencies to latest stable ([dd387a6](dd387a6)) ### Continuous Integration * use the release-please PR body for pre-release notes ([288d13a](288d13a)) --- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Devices-page work accumulated on this branch since grouping landed on main: per-device app-chip indicators, close/terminate from a chip, card-height/divider options, Ctrl+Z undo for structural actions, and a reworked card reflow animation.
Changes
WM_CLOSEor force-kill, acting on every process the app spawns (a browser's renderer/audio children), elevation-aware.Testing
Checklist
feat: per-device app-chip indicators with drag-to-reroute on the Devices page
feat: close and terminate an app from its chip menu, across all the app's processes
feat: card-height and card-divider options for the Devices page
feat: add "always show pinned apps" setting for rule-pinned chips
feat: persist the navigation pane expand/collapse state across relaunches
feat: undo app-chip hide, reorder, and group changes with Ctrl+Z
fix: glide app chips on re-sort by ranking, not collection Move
fix: always animate the Devices card reflow (apps row, device add/remove, resize)
fix: expanding a card's rules no longer shrinks a shorter sibling card
fix: move a device directly from one group into another in one drag
fix: lay out Insights.Resource.dll for self-contained app notifications
build: update dependencies to latest stable