Group settings pages into sections with icons#230
Merged
Conversation
Split the flat settings nav into a General item (no header) plus Appearance, Game, and Account sections via a new SettingsGroup, and give every page a leading icon (SettingsPage.icon), rendered by both the mobile (Material3 ListItem) and desktop (Jewel) navs. Adds a hand-authored group.xml (two-person) drawable for the Characters page, since the existing Material Symbols set had no multi-person glyph. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sproctor
added a commit
that referenced
this pull request
Jul 15, 2026
Split the flat settings nav into a General item (no header) plus Appearance, Game, and Account sections via a new SettingsGroup, and give every page a leading icon (SettingsPage.icon), rendered by both the mobile (Material3 ListItem) and desktop (Jewel) navs. Adds a hand-authored group.xml (two-person) drawable for the Characters page, since the existing Material Symbols set had no multi-person glyph. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
sproctor
added a commit
that referenced
this pull request
Jul 17, 2026
…st previews, skin-referenced colors (#232) * Group settings pages into sections with icons (#230) Split the flat settings nav into a General item (no header) plus Appearance, Game, and Account sections via a new SettingsGroup, and give every page a leading icon (SettingsPage.icon), rendered by both the mobile (Material3 ListItem) and desktop (Jewel) navs. Adds a hand-authored group.xml (two-person) drawable for the Characters page, since the existing Material Symbols set had no multi-person glyph. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Move per-window styling into settings; split Appearance into Presets and Windows Per-window color/font settings now live in the main Settings dialog instead of a standalone popup. A window header's "..." / right-click "Window settings" action opens Settings focused on that window's editor, routed via a GameViewModel SharedFlow event collected by the app host. Add a Windows settings section (Shown / configured-not-shown / other-windows buckets + add-by-id, live show/hide via a WindowSettingsLiveContext) on desktop (Jewel) and mobile (M3). Split the Appearance page into separate Presets and Windows nav pages and drop the multi-line preview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add appearance resolve core + style-rendering characterization tests Introduce the pure appearance model alongside StyleDefinition (not yet wired): Background (tri-state Fill/None/Unset), StyleLayer (sparse, weight-not-bold, per-item font), ResolvedStyle, resolve(), and StyleDefinition<->layer adapters. toLayer() maps "off" booleans to null so first-set-wins reproduces the old boolean-OR merge for existing data. Add golden characterization tests pinning toSpanStyle/toAnnotatedString output and preset/window/name TOML round-trips, as the safety net for the upcoming renderer migration onto resolve(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add per-item font + weight fields to style configs (backward-compatible) PresetStyleConfig/HighlightStyleConfig/NameConfig gain nullable weight, fontFamily, and fontSize; WindowStyleConfig gains bold/italic/underline for the shared style editor. All additive with defaults, so pre-existing TOML still parses and a bold-only preset stays byte-stable (the nullable fields drop when unset). toStyleDefinition folds an explicit weight back into bold so a hand-set weight still renders during the transition; per-item font family/size are stored but not yet applied (the renderer migration wires them next). Deferred to the UI phase: explicit tri-state None background storage and applying per-preset skin fonts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Route text rendering through the resolve() model (behavior-preserving) Replace the StyleDefinition -> SpanStyle choke point with a ResolvedStyle -> SpanStyle primitive that can carry per-item font family/size/weight and a tri-state background, and rebuild each leaf's span from resolve() over the leaf's named-style layers. StyleDefinition.toSpanStyle now delegates through the same path, so the highlight / name / entire-line / link call sites are unchanged and every existing render stays byte-identical (the P0 golden tests pass unmodified). Wiring the preset map to StyleLayer (so per-item preset fonts and tri-state None actually flow to the renderer) rides with the settings UI in a later phase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add a global (all-characters) preset layer PresetRepository gains observeForCharacter (a character's presets layered over the global ones, character winning per key) and saveGlobal, mirroring the existing highlight/name global idiom. The renderer's preset resolution becomes skin -> global -> character. With no global presets saved, behavior is identical to before. Window styling globalization rides with the windows scope UI in the next phase (its geometry stays per-character in SQLite, so only the styling half globalizes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * P5 step 1: source-tracking resolve + config<->StyleLayer mappers Add the editor-side model: StyleScope, Sourced<T>, SourcedStyle, and resolveSourced() (the source-tracking twin of resolve(), for "set here / inherited from …" tags + per-attribute reset). Add tri-state Background <-> WarlockColor helpers (transparent argb 0 == None) and the preset config<->StyleLayer mappers, with reverse canonicalization (weight 700 -> bold, no weight field) so bold-only TOML stays byte-stable. Not wired yet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * P5: store the base text color/style next to defaultFont CharacterSettingsConfig gains defaultTextColor / defaultBackgroundColor / defaultItalic / defaultUnderline beside defaultFont / monoFont — the color half of the former presets["default"] (defaultFont being the font/weight half). Add CharacterSettingsRepository.observeBaseStyle / saveBaseStyle that assemble and split a base StyleLayer, plus the config<->StyleLayer base mappers. Not yet wired into the renderer or the editor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * P5: make the base style not a preset; feed it from a resolved cascade Remove "default" from the rendered presets map and from WarlockStyle.presets. Add WindowRegistry.baseStyle: the resolved base ("default text") color + font + weight + italic/underline, cascaded character -> global -> skin (from CharacterSettingsConfig, with a legacy "default"-preset fallback so older configs keep their default color until the P6 destructive migration). Provide it as LocalBaseStyle, with the base font half via LocalDefaultFont; the ~10 chrome sites that read presets["default"] now read the resolved base style. Behavior-preserving: the P0 golden render tests pass unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Widen the render preset map to sparse StyleLayer The stream renderer keyed presets by dense StyleDefinition, which cannot carry per-item fonts or the tri-state (Fill/None/Unset) background. Retype the whole preset render path to Map<String, StyleLayer> so those reach the renderer: - WindowRegistry.presets + WindowRegistryImpl (via the new PresetRepository.observeLayersForCharacter), ComposeTextStream, and the StyledStringHelpers/AnnotatedStringHelpers.markLinks choke points now speak StyleLayer; appendStyledStringLeaf drops its per-leaf .toLayer(). - LocalStyleMap becomes Map<String, StyleLayer>; a resolvedStyle(key) helper projects a preset back to a dense StyleDefinition for the input-line chrome that still consumes the legacy type. Dialog link lookups read the layer's nullable textColor directly. - getEntireLineStyles reads layer.entireLine and projects to StyleDefinition, keeping the entire-line/highlight flatten path (still StyleDefinition-based) unchanged. Behavior-preserving: existing presets carry no fonts, so resolve() output equals the old StyleDefinition span. Golden StyleRenderCharacterization and ComposeTextStream tests stay green; Android + benchmark source sets updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the pure style-editor reducer (StyleEdit + applyEdit) The shared appearance editor needs a pure, testable core: a StyleEdit per control, StyleLayer.applyEdit to fold an edit into the edited scope's own layer (concrete color/background sets; boolean sets explicitly so an inherited true can be overridden to false; Reset/null clears to inherit), SourcedStyle .sourceOf(attribute) to drive the per-control "set here"/reset state, and sampleStyle(stack) for the live preview. No Compose dependency; unit-tested beside StyleResolveTest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add the shared desktop style editor + rebuild the Presets page The desktop Appearance -> Presets page becomes a scope-aware master-detail: a Global/character selector over a list of the base "default text" plus the named presets (each row drawn in its own resolved style), drilling in to a new shared DesktopTextStyleEditor. - DesktopTextStyleEditor (desktop/components): one reusable Jewel editor for a single style at one scope. Per attribute it shows the control, a "set here"/ "from Global"/"from skin" tag, and a reset enabled only when the value was set at the edit scope; a live sample renders the resolved cascade. Text color, tri-state background (fill + None), weight, italic, underline, and per-item font (family/size/weight, sharing the one weight field with the Weight row); optional entire-line/monospace rows for reuse by other sections. Edits fold through StyleLayer.applyEdit and are handed back as a whole layer to persist. - core: styleEditorModel(characterLayer, globalLayer, skinLayer) assembles the cascade for one item (a null character layer = editing the global scope, which then omits any character overrides), plus StyleEditorModel. Unit-tested. - PresetRepository: observeScopeLayers (one scope's own presets as layers) and saveLayer (persist a preset as a sparse StyleLayer). The base "default text" item edits CharacterSettings' base style; presets edit their own layer; monospace font (not a style layer) keeps its own row. Global scope writes the all-characters layer. Mobile Presets still uses the old view. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Bring the mobile Presets page to parity with the shared editor Mirror the desktop rebuild on Material3: a mobile TextStyleEditor (the M3 twin of DesktopTextStyleEditor - same attribute rows, source tags, per-attribute reset, tri-state background, per-item font, live sample) and a scope-aware master-detail PresetsView (base "default text" + named presets each drawn in their own resolved style, drilling in to the editor; monospace font kept as its own row). Both platforms now edit the same StyleLayer scopes via styleEditorModel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Rename Presets page to "Text styles"; lift base + mono font above presets The page now covers the base text style, the monospace font, and the named presets, so "Presets" was too narrow: rename the settings page to "Text styles" (SettingsPage.TextStyles). Move the "Default text" and "Monospace font" rows above a "Presets" heading on both platforms, so the base style and fonts read as distinct from the named-preset list rather than sitting inside it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Names: adopt the shared style editor Replace the Names dialog's hex color text fields with the shared style editor (color pickers + tri-state background + weight + italic + underline), which also surfaces the bold/italic/underline that NameConfig already stored but the dialog never exposed. Names carry no font, so the editor runs with showFont = false; text + sound stay as-is. A commonMain StyleEditing helper maps NameConfig to/from the editor's StyleLayer, shared by both platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Highlights: adopt the shared style editor per capture group Replace each highlight group's hex color fields + bold/italic/underline/mono checkboxes with the shared style editor (color pickers, tri-state background, weight dropdown, italic/underline, monospace). Group styles are still stored as StyleDefinition, projected to/from the editor's StyleLayer via the StyleEditing helper. entire-line / match-partial / ignore-case / sound stay as-is. Drops the mobile-local ColorTextField (now unused after Names + Highlights moved to pickers). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Windows: adopt the shared style editor + thread weight/italic/underline The per-window settings row now edits its style with the shared editor instead of two bare color-picker buttons, so a window can override weight, italic, and underline (not just colors). Those flags already existed on WindowStyleConfig but were never surfaced; thread them through WindowSettings, observeWindowSettings, setStyle, and getStyle so they persist and render (via uiState.style.mergeWith). The editor gets a single-layer `sourced` (tags read "set here"/"default", since a window has no cascade) but a two-layer `sample` (window over the character default) for a realistic preview. Fonts stay as the separate normal/mono pickers (showFont = false); name filter, revert, show/hide, and the window buckets are unchanged. Per-window global scope is left for later. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * P6: fold legacy default preset into the base + export the new style fields Base migration (the correctness piece): when a config loads, fold any lingering presets["default"] into the character/global base style and drop it, so the base text editor is authoritative and the orphaned preset is cleaned up. Base values the user has already set win; the legacy preset only fills what the base leaves unset. Runs per scope in CharacterConfigStore.load() alongside id generation, and persists the rewritten presets/settings sections. Tested (fold + drop, persistence, and base-wins). Export: per-preset weight/fontFamily/fontSize and per-window bold/italic/underline were editable but silently dropped on export. Add them to StyleExport / WindowSettingsExport (all defaulted, so older export files still load and the JSON stays forward/backward compatible) and wire the preset + window export/import sites. Round-trip + legacy-load tests added. Still not exported (pre-existing, separate task): the base style itself and the default/monospace fonts live in character settings, which the export only carries as typeahead + script prefix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Export the base style + default/mono fonts The base ("default text") style and the default/monospace fonts live in the character settings, which the export never carried, so they were lost on export/import. Add an optional BaseStyleExport block to CharacterExport (textColor/backgroundColor/italic/underline + font + monoFont) populated on export and applied on import. Backward compatible: the block is nullable and defaults to null, so an export written before it existed (no `baseStyle` key) still deserializes. Import treats null as "no base in this file": REPLACE keeps the target character's base style and fonts (the prior behavior), MERGE changes nothing. A present block wins wholesale on REPLACE and per-set-attribute on MERGE. Round-trip + legacy-load tests added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Honest style chips: split identity from data + fix the preview surface The preset list rendered each item's name in that item's own style on the settings panel surface, which both lied about legibility (game text sits on the window background, not the panel) and could make the row itself unreadable. Split the two jobs: - New shared StyleChip (commonMain): a fixed-width swatch that composites the resolved style over the effective *game window* background, never the panel. Two distinct boundaries - an outer panel hairline and, only when the background is explicitly set (Fill or None), a luminance-derived inset ring - so a background equal to the window color is still visible and unset vs None vs Fill stay distinguishable. Fixed sample text ("Aa" / a phrase), never the item name. - Preset rows (both platforms): the name is now normal, always-legible UI text (never its own style); the chip carries the style; a muted trailing label shows the tri-state background (no bg / none / #hex). Chips resolve the item over the base so unset attributes inherit like in game. - The shared editor's large preview now uses StyleChip over the real window background and shows a WCAG contrast warning with the actual ratio when text vs effective background drops below 3:1 - warn, never block. - core: contrastRatio / relativeLuminance util next to resolve, unit-tested. Decision (skin-ref vs literal, spec section 6): colors stay literal for now; ColorValue/SkinRef would ripple through StyleLayer/ResolvedStyle/resolve/storage and is deferred. Names/highlights/windows list swatches not yet on StyleChip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * List swatches: names + highlights adopt the shared StyleChip Replace the panel-composited swatches in the Names and Highlights lists (both platforms) with the shared StyleChip, so those rows preview honestly on the game window background with the tri-state ring, matching the presets list. The item name/pattern was already legible in these lists; only the swatch changes. They have no per-scope base handy, so the chip composites against the default game background (SAFE_DEFAULT_STYLE) - a fine v1 per the spec. Window list rows are disclosure headers with no swatch; their editor already shows the chip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Annotated tri-state background picker Replace the editor's background control (a Fill color button + a None checkbox) with a dedicated picker that presents the three states as explicit, selectable rows: Inherit, None, Color. Inherit is annotated with what it falls back to ("inherits the window background" / "inherits none" / "inherits #hex") so it is distinguishable from None, which looks identical in game but does not pick up a later global background. Color opens the standard color picker. The row now shows the current state's label (no bg / none / #hex) and opens the dialog. The presets pages compute the true fallback (resolve of the layers below the edited scope) and pass it; the flat editors (names/highlights/windows) default to "inherits the window background", which is exactly what they do. New DesktopBackgroundPickerDialog (Jewel) + BackgroundPickerDialog (M3) twin; the inherit annotation helper is shared in commonMain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: core ColorValue + StyleLayer ref metadata Foundation for palette colors that track the skin (spec section 6). ColorValue = Literal (frozen) | SkinRef (resolves against a skin palette). StyleLayer carries textColorRef/backgroundRef beside the resolved color, and resolveRefs(palette) refreshes the colors from the current skin while keeping the ref, so the render path keeps reading plain WarlockColor and stays untouched (golden tests green). The reducer gains SetTextColorRef, and a literal color / reset clears the ref. Unit-tested. Config storage, the compose resolve boundary, and the palette picker UI follow in later commits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: persist the refs in presets + base config Store the skin-palette slot beside the color in the config so a ref survives save/reload: PresetStyleConfig gains textColorRef/backgroundColorRef and CharacterSettingsConfig (base) gains defaultTextColorRef/defaultBackgroundColorRef, threaded through the toStyleLayer / toPresetStyleConfig / base mappers. All nullable with null defaults, so older files still parse and a literal-only preset stays byte-stable. Round-trip tests added. Names/highlights/windows keep literal colors for now. Compose resolve boundary + palette picker UI follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: palette picker + resolve at the compose boundary Wire skin-referenced text colors end to end for presets + base. A skin color palette is derived from the skin's presets (name -> text color, name+Bg -> background); resolveRefs is applied where the skin is known - WindowRegistryImpl (so refs render and follow the skin) and the presets pages (so the editor/chip show the resolved color while keeping the ref). The text-color control now opens a palette picker: clicking a skin swatch stores a SkinRef that tracks the skin; "Custom color" opens the standard picker and stores a frozen literal. The row shows "tracks <slot>" when a ref is active. DesktopColorRefPickerDialog (Jewel) + ColorRefPickerDialog (M3). Render path stays WarlockColor-based; golden tests unchanged. Background-fill refs and the names/highlights/windows sections keep literals for now (the model + config already carry backgroundRef for a later pass). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: background-fill refs too Extend skin-referencing to the background fill. The background picker now shows the skin palette below the Fill/None/Inherit rows: a palette swatch stores a SetBackgroundRef (tracks the skin), while the custom color picker still stores a frozen literal. The background row shows "tracks <slot>" when a ref is active. resolveRefs now resolves a background ref to a Fill of the slot color regardless of the cached background, so the ref survives a save/reload even when the stored fill color was dropped to unspecified. Reducer gains SetBackgroundRef (a literal fill / reset still clears the ref). Unit-tested. Both preset text and background colors now track the skin end to end. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: names track the skin NameConfig gains textColorRef/backgroundColorRef; the NameConfig<->StyleLayer helpers carry them, so the Names editor's palette picker persists a skin ref. The name render path in WindowRegistryImpl resolves the ref against the skin palette (names render color only), and the Names editor + list chip resolve for display - so a name's palette color follows the skin like presets do. Round-trip tested. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: windows track the skin WindowStyleConfig + WindowSettings gain textColorRef/backgroundColorRef, threaded through observeWindowSettings. WindowSettings.toStyleLayer() carries the refs for the shared editor; the windows editor resolves them for display and persists via a new setStyleLayer (setStyle still clears refs, so Revert resets them). getStyle(palette) resolves a ref against the skin, falling back to the last resolved color when no palette is passed - so the render path is correct without threading the palette (window colors follow the skin live in settings; at render they refresh on save). Round-trip tested. With this, all four Appearance sections (presets, names, highlights*, windows) carry skin refs. (*highlights: their per-group styles still route through the StyleDefinition-based Highlight model; left literal-only.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Skin-ref colors: highlights track the skin Convert the Highlight model's per-group styles from Map<Int, StyleDefinition> to Map<Int, StyleLayer>, so a highlight color can carry a skin ref. HighlightStyleConfig gains textColorRef/backgroundColorRef; the config<->model mappers (and the legacy DB migration + WSL/Wrayth importers) go through StyleLayer. The render path in WindowRegistryImpl resolves each group's ref against the skin palette and flattens to the dense StyleDefinition that ViewHighlight/applyStyleAtRange still consume, so the hot path and its golden tests are unchanged. The highlight editor now stores StyleLayers directly (dropping the toLayer/toStyleDefinition round-trips) and its palette picker persists refs; the list chip resolves for display. Round-trip tested. All four Appearance sections - presets, names, highlights, windows - now carry skin-referenced colors that follow the skin. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix appearance-rewrite review findings Addresses the confirmed findings from the automated deep review on #232. The dominant theme was that the new editor and resolve model taught per-attribute cascade semantics that the persistence layer and several render paths did not implement yet. Cascade / persistence: - Merge presets per attribute (new mergeLayers) across skin -> global -> character, instead of replacing a preset's layer wholesale per name. - Make the tri-state style booleans nullable in the config schema so an explicit "off" round-trips instead of decaying to "inherit". - Persist weight for windows, and wire NameConfig's weight/font fields, which were previously dead. - Carry a color's skin ref through foldLegacyDefaultPreset, and fold at every config entry point rather than only on load(). - Clamp font weights to 1..1000 when decoding a section, so hand-edited TOML cannot crash composition or swallow stream lines. Render paths: - Resolve window skin refs at the registry boundary and thread the skin palette to GameViewModel's getStyle() call sites. - Keep names and highlights sparse end to end so their weight, per-item font, and bold/italic/underline actually render. - Consume italic/underline in the stream row text style. Export / import: - Carry skin refs (and weight/font for highlights and names) through StyleExport, BaseStyleExport, and WindowSettingsExport. - Map a legacy presets["default"] into baseStyle when importing an export that predates the base-style field. - Stop mergeBase keeping a stale target ref that outranked an imported color. Editors: - Drive the background picker's selection from the sparse edit layer, so Inherit can show as selected. - Composite the highlights/names previews and contrast warnings against the real resolved base background instead of a hardcoded dark color. - Compute the Windows page's default text from the real base cascade rather than the folded-away presets["default"]. Also fixes the iOS build: toSortedMap() is JVM-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * StyleChip: draw a single border The chip drew two: an always-on outer hairline bounding it against the settings panel, and an inset ring drawn only when the background was explicitly set. The conditional ring made some rows read as double-bordered and others not. Keep the hairline, which is present in every state and does the actual bounding. The explicit-vs-inherited distinction the ring encoded is already reported textually by backgroundLabel() (no bg / none / hex), so no information is lost. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Preview each preset with the line it styles in game Every style editor showed the same hardcoded speech line ("You hear Lyrena say, ...") no matter what was being edited, so the preview said nothing about the preset in front of you. Give each preset the in-game line it actually applies to, restoring the per-preset lines the pre-rewrite Appearance preview had. echo/error/link had no line there, so those come from where the client emits them. The style applies to the fragment it really marks, not the whole line: bold marks the creature name, speech the "You say" verb. StyleSample carries prefix/styled/suffix and the chip renders the surrounding text in the base style. Backgrounds follow the same split - a whole-line style fills the chip, a fragment style paints behind its fragment only, leaving the line on the window background as it would be in game. Windows, names, and highlights style arbitrary text, so they get a pangram instead: it exercises every letter, which is what makes a font or weight change legible in a one-line preview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Settings: clearer nav selection, drop redundant title, label Base Three desktop Appearance/settings tweaks: - The active nav page tinted with the neutral border color at low alpha, which barely showed. Use the accent (focused-outline) color instead so the selection reads clearly. - SettingsListScaffold no longer repeats the page title; the settings-dialog nav already shows it. Dropped the param and its eight call-site arguments. - The Presets page gains a "Base" heading over the base-text and monospace rows, matching the "Presets" heading below. Also simplify the base-text preview to the generic pangram rather than its own room-description line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.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.
What
Reorganizes the settings navigation:
SettingsGroup— General (no header, stands alone), then Appearance (Appearance, Highlights, Names, Alterations), Game (Actions, Macros, Aliases, Variables), and Account (Accounts, Characters).SettingsPage.icon), rendered by both the mobile (Material3ListItemleadingContent) and desktop (JewelImage+ColorFilter.tint) navs.group.xml(two-person) drawable for the Characters page, since the existing Material Symbols set had no multi-person glyph.Icons
Mostly existing Material Symbols. Three were the closest available stand-ins where the set lacks a dedicated glyph: Macros →
space_dashboard, Variables →circle_filled(no keyboard/data icon). Easy to swap later if better ones are added.Note
Stacked on #229 (base =
remove-gradle-daemon-jvm) so the diff stays limited to the settings changes; will retarget tomasteronce #229 merges.🤖 Generated with Claude Code