Skip to content

Choose a surface material for the desktop app - #1035

Closed
alexeyzimarev wants to merge 47 commits into
mainfrom
alexeyzimarev/desktop-glass-material
Closed

alexeyzimarev wants to merge 47 commits into
mainfrom
alexeyzimarev/desktop-glass-material

Conversation

@alexeyzimarev

@alexeyzimarev alexeyzimarev commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

Closes #1033 — AI-2983

What & why

The desktop app draws its session rail and launcher in a material chosen under Settings → Appearance: Opaque, Soft glass or Liquid glass; Opaque is the default and glass an explicit choice. Material is a second axis beside palette, carried by an inherited MaterialScope.Material property, so a later light palette does not multiply the glass variants. Glass is a control, not a brush: every inline card outside the chat view is a Surface whose template changes, and one GlassLayer owns all glass drawing. LiquidGlassAvaloniaUI is vendored as source (it is not on NuGet.org) with one patch that reports a shader pipeline that cannot run; on it the app latches Opaque for the session and keeps the stored choice.

Where to look

The glass rail row fills sit at the end of SessionRailView's own styles: a view's styles are applied after Application.Styles and win an equal-priority tie, so the same rule at application level is dead. Panel flyouts stay opaque — glass inside a Flyout's popup never receives a backdrop snapshot; the runnable probe under docs/probes/ holds the measurements.

Verification

  • dotnet build Capacitor.slnx: 17 projects, 0 warnings, 0 errors.
  • App suite: 2582 tests, 2581 green; the one failure is AttachmentTrayTests.Size_label_and_image_flag, this machine's decimal-comma locale, unrelated.
  • Moving the rail's glass row styles to application level paints the selected row #ff1e2e52 instead of #244ed6ba; A_selected_rail_row_takes_the_glass_fill_under_glass catches it. Dropping the chip root's IsExcludedFromCapture fails GlassChipTests the same way.
  • Manual macOS check (three materials live, floating rail, drag-over rim, Reduce transparency): pending.

🤖 Generated with Claude Code

alexeyzimarev and others added 30 commits September 18, 2026 13:03
Material is a second axis beside palette: ThemeVariant stays pinned to Dark, so a light palette later does not multiply the glass variants.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Foreground drawn beside a glass layer is captured into its own backdrop unless the template root opts out of capture, so every glass template sets the flag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A site's local CornerRadius outranks any style, so the glass radius is its own property; the chip presenter is renamed because Fluent's state styles survive a Template swap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A scratch spike settled the mechanisms first: the vendored source builds on Avalonia 12.1.2, inherited-property selectors reach flyouts, and an overlay popup refracts the window.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two of them are rows of the virtualised list, where a templated control triples the visuals; the permission and question cards still migrate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Later-declared styles win at equal priority, so an include above the inline kcapChip style would lose the picker padding.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The package is not on NuGet.org, and upstream reports no pipeline failure, so the copy carries one event the app can fall back on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The root .editorconfig reaches src/ThirdParty by directory ancestry, so not importing the root props does not stop its CA severities.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The stored choice is a string because the state store resets the whole file on any deserialization failure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
SetAsync resumes off the UI thread, so an unsynchronized publish could overwrite a latched failure with a stale snapshot.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The library raises its failure event on the render thread, so the report is posted to the UI thread rather than made in place.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The glass template's root opts out of the window snapshot, or its own content is blurred underneath itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The XAML selector grammar rejects a :not() around a property match, so an any-glass style carries one arm per glass material.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The coordinator is built in a synchronous method on the UI thread, so the awaited load belongs one call earlier.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The vendored glass surface builds a presenter of its own, so a lookup by type alone finds two.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The chat's own cards stay Borders: two are rows of the virtualised list, where a templated control triples the visuals.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A templated control realises its content on first measure, so content under a collapsed ancestor is reachable by name scope only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The rail's own styles outrank application styles, so an app-level glass fill could lose without any layout assertion noticing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The presenter is renamed because Fluent's per-state fills target PART_ContentPresenter and survive a Template swap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two selector arms carry one template, so a dropped arm would leave Liquid glass opaque with no failing test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two selector arms carry one template, so a dropped arm leaves Liquid glass opaque with no failing test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The work-context LinkCard takes main's button and this branch's Surface: the card
style selects kcap|Surface.card, so main's Border.card wrapper stands on its own
transparent chrome. AppState carries main's five window fields and this branch's
Material together — JSON is by name, so the order is free.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The workspace host pins itself opaque, so a reading surface never sits on the backdrop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A control's own styles are applied after application styles and win an equal-priority tie.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A control's own styles are applied after application styles and win an equal-priority tie, so a glass row fill declared at application level lost to the rail's opaque row styles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
alexeyzimarev and others added 16 commits September 18, 2026 19:00
The panel tints but never refracts: the same GlassLayer loses all stripe contrast in the window and in a bare overlay-layer popup, yet keeps 4.3 of 10.8 inside a flyout presenter. The styles and the helper stay out of App.axaml and off every flyout site until that is understood.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A glass layer in the presenter's own template tints but never paints the backdrop, while the same layer as flyout content does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Content wrapping paints no backdrop either: the same layer that reaches 0.0 edge contrast in a bare overlay-layer popup keeps 4.4 of 10.4 as flyout content, so the earlier 0.0 for content was Fluent's opaque presenter, not refraction. Everything stays unwired.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Glass in a Flyout's popup never receives a backdrop snapshot in either placement, while a bare overlay-layer Popup does; the probe records the lead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Glass in a Flyout's popup never receives a backdrop snapshot, whether in the presenter's template or as wrapped content; the probe keeps both shapes runnable for the follow-up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The flyout probe failed, so the copy the plan hands the docs task must not describe glass menus.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Nothing pinned IsExcludedFromCapture on the glass chip template's
root; dropping it would blur each chip's own label under itself
with the suite green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
LiquidGlassPipeline's report latches once per process, and the
render test beside it can trip that latch first, making the
count assertion vacuous whichever test wins the race.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Radial defaults are relative units, so one immutable instance
paints any bounds; the vendored backdrop provider re-renders on
every capture under glass, so a fresh brush per glow per Render
was wasted allocation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A SetAsync still awaiting its file write when the app quits
resumes into Publish on a disposed BehaviorSubject; a _disposed
flag under the same gate makes that publish a no-op instead of
an unobserved ObjectDisposedException.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pins the rail's styled width against real headless layout, drops
dead XAML (a Classes="card" no style targets anymore), removes
change narration from two comments, and re-indents kcap:Surface
continuation attributes to the rest of each file's convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-19T08:07:37.453698Z 89de5d9 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add selectable desktop surface materials with glass rendering

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Adds live, persisted Opaque, Soft glass, and Liquid glass appearance choices.
• Introduces scoped glass rendering with macOS accessibility and pipeline-failure fallbacks.
• Vendors the rendering pipeline and validates behavior with tests and render probes.
Diagram

graph TD
  Settings["Appearance Settings"] --> Service["Material Service"] --> State["Material State"] --> Scope["Material Scope"]
  Environment["macOS Environment"] --> Service
  Pipeline["Glass Pipeline"] -->|failure| Service
  Scope --> Surface["Surface Templates"] --> Layer["Glass Layer"]
  Pipeline --> Layer
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Wait for an official NuGet package
  • ➕ Avoids maintaining vendored source
  • ➕ Simplifies future dependency updates
  • ➖ The required version is not available on NuGet.org
  • ➖ Does not provide the required pipeline-failure callback
  • ➖ Blocks the feature on an external release timeline
2. Vendor the upstream binary package
  • ➕ Adds less source code to the repository
  • ➕ Keeps upstream implementation encapsulated
  • ➖ Cannot patch silent shader and renderer failures cleanly
  • ➖ Makes debugging the rendering pipeline harder
  • ➖ Provides weaker source and patch traceability

Recommendation: Keep the PR's vendored-source approach. The dependency is unavailable on NuGet.org, and the app needs a narrowly documented failure-reporting patch to guarantee an opaque fallback. The dedicated ThirdParty boundary, pinned provenance, MIT license, compatibility tests, and VENDORED.md make the maintenance cost explicit and manageable.

Files changed (88) +9766 / -172

Enhancement (27) +763 / -61
App.axamlRegister material resources and styles +6/-0

Register material resources and styles

• Loads GlassLayer and Surface themes plus glass, surface, chip, and rail styles in precedence order.

src/Capacitor.App/App.axaml

App.axaml.csCompose the material subsystem +24/-4

Compose the material subsystem

• Loads the material service, watches pipeline failures, injects state into windows, and disposes subscriptions safely.

src/Capacitor.App/App.axaml.cs

GlassChipStyles.axamlApply glass templates to launcher pickers +50/-0

Apply glass templates to launcher pickers

• Defines glass-only picker templates and hover, pressed, focus, disabled, padding, and capture behavior.

src/Capacitor.App/Controls/GlassChipStyles.axaml

GlassKind.csClassify glass rendering sites +9/-0

Classify glass rendering sites

• Introduces Card, Rail, Panel, and Chip glass parameter categories.

src/Capacitor.App/Controls/GlassKind.cs

GlassLayer.axamlTemplate the shared glass layer +19/-0

Template the shared glass layer

• Combines one LiquidGlassSurface with a matching non-interactive rim.

src/Capacitor.App/Controls/GlassLayer.axaml

GlassLayer.csAdd the shared glass control +18/-0

Add the shared glass control

• Defines the non-hit-testable templated control and its bindable glass kind.

src/Capacitor.App/Controls/GlassLayer.cs

GlassRailStyles.axamlStyle the floating glass rail +43/-0

Style the floating glass rail

• Sets glass rail margins, chrome height, width, and new-session button treatments.

src/Capacitor.App/Controls/GlassRailStyles.axaml

GlassStyles.axamlCentralize glass rendering parameters +106/-0

Centralize glass rendering parameters

• Defines material-specific tint, blur, refraction, highlight, shadow, and aberration settings by glass kind.

src/Capacitor.App/Controls/GlassStyles.axaml

MaterialBackdrop.csPaint the glass shell backdrop +48/-0

Paint the glass shell backdrop

• Draws static radial glows behind the rail and pane so glass has colored content to refract.

src/Capacitor.App/Controls/MaterialBackdrop.cs

MaterialScope.csAdd inherited material scoping +18/-0

Add inherited material scoping

• Defines an inherited Avalonia attached property with an Opaque default.

src/Capacitor.App/Controls/MaterialScope.cs

Surface.axamlDefine the opaque Surface theme +23/-0

Define the opaque Surface theme

• Provides the default bordered card template used when glass is not active.

src/Capacitor.App/Controls/Surface.axaml

Surface.csAdd the material-aware Surface control +24/-0

Add the material-aware Surface control

• Introduces separate glass radius and glass-kind properties for templated cards.

src/Capacitor.App/Controls/Surface.cs

SurfaceStyles.axamlSwitch Surface templates by material +43/-0

Switch Surface templates by material

• Defines raised and rail variants, capture-safe glass templates, rail rims, and drag-over borders.

src/Capacitor.App/Controls/SurfaceStyles.axaml

IMaterialService.csDefine the material service contract +13/-0

Define the material service contract

• Exposes current and observable state, persisted selection, and latched pipeline-failure reporting.

src/Capacitor.App/Materials/IMaterialService.cs

MaterialAvailability.csModel glass availability +3/-0

Model glass availability

• Distinguishes available, unsupported-platform, and failed-pipeline states.

src/Capacitor.App/Materials/MaterialAvailability.cs

MaterialEnvironment.csDetect material environment +9/-0

Detect material environment

• Captures macOS glass capability and Reduce transparency once during startup.

src/Capacitor.App/Materials/MaterialEnvironment.cs

MaterialService.csResolve and persist effective materials +72/-0

Resolve and persist effective materials

• Combines stored choice, capability, accessibility, and latched failures into a replaying material state stream.

src/Capacitor.App/Materials/MaterialService.cs

MaterialState.csDefine material state snapshots +12/-0

Define material state snapshots

• Records effective and requested materials, availability, failure reason, and accessibility state.

src/Capacitor.App/Materials/MaterialState.cs

SurfaceMaterial.csDefine supported surface materials +21/-0

Define supported surface materials

• Adds material values with lenient stored-string conversion and a glass predicate.

src/Capacitor.App/Materials/SurfaceMaterial.cs

AppStateStore.csPersist the selected material safely +4/-1

Persist the selected material safely

• Adds a string material field so unknown future values do not invalidate the entire state file.

src/Capacitor.App/Services/AppStateStore.cs

MainWindowViewModel.csExpose effective window material +19/-1

Expose effective window material

• Subscribes to material state and publishes the effective material and glass visibility flag.

src/Capacitor.App/ViewModels/MainWindowViewModel.cs

SettingsViewModel.csManage appearance material choices +49/-1

Manage appearance material choices

• Exposes radio selections, availability, contextual hints, and immediate persistence through the material service.

src/Capacitor.App/ViewModels/SettingsViewModel.cs

AppKitAccessibility.csRead macOS Reduce transparency +26/-0

Read macOS Reduce transparency

• Uses Objective-C interop to query the NSWorkspace accessibility setting on macOS.

src/Capacitor.App/Views/AppKitAccessibility.cs

LauncherPaneView.axamlEnable glass launcher cards and pickers +13/-13

Enable glass launcher cards and pickers

• Migrates GoalCard to Surface and marks the five material-sensitive launcher chips as pickers.

src/Capacitor.App/Views/LauncherPaneView.axaml

MainWindow.axamlScope material to the session shell +7/-2

Scope material to the session shell

• Binds the session surface to effective material, adds the backdrop, and pins workspace reading content opaque.

src/Capacitor.App/Views/MainWindow.axaml

SessionRailView.axamlRender and style the material-aware rail +28/-6

Render and style the material-aware rail

• Replaces the root Border with a rail Surface and adds view-local glass row styles with correct precedence.

src/Capacitor.App/Views/SessionRailView.axaml

SettingsWindow.axamlAdd Appearance material controls +56/-33

Add Appearance material controls

• Adds three live material choices and reorganizes daemon settings into opaque Surface cards.

src/Capacitor.App/Views/SettingsWindow.axaml

Bug fix (2) +38 / -0
MaterialPipelineWatch.csBridge pipeline failures to material state +17/-0

Bridge pipeline failures to material state

• Posts render-thread failure events to the UI thread and unsubscribes on disposal.

src/Capacitor.App/Materials/MaterialPipelineWatch.cs

LiquidGlassPipeline.csReport glass pipeline unavailability +21/-0

Report glass pipeline unavailability

• Adds a local once-per-process failure event and a deterministic test reset hook.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPipeline.cs

Refactor (8) +76 / -97
HomeView.axamlMigrate home session cards to Surface +5/-5

Migrate home session cards to Surface

• Replaces card Borders with material-aware Surface controls while retaining their existing layout.

src/Capacitor.App/Views/HomeView.axaml

OnboardingWindow.axamlMigrate onboarding cards to Surface +15/-21

Migrate onboarding cards to Surface

• Replaces onboarding card Borders with Surface controls while keeping the separate window opaque.

src/Capacitor.App/Views/Onboarding/OnboardingWindow.axaml

SignInStepView.axamlMigrate sign-in cards to Surface +8/-11

Migrate sign-in cards to Surface

• Uses Surface for browser fallback and device-code cards without changing sign-in behavior.

src/Capacitor.App/Views/Onboarding/SignInStepView.axaml

PendingCardTemplates.axamlMigrate pending interaction cards +12/-16

Migrate pending interaction cards

• Uses raised Surface controls for permission and question cards, retaining their local styles and names.

src/Capacitor.App/Views/PendingCardTemplates.axaml

PullRequestCard.axamlMigrate pull request card to Surface +3/-3

Migrate pull request card to Surface

• Replaces the raised Border shell with a raised Surface.

src/Capacitor.App/Views/PullRequestCard.axaml

RemoteSessionView.axamlMigrate remote-session banners +8/-9

Migrate remote-session banners

• Uses Surface controls for access and terminal phase cards while the reading view remains opaque.

src/Capacitor.App/Views/RemoteSessionView.axaml

WorkContextView.axamlMigrate work-context link cards +6/-8

Migrate work-context link cards

• Retargets card styles and link-card markup to raised Surface controls.

src/Capacitor.App/Views/WorkContextView.axaml

WorkspaceView.axamlMigrate workspace status cards +19/-24

Migrate workspace status cards

• Replaces terminal and startup banner Borders with Surface controls inside the pinned opaque workspace.

src/Capacitor.App/Views/WorkspaceView.axaml

Tests (15) +818 / -13
AppStateStoreTests.csTest material state persistence +19/-0

Test material state persistence

• Verifies material round trips and unknown stored values preserve unrelated app state.

test/Capacitor.App.Tests.Unit/AppStateStoreTests.cs

ChatTabViewSmokeTests.csUpdate pending-card smoke lookup +2/-1

Update pending-card smoke lookup

• Finds migrated question cards as Surface controls while retaining brush assertions.

test/Capacitor.App.Tests.Unit/ChatTabViewSmokeTests.cs

