From bf10f3a68eec2ee781e327999e9198758ec397b8 Mon Sep 17 00:00:00 2001 From: Chris Pelatari Date: Wed, 10 Jun 2026 21:30:25 -0500 Subject: [PATCH 1/2] docs(spec): dictation discoverability (#14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Approved brainstorming output for #14: a docs how-to + a subtle mdi-microphone cue (no speech engine — dictation already works via the OS: Android keyboard mic, Windows Win+H). Decisions: real mdi-microphone icon (Material icon font, subsetted) on BOTH platforms; tapping focuses the editor (existing window.PostXING.focus()) and shows a transient platform-specific hint ("Press Win+H" / "Tap the mic on your keyboard"). Plus docs/dictation.md. --- ...-06-10-dictation-discoverability-design.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-10-dictation-discoverability-design.md diff --git a/docs/superpowers/specs/2026-06-10-dictation-discoverability-design.md b/docs/superpowers/specs/2026-06-10-dictation-discoverability-design.md new file mode 100644 index 0000000..6f6fdcd --- /dev/null +++ b/docs/superpowers/specs/2026-06-10-dictation-discoverability-design.md @@ -0,0 +1,62 @@ +# Dictation discoverability — design + +**Issue:** [#14 "Enable dictation"](https://github.com/BlueFenixProductions/PostXING/issues/14) +**Date:** 2026-06-10 +**Status:** Approved design, pending implementation. + +## Problem + +Users want to dictate posts. Dictation **already works** via the OS — Android's keyboard mic (the editor's IME composition path in `index.html` is explicitly written to support it) and Windows `Win+H` dictate into any focused field, including the editor's contenteditable. What's missing is **discoverability**: there's no in-app cue, so users don't know they can dictate. The issue author leaned toward a docs how-to plus an `mdi-mic` cue rather than building a speech engine. + +## Decisions (from the brainstorming interview) + +1. **Deliver a docs how-to + a subtle in-app mic cue.** No speech-recognition engine. (Operator decision.) +2. **The cue focuses the editor and shows a transient, auto-dismissing hint** pointing at the OS dictation — no OS input injection. (Operator decision.) +3. **Use a real `mdi-microphone` icon** (a Material Design Icons font), not a text affordance — "the icon is visually useful to humans." (Operator decision; overrides the text-label house aesthetic for this one affordance.) +4. **Show the cue on both platforms** (not Windows-only). (Operator decision.) + +## Design + +### Material icon font + +Register a Material Design Icons TTF in `Resources/Fonts/` (alongside Hack) via `MauiProgram.ConfigureFonts`, e.g. `fonts.AddFont("materialdesignicons-webfont.ttf", "MaterialIcons")`. **Subset the font to the few glyphs used** (`microphone`, and `microphone-off` for a possible future toggle) to avoid shipping the full ~1.2 MB MDI webfont in the APK/MSIX — a subsetted TTF is a few KB. The mic glyph is referenced via a `FontImageSource` with `FontFamily="MaterialIcons"` and the `mdi-microphone` codepoint **U+F036C** -- above the BMP, so C# uses the surrogate pair `"\U000F036C"` and XAML uses the `󰍬` entity. Some MDI builds remap glyphs into the BMP private-use range; if the bundled font does, use that codepoint instead. + +### Cue placement + +- **Windows** — a mic `Button` in the editor's bottom status bar (`EditorPage.xaml`, `Grid.Row=1`), using `ImageSource` = the `FontImageSource` mic glyph instead of `Text`. Sits with `new`/`open`/`settings`/…; the icon is the one non-text affordance, intentionally. +- **Android** — a **primary** `ToolbarItem` (visible in the Material top app bar, not the overflow) with `IconImageSource` = the same `FontImageSource`. The existing actions stay in the overflow (`Order="Secondary"`); the mic is promoted so it's a visible, tappable icon. + +### Behavior + +Tapping the mic: +1. **Focuses the editor** — `EditorWebView.EvaluateJavaScriptAsync("window.PostXING.focus()")` -- `window.PostXING.focus()` already exists in `index.html` (calls `editor.focus()`), so no JS change is needed. (Fire-and-forget on Android per the existing bridge pattern.) +2. **Shows a transient, auto-dismissing hint** with platform-specific text: + - Windows: `Press Win+H to dictate` + - Android: `Tap the mic on your keyboard to dictate` + +The hint is a self-contained element (a `Border`+`Label` overlaid near the status bar) that fades in, waits ~2.5 s, and fades out — **no new dependency** (CommunityToolkit.Maui is not referenced). A single `DictationHintRequested` event / bool drives its visibility. + +### Hint text helper (the testable seam) + +The platform→hint-text mapping lives in a tiny pure helper (e.g. `DictationHints.For(DevicePlatform)` returning the string), so the one piece of logic is unit-testable off the MAUI TFM in `PostXING.ViewModels`. The focus call and the fade are view-layer (`EditorPage` code-behind), not unit-tested. + +### Docs + +`docs/dictation.md` — "Dictating posts in PostXING": +- **Windows:** press `Win+H` to open the dictation toolbar; speak; it types into the editor. Punctuation commands ("period", "new line"). The in-app mic button is a reminder/focus shortcut, not a separate engine. +- **Android:** tap the mic on your soft keyboard; the editor handles voice input (it's written to not drop composition mid-highlight). +- Note that this uses the OS's own speech recognition — nothing leaves the device beyond what the OS dictation already does. + +## Acceptance criteria + +- A mic icon (real `mdi-microphone` glyph) is visible in the editor on both Windows and Android. +- Tapping it focuses the editor and briefly shows the correct platform hint, then auto-dismisses. +- `docs/dictation.md` documents Win+H (Windows) and the keyboard mic (Android). +- The Material icon font is subsetted (not the full ~1.2 MB webfont). +- No speech-recognition code, no `Win+H` injection; existing editor behavior unchanged. + +## Non-goals (YAGNI) + +- No in-app speech-to-text engine (`System.Speech` / `Windows.Media.SpeechRecognition`). +- No programmatic `Win+H` injection. +- No mic-state/recording UI — the OS owns the dictation session. From 0f9f38262779bedf5bd83b92f1504a75d7a56be9 Mon Sep 17 00:00:00 2001 From: Chris Pelatari Date: Wed, 10 Jun 2026 21:49:54 -0500 Subject: [PATCH 2/2] feat(editor): dictation mic cue + how-to (#14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dictation already works via the OS (Android keyboard mic, Windows Win+H); #14 is about discoverability. Adds a real mdi-microphone cue that focuses the editor and shows a transient platform hint, plus docs/dictation.md. No speech engine. - subsetted Material Design Icons font (microphone glyph U+F036C only, ~840 bytes, not the 1.3 MB webfont) registered as "MaterialIcons" - Windows: shapes:Path mic in the status bar (theme-reactive Fill, matches the preview/sync icon convention); Android: a primary mic ToolbarItem (FontImageSource) - tap -> window.PostXING.focus() + a self-contained fade-in/out hint ("Press Win+H" / "Tap the mic on your keyboard"); no new dependency - DictationHints.For(platform) — the one pure, unit-tested seam (3 tests) - docs/dictation.md: Win+H (Windows) and keyboard mic (Android) how-to Windows head builds 0/0; ViewModels 254 green. Android on-device verification is BLOCKED by the build host's memory (#57): the Dell OptiPlex 3060 (8 GB RAM, fixed 6 GB page file) can't give the Android build JVM commit headroom — needs the RAM bump / page-file fix before the Android glyph + cue can be verified on panther. --- MauiProgram.cs | 3 ++ Resources/Fonts/mdi-microphone.ttf | Bin 0 -> 840 bytes Views/EditorPage.xaml | 33 +++++++++++++++++ Views/EditorPage.xaml.cs | 34 ++++++++++++++++++ docs/dictation.md | 27 ++++++++++++++ src/PostXING.ViewModels/DictationHints.cs | 23 ++++++++++++ .../DictationHintsTests.cs | 23 ++++++++++++ 7 files changed, 143 insertions(+) create mode 100755 Resources/Fonts/mdi-microphone.ttf create mode 100644 docs/dictation.md create mode 100644 src/PostXING.ViewModels/DictationHints.cs create mode 100644 tests/PostXING.ViewModels.Tests/DictationHintsTests.cs diff --git a/MauiProgram.cs b/MauiProgram.cs index f13223e..4545af8 100644 --- a/MauiProgram.cs +++ b/MauiProgram.cs @@ -23,6 +23,9 @@ public static MauiApp CreateMauiApp() { fonts.AddFont("Hack-Regular.ttf", "HackRegular"); fonts.AddFont("Hack-Bold.ttf", "HackBold"); + // Subsetted Material Design Icons (microphone glyph U+F036C only, ~840 bytes) for + // the dictation cue (#14) — not the full ~1.3 MB MDI webfont. + fonts.AddFont("mdi-microphone.ttf", "MaterialIcons"); }); #if DEBUG diff --git a/Resources/Fonts/mdi-microphone.ttf b/Resources/Fonts/mdi-microphone.ttf new file mode 100755 index 0000000000000000000000000000000000000000..0fa5d7b6ff1932b07ddb0e0c390c51e4a1987cfd GIT binary patch literal 840 zcmZuvO=}ZT6g}_FWEz{ADom<2O-SoZY6Fc)+Jr(?(h@B~wPLj(E@VjaA><1ap_MMO zaOuL0-HCsp;HC@FAm~a#aOLmNZln;;n<*HHmwES{^X|DH^JX9b1kid92~oOMx$z$$m@ZA6w0K z2dXpVv5LbjCicZX#xTRI%tS<(#!URGSj?R>gJL9fF`Jax1v4raGS@^_AZ*(?+di0H zwi4FzbmDAuHWW!m#49`8os7pPyJ5R$=jV)-6=N=Mhi0Q^rqU4>RxQOY=2dT(x!@nC z-b3lQetg5}N8?wH5b)l1&wkxgTDAB4{r6HApGf`Q{3^oo$}v~;`aQ*{JC^!TFA2ft zC45vCM435jC;JgDfVV2)(^RQpyHmctjXdl2-5yEKuu7Gh*)uhQ&Smmn7om+6wK?zUrn5c#r3S@1v z3L0cLQACrdjk`Rr;3+i@)mv_k(y3?+X(W*vsy0~bZzVOcXS~h-n!1}&&UXp2aAW-* Rf;Fepz