Skip to content

Merge upstream AnkiDroid - #64

Open
float3 wants to merge 338 commits into
float3:ankiquestfrom
ankidroid:main
Open

float3 wants to merge 338 commits into
float3:ankiquestfrom
ankidroid:main

Conversation

@float3

@float3 float3 commented Oct 15, 2026

Copy link
Copy Markdown
Owner

10 new commits from ankidroid/Anki-Android main.

Merge with a merge commit, never squash or rebase, so ankiquest keeps upstream's history.

If this conflicts, merge ankidroid/Anki-Android main into a branch from ankiquest, resolve there, and merge that branch instead; this pull request then shows as merged.

@github-actions

Copy link
Copy Markdown

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

  • AddEditReminderDialogScreenshotTest: 1 change
  • ChangeNoteTypeDialogScreenshotTest: 26 changes
  • CollectionTooLargeScreenshotTest: 1 change
  • DeckPickerScreenshotTest: 10 changes
  • DeckPickerTabletScreenshotTest: 2 changes
  • LocaleSelectionDialogScreenshotTest: 2 changes
  • MultimediaScreenshotTest: 5 changes
  • NavigationDrawerScreenshotTest: 2 changes
  • NoteEditorScreenshotTest: 2 changes
  • PreferencesScreenshotTest: 2 changes
  • PreviewerScreenshotTest: 1 change
  • ReviewRemindersScreenshotTest: 5 changes
  • SortOrderBottomSheetFragmentScreenshotTest: 3 changes
  • StudyScreenScreenshotTest: 6 changes
  • TagsDialogScreenshotTest: 1 change
  • TemplatePreviewerScreenshotTest: 1 change
All 70 changed screenshots

AddEditReminderDialogScreenshotTest

  • delete_confirmation_dialog_compare.png

ChangeNoteTypeDialogScreenshotTest

  • desktop_fields_fit_viewport_compare.png
  • desktop_gesture_navigation_compare.png
  • desktop_landscape_compare.png
  • desktop_long_note_type_names_large_text_landscape_compare.png
  • desktop_long_note_type_names_large_text_narrow_portrait_compare.png
  • desktop_many_fields_large_text_landscape_compare.png
  • desktop_many_fields_scrolled_to_bottom_compare.png
  • desktop_many_templates_large_text_landscape_compare.png
  • desktop_many_templates_scrolled_to_bottom_compare.png
  • desktop_portrait_compare.png
  • desktop_portrait_cutout_compare.png
  • desktop_templates_fit_viewport_compare.png
  • desktop_templates_tab_large_text_compare.png
  • fields_fit_viewport_compare.png
  • gesture_navigation_compare.png
  • landscape_compare.png
  • long_note_type_names_large_text_landscape_compare.png
  • long_note_type_names_large_text_narrow_portrait_compare.png
  • many_fields_large_text_landscape_compare.png
  • many_fields_scrolled_to_bottom_compare.png
  • many_templates_large_text_landscape_compare.png
  • many_templates_scrolled_to_bottom_compare.png
  • portrait_compare.png
  • portrait_cutout_compare.png
  • templates_fit_viewport_compare.png
  • templates_tab_large_text_compare.png

CollectionTooLargeScreenshotTest

  • collection_too_large_dialog_compare.png

DeckPickerScreenshotTest

  • deck_list_after_dismissing_create_deck_dialog_compare.png
  • edgeToEdge_30_decks_compare.png
  • hierarchy_lines_collapsed_compare.png
  • hierarchy_lines_compare.png
  • hierarchy_lines_deep_nesting_compare.png
  • hierarchy_lines_many_siblings_compare.png
  • keyboard_open_scrolled_to_bottom_compare.png
  • keyboard_studied_line_overlaying_deck_name_compare.png
  • snackbar_keyboard_closed_compare.png
  • snackbar_keyboard_open_compare.png

DeckPickerTabletScreenshotTest

  • 30_decks_tablet_compare.png
  • keyboard_open_compare.png

LocaleSelectionDialogScreenshotTest

  • landscape_compare.png
  • portrait_compare.png

