Skip to content

feat(compose): text input improvements, reduced motion and better popup menus - #22800

Merged
mikehardy merged 11 commits into
ankidroid:mainfrom
david-allison:compose-dialog-fixes
Oct 28, 2026
Merged

mikehardy merged 11 commits into
ankidroid:mainfrom
david-allison:compose-dialog-fixes

Conversation

@david-allison

Copy link
Copy Markdown
Member

Note

Assisted-by: GPT-6-Astra xhigh

Purpose / Description

These 3 changes were split out of my 'Manage Tags' dialog:

Fixes

Approach

  • Multiple improvements to TextInputDialog.kt, in order to handle various iterations of my 'rename' operation
    • Split out into micro-commits to make them reviewable
  • Stop the input dialog moving on screen when the keyboard is already opening, it produced a 'jumpy' effect
  • The app bar menus were transparent, make them opaque

How Has This Been Tested?

A few tests, and screenshot tests added

Checklist

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

@mikehardy mikehardy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assisted-by: grok-4.7-medium

Thanks for splitting the compose dialog work — the behavior and motion fixes read well.

Local prep: clean rebase (no push). Lint, jacocoUnitTestReport, and release emulator tests on API35_GAPI / emulator-5556 all passed.

TextInputDialog gains selection, transforms, helper text, confirm-time validation, and pinned actions; AnkiDroidDialog / dialog_styles use fade-only window animation; Theme.kt blends translucent surface-container XML tints to opaque Compose colors. Robolectric + Roborazzi tests cover the dialog.

Some required GitHub matrix legs were still pending at review; lint/javascript and local prep were green.

@mikehardy mikehardy added the Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) label Oct 26, 2026
@david-allison david-allison added the Jetpack Compose Code or UI components built with or migrating to Jetpack Compose. label Oct 26, 2026
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Snapshot diff report vs main. Open screenshot-diff for diffs.

  • PreferencesScreenshotTest: 2 changes
  • TextInputDialogScreenshotTest: 4 changes
All 6 changed screenshots

PreferencesScreenshotTest

  • TimeboxSettingsFragment_compare.png
  • TimeboxSettingsFragment_disabled_compare.png

TextInputDialogScreenshotTest

  • add_profile_empty_light_compare.png
  • add_profile_valid_light_compare.png
  • large_text_short_window_input_light_compare.png
  • large_text_short_window_title_light_compare.png

@david-allison

david-allison commented Oct 26, 2026 •

Copy link
Copy Markdown
Member Author
TimeboxSettingsFragment_compare TimeboxSettingsFragment_disabled_compare

@criticalAY @BrayanDSO @ZornHadNoChoice

What do you feel about the above; I'm not too happy with it when it's a fullscreen view of the image, ambivalent when viewing a non-fullscreen image. EDIT: after viewing it for a minute, I like the 'after' better.


The below are new tests, the dialog would never look good on such a small screen with a huge font, but it's about as 'not terrible' as we can be

large_text_short_window_input_light_compare large_text_short_window_title_light_compare

@david-allison david-allison added Needs reviewer reply Waiting for a reply from another reviewer and removed Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) labels Oct 26, 2026
@david-allison
david-allison marked this pull request as draft October 26, 2026 20:26
@david-allison
david-allison marked this pull request as ready for review October 26, 2026 20:46
@david-allison david-allison added the Review High Priority Request for high priority review label Oct 26, 2026
@david-allison david-allison added this to the 2.26 release milestone Oct 27, 2026
@ZornHadNoChoice

Copy link
Copy Markdown
Collaborator

I lean towards the old toggle color, but the new one is fine if it looks like that on your Pixel device.

@david-allison

Copy link
Copy Markdown
Member Author

Google Pixel 9 Pro, for reference

Screenshot_20261027-024647

@mikehardy
mikehardy force-pushed the compose-dialog-fixes branch 3 times, most recently from 17cca46 to 8a96ed1 Compare October 27, 2026 11:15

@mikehardy mikehardy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assisted-by: grok-4.7-medium

Thanks for splitting this into small commits and for the Robolectric coverage of selection, deferred validation, and the fade.

Git: clean replay against current main (11/11 rebase); no push (act_sha 8a96ed16c4c286a455b38f046af3a5f1c9936ad1).

Local prep: lintAll / ktlintCheck / lint-rules:test, jacocoUnitTestReport, and TEST_RELEASE_BUILD=true emulator tests on API35_GAPI (emulator-5556) — all passed.

ProfileNameDialog is the only production caller. It still passes lengthOf = { it.trim().length }, maxLengthCounter = ProfileName.MAX_LENGTH, and errorMessageFor from ProfileName.validate plus the exists check. Defaults keep validateOnInput = true and enabled = true. Inside TextInputDialog, rememberSaveable(stateSaver = TextFieldValue.Saver) stores text and selection together; onValueChange calls transformInput only when the text differs. AnkiDroidDialog sets fade animations via SideEffect before dialog.show(). toMaterial3ColorScheme composites the five surfaceContainer* slots over surface, which is why the timebox switch track changed on light theme.