GlassChipTests.csTest glass picker templates and states +134/-0

Test glass picker templates and states

• Covers opaque and glass templates, capture exclusion, both variants, and interactive visual states.

test/Capacitor.App.Tests.Unit/GlassChipTests.cs

GlassLayerTests.csTest shared glass parameters +71/-0

Test shared glass parameters

• Verifies inherited scope, material-specific parameters, rail settings, radius synchronization, and hit testing.

test/Capacitor.App.Tests.Unit/GlassLayerTests.cs

HomeViewSmokeTests.csUpdate GoalCard smoke lookup +2/-1

Update GoalCard smoke lookup

• Targets the migrated GoalCard Surface while retaining drag-over behavior checks.

test/Capacitor.App.Tests.Unit/HomeViewSmokeTests.cs

InMemoryAppStateStore.csAdd a material-service state-store fake +14/-0

Add a material-service state-store fake

• Provides controllable in-memory persistence with optional write failures.

test/Capacitor.App.Tests.Unit/InMemoryAppStateStore.cs

MaterialPipelineWatchTests.csTest pipeline failure dispatch +31/-0

Test pipeline failure dispatch

• Verifies failures are posted before reaching the service and disposal unsubscribes the watcher.

test/Capacitor.App.Tests.Unit/MaterialPipelineWatchTests.cs

MaterialServiceTests.csTest material resolution and concurrency +136/-0

Test material resolution and concurrency

• Covers defaults, accessibility, capability, persistence, replay, failure latching, disposal, and concurrent updates.

test/Capacitor.App.Tests.Unit/MaterialServiceTests.cs

MaterialWindowTests.csTest window material scoping and rail layout +134/-0

Test window material scoping and rail layout

• Verifies live scope changes, opaque workspaces, backdrop visibility, floating rail geometry, and selected-row styling.

test/Capacitor.App.Tests.Unit/MaterialWindowTests.cs

RemoteSessionViewSmokeTests.csUpdate remote Surface lookups +3/-2

Update remote Surface lookups

• Targets migrated pending and access cards as Surface controls.

test/Capacitor.App.Tests.Unit/RemoteSessionViewSmokeTests.cs

SettingsMaterialTests.csTest Appearance material controls +88/-0

Test Appearance material controls

• Covers selection persistence, unsupported platforms, pipeline failures, accessibility hints, and XAML bindings.

test/Capacitor.App.Tests.Unit/SettingsMaterialTests.cs

SurfaceTests.csTest material-aware Surface behavior +117/-0

Test material-aware Surface behavior

• Covers opaque and glass templates, variants, capture exclusion, scoped overrides, live switching, and drag-over rims.

test/Capacitor.App.Tests.Unit/SurfaceTests.cs

VendoredGlassTests.csGuard vendored glass integration +52/-0

Guard vendored glass integration

• Pins the reflected Avalonia renderer member, smoke-tests headless rendering, and verifies one-shot failure reporting.

test/Capacitor.App.Tests.Unit/VendoredGlassTests.cs

WorkContextViewSmokeTests.csUpdate work-context card lookup +2/-1

Update work-context card lookup

• Targets migrated link cards as Surface controls while retaining hover behavior coverage.

test/Capacitor.App.Tests.Unit/WorkContextViewSmokeTests.cs

WorkspaceViewSmokeTests.csAdapt tests to deferred Surface realization +13/-8

Adapt tests to deferred Surface realization

• Uses name scopes or absence checks for content inside collapsed Surface controls and preserves state assertions.

test/Capacitor.App.Tests.Unit/WorkspaceViewSmokeTests.cs

Documentation (8) +3519 / -1
CLAUDE.mdDocument vendored-source conventions +1/-1

Document vendored-source conventions

• Adds src/ThirdParty to the repository map and records that vendored code follows its own documented patch rules.

CLAUDE.md

README.mdDocument desktop material settings +2/-0

Document desktop material settings

• Explains the three materials, live application, accessibility default, opaque scope, and renderer fallback.

README.md

CHANGES.mdRecord the surface-material architecture +29/-0

Record the surface-material architecture

• Documents material scoping, Surface templates, capture boundaries, opaque flyouts, vendoring, and failure behavior.

docs/CHANGES.md

findings.mdDocument failed flyout glass measurements +105/-0

Document failed flyout glass measurements

• Records that Flyout popups receive no backdrop snapshot while equivalent overlay popups refract correctly.

docs/probes/2026-09-18-glass-overlay-flyout/findings.md

2026-09-18-desktop-glass-material.mdAdd the material implementation plan +2838/-0

Add the material implementation plan

• Provides the task-by-task implementation, verification, migration, and delivery plan for desktop materials.

docs/superpowers/plans/2026-09-18-desktop-glass-material.md

2026-09-18-desktop-glass-material-design.mdSpecify desktop material behavior +491/-0

Specify desktop material behavior

• Defines scope, architecture, persistence, accessibility, rendering, fallback, migration, and testing requirements.

docs/superpowers/specs/2026-09-18-desktop-glass-material-design.md

LICENSEAdd upstream MIT license +21/-0

Add upstream MIT license

• Includes the license governing the vendored LiquidGlassAvaloniaUI source.

src/ThirdParty/LiquidGlassAvaloniaUI/LICENSE

VENDORED.mdRecord glass source provenance and patches +32/-0

Record glass source provenance and patches

• Pins the upstream tag and commit and documents local files, failure-reporting changes, and update procedure.

src/ThirdParty/LiquidGlassAvaloniaUI/VENDORED.md

Other (28) +4552 / -0
Capacitor.slnxAdd the glass library project +1/-0

Add the glass library project

• Includes the vendored LiquidGlassAvaloniaUI project in the solution build.

Capacitor.slnx

Directory.Packages.propsPin Skia rendering dependencies +2/-0

Pin Skia rendering dependencies

• Adds centrally managed Avalonia.Skia 12.1.2 and SkiaSharp 3.119.4 versions.

Directory.Packages.props

GlassFlyouts.csDefine probe-only flyout placements +18/-0

Define probe-only flyout placements

• Provides overlay-layer and wrapped-Surface helpers used to compare glass placement strategies.

docs/probes/2026-09-18-glass-overlay-flyout/GlassFlyouts.cs

Probe.csprojConfigure the flyout render probe +19/-0

Configure the flyout render probe

• Creates a standalone Skia-backed headless executable referencing the app and glass dependencies.

docs/probes/2026-09-18-glass-overlay-flyout/Probe.csproj

ProbeGlassStyles.axamlStyle probe flyout variants +49/-0

Style probe flyout variants

• Defines opaque controls and two probe-only glass flyout template strategies.

docs/probes/2026-09-18-glass-overlay-flyout/ProbeGlassStyles.axaml

Program.csMeasure flyout backdrop rendering +183/-0

Measure flyout backdrop rendering

• Captures rendered frames and measures material inheritance, blur contrast, opaque differences, and text ghosting.

docs/probes/2026-09-18-glass-overlay-flyout/Program.cs

Capacitor.App.csprojReference the vendored glass project +1/-0

Reference the vendored glass project

• Adds the LiquidGlassAvaloniaUI project dependency to the desktop app.

src/Capacitor.App/Capacitor.App.csproj

Directory.Build.propsIsolate vendored build rules +11/-0

Isolate vendored build rules

• Disables repository analyzers and root build conventions for byte-compatible upstream source.

src/ThirdParty/Directory.Build.props

LiquidGlassBackdropTransform.skslVendor backdrop transform shader +18/-0

Vendor backdrop transform shader

• Adds the runtime shader for backdrop zoom and offset sampling.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassBackdropTransform.sksl

LiquidGlassGamma.skslVendor gamma correction shader +14/-0

Vendor gamma correction shader

• Adds runtime gamma adjustment for filtered glass backdrops.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassGamma.sksl

LiquidGlassHighlight.skslVendor edge highlight shader +53/-0

Vendor edge highlight shader

• Adds rounded-rectangle directional highlight rendering.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassHighlight.sksl

LiquidGlassInteractiveHighlight.skslVendor interactive highlight shader +16/-0

Vendor interactive highlight shader

• Adds pointer-positioned highlight rendering for interactive glass surfaces.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassInteractiveHighlight.sksl

LiquidGlassProgressiveMask.skslVendor progressive blur shader +36/-0

Vendor progressive blur shader

• Adds the progressive mask and tint stage for glass rendering.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassProgressiveMask.sksl

LiquidGlassShader.skslVendor liquid-glass lens shader +116/-0

Vendor liquid-glass lens shader

• Adds rounded lens refraction and optional chromatic dispersion over captured content.

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassShader.sksl

LiquidGlassAppBuilderExtensions.csVendor glass performance defaults +25/-0

Vendor glass performance defaults

• Provides composition dirty-rectangle and Skia GPU-resource configuration helpers.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassAppBuilderExtensions.cs

LiquidGlassAvaloniaUI.csprojBuild the vendored glass library +17/-0

Build the vendored glass library

• Targets .NET 10, references Avalonia and Skia, and embeds the runtime shaders.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassAvaloniaUI.csproj

LiquidGlassBackdrop.csVendor backdrop capture exclusion +34/-0

Vendor backdrop capture exclusion

• Defines the attached property used to exclude visual subtrees from captured backdrops.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassBackdrop.cs

LiquidGlassBackdropProvider.csVendor backdrop snapshot provider +805/-0

Vendor backdrop snapshot provider

• Captures per-window visual snapshots, tracks subscribers, excludes glass roots, and coalesces renderer invalidations.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassBackdropProvider.cs

LiquidGlassBackdropSnapshot.csVendor leased backdrop snapshots +230/-0

Vendor leased backdrop snapshots

• Manages snapshot lifetime and a bounded cache of filtered Skia images.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassBackdropSnapshot.cs

LiquidGlassDiagnostics.csVendor glass rendering diagnostics +209/-0

Vendor glass rendering diagnostics

• Tracks capture, invalidation, copying, filtering, cache, and rendering counters.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDiagnostics.cs

LiquidGlassDrawOperation.csVendor and patch glass draw operations +871/-0

Vendor and patch glass draw operations

• Implements Skia shader rendering and locally reports missing Skia leases or shader loading and compilation failures.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDrawOperation.cs

LiquidGlassDrawParameters.csVendor glass draw parameters +64/-0

Vendor glass draw parameters

• Defines rendering passes and the complete parameter snapshot consumed by draw operations.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDrawParameters.cs

LiquidGlassInteractiveSurface.csVendor interactive glass behavior +387/-0

Vendor interactive glass behavior

• Adds spring-based pointer deformation and interactive highlights to glass surfaces.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassInteractiveSurface.cs

LiquidGlassOverlays.csVendor glass overlay controls +53/-0

Vendor glass overlay controls

• Renders interactive highlights, front highlights, and inner shadows around surface content.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassOverlays.cs

LiquidGlassPathUtils.csVendor rounded-path helpers +42/-0

Vendor rounded-path helpers

• Creates clamped per-corner radii and Skia rounded-rectangle paths.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPathUtils.cs

LiquidGlassShadowDrawOperations.csVendor glass shadow rendering +226/-0

Vendor glass shadow rendering

• Implements Skia outer- and inner-shadow custom draw operations.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassShadowDrawOperations.cs

LiquidGlassSurface.csVendor the primary glass surface +899/-0

Vendor the primary glass surface

• Provides the configurable backdrop, refraction, tint, highlight, shadow, and adaptive-luminance control.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassSurface.cs