MultimediaScreenshotTest

  • image_editor_camera_compare.png
  • image_editor_compare.png
  • image_editor_drawing_compare.png
  • image_editor_error_compare.png
  • landscape_compare.png

NavigationDrawerScreenshotTest

  • navigationDrawer_compare.png
  • sideNavigationBar_compare.png

NoteEditorScreenshotTest

  • tablet_compare.png
  • tablet_keyboard_compare.png

PreferencesScreenshotTest

  • AnkiquestStudySettingsFragment_compare.png
  • SwitchProfilesFragment_compare.png

PreviewerScreenshotTest

  • base_compare.png

ReviewRemindersScreenshotTest

  • studyOptionsFragmentHost_scheduleReminders_compare.png
  • studyOptionsFragmentHost_systemBars_compare.png
  • studyOptionsFragmentHost_systemBars_scrolledToEnd_compare.png
  • studyOptionsFragmentHost_troubleshooting_compare.png
  • studyOptionsFragmentHost_troubleshooting_systemBars_compare.png

SortOrderBottomSheetFragmentScreenshotTest

  • landscape_compare.png
  • landscape_scrolled_to_bottom_compare.png
  • landscape_scrollshot_compare.png

StudyScreenScreenshotTest

  • bar=BOTTOM_frame=CARDbttns=false_compare.png
  • bar=BOTTOM_frame=CARDbttns=true_compare.png
  • bar=NONE_frame=CARDbttns=false_compare.png
  • bar=NONE_frame=CARDbttns=true_compare.png
  • bar=TOP_frame=CARDbttns=false_compare.png
  • bar=TOP_frame=CARDbttns=true_compare.png

TagsDialogScreenshotTest

  • empty_tags_compare.png

TemplatePreviewerScreenshotTest

  • base_compare.png

david-allison and others added 28 commits October 20, 2026 23:27
* Replace both branches with one, using the offsets in the enum
* Use one listener for both buttons.
* Return early when animations are disabled

Assisted-by: GPT-6-Astra default
It looked bad: color change, collapsing, etc...

and clear stale FAB dismissal listeners

`addNote()` now:

* Sets `pendingMenuReset` - ensures the code runs once
* Sets `!isFABOpen` for saved state
* Opens the editor, without changing appearance

The reset either occurs:
* `onStop` when the deck screen becomes hidden.
* `onResume` - workaround for multi-window mode

Fixes 22580

Assisted-by: GPT-6-Astra default
Allow simultaneous runs to occur:

* very fast check
* can cause a required check to show as canceled, wasting dev time

Fixes 22619

Assisted-by: GPT-6-Astra default
For work belonging to a fragment's current view which should
be canceled/skipped if the view is destroyed.

Part of 22065

Assisted-by: GPT-6
Assisted-by: GPT-6-Astra xhigh
A fragment replacement can detach the options before the refresh starts.

Part of 22065

Assisted-by: GPT-6
Assisted-by: GPT-6-Astra xhigh
Part of 22065

Assisted-by: GPT-6
Assisted-by: GPT-6-Astra xhigh
A deck list refresh could outlive the screen and cause a collection to
be reopened which is held by another backend.

Fix this by not requesting that the collection is reopened.

Part of 20986

Assisted-by: GPT-6-Astra xhigh
Prep for a `Config` delegation refactor

Assisted-by: GPT-6-Astra xhigh
Part of 22249

Assisted-by: GPT-6
Assisted-by: GPT-6-Astra default
Assisted-by: GPT-6-Astra xhigh
For:
* completion navigation
* preference handling
* messages (legacy)

Extracted from `CongratsPage`

Part of 22249

Assisted-by: GPT-6-Astra xhigh
Combine details of the study state in one object, produced while in
`withCol`.

Make a distinction between an empty deck and a non-empty deck which can't
be studied.

Use this to determine if the `Congrats` page should be shown,
 and to replace a legacy `cardsInDeck` boolean for a snackbar.

Part of 22249

Assisted-by: GPT-6-Astra xhigh
...when building `StudyOptionsState`

Part of 22249.

