Skip to content

feat(reminders): release review reminders - #22887

Open
ericli3690 wants to merge 4 commits into
ankidroid:mainfrom
ericli3690:ericli3690-reminders-intro-dialog
Open

ericli3690 wants to merge 4 commits into
ankidroid:mainfrom
ericli3690:ericli3690-reminders-intro-dialog

Conversation

@ericli3690

@ericli3690 ericli3690 commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Note

Assisted-by: Claude Opus 5.5

Screenshot_20261031_165542_AnkiDroid Screenshot_20261102_123844_AnkiDroid

Purpose / Description

This is the big one!

Releases review reminders to the general public, deleting the dev gate and all legacy notification code.

Migrates preferences accordingly. Users who previously had a legacy notification will see an orange warning dot (modelled after the sync warning dot) next to the review reminders setting in Settings. The dot disappears after ScheduleRemindersFragment is viewed once. These users also see a new dialogue when they first open ScheduleRemindersFragment.

Users who freshly install the app, or who did not have legacy notifications in the past and who upgrade the app, will not see any new visual cues. We will rely on the changelog to signpost that review reminders have arrived.

Fixes

Approach

Might as well do it all in one PR. In particular, I can't really implement the new UI cues if the actual legacy-notification-removal PR is not present yet. The four commits here should be cleanly revertable if issues occur upon release. We should carefully stage the release out to alpha, beta, etc. I will personally be more available and on hand to patch issues.

How Has This Been Tested?

  • Unit tests.
  • Physical Samsung S23, API 36, plus a physical Lenovo Tab M11, API 35.
  • Dialog shows up when it's supposed to.
  • Badge shows up when it's supposed to, even on wide screens.
  • Clicking into ScheduleRemindersFragment from the deck-specific view hides the app-wide Settings icon badge.
  • Review reminders all works.

Learning

Woopee! I've learned a lot contributing to AnkiDroid for the last year and a bit. Really wish we could have launched sooner, but life got in the way. Even software development as a skill and craft has changed so much since early 2025...

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

@ericli3690 ericli3690 self-assigned this Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

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

  • CustomStudyScreenshotTest: 1 change
  • DeckPickerTabletScreenshotTest: 3 changes
  • PreferencesScreenshotTest: 7 changes
  • ReviewRemindersScreenshotTest: 2 changes
  • StudyOptionsScreenshotTest: 3 changes
All 16 changed screenshots

CustomStudyScreenshotTest

  • tablet_unavailable_deck_compare.png

DeckPickerTabletScreenshotTest

  • 30_decks_tablet_compare.png
  • 30_decks_tablet_rtl_compare.png
  • keyboard_open_compare.png

PreferencesScreenshotTest

  • DeveloperOptionsFragment_compare.png
  • HeaderFragment_compare.png
  • HeaderFragment_gesture_bar_hidden_scrolled_to_bottom_compare.png
  • HeaderFragment_gesture_bar_scrolled_to_bottom_compare.png
  • HeaderFragment_portrait_compare.png
  • HeaderFragment_toolbar_collapsed_compare.png
  • HeaderFragment_toolbar_expanded_compare.png

ReviewRemindersScreenshotTest

  • settingsHostTablet_scheduleReminders_compare.png
  • settingsHostTablet_troubleshooting_compare.png

StudyOptionsScreenshotTest

  • keyboard_open_compare.png
  • landscape_compare.png
  • with_counts_compare.png

@ericli3690

Copy link
Copy Markdown
Member Author

I've checked the screenshot test diffs and they're all due to review reminders now being public. Ex. the bell icon showing up in the DeckPicker app bar.

@criticalAY

Copy link
Copy Markdown
Contributor

@ericli3690 your agent seems to have bypassed the rules, we don't want co-authored... in the commits, ensure you double check before pushing the changes

@criticalAY criticalAY added Needs Author Reply Waiting for a reply from the original author and removed Needs Review labels Nov 1, 2026
@ericli3690
ericli3690 force-pushed the ericli3690-reminders-intro-dialog branch from 83aaf60 to 1de97b9 Compare November 1, 2026 18:21
@ericli3690 ericli3690 added Needs Review and removed Needs Author Reply Waiting for a reply from the original author labels Nov 1, 2026
@ericli3690

Copy link
Copy Markdown
Member Author

@criticalAY Oops, sorry about that. Will make sure to enforce in the future 👍

Fixed!

@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

Thank you. The flag, the old settings screen, and the widget hook are gone together, and the upgrade test covers both sentinels and the unset key.

Rebased four commits onto current main locally with a clean replay; no force-push.

Local testing: lintAll, ktlintCheck, lint-rules:test; jacocoUnitTestReport; TEST_RELEASE_BUILD=true emulator suite on emulator-5556 / API35_GAPI. Lint, unit, and emulator lanes all passed.

RemoveLegacyNotificationPrefs is preference upgrade 30, after ResetAnalyticsOptIn2 at 29. performUpgrade runs upgrade and then stores that version. getPendingUpgrades keeps instances whose version is above the stored one, and getLatestVersion is the max of those ids.

HeaderPreference.showBadgeWhen calls refreshBadge, which sets isBadged. The setter wraps the current icon in BadgeDrawable and tints R.drawable.badge_drawable with badgeWarningColor. A second refresh while the condition is unchanged returns before wrapping again. Turning the condition off restores the inner drawable. onBindViewHolder sets the state description to settings_header_badge_state (New) only when the icon is a BadgeDrawable, and clears it on recycle. The listener is stored on the fragment because SharedPreferences keeps listeners in a WeakHashMap.

