Skip to content

fix: speed control bounds come from the engine, not a hardcoded 20–400 - #14

Merged
willwade merged 1 commit into
mainfrom
fix/speed-range-from-engine
Aug 22, 2026
Merged

fix: speed control bounds come from the engine, not a hardcoded 20–400#14
willwade merged 1 commit into
mainfrom
fix/speed-range-from-engine

Conversation

@willwade

Copy link
Copy Markdown
Contributor

Fixes #13.

Problem

The speed stepper coerced to a fixed 20–400 % (MainActivity.kt speed steppers). Dasher v5's UI allowed raw MaxBitRateTimes100 10–800 (6–500 %) and long-term users sit at the top of the range — a v5 user at 5.0× (raw 500) cannot reach their speed. Two layers caused it:

  1. The UI hardcoded 20/400.
  2. The engine's dasher_set_speed_percent also clamped to 20–400 — fixed engine-side in DasherCore #55, released as v0.2.3.

Changes

  • DasherEngine.speedRangePercent(): derives the percent bounds from the engine's LP_MAX_BITRATE manifest entry (raw 1–1000 → ~1–625 %), historic 20–400 only as fallback.
  • MainActivity: speedRange state initialised from the engine once realised; steppers coerce to it.
  • NativeBridge doc comment updated to describe the engine-range clamp.
  • Submodule third_party/DasherCorev0.2.3 (also brings output event type 2 — buffer-clear — unused here for now; the IME's per-char handler ignores unknown types, verified).

Cross-repo context

Testing

  • :app:compileDebugKotlin + :app:testDebugUnitTest + :app:assembleDebug (native build vs v0.2.3 for arm64-v8a + x86_64) all green locally.
  • Manual check on-device/emulator recommended: stepper reaches 500 % and getSpeedPercent round-trips it.

DCO signed.

The speed stepper coerced to a fixed 20–400 %, but Dasher v5 allowed raw
MaxBitRateTimes100 10–800 (up to 500 %) and long-term users sit at the top
of the range. The bounds now come from the engine's LP_MAX_BITRATE
manifest entry (DasherEngine.speedRangePercent; raw 1–1000 → ~1–625 %),
with the historic range as fallback.

Bumps third_party/DasherCore to v0.2.3, whose percent helper no longer
pre-clamps to 400 (DasherCore #55) and which adds output event type 2.

Fixes #13. Cross-repo context: Dasher-GTK #51, governance RFC 0005
parity notes (PR 28).

Signed-off-by: will wade <willwade@gmail.com>
@willwade
willwade merged commit 410d659 into main Aug 22, 2026
2 checks passed
willwade added a commit that referenced this pull request Aug 22, 2026
Stacked on #14 (branches from it; merge #14 first). Implements the
Android side of [DasherCore
#56](dasher-project/DasherCore#56) /
[v0.2.4](https://github.com/dasher-project/DasherCore/releases/tag/v0.2.4).

## What

The engine laid out node labels using a `codepoints × fontSize/2` width
estimate; the error compounds down the label shunting chain and
deep-zoom text degenerates into jumbles (reported making long sentences
untypeable on Windows; Android shares the engine path).

Wires the new `dasher_set_text_size_callback` end to end:

- **JNI** (`jni_bridge.cpp`): `textSizeCallback` marshals into a cached
`NativeBridge.onTextSize(String, int, float[]) → boolean` method — the
same pattern as clipboard/speak/message/parameter callbacks. New
bindings: `nativeSetTextSizeCallback`, `nativeTextMetricsChanged`.
- **Canvas** (`DasherCanvasView`): `measureGlyphText` measures with the
**same Paint** the canvas draws opcode-5 text with, including its size
transform (`engineSize × 2.5, floored at 8`) — measuring with the raw
font size would desync layout from drawing. `glyphFontName` changes now
fire `nativeTextMetricsChanged` so a font switch re-measures.
- **Both engines**: MainActivity *and* the IME install their own
measurement. `NativeBridge` listeners are static, so the IME must
reinstall on every `createEngine()` — otherwise it would inherit the
(possibly destroyed) Activity's canvas.

Caveat documented in code: the canvas's emergency *normalize* transform
(off-screen/huge-span frames) scales geometry per-frame and can't be
known at measurement time; measurement matches the normal
(non-normalized) path, which is the steady state.

Submodule: DasherCore → **v0.2.4**.

## Testing

- `:app:compileDebugKotlin` + `:app:testDebugUnitTest` +
`:app:assembleDebug` (native build vs v0.2.4, arm64-v8a + x86_64) green
locally.
- Manual check recommended: long sentence; frontier labels no longer
crowd/overlap; toggle canvas font in Settings → letters re-space.

Sibling wiring: Dasher-GTK #53; Dasher-Windows tracked in
[#28](dasher-project/Dasher-Windows#28).

DCO signed.

Signed-off-by: will wade <willwade@gmail.com>
willwade added a commit to dasher-project/Dasher-Apple that referenced this pull request Aug 24, 2026
…#36)

Fixes #34.

## What
- **DasherCore submodule → v0.2.4**, which contains [DasherCore
#55](dasher-project/DasherCore#55):
`dasher_get_speed_percent` no longer pre-clamps to raw 32–640, and
`dasher_set_speed_percent` clamps to the engine's declared
`LP_MAX_BITRATE` manifest range instead of 20–400 %
- New `DasherBridge.speedRangePercent` on **all four targets** (macOS,
iOS app, iOS keyboard, visionOS): reads `LP_MAX_BITRATE` min/max from
the parameter manifest and converts raw → percent (raw 160 = 100 % ⇒ raw
1–1000 ≈ 1–625 %), falling back to the historic 20–400 if the manifest
is unavailable
- The four view models' steppers now clamp with those bounds

## Why
Issue #34: every target clamped to 20–400 %, below v5's 500 % top;
migrated v5 users above 4.0× couldn't even display their speed. Mirrors
[Dasher-Android
#14](dasher-project/Dasher-Android#14) and
[Dasher-GTK #51](dasher-project/Dasher-GTK#51).

## Notes
- Kept the manual `outputText` re-syncs after `reset()` — the optional
event-type-2 simplification from the issue can ride a later PR
- Verified: `xcodebuild -scheme DasherMac` (CI gate) — **BUILD
SUCCEEDED**, 0 errors

Signed-off-by: will wade <willwade@gmail.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.

Speed control coerces to 20–400 — below v5's max (500%); follow the engine manifest

1 participant