Assisted-by: GPT-6-Astra xhigh
Dragging the tablet divider could shrink a pane to as little as a
tenth of the screen, too narrow to use, and worse with a large font.
Each pane now keeps at least 240dp times the font scale, also when a
saved layout opens or the screen rotates.

Fixes 22533

Assisted-by: Claude Opus 5.5
On slow runners the test jumped the clock ahead while the login was
still finishing, so the progress dialog opened over the error dialog.
Wait for the login to finish instead.

Assisted-by: Claude Opus 5.5
Part of 22609

Assisted-by: GPT-6-Astra default
Adds a 104dp bottom margin, so the list can scroll past the final item

Fixes 22609

Assisted-by: GPT-6-Astra xhigh
Some devices refuse to save a shared deck download into AnkiDroid's own
storage folder, and opening the download screen crashed. Now the screen
shows the download as failed, with Try again and Open in browser, and
the error is reported.
On some devices Android rejects our own folder as a download
destination. Instead of failing, download into DownloadManager's
own storage and import the deck from there.
CALLER_KEY was a top-level public constant, but only NoteEditorFragment
uses it, so it now lives in the companion object as a private constant.

Issue 22408

Assisted-by: Claude Opus 5.5
onCreate restored the formats from whichever bundle it had, so saved
state was read with the intent extra keys. It now reads saved state
and the intent separately, so their keys can be named apart.

Issue 22408

Assisted-by: Claude Opus 5.5
Rename the saved instance state key constants that didn't follow the
STATE_ convention. Keys that were also intent extras or preference keys
get their own STATE_ constant instead. The key strings stay the same.

Issue 22408

Assisted-by: Claude Opus 5.5
Constants used as keys in the saved instance state bundle now need the
STATE_ prefix, so new keys follow the same naming as the rest.

Fixes 22408

Assisted-by: Claude Opus 5.5
Also delegate Config.browserSortNotesColumn.

Assisted-by: GPT-6-Astra xhigh
Also delegate Config.browserSortNotesBackwards.

Assisted-by: GPT-6-Astra xhigh
Restore the mandatory scheduler decision with a DialogFragment and deliver its result to the current DeckPicker. Keep the existing upgrade, Cancel, Back and help behavior without retaining activity-owned callbacks.

Add phone and tablet regression tests for repeated recreation, collection refreshes, confirmation and cancellation.

Fixes #22632

GPT-6.1 Sol implemented the lifecycle fix and regression tests.

Assisted-by: GPT-6.1 Sol
on the 26.04 runner, `/tmp` is RAM-backed.

Issue 22664
Related: https://redirect.github.com/actions/runner-images/issues/14777#issuecomment-5814952530

Assisted-by: GPT-6.1-Sol xhigh
david-allison and others added 30 commits October 25, 2026 00:01
Skip backend defaults for empty and hidden decks.

'Default' can still appear in Study Options after becoming unavailable (22249)
If this occurs, dismiss the dialog and show a snackbar.

Part of 22249

Assisted-by: GPT-6-Astra xhigh
Assisted-by: GPT-6.1-Sol xhigh
Deleted/empty/hidden default decks now show a snackbar rather than
opening the dialog using old defaults.

Part of 22249

Assisted-by: GPT-6.1-Sol xhigh
Part of 22249

Assisted-by: GPT-6.1-Sol xhigh
Part of 22249

Assisted-by: GPT-6.1-Sol xhigh
* Helper
* ViewModel

Not integrated yet.

This models the operation of taking an image, copying it, passing it to an
external editor, then processing the results safely.

File operations are off the main thread, and format detection is implemented

Validate copied image headers before import and derive the extension from
the detected format. Reject non-image results and preserve the original
when editing is cancelled, even after writes to the working copy.

GPT-6.1-Sol xhigh implemented result validation and seven regression cases,
and documented the intentional cancellation behavior.

Part of 14222

Assisted-by: GPT-6.1-Sol high
Assisted-by: GPT-6-Astra xhigh
Assisted-by: GPT-6.1-Sol xhigh
Integrates the past ViewModel and helper: an 'Edit' item is shown
when there are available editors on the phone.