Blockers

  1. Commit history does not compile. Commit a241cd326f (refactor(compose): inline TextInputDialogCard) removes the lengthOf parameter while ProfileNameDialog still passes lengthOf = { it.trim().length } at that commit and through the next eight commits until 8a96ed16 puts lengthOf back. This PR is not squash-merge labelled, so those intermediate commits can land. Please restore lengthOf in the inline commit and drop the restore from the animation commit.

  2. Label accessibility regression. The label commit applies clearAndSetSemantics {} on the label Text, which removes it from Material3’s merged field semantics, then sets contentDescription on the field. That can make screen readers drop other information. The commit also applies testTag("text_input_label") before clearAndSetSemantics, so the tag is cleared. Please keep the merged label behavior or add a semantics assertion that documents the intended a11y outcome.

some acceptable findings, no action required, just leaving for posterity: three commit subjects exceed the 50-character suggestion; validateOnInput = false reserves an empty supporting line when helperText is null.

@mikehardy mikehardy added Needs Author Reply Waiting for a reply from the original author and removed Needs Review labels Oct 27, 2026
@david-allison david-allison removed the Needs Author Reply Waiting for a reply from the original author label Oct 27, 2026
@david-allison

Copy link
Copy Markdown
Member Author

hey... that compile error was your rebase 😆

@mikehardy

Copy link
Copy Markdown
Member

hey... that compile error was your rebase 😆

That's so excellent 😆 🫠 . Sincere apologies - I've told the loop that each commit needs to not just compile but also pass tests because we use git bisect, but I don't validate every commit. Which in a meta sense validates my family saying "if it's not tested, it's broken". Sigh

@criticalAY criticalAY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! just few questions

@david-allison david-allison added Needs Second Approval Has one approval, one more approval to merge and removed Needs reviewer reply Waiting for a reply from another reviewer labels Oct 27, 2026
Affects all surface containers.

Some of our XML colors are heavily transparent:

By using `compositeOver` this blends it with the opaque surface color
of the theme, producing a tinted window as expected, rather than
a semi-transparent popup menu.

Part of 10397

Assisted-by: GPT-6-Astra xhigh
Assisted-by: GPT-6.1-Sol xhigh
Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Callers can set the initial cursor/range (default: end of text).

Save text and selection together.
Selection changes do not mark the field as edited.

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
e.g. `Science Biology` => `Science::Biology`

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Text displayed when no validation error is displayed.

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Text below the title

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Validation can be deferred until confirmation.

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
For both the buttons + keyboard input

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
If vertical space is limited, the buttons should remain available.

Part of 10397

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Make the animations opacity-only.

Remove the motion from `AnkiDroidDialog` so the dialog does not
'jump' on dialogs which trigger focus/soft keyboard opening.

Part of 10397

Assisted-by: GPT-6-Astra xhigh
Assisted-by: GPT-6.1-Sol xhigh
@mikehardy
mikehardy force-pushed the compose-dialog-fixes branch from d660d5b to ffb2923 Compare October 28, 2026 14:04

@mikehardy mikehardy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assisted-by: grok-4.7-medium

Thanks for the small commits and the Robolectric coverage — this reads solid.

Prep rebased eleven commits onto current main with a trivial keep-both import fix in ThemeTest.kt, then force-with-lease pushed to the PR branch.

Local prep ran lintAll, ktlintCheck, and lint-rules:test, jacocoUnitTestReport, and TEST_RELEASE_BUILD=true emulator tests on API35_GAPI (emulator-5556); all passed.

ProfileNameDialog is the only production caller. It still passes lengthOf = { it.trim().length }, maxLengthCounter = ProfileName.MAX_LENGTH, and errorMessageFor from ProfileName.validate plus the exists check. Defaults keep validateOnInput = true and enabled = true, so the confirm button is disabled while the current text is invalid, and the error string stays hidden until the user edits. Inside TextInputDialog, rememberSaveable(stateSaver = TextFieldValue.Saver) stores text and selection together; the default range is the end of initialText. onValueChange calls transformInput only when the text differs, and that path sets hasUserEdited and clears submissionAttempted. A selection-only change writes the new TextFieldValue and does not mark the field edited. confirmIfValid returns immediately when enabled is false; otherwise it sets submissionAttempted and calls onConfirm only when a fresh errorMessageFor is null. The button and IME Done both use that function. With validateOnInput = false, errorMessageFor is not called until confirm, the confirm button stays enabled, and the next text edit clears the error until the next confirm. The custom Layout measures the button FlowRow first and gives the scrolling body maxHeight minus that height, so the actions stay on screen at 200% font in a 320dp window. AnkiDroidDialog sets R.style.Animation_AnkiDroidDialog from a SideEffect on the dialog window before the content draws; dialog_fade_in / dialog_fade_out are alpha animations. toMaterial3ColorScheme composites the five surfaceContainer* slots over surface, which is why the timebox switch track changed on light theme.

Some required GitHub matrix legs were still pending at review; local prep was green.

Screenshot changes have been detected, so leaving this for a good manual look.

@mikehardy
mikehardy added this pull request to the merge queue Oct 28, 2026
@mikehardy mikehardy added Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) and removed Review High Priority Request for high priority review Needs Second Approval Has one approval, one more approval to merge labels Oct 28, 2026
@david-allison

Copy link
Copy Markdown
Member Author

YESSSSS!!!! Thank you

Merged via the queue into ankidroid:main with commit 8bc4866 Oct 28, 2026
26 checks passed
@github-actions github-actions Bot removed the Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) label Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Jetpack Compose Code or UI components built with or migrating to Jetpack Compose.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants