Skip to content

Android: use shipped Gtk.Button/Adw.ButtonContent - #197

Merged
JumpLink merged 1 commit into
mainfrom
refactor/android-use-shipped-widgets
Sep 22, 2026
Merged

JumpLink merged 1 commit into
mainfrom
refactor/android-use-shipped-widgets

Conversation

@JumpLink

Copy link
Copy Markdown
Owner

Summary

Replaces hand-built widget composition in packages/app-android/app/ with
components @gjsify/adwaita-nativescript already ships, where the fit is
verified against that package's shipped API (packages/nativescript-bridge/adwaita/src/widgets/).

  • app/widgets/adw-main-button.ts (89 → 87 lines): the hand-composed
    Gtk.Image + plain NativeScript Label inside a StackLayout IS
    Adw.ButtonContent inside Gtk.Button. AdwMainButton now extends
    Gtk.Button and holds an Adw.ButtonContent as its child; the
    MainButtonState machine and the .adw-fab pill CSS are unchanged.
    Gtk.Button's own constructor already wires press-darken
    (attachRowPressFeedback), so the widget's manual call to it is gone too.
    app/app.css gets two small compensating rules: .adw-fab { height: auto }
    (the base .adw-button class now present sets a fixed height: 38, which
    would clip the pill) and .adw-fab .adw-button-content-label { color: #ffffff } (replacing the now-dead .adw-fab-label rule — Adw.ButtonContent's
    label only turns white for .suggested-action/dark mode by default, and the
    FAB needs it white unconditionally, as the old widget did).

  • app/widgets/game-console/gamepad.ts (97 lines, unchanged count):
    gamepad.xml's Builder.load'd plain @nativescript/core Buttons become
    gtk:Button, through a new app/gtk.ts — the app-local XML door
    @gjsify/adwaita-nativescript's own widget barrel documents (mirrors the
    existing ~/widgets/index convention this app already uses for <w:SourceView>).
    text= becomes label= (Gtk.Button dropped text for the GIR name), and
    class= becomes the widget's own styleClasses= door — a plain class=
    write would silently drop the adw-button base class Gtk.Button's
    constructor already put there.

  • app/widgets/debugger/hex-monitor.ts: left alone. AdwDataGrid was
    checked and does not fit:

    • it always renders a header row; this dump has never had one
    • its default cell padding (9,12 DIP) is tuned for sparse financial-statement
      rows, while BYTES_PER_ROW was already cut 16→8 specifically because 8
      tight byte columns already exhaust the measured 850px phone-card width
    • its default track layout gives the FIRST column all the slack and sizes the
      rest to content — the inverse of the tight, equal-width byte columns wanted
      here — and working around it means an explicit fixed pixel width, not a
      zero-config swap
    • it has no row shape for the single, spanning "invalid range" error message
      the widget renders today

No direct Android SDK/AndroidX/Material API is introduced — Gtk.Button is
already used elsewhere in this app (views/main.ts, views/main/game-console.ts)
and Adw.ButtonContent composes only @nativescript/core primitives
(StackLayout/Label) plus the already-used GtkImage — so
data/Android/native-api-usage.json is untouched.

Test plan

  • gjsify workspace @learn6502/app-android run check — exits 0, zero error TS
  • gjsify format --check — clean
  • Not built/run — per task scope, no APK build or emulator use

🤖 Generated with Claude Code

adw-main-button.ts hand-composed a Gtk.Image + Label in a StackLayout;
that pair is Adw.ButtonContent inside Gtk.Button, both shipped by
@gjsify/adwaita-nativescript. Keep the MainButtonState machine and the
.adw-fab pill CSS, replace only the composition.

gamepad.xml Builder.load'd plain @nativescript/core Buttons; swap them
for gtk:Button via a new app/gtk.ts XML door (the app's own convention,
mirrored from ~/widgets/index). class= becomes the widget's own
styleClasses= door so "adw-button" survives, text= becomes label=.

hex-monitor.ts is left alone: AdwDataGrid always renders a header row
this dump never had, its default cell padding (9,12) is tuned for
sparse financial-statement rows while BYTES_PER_ROW was already cut
8<-16 to fit phone width, its "first column absorbs slack" default
inverts the desired tight equal-width byte columns, and it has no row
shape for the single spanning "invalid range" message.
@JumpLink

Copy link
Copy Markdown
Owner Author

Holding this until gjsify#1746 lands.

Two of the three parts here are compensations for defects in the shipped components, and
that PR fixes one of them at the source: .adw-button pinned height: 38 on the base
class while .adw-button.pill right below it asks for 10+10 vertical padding, so the pill
was clipped and every consumer had to override the height. gjsify#1746 gives the pill its
own height: 48 and writes the invariant beside it — a variant that changes vertical
padding on a base with an exact height must restate that height.

So .adw-fab { height: auto } here becomes unnecessary once this repo picks that up, and
merging now would land a workaround for a bug that is already fixed upstream.

The label-colour rule is a separate question: the claim that Adw.ButtonContent's label
ignores the button's style class was measured and REFUTED — the stylesheet carries
.adw-button.suggested-action .adw-button-content-label and a full .ns-dark mirror, so
the near-black literal is simply the light-scheme value. Whether .adw-fab needs its own
rule therefore depends on which style class the FAB carries, which is worth one measurement
before this merges.

Net line change here was 89 -> 87 on the main button; the gamepad part is type-only churn
at equal line count plus a new app-local XML door. The value of this PR is the two upstream
findings, not the line count, and that is worth saying in the body when it is rebased.

@JumpLink
JumpLink merged commit 860b2af into main Sep 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant