Repository navigation
LT-22687: Add a UX guide and decision register under Docs/ux - #1191
jasonleenaylor wants to merge 3 commits into
Conversation
Docs/ux/README.md states how the FieldWorks UI should look and behave, in sections for universal rules, dialogs, browse views, detail views and interlinear text. Most rules keep long-standing WinForms behavior; the three that depart from it are marked as needing team consensus. A register tracks the adopted, provisional and temporary decisions. winforms-theme-baseline.md lists the WinForms colors and sizes beside the Avalonia tokens that replaced them, so divergence can be measured. Also points the ADR index and the Avalonia migration skills at the guide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NUnit Tests 1 files ± 0 1 suites ±0 8m 24s ⏱️ - 5m 50s Results for commit 48a65c9. ± Comparison against base commit 90318d4. This pull request removes 23 and adds 146 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1191 +/- ##
==========================================
+ Coverage 39.72% 39.88% +0.16%
==========================================
Files 1543 1542 -1
Lines 354916 355307 +391
Branches 41201 41315 +114
==========================================
+ Hits 140975 141724 +749
+ Misses 184589 184227 -362
- Partials 29352 29356 +4 🚀 New features to boost your workflow:
|
|
@MarlonH noted that there isn't any guidance on modal vs non-modal dialogs. I'll be adding a section about that. |
| A superseded entry stays in the table, marked as superseded and pointing to the | ||
| entry that replaces it. | ||
|
|
||
| | Decision | Status | Revisit trigger / end condition | Decided | |
There was a problem hiding this comment.
Add an ID column and a "Why" column (one sentence plus a Jira, ADR or commit link). Then rows can be cited, and a reader can see why a row is Provisional.
There was a problem hiding this comment.
Added the ID column (UX-1 to UX-5). I've left out a Why column: Decided already links each row's Jira issue or commit, and the revisit trigger says what would reopen a Provisional row.
| | Empty or appendable sequences in detail views show a "Type to add {item}" row as an extra in-place way to add; insert commands stay in the menus and section commands. | Adopted | — | 2026-08-11, LT-22687 | | ||
| | Sections that offer commands show them on the section header at all times (see *Sections and expansion*). | Adopted | — | 2026-08-11, LT-22687 | | ||
| | Section commands appear as one "Field options" link per section that opens a menu (WinForms shows one link per command), and that link is a Tab stop. | Provisional | LT-22693 | 2026-08-11, LT-22687 | | ||
| | Edit boxes in detail views have a visible border. | Provisional | Users push back on the look | 2026-08-11, LT-22687 | |
There was a problem hiding this comment.
"Users push back on the look" can't be checked. Say who reports it and where, for example a Jira label or a named review.
There was a problem hiding this comment.
Changed the trigger to "A Jira issue or user-testing report asks to remove the border".
| | Writing-system abbreviation color | #404040 (measured) | `Common/Controls/DetailControls/DetailControlsTests/DataTreeRenderTests.DataTreeRender_multiws.verified.png` | `FwWsAbbrevBrush` (#404040) | Match | | ||
| | Rule between rows | 1 px, `Color.LightGray` | `Common/Controls/DetailControls/DataTree.cs:1999` | `FwSliceRuleBrush` (LightGray), `DataTree.SliceRuleHeight` (1) | Match | | ||
| | Rule above a section header | 3 px, `Color.LightGray` (1 + `HeavyweightRuleThickness` 2) | `Common/Controls/DetailControls/DataTree.cs:199, 2000` | `FwSectionRuleBrush` (LightGray), `DataTree.SectionRuleHeight` (2) | Differs: 2 px, no register entry | | ||
| | Space above a section header rule | 10 px (`HeavyweightRuleAboveMargin`) | `Common/Controls/DetailControls/DataTree.cs:201` | `DataTree.SectionRuleMargin` (top 6) | Differs: 6 px, no register entry | |
There was a problem hiding this comment.
This "Differs" row says "no register entry", but L15-L18 calls that a bug. Please add a register entry and link it here. The same applies to the section-rule row (L33) and the button-height row (L53).
There was a problem hiding this comment.
The button-height row now cites the 24 DIP target rule. The section-rule height and margin (2 px, 6 px) came in with #964 and moved into tokens in #1083, with no note on why they differ from WinForms' 3 px and 10 px. Were those deliberate? If so I'll add a register entry; if not, they're bugs and I'll file them.
| it; then Help when a help topic exists. Buttons that act without closing the | ||
| dialog (Browse, Restore Defaults, Select All, More) do not join that group: | ||
| place them next to the content they affect, or at the bottom left. Enter | ||
| activates the confirming button and Esc cancels. A dialog that only shows |
There was a problem hiding this comment.
Enter activates the confirming button, which can be Delete (L192). Suggest: a confirmation that deletes data or can't be undone has no default button, so Enter does nothing and Esc cancels. GNOME says the same: dialogs. If the team keeps Enter-confirms for WinForms parity, record it as a register entry.
There was a problem hiding this comment.
Agreed, and it matches what ConfirmDeleteObjectDlg already does: no default button, with focus on Cancel. I added that as the exception to Enter-confirms.
|
|
||
| **Dialog buttons sit in one place and behave one way.** Buttons that close the | ||
| dialog form one group at the bottom right, in this order: the confirming button, | ||
| named for its action where that's clearer than OK (Delete, Merge, Create); any |
There was a problem hiding this comment.
Name the button with the verb and count for destructive actions ("Delete 12 Entries"), as Bulk Edit already does (L334-L336).
There was a problem hiding this comment.
The rule already names the button for its action (Delete). Bulk Edit puts the count in the confirmation message rather than on the button, which keeps the label free of plural forms.
| this rule: it may appear untranslated in the error report dialogs and in logs | ||
| meant for the development team. | ||
|
|
||
| ### Keyboard and assistive access |
There was a problem hiding this comment.
Add measurable accessibility rules from WCAG 2.2. Text contrast 4.5:1 (3:1 for large text), and 3:1 for control borders, icons and focus indicators (1.4.3, 1.4.11). ADR 0003 says the layout tests don't catch contrast defects.
There was a problem hiding this comment.
Added to Keyboard and assistive access. The current tokens already meet it.
| **Everything works without a mouse and can be read by assistive tools.** Every | ||
| control the user can act on can be reached and operated from the keyboard, in a | ||
| sensible Tab order that follows the visual reading order, and the focused item | ||
| is always visibly marked. Every such control has an accessible name in the |
There was a problem hiding this comment.
The focus indicator should be always visible and never completely hidden by another element (WCAG 2.4.7, 2.4.11). Motif checks focus-ring contrast at 3.0: ContrastTests.cs.
There was a problem hiding this comment.
The guide already required a visible focus mark, and 3:1 contrast for focus marks is in the contrast sentence added for the earlier comment. I added "never fully hidden behind other content" for 2.4.11.
|
|
||
| **Everything works without a mouse and can be read by assistive tools.** Every | ||
| control the user can act on can be reached and operated from the keyboard, in a | ||
| sensible Tab order that follows the visual reading order, and the focused item |
There was a problem hiding this comment.
Add a target size rule: pointer targets at least 24 by 24 DIP unless spaced apart (WCAG 2.5.8). Also text scales to 200% and a narrow window doesn't force two-way scrolling (1.4.4, 1.4.10).
There was a problem hiding this comment.
Added a 24 DIP target rule for controls, which DialogMinControlHeight already follows. Browse rows stay at the view's row height (18, matching WinForms density). I've left out 200% text and reflow: FieldWorks' browse and interlinear views are wide data by design.
| is always visibly marked. Every such control has an accessible name in the | ||
| interface language (usually its visible label) and a stable automation id that | ||
| does not change with language or layout, so screen readers and automated tests | ||
| can find it. Icon-only buttons always have a tooltip that matches their |
There was a problem hiding this comment.
Add an icon rule: one icon set and grid, sizes from theme tokens, vector shapes coloured by a theme brush so they follow any theme. Icons never carry meaning alone (WCAG 1.4.1). Motif draws sidebar icons as path data on a 24-unit grid: PageRegistry.cs.
There was a problem hiding this comment.
Leaving this out for now. The Avalonia screens draw one icon so far (the HoverReveal gear, which is already vector, theme brush, token size); an icon rule can come with the first icon set.
| keeps the user's place; how each tool shows those records belongs to that tool. | ||
| These settings are kept per project and per user. Anything remembered can be | ||
| returned to its default from where it was set (Show All in a filter, the default | ||
| sort, the default columns). |
There was a problem hiding this comment.
The guide has no progress rule. Suggest: say in words what is happening ("Parsing word 120 of 500"); determinate bar when the total is known; modal progress dialog only for blocking work, otherwise the status bar; Cancel only when possible, saying what it leaves behind.
There was a problem hiding this comment.
Added a Long-running work rule: specific progress when the amount of work is known, indeterminate otherwise, words for what is happening and for the outcome, and reuse of the existing progress classes.
| keeps the user's place; how each tool shows those records belongs to that tool. | ||
| These settings are kept per project and per user. Anything remembered can be | ||
| returned to its default from where it was set (Show All in a filter, the default | ||
| sort, the default columns). |
There was a problem hiding this comment.
Progress should never freeze the window, and should report completion or failure in words, not just by the bar disappearing. Motif's status bar switches between determinate and indeterminate: MainWindow.axaml.
There was a problem hiding this comment.
Covered in the same new rule: the window never freezes, and the outcome is reported in words.
| **Dialogs are compact, owned windows.** A dialog belongs to the window that | ||
| opened it: it opens centered on that window, stays in front of it, has no | ||
| minimize or maximize button, and doesn't appear separately in the taskbar. It | ||
| shows the FieldWorks icon. Layout is compact, matching the density users know |
There was a problem hiding this comment.
Add a DPI rule: all sizes are DIP, and each screen is checked at 100% and 150% display scaling and at the smallest supported window. Motif runs layout tests at both scales: LayoutInvariantFixtures.cs.
There was a problem hiding this comment.
Added. Avalonia sizes are already DIP. The layout tests run at one scale today, so this is a check for now rather than a test.
| minimize or maximize button, and doesn't appear separately in the taskbar. It | ||
| shows the FieldWorks icon. Layout is compact, matching the density users know | ||
| from FieldWorks rather than roomy default spacing. A dialog whose content can | ||
| grow (lists, trees, previews, long text) is resizable, has a sensible minimum |
There was a problem hiding this comment.
"Sensible minimum size" has no number. Suggest stating the minimum interactive control height (24 DIP, from baseline L53) and the minimum window size per view. Note browse rows at 18 (baseline L45) are below WCAG 2.5.8's 24 unless spacing applies.
There was a problem hiding this comment.
The 24 DIP control height and the browse-row exception are now in Keyboard and assistive access (from your target-size comment). For dialog minimum size I replaced "sensible" with "every control stays visible and usable". A per-view number would differ for every dialog.
| **Every word the user reads can be translated.** All interface text, including | ||
| labels, tooltips, messages, accessible names and the "…" on commands, comes from | ||
| localizable resources, never from strings written in code. Messages are whole | ||
| sentences with placeholders ("Delete {0}?"), not fragments joined in code, |
There was a problem hiding this comment.
Counts need plural forms. "1 change" and "5 changes" can't share one {0} string in many languages. Suggest: a message with a count is one plural message (for example ICU MessageFormat), never {0} item(s), never n == 1 ? a : b in code.
There was a problem hiding this comment.
Leaving this out; it's more specific than this guide needs. FieldWorks has avoided the need for plural-aware messages up to this point.
| control the user can act on can be reached and operated from the keyboard, in a | ||
| sensible Tab order that follows the visual reading order, and the focused item | ||
| is always visibly marked. Every such control has an accessible name in the | ||
| interface language (usually its visible label) and a stable automation id that |
There was a problem hiding this comment.
Make the automation id rule testable: IDs are never built from translated text or position, are unique within a window, are defined in one place, and carry a prefix when hosted in another shell. Motif keeps them in one class and tests uniqueness: AutomationIds.cs.
There was a problem hiding this comment.
Added: never from translated text, unique within the window, prefixed with the dialog or view name, which current ids already follow (AddNewSense.Ok). Ids are declared beside their controls in each dialog's XAML rather than in one class, so I've left "defined in one place" out.
|
|
||
| ### Theme values | ||
|
|
||
| **Every color, size and spacing comes from the theme.** Screens use named theme |
There was a problem hiding this comment.
Suggest adding: colour tokens are defined per theme variant (ThemeDictionaries) and used with DynamicResource, never as literals in a view or code. This keeps dark mode possible later. See Avalonia theme variants.
There was a problem hiding this comment.
Added to Theme values. FwColorTokens.axaml already defines its brushes per variant; this makes DynamicResource the rule for using them.
| minimize or maximize button, and doesn't appear separately in the taskbar. It | ||
| shows the FieldWorks icon. Layout is compact, matching the density users know | ||
| from FieldWorks rather than roomy default spacing. A dialog whose content can | ||
| grow (lists, trees, previews, long text) is resizable, has a sensible minimum |
There was a problem hiding this comment.
Add: a component may alias Semi keys but must not override them app-wide; heights come from its own control themes. Motif overrides SemiHeightControlSmall to 26 for its whole app (Primitives.axaml), which would change FieldWorks' DialogMinControlHeight in a shared shell. We plan to scope it.
There was a problem hiding this comment.
Follow-up: Motif now does this. The 26/28 px height overrides moved out of the app-wide Primitives into a ControlHeights dictionary merged only into Motif's own window roots (main window, flyouts, diagnostic, problem-report and crash windows). Semi controls outside those roots keep Semi's own heights, and no Semi key is overridden application-wide. sillsdev/motif@4edc8dbe2
There was a problem hiding this comment.
Added under Theme values: FieldWorks tokens alias Semi keys and never redefine one, which FieldWorks already follows (no Semi key is set anywhere in its XAML). Thanks for scoping Motif's overrides.
|
|
||
| ### Checking input | ||
|
|
||
| > **Needs team consensus.** Intentional departure from WinForms; modernization. |
There was a problem hiding this comment.
This is one of three "Needs team consensus" notes (also L236, L433-L434). Suggest a register entry for each, marked Provisional with a revisit trigger, so the open decisions are visible in one place.
There was a problem hiding this comment.
Added UX-6 to UX-8 as Provisional, and each note now cites its row.
|
|
||
| ### Checking input | ||
|
|
||
| > **Needs team consensus.** Intentional departure from WinForms; modernization. |
There was a problem hiding this comment.
Motif plans to follow this as written: problems show next to the item, not in message boxes. We have no field-level error pattern yet to compare.
| > **Needs team consensus.** Last sentence: field-level problem display replaces | ||
| > WinForms message boxes. | ||
|
|
||
| **Edits save themselves, one undoable step per field.** There is no Save button |
There was a problem hiding this comment.
Add a scope note: undo covers only the commands this guide says are undoable. An operation that can't be undone says so before it runs and, where possible, offers a preview first. Bulk Edit already does the first part (L335-L337).
There was a problem hiding this comment.
Added: a command that can't be undone says so before it runs. The guide doesn't list which commands are undoable, so I left out the scope note, and preview stays Bulk Edit's.
| | Sections that offer commands show them on the section header at all times (see *Sections and expansion*). | Adopted | — | 2026-08-11, LT-22687 | | ||
| | Section commands appear as one "Field options" link per section that opens a menu (WinForms shows one link per command), and that link is a Tab stop. | Provisional | LT-22693 | 2026-08-11, LT-22687 | | ||
| | Edit boxes in detail views have a visible border. | Provisional | Users push back on the look | 2026-08-11, LT-22687 | | ||
| | Tab stops at the first and last detail-view row instead of carrying on into the rest of the window. | Temporary | The whole window is Avalonia (LT-22688) | 2026-09-22, commit 23965cd67 | |
There was a problem hiding this comment.
Proposed register row from #1196 (LT-22854): "The Avalonia interface font is set by the theme token FwUiFontFamily and bundled, with per-language fallbacks for fa, hi, ko, te and zh-CN. Proposed default: Andika 7.000. Writing-system fonts are unchanged." Status: Proposed until #1196 merges. Revisit: the team picks a different default (alternatives in ADR 0004).
| | --- | --- | --- | --- | --- | | ||
| | OK / Cancel / Help button size | 75 × 23 px | `FwCoreDlgs/FwStylesDlg.resx:516-517, 546-547` | `DialogMinControlHeight` (Semi `SemiHeightControlSmall`, 24) | Differs: 24 px minimum height, kept for the pointer-target size (token comment); no register entry | | ||
| | Gap between dialog buttons | 6 px | `FwCoreDlgs/FwStylesDlg.resx:513-514, 543-544` | `DialogButtonStripGap` (Semi `SemiSpacingTight`) | Check: Semi step value not yet confirmed | | ||
| | Interface font | MS Sans Serif, 8.25 pt | Form designer defaults (for example `FwCoreDlgs/FwStylesDlg.resx`) | `FwSurfaceFontSize` (11 px, about 8.25 pt) | Match | |
There was a problem hiding this comment.
If #1196 (LT-22854) merges, this row becomes "Differs": the interface font is the bundled default (Andika, 11 px), not the platform font. Lines are about 3 px taller (1.61 em vs 1.33 em). Register entry: ADR 0004.
There was a problem hiding this comment.
Same as the register row: whichever of this PR and #1196 merges second updates this row to Differs and cites ADR 0004.
Answers the first review round on the UX guide. - Keyboard and assistive access: WCAG 2.2 AA contrast, a 24 DIP target size for controls, focus never fully hidden, and rules for automation ids. - New Long-running work rule: specific progress when the amount of work is known, indeterminate otherwise, reusing the existing progress classes. - Theme values: color tokens per theme variant via DynamicResource, and FieldWorks never redefines a Semi key. - Delete and can't-undo confirmations focus Cancel, so Enter does not delete. - Dialogs are checked at 100% and 150% scaling, and their minimum size keeps every control usable. - A command that can't be undone says so before it runs. - Decision register: add an ID column, add UX-6 to UX-8 for the three team-consensus notes, and give UX-4 a checkable trigger. - Baseline: the button-height row cites the target-size rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A converted window keeps the modality of its WinForms version. In WinForms nearly every dialog is modal (ShowDialog); the few modeless windows are tools that act on the content behind them (Find and Replace) and companion windows kept open during work (Try A Word, parser reports). Changing a window's modality needs a register entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Added Modal and modeless windows under Dialogs. |
Docs/ux/README.md states how the FieldWorks UI should look and behave, in sections for universal rules, dialogs, browse views, detail views and interlinear text. Most rules keep long-standing WinForms behavior; the three that depart from it (checking input, advanced options, and field-level problems in detail views) are marked as needing team consensus. A register tracks the adopted, provisional and temporary decisions.
winforms-theme-baseline.md lists the WinForms colors and sizes beside the Avalonia tokens that replaced them, so divergence can be measured.
Also points the ADR index and the Avalonia migration skills at the guide.
Why
The Avalonia conversions were settling UX questions one screen at a time, in Jira comments and code blocks, so the same question got argued again in the next conversion. LT-22687 asked for one place to hold those decisions. The guide pulls in the WinForms conventions users already rely on, guided by the stealth-to-wealth design FieldWorks has always had.
🤖 Generated with Claude Code
This change is