Handles activity lifecycle, previewing files, handling edits which
are no-ops or canceled, and general error handling from the action.

GPT-6.1-Sol xhigh updated the import and lifecycle tests to use real PNG
data with the helper's image-header validation.

Fixes 14222

Assisted-by: GPT-6.1-Sol high
Assisted-by: GPT-6-Astra xhigh
Assisted-by: GPT-6.1-Sol xhigh
Fixes 14222

Assisted-by: GPT-6-Astra xhigh
Part of 6017

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Use `originalTemplateOrds` and add `deletedTemplateOrds` to track unsaved
additions, and the ordinals of deleted templates.

This allows us to replace CardTemplateChanges.kt entirely.

Part of 6017

GPT-6.1-Sol xhigh implemented the tracking refactor and its tests.

Assisted-by: GPT-6.1-Sol xhigh
* Enable the existing reposition dialog

Fixes 6017

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6-Astra xhigh
Mocking `BackendTranslations` was a very heavy call as the class
was large.

We now have `PreviewTranslations` which improves performance as
the strings are hardcoded.

Part of 22758

Assisted-by: GPT-6.1-Sol xhigh
Replace the ambiguous instructions and bare number field with +/- stepper buttons and clearer copy. Renamed the confirm button from OK to Increase

Signed-off-by: Owm <[email protected]>
Handled by Crowdin

Assisted-by: GPT-6-Astra xhigh
* `Deck.name`
* `Deck.id`

Co-authored-by: David Allison <[email protected]>
Assisted-by: GPT-6

Assisted-by: GPT-6.1-Sol xhigh
Assisted-by: GPT-6

Assisted-by: GPT-6.1-Sol xhigh
Add:
* `deck.noteTypeId`
* `deck.resched`

GPT-6 split and adapted this part of the original change.

Assisted-by: GPT-6

Assisted-by: GPT-6.1-Sol xhigh
We're getting a lot of people breaking the policy.
Adding it to another location may help.

Assisted-by: GPT-6.1-Sol xhigh - initial wording
Assisted-by: GPT-6-Astra xhigh - applying fixups
This makes the following syntax suggested, but optional:

```
> [!NOTE]
```

There were many places where it was overkill, and a short sentence
would be more high-signal.

This suggestion is maintained in the PR template, as standardization
for PRs is useful for reviewers.

Assisted-by: GPT-6.1-Sol xhigh - initial wording
Assisted-by: GPT-6-Astra xhigh - applying fixups
Mike has a LLM-assisted review loop which I find extremely useful,
and I want a general exception for this style of reviews
(assuming it's not slop).

David often posts GPT-6 patches with failing regression tests

Assisted-by: GPT-6.1-Sol xhigh - initial wording
Assisted-by: GPT-6-Astra xhigh - applying fixups
Now, only the tool name + optional effort level is required, not
a description of what the tool performed.

I found myself deleting this disclosure and it didn't catch on:

* It made the commit messages more verbose than necessary
* I only found it useful when there were multiple tools and wanting to differentiate what each tool did.

Assisted-by: GPT-6.1-Sol xhigh - initial wording
Assisted-by: GPT-6-Astra xhigh - applying fixups
`n1snt` is doing a great job:

* Split out an issue from a huge AI-generated epic
  * https://redirect.github.com/david-allison/Anki-Android/issues/71
* Generate an issue:
  * https://redirect.github.com/ankidroid/Anki-Android/issues/22632
* Self-assign and add a PR

This is a great use of AI, allowing a contributor to move quickly, while
keeping the work auditable. I want this to be explicitly allowed.

Assisted-by: GPT-6.1-Sol xhigh - initial wording
Assisted-by: GPT-6-Astra xhigh - applying fixups
The error dialog's deck options and advanced settings help actions
no longer need the app's toIntent functions.

Assisted-by: Claude Opus 5.5
* Duration card has a neutral background

Part of 22750

Assisted-by: GPT-6.1-Sol xhigh
* buttons: white background + black border
* match the textbox with the button border thickness
* opaque textbox background

Part of 22750

Assisted-by: GPT-6.1-Sol xhigh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.