LiquidGlassVisualRenderer.csVendor backdrop visual-tree rendering +153/-0

Vendor backdrop visual-tree rendering

• Re-renders ordered visual trees into snapshots while respecting clipping, transforms, opacity, and exclusions.

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassVisualRenderer.cs

@qodo-code-review

qodo-code-review Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (7) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Material choices can erase window state 🐞 Bug ☼ Reliability
Description
StartAsync creates a dedicated AppStateStore for MaterialService, while main-window
construction creates a different store instance targeting the same app-state.json file, and each
store protects full-file read-modify-write operations with only its own semaphore. When material
selection overlaps the window-size timer or close-handler geometry save, both stores can read stale
state and overwrite the other update, losing either the selected material or the latest window
geometry.
Code

src/Capacitor.App/App.axaml.cs[R293-294]

+            _material ??= await MaterialService.LoadAsync(
+                new AppStateStore(_config.Path("app-state.json")), MaterialEnvironment.Detect());
Evidence
The material service receives a newly constructed store and writes through it, while main-window and
window-size persistence separately construct another store for the same path. Because
AppStateStore uses an instance field to guard full-file read-modify-write operations, these two
stores are not mutually exclusive and can independently update and replace the same shared record.

src/Capacitor.App/App.axaml.cs[293-294]
src/Capacitor.App/App.axaml.cs[1211-1212]
src/Capacitor.App/Materials/MaterialService.cs[32-35]
src/Capacitor.App/Services/AppStateStore.cs[31-56]
src/Capacitor.App/Services/WindowSizeMemory.cs[68-97]
src/Capacitor.App/App.axaml.cs[1211-1250]
src/Capacitor.App/Services/AppStateStore.cs[35-52]
src/Capacitor.App/Services/WindowSizeMemory.cs[68-82]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Material persistence uses a separate `AppStateStore` instance from the one used by main-window and `WindowSizeMemory` persistence, even though both target `app-state.json`. Because synchronization is instance-local, concurrent full-file read-modify-write operations can overwrite one another.

## Fix Focus Areas
- src/Capacitor.App/App.axaml.cs[293-294]
- src/Capacitor.App/App.axaml.cs[1211-1250]
- src/Capacitor.App/Materials/MaterialService.cs[32-35]
- src/Capacitor.App/Services/AppStateStore.cs[35-52]

## Recommended Fix
Create and retain one application-level `IAppStateStore`/`AppStateStore` for `app-state.json`, then pass that same instance to `MaterialService.LoadAsync` and the main-window/window-size persistence path. Alternatively, ensure every `AppStateStore` targeting the same normalized path shares one synchronization gate, keeping the entire read-modify-write and temporary-file replacement operation inside that shared critical section.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Six shader headers narrate history 📘 Rule violation ⚙ Maintainability
Description
Six vendored shader files begin with labels such as Liquid Glass Gamma Adjustment Shader and
Adapted for SKRuntimeEffect, which repeat the effect name and record adaptation provenance rather
than a rendering constraint. These comments accompany every newly added shader, leaving later
readers to maintain origin text that explains no current behavior or usage trap.
Code

src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassGamma.sksl[R1-2]

+// Liquid Glass Gamma Adjustment Shader
+// Adapted for SKRuntimeEffect.
Relevance

●●● Strong

Recent accepted reviews remove provenance and historical narration from code comments.

PR-#411
PR-#692

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rules 2762993 and 2897915 restrict comments to current, non-obvious behavior-critical information
and reject historical metadata. The cited headers merely repeat shader identity or state that the
source was adapted.

Rule 2762993: Restrict comments to documenting non-obvious, behavior‑critical constraints
Rule 2897915: Avoid time-sensitive or process-reference metadata in code comments
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassGamma.sksl[1-2]
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassHighlight.sksl[1-2]
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassInteractiveHighlight.sksl[1-2]
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassProgressiveMask.sksl[1-2]
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassShader.sksl[1-2]
src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassBackdropTransform.sksl[1-2]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The vendored shaders contain redundant effect labels and historical adaptation notes rather than behavior-critical comments.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassGamma.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassHighlight.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassInteractiveHighlight.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassProgressiveMask.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassShader.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassBackdropTransform.sksl[1-2]

## Recommended Fix
Remove the redundant headers, retaining only comments that explain current shader invariants, coordinate conventions, or non-obvious rendering constraints.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. A pipeline comment records provenance 📘 Rule violation ⚙ Maintainability
Description
The comment above LiquidGlassPipeline says Local addition, not upstream: see VENDORED.md instead
of documenting the event latch or reporting contract implemented below it. Its truth depends on
repository history and upstream status, so a later vendor refresh can make the comment stale without
any behavioral change.
Code

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPipeline.cs[6]

+    // Local addition, not upstream: see VENDORED.md.
Relevance

●●● Strong

Recent accepted reviews consistently remove vendor provenance and process-history comments.

PR-#411
PR-#692

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rules 2762993 and 2897915 prohibit comments that rely on historical or external process context
rather than current behavior. The cited comment describes source provenance and points readers to
external vendoring history.

