diff --git a/packages/app-android/app/views/main.ts b/packages/app-android/app/views/main.ts index 3301bd5f..aa67cbdd 100644 --- a/packages/app-android/app/views/main.ts +++ b/packages/app-android/app/views/main.ts @@ -294,8 +294,16 @@ export class MainController implements MainView { toolbar.set_content(toast); // Bottom view switcher bar bound to the stack. + // + // REVEALED, explicitly. `Adw.ViewSwitcherBar:reveal` defaults to FALSE — in a GNOME + // window the bar is asked for by an `Adw.Breakpoint` (`setters { bar.reveal: true; }`) + // once the window goes narrow, and a desktop-width window keeps it collapsed in favour + // of the header-bar switcher. Android has no wide branch: this shell is the narrow + // layout, always. Without this line the bar measured THREE PIXELS on the emulator and + // the app had no visible way to change page at all. const switcher = new Adw.ViewSwitcherBar(); switcher.set_stack(stack); + switcher.reveal = true; toolbar.add_bottom_bar(switcher); return toolbar; diff --git a/packages/app-android/app/widgets/source-view.ts b/packages/app-android/app/widgets/source-view.ts index 77393435..07d1b4f7 100644 --- a/packages/app-android/app/widgets/source-view.ts +++ b/packages/app-android/app/widgets/source-view.ts @@ -143,25 +143,17 @@ export class SourceView extends ContentView implements SourceViewWidget { } // Instance methods - public - /** - * Get the source code - */ - get code(): string { - return this.textView ? this.textView.text : this._pendingCode; - } - - /** - * Set the source code - */ - set code(value: string) { - if (this.code === value) return; - - this._pendingCode = value; - if (this.textView && this.textView.text !== value) { - this.textView.text = value; - } - this.notifyPropertyChange("code", value); - } + // + // NOTE — `code` has NO accessor here on purpose. `codeProperty.register(SourceView)` + // (bottom of this file) defines `code` on the prototype itself, so a `get code()` / + // `set code()` written in the class body is overwritten before any instance exists. + // A pair of them lived here and looked authoritative; reads went to NativeScript's + // property store instead, which is why the editor's text never reached the + // assembler. Reading and writing both go through the property now: the widget + // pushes with `nativeValueChange` (see `textChange`), and `valueChanged` writes + // the other way. + /** Defined on the prototype by `codeProperty.register()`; declared so TypeScript sees it. */ + declare code: string; /** * Get whether the source view has code @@ -357,6 +349,29 @@ export class SourceView extends ContentView implements SourceViewWidget { if (this.textView) { const newText = args.value as string; + // THE TYPED TEXT GOES BACK INTO THE `code` PROPERTY, and without this line + // nothing ever reads what the user wrote. + // + // `SourceView.codeProperty.register(SourceView)` at the bottom of this file + // does `Object.defineProperty` on the prototype, which REPLACES the + // `get code()` written above — those accessors are dead from the moment the + // module loads. So `sourceView.code` is NativeScript's stored property value, + // and typing changes the inner TextView, never that store. + // + // Measured on the emulator (2026-09-22), after typing `LDA #$01`: + // textChange fired "LDA #$01" <- the event is fine + // textView.text "LDA #$01" <- the inner widget is fine + // native getText() "LDA #$01" <- Android is fine + // editorController.code "" <- what Assemble actually assembled + // The toast then said only "Assemble failed", because an empty program is a + // failed assembly and the port never showed the assembler's own message. + // The same program assembles headlessly: `learn6502 assemble` -> 2 bytes. + // + // `nativeValueChange` is the direction NativeScript provides for exactly + // this: the native side moved, tell the property, and do NOT re-enter + // `valueChanged`'s write-back into the widget the value just came from. + SourceView.codeProperty.nativeValueChange(this, newText); + this.debouncedHighlighting(newText); this.updateLineNumbers(newText); this.events.dispatch("changed", { code: newText });