showIntroIfNeeded runs at the end of ScheduleRemindersFragment.onViewCreated. It uses the child FragmentManager. showDialogFragmentImpl executes pending transactions, removes any dialog under DIALOG_FRAGMENT_TAG, and commits the intro on the back stack with executePendingTransactions before the boolean is cleared. A later view creation finds the boolean false. The fragment manager restores the dialog itself.

The old daily alarm is AlarmManager.setRepeating with request code 0 and Intent(context, NotificationService::class.java), which has no action. BootService no longer schedules or cancels it. NotificationService.onReceiveBroadcast returns when intent.action is null, and returns again when the reminder id or scope parcel is missing. After reboot that alarm is gone, and boot only restores review-reminder alarms plus the widget rollover alarms. WidgetStatus.update launches the small-widget job only when widgetSmallEnabled is true. It no longer reads a notification preference or calls widgetNotificationScheduler.

some acceptable findings, no action required, just leaving for posterity: the legacy setRepeating daily wakeup is left in place until reboot; BootService.wasRun still says AnkiDroidApp runs this receiver though app start calls scheduleAllNotifications directly.

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

@mikehardy mikehardy added Needs Second Approval Has one approval, one more approval to merge and removed Needs Review labels Nov 2, 2026
@david-allison

Copy link
Copy Markdown
Member

(not pushing for changes, just opinion): how would you feel about moving the dialog into a default 'empty state' screen, rather than something that a user will see only once

@ericli3690

ericli3690 commented Nov 2, 2026 •

Copy link
Copy Markdown
Member Author

That... is a good idea. I will do that. Less dialog clutter, more long-term helping and feature explanation.

@david-allison Do you think we should still keep the little orange dot next to the icon for users who had legacy notifications in the past?

EDIT: Actually, wait, changing my mind. I think the existing UI is intuitive as is. The dialog is more to explain to users who had legacy notifications in the past that "AnkiDroid now has review reminders". That sentence wouldn't belong on the main screen. IMO either we keep the dialog with this kind of text, or we don't have a dialog at all. The main screen doesn't need extra text cluttering it up. Put another way, perhaps we should change the dialog text to be "Your old legacy notification has been removed. AnkiDroid now has improved review reminders. Try setting one!" or something like that; the dialog is for explaining the migration, not the feature.

@ericli3690
ericli3690 marked this pull request as draft November 2, 2026 10:28
@ericli3690
ericli3690 marked this pull request as ready for review November 2, 2026 10:34
@david-allison

Copy link
Copy Markdown
Member

Ahh - that works for a dialog. It doesn't need to be combative ("we've removed your notifications").

Go more for a style of "we've upgraded our notifications, [hope you enjoy them]" and it sounds good to go. (have fun with the text 😁).

Review reminders are now available to all users, replacing the legacy
notifications system. The 'Enable new notifications' developer option
and its `newReviewReminders` flag are removed, and the app behaves as if
it were enabled.

Removed:
* the 'Notifications' settings screen and its strings
* the legacy due-cards notification, its daily alarm and the widget
  hooks which triggered it
* `@LegacyNotifications` and `NotificationPreferences`

The legacy alarm survives app updates until the device restarts. When it
fires, `NotificationService` ignores it, as its intent has no action.

Assisted-by: Claude Opus 5.5
Adds a preference upgrade removing the preferences which were only
used by the legacy notifications system, including the
`newReviewReminders` developer flag.

Users who had a legacy due-cards notification enabled have the new
`shouldShowReviewRemindersIntro` preference set, so review reminders
can be introduced to them.

Assisted-by: Claude Opus 5.5
Any header in the main settings menu can now show a dot at the top-right
of its icon, to draw the user's attention to it:
`HeaderPreference.showBadgeWhen`.

The condition is re-checked whenever a preference changes, so a badge
clears as soon as its condition does, including on large screens, where
the header list stays visible beside the opened screen.

Screen readers announce badged headers as 'New'.

Assisted-by: Claude Opus 5.5
Users who had a legacy due-cards notification
(`shouldShowReviewRemindersIntro`) now see:
* a badge on the 'Review reminders' settings header
* `ReviewRemindersIntroDialog` when review reminders are first opened

Opening review reminders from anywhere, including a deck, clears the
preference, so the badge disappears and the dialog shows only once.

Assisted-by: Claude Opus 5.5
@ericli3690
ericli3690 force-pushed the ericli3690-reminders-intro-dialog branch from 1de97b9 to 554cc77 Compare November 2, 2026 20:40
@ericli3690

Copy link
Copy Markdown
Member Author

@david-allison Updated to be:

AnkiDroid’s notifications have been upgraded into more powerful review reminders! Try setting one to remind yourself to review your cards, or to review a specific deck in particular.

See screenshot in the PR description! Let me know if you dislike this copy or want to change it. Also rebased, but otherwise no other changes.

Also, does this PR need a strings sync?

@david-allison

david-allison commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

It should trigger the strings bot... CI is a little backed up right now

EDIT: 🤖 Beep boop; you broke the strings bot, I'll add the label 🤖 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Has Conflicts Needs Second Approval Has one approval, one more approval to merge Strings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Review reminders: migration

4 participants