Rule 2762993: Restrict comments to documenting non-obvious, behavior‑critical constraints
Rule 2897915: Avoid time-sensitive or process-reference metadata in code comments
src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPipeline.cs[6-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The pipeline comment records local-versus-upstream provenance rather than a current behavior-critical constraint.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPipeline.cs[6-6]

## Recommended Fix
Remove the provenance comment or replace it with a concise explanation of the one-report-per-process latch if that invariant is not already clear from the implementation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. The material file holds two main types 📘 Rule violation ⚙ Maintainability
Description
SurfaceMaterial.cs declares both the SurfaceMaterial enum and the top-level SurfaceMaterials
helper class. The helper also contains the non-extension Parse method and does not follow the
enum-extension naming exception, leaving two independently discoverable types in one file.
Code

src/Capacitor.App/Materials/SurfaceMaterial.cs[5]

+public static class SurfaceMaterials {
Evidence
Rule 3162234 permits an enum and extension class only under a narrow naming and purpose exception.
SurfaceMaterials includes a regular parsing method and is a second top-level type.

Rule 3162234: One primary type per file, with only narrow documented exceptions
src/Capacitor.App/Materials/SurfaceMaterial.cs[3-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`SurfaceMaterial.cs` contains both the enum and a separate top-level helper type that does not satisfy the narrow enum-extension exception.

## Fix Focus Areas
- src/Capacitor.App/Materials/SurfaceMaterial.cs[3-20]

## Recommended Fix
Move `SurfaceMaterials` into `SurfaceMaterials.cs`, or reshape it into a conventionally named enum extension class whose sole purpose is extension methods.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (1)
5. Two shadow operations share one file 📘 Rule violation ⚙ Maintainability
Description
LiquidGlassShadowDrawOperations.cs declares LiquidGlassShadowDrawOperation and
LiquidGlassInnerShadowDrawOperation as separate top-level draw-operation classes. Neither class
matches the plural filename or belongs to an allowed private hierarchy, so maintainers must search
inside an unrelated filename to find either implementation.
Code

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassShadowDrawOperations.cs[126]

+    internal sealed class LiquidGlassInnerShadowDrawOperation : ICustomDrawOperation
Evidence
Rule 3162234 requires one primary type per file with a matching filename. The branch adds two
distinct top-level rendering classes to this file.

Rule 3162234: One primary type per file, with only narrow documented exceptions
src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassShadowDrawOperations.cs[11-126]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Two concrete top-level shadow draw operations are grouped under a plural filename that matches neither type.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassShadowDrawOperations.cs[11-126]

## Recommended Fix
Move each draw-operation class into a source file whose name exactly matches that class, preserving namespace and internal visibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

6. The probe file holds three main types 📘 Rule violation ⚙ Maintainability
Description
Program.cs declares the separate top-level types ProbeApp, Stripes, and Program instead of
one filename-matching primary type. These ordinary application, control, and entry-point types do
not form an allowed hierarchy, so later changes cannot locate them by the repository's file
convention.
Code

docs/probes/2026-09-18-glass-overlay-flyout/Program.cs[38]

+sealed class Stripes : Control {
Relevance

● Weak

Recent one-type-per-file findings were rejected, including a closely matching multi-type file
violation.

PR-#976
PR-#873

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3162234 requires one filename-matching primary type per source file. The cited probe file
declares three separate top-level types that do not match an allowed exception.

Rule 3162234: One primary type per file, with only narrow documented exceptions
docs/probes/2026-09-18-glass-overlay-flyout/Program.cs[16-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The probe defines three unrelated top-level types in `Program.cs`, contrary to the one-primary-type-per-file convention.

## Fix Focus Areas
- docs/probes/2026-09-18-glass-overlay-flyout/Program.cs[16-48]

## Recommended Fix
Keep `Program` in `Program.cs` and move `ProbeApp` and `Stripes` into `ProbeApp.cs` and `Stripes.cs`, preserving their existing visibility and behavior.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Drawing parameters share an enum file 📘 Rule violation ⚙ Maintainability
Description
LiquidGlassDrawParameters.cs declares LiquidGlassDrawPass as a top-level enum beside the
top-level LiquidGlassDrawParameters struct. The enum is not paired with an extension-only class or
another allowed exception, so its declaration cannot be found in a matching file.
Code

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDrawParameters.cs[6]

+    internal enum LiquidGlassDrawPass
Relevance

● Weak

Recent one-type-per-file findings involving enums beside another type were rejected.

PR-#875
PR-#976

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3162234 requires one primary type per file. The cited file introduces a top-level enum and a
top-level struct without meeting an allowed exception.

Rule 3162234: One primary type per file, with only narrow documented exceptions
src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDrawParameters.cs[6-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The drawing-parameters file contains a separate top-level enum in addition to its filename-matching struct.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassDrawParameters.cs[6-13]

## Recommended Fix
Move `LiquidGlassDrawPass` into a new `LiquidGlassDrawPass.cs` file in the same directory and namespace.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Two overlay controls lack matching files 📘 Rule violation ⚙ Maintainability
Description
LiquidGlassOverlays.cs declares both LiquidGlassInteractiveOverlay and LiquidGlassFrontOverlay
as top-level controls, while neither type matches the plural filename. They are separate concrete
controls rather than a tiny implementation hierarchy, making ownership and discovery ambiguous for
later rendering changes.
Code

src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassOverlays.cs[33]

+    internal sealed class LiquidGlassFrontOverlay : Control
Relevance

● Weak

Recent one-type-per-file findings for multiple independent top-level types were rejected.

PR-#873
PR-#817

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Rule 3162234 requires a filename-matching primary type and permits only narrow additional-type
patterns. These two independent controls satisfy neither requirement.

Rule 3162234: One primary type per file, with only narrow documented exceptions
src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassOverlays.cs[7-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The plural overlay file contains two concrete top-level controls and does not match either type name.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassOverlays.cs[7-33]

## Recommended Fix
Move each overlay control into its own filename-matching source file while retaining the current namespace and internal visibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
  Explored: repo: kurrent-io/kcap-server (sha: 49c47dcd)
Review mode: 🧠 Deep: This is a high-density cross-cutting change spanning material state, Avalonia controls/styles, vendored shader/rendering code, platform fallbacks, settings, and many independent UI paths, making multiple subtle defects likely to evade one review pass.

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo


public enum SurfaceMaterial { Opaque, SoftGlass, LiquidGlass }

public static class SurfaceMaterials {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. The material file holds two main types 📘 Rule violation ⚙ Maintainability

SurfaceMaterial.cs declares both the SurfaceMaterial enum and the top-level SurfaceMaterials
helper class. The helper also contains the non-extension Parse method and does not follow the
enum-extension naming exception, leaving two independently discoverable types in one file.
Agent Prompt
## Issue description
`SurfaceMaterial.cs` contains both the enum and a separate top-level helper type that does not satisfy the narrow enum-extension exception.

## Fix Focus Areas
- src/Capacitor.App/Materials/SurfaceMaterial.cs[3-20]

## Recommended Fix
Move `SurfaceMaterials` into `SurfaceMaterials.cs`, or reshape it into a conventionally named enum extension class whose sole purpose is extension methods.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}
}

internal sealed class LiquidGlassInnerShadowDrawOperation : ICustomDrawOperation

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Two shadow operations share one file 📘 Rule violation ⚙ Maintainability

LiquidGlassShadowDrawOperations.cs declares LiquidGlassShadowDrawOperation and
LiquidGlassInnerShadowDrawOperation as separate top-level draw-operation classes. Neither class
matches the plural filename or belongs to an allowed private hierarchy, so maintainers must search
inside an unrelated filename to find either implementation.
Agent Prompt
## Issue description
Two concrete top-level shadow draw operations are grouped under a plural filename that matches neither type.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassShadowDrawOperations.cs[11-126]

## Recommended Fix
Move each draw-operation class into a source file whose name exactly matches that class, preserving namespace and internal visibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +2
// Liquid Glass Gamma Adjustment Shader
// Adapted for SKRuntimeEffect.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Six shader headers narrate history 📘 Rule violation ⚙ Maintainability

Six vendored shader files begin with labels such as Liquid Glass Gamma Adjustment Shader and
Adapted for SKRuntimeEffect, which repeat the effect name and record adaptation provenance rather
than a rendering constraint. These comments accompany every newly added shader, leaving later
readers to maintain origin text that explains no current behavior or usage trap.
Agent Prompt
## Issue description
The vendored shaders contain redundant effect labels and historical adaptation notes rather than behavior-critical comments.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassGamma.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassHighlight.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassInteractiveHighlight.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassProgressiveMask.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassShader.sksl[1-2]
- src/ThirdParty/LiquidGlassAvaloniaUI/Assets/Shaders/LiquidGlassBackdropTransform.sksl[1-2]

## Recommended Fix
Remove the redundant headers, retaining only comments that explain current shader invariants, coordinate conventions, or non-obvious rendering constraints.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


namespace LiquidGlassAvaloniaUI
{
// Local addition, not upstream: see VENDORED.md.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. A pipeline comment records provenance 📘 Rule violation ⚙ Maintainability

The comment above LiquidGlassPipeline says Local addition, not upstream: see VENDORED.md instead
of documenting the event latch or reporting contract implemented below it. Its truth depends on
repository history and upstream status, so a later vendor refresh can make the comment stale without
any behavioral change.
Agent Prompt
## Issue description
The pipeline comment records local-versus-upstream provenance rather than a current behavior-critical constraint.

## Fix Focus Areas
- src/ThirdParty/LiquidGlassAvaloniaUI/LiquidGlassPipeline.cs[6-6]

## Recommended Fix
Remove the provenance comment or replace it with a concise explanation of the one-report-per-process latch if that invariant is not already clear from the implementation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +293 to +294
_material ??= await MaterialService.LoadAsync(
new AppStateStore(_config.Path("app-state.json")), MaterialEnvironment.Detect());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Material choices can erase window state 🐞 Bug ☼ Reliability

StartAsync creates a dedicated AppStateStore for MaterialService, while main-window
construction creates a different store instance targeting the same app-state.json file, and each
store protects full-file read-modify-write operations with only its own semaphore. When material
selection overlaps the window-size timer or close-handler geometry save, both stores can read stale
state and overwrite the other update, losing either the selected material or the latest window
geometry.
Agent Prompt
## Issue description
Material persistence uses a separate `AppStateStore` instance from the one used by main-window and `WindowSizeMemory` persistence, even though both target `app-state.json`. Because synchronization is instance-local, concurrent full-file read-modify-write operations can overwrite one another.

## Fix Focus Areas
- src/Capacitor.App/App.axaml.cs[293-294]
- src/Capacitor.App/App.axaml.cs[1211-1250]
- src/Capacitor.App/Materials/MaterialService.cs[32-35]
- src/Capacitor.App/Services/AppStateStore.cs[35-52]

## Recommended Fix
Create and retain one application-level `IAppStateStore`/`AppStateStore` for `app-state.json`, then pass that same instance to `MaterialService.LoadAsync` and the main-window/window-size persistence path. Alternatively, ensure every `AppStateStore` targeting the same normalized path shares one synchronization gate, keeping the entire read-modify-write and temporary-file replacement operation inside that shared critical section.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

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: 89de5d9ceb

ℹ️ 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".

// ??= keeps a second pass (the wizard hands over to a fresh graph) from building a
// second service or a second event subscription.
_material ??= await MaterialService.LoadAsync(
new AppStateStore(_config.Path("app-state.json")), MaterialEnvironment.Detect());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Share the app-state store for material writes

This creates a separate AppStateStore for the material service even though the main window, lifecycle coordinator, and re-auth flows create other instances for the same app-state.json. Because the store's semaphore is instance-local and every update reads and rewrites the entire file, a material selection concurrent with a background shim/consent update can overwrite that update or have its new Material value overwritten. Reuse one store instance, or otherwise serialize updates by path, so independent fields cannot be lost.

Useful? React with 👍 / 👎.

Reduce transparency stays on the material state and in the Appearance hint, but it no longer chooses anything: glass is an explicit choice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.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.

Desktop app: choose a surface material (Opaque, Soft glass, Liquid glass) in Settings

1 participant