Skip to content

feat(reminders): streamline review reminders UI#21140

Draft
ericli3690 wants to merge 11 commits into
ankidroid:mainfrom
ericli3690:ericli3690-schedule-reminders-frag-rework
Draft

feat(reminders): streamline review reminders UI#21140
ericli3690 wants to merge 11 commits into
ankidroid:mainfrom
ericli3690:ericli3690-schedule-reminders-frag-rework

Conversation

@ericli3690
Copy link
Copy Markdown
Member

@ericli3690 ericli3690 commented May 25, 2026

Purpose / Description

This change was originally proposed by @BrayanDSO. Thanks Brayan!

Also, after #18734 got in, you probably are capable to stop using a separate Activity for the ScheduleReminders fragment

This took a long time to get right and required a lot of iteration. I had to scrap a lot of approaches. I also ran into a lot of issues that I consider out of scope with regards to this PR. I've added TODO comments and might create some issues.

As of right now, the code is lacking screenshot tests and unit tests. I will add them once the broad approach of this PR is validated and accepted.


ScheduleReminders can be hosted in multiple places, each of which presents their own unique UI challenges:

  1. Long-pressing a deck from DeckPicker: On small screens, there is no suitable activity currently available, and so we should launch one to host ScheduleRemindersFragment in the form of SingleFragmentActivity. On large screens, there MAY be a right-side panel available (it is hidden in the edge case where the collection is empty); the UI looks cleanest if it is used.
  2. Clicking on the "bell" icon from StudyOptionsFragment: On small screens, StudyOptionsActivity is currently active, and so it should be used as the host rather than launching a new activity. However, it manages an external toolbar and so using an internal toolbar would not work. We need to latch onto the external support action bar and modify it. On large screens, the right-side panel is available similar to option 1 if the collection is non-empty.
  3. The screen may be launched from Settings, in which case the user is inspecting all reminders across all decks. Here, it should match the style of the other Settings Preferences screens, i.e. a collapsing toolbar, and should align whether on a small screen or large screen.
phone.mp4
tablet.mp4

Fixes

  • Fixes long-standing UI inconsistencies for review reminders.

Approach

Previously:

  • The ScheduleRemindersFragment was always launched in a SingleFragmentActivity.
  • This made it stylistically stick out like a sore thumb inside the Settings menu, particularly on wide screens.
  • It unnecessarily creates new activities all over the place when it could use pre-existing activities, like StudyOptionsActivity, that are already active.

Now:

  • The ScheduleRemindersFragment renders using the current available activity if possible, modifying its styling and toolbar as necessary.
  • Logic for doing so is encapsulated in FragmentHost and ToolbarType. In my opinion, this is the cleanest way to handle the various ways ScheduleRemindersFragment can be launched, keeping all logic centralized within the file and maintaining a single source of truth.

How Has This Been Tested?

  • Permission requesting dialog works as before.

  • The permission requesting Snackbar auto-dismisses upon navigating away from the fragment.

  • Searching for "Notifications" or "Review Reminders" in settings locates the setting.

  • Rotation of all screens works.

  • Visuals on all screens have no visual glitches.

  • Creating, updating, viewing, and deleting reminders works.

  • All four app themes work.

  • When the collection is empty and the right-hand study options fragment panel is hidden on a tablet, long-clicking to open schedule reminders opens it in SingleFragmentActivity.

  • Tested on a emulated Google Pixel, API 25.

  • Tested on a physical Lenovo Tab M11, API 35.

  • Tested on a physical Samsung S23, API 36.

Learning

  • See the TODO comments.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 25, 2026

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

  • PreferencesScreenshotTest: 1 change
All 1 changed screenshots

PreferencesScreenshotTest

  • ScheduleRemindersFragment_compare.png

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors how the “Review reminders” screens are routed and displayed across Settings, Study Options, and DeckPicker, moving toward fragment-based navigation with more flexible toolbar handling.

Changes:

  • Route “Review reminders” as a ScheduleRemindersFragment destination (Settings header, preference search, Study Options, DeckPicker side panel).
  • Rework the Schedule Reminders UI to support multiple host contexts (external activity toolbar vs internal collapsible/non-collapsible toolbars).
  • Add a FragmentManager.showDialogFragment() helper and scope reminder dialogs to childFragmentManager.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
AnkiDroid/src/main/res/xml/preferences_review_reminders.xml Adds a placeholder XML to provide a stable @XmlRes routing key for preference search.
AnkiDroid/src/main/res/xml/preference_headers.xml Routes “Review reminders” header directly to ScheduleRemindersFragment.
AnkiDroid/src/main/res/values/styles.xml Adds a TopAppBar subtitle text appearance for the collapsible toolbar.
AnkiDroid/src/main/res/layout/fragment_schedule_reminders.xml Reworks layout to include an AppBar + (optional) collapsing toolbar patterns.
AnkiDroid/src/main/res/layout/fragment_reminder_troubleshooting.xml Updates toolbar id/structure and system window fitting.
AnkiDroid/src/main/res/layout/activity_study_options.xml Enables fitsSystemWindows on the root layout.
AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/Fragment.kt Makes onWindowFocusChanged cleanup safer against dead ViewTreeObserver.
AnkiDroid/src/main/java/com/ichi2/anki/utils/Dialog.kt Adds FragmentManager.showDialogFragment() convenience wrapper.
AnkiDroid/src/main/java/com/ichi2/anki/StudyOptionsFragment.kt Emits a fragment result to request opening review reminders instead of starting an activity.
AnkiDroid/src/main/java/com/ichi2/anki/StudyOptionsActivity.kt Listens for the fragment result and opens ScheduleRemindersFragment in-place with back stack support.
AnkiDroid/src/main/java/com/ichi2/anki/reviewreminders/ScheduleRemindersFragment.kt Introduces host-dependent toolbar strategy, new fragment factory, and dialog scoping changes.
AnkiDroid/src/main/java/com/ichi2/anki/reviewreminders/ReminderTroubleshootingFragment.kt Adds support for using an external activity toolbar when embedded in certain hosts.
AnkiDroid/src/main/java/com/ichi2/anki/reviewreminders/AddEditReminderDialog.kt Adds rotation workaround for MaterialTimePicker callbacks and adjusts fragment result listening.
AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt Special-cases preference search routing to open ScheduleRemindersFragment.
AnkiDroid/src/main/java/com/ichi2/anki/preferences/HeaderFragment.kt Updates preference search indexing/routing and fragment-to-header mapping for reminders.
AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt Migrates toolbar API usage to setToolbarText.
AnkiDroid/src/main/java/com/ichi2/anki/multimedia/MultimediaFragment.kt Migrates toolbar API usage to setToolbarText.
AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt Opens schedule reminders either in the side panel (large screens) or via the existing destination flow.
AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt Replaces setToolbarTitle with setToolbarText (title + optional subtitle).
Comments suppressed due to low confidence (1)

AnkiDroid/src/main/java/com/ichi2/anki/reviewreminders/ScheduleRemindersFragment.kt:265

  • Toolbar title is set via hardcoded string literal ("Review reminders") when using the activity toolbar. This is user-visible text; consider using a string resource (and keep it consistent with the Settings header title).
            retrieveSubtitle { subtitle ->
                setToolbarText("Review reminders", subtitle)
            }
            invalidateMenu()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread AnkiDroid/src/main/res/xml/preference_headers.xml
Comment thread AnkiDroid/src/main/res/layout/fragment_reminder_troubleshooting.xml
ericli3690 added 10 commits May 25, 2026 00:28
After the review reminders UI refactoring changes that come after this commit, there is a chance that when the troubleshooting screen is rotated twice in quick succession from within the settings screen that it crashes due to removeOnWindowFocusChangeListener trying to run on a detached viewTreeObserver. This change fixes this by only removing the listener if it is existent and alive.
Previously, there was a horizontal divider between the toolbar and review reminders list / troubleshooting menu, along with horizontal dividers between each individual review reminder listing. I think this should be removed to bring the screen more in line stylistically with how the rest of the settings menu looks (there are no dividers between Preferences, nor between the toolbar and primary content).
The AddEditReminderDialog's TimePicker was incredibly fragile with respect to orientation and configuration changes. It breaks and fails to save information if rotated in some scenarios after the upcoming commits which rejiggle the review reminders UI are implemented. This is due to latent issues in SingleFragmentActivity and the TimePicker component. See the ODO comments and docstrings for more details.
A future change will involve setting the subtitle of StudyOptionsActivity from a fragment nested inside it (ScheduleRemindersFragment, ReminderTroubleshootingFragment). Hence, we modify the contract of the pre-existing setToolbarText methods in AnkiActivity, which is inherited by StudyOptionsActivity.
…otingFragment

In a future commit, it will be possible for the ScheduleRemindersFragment (and hence the ReminderTroubleshootingFragment) o be hosted within an external activity which manages the toolbar (namely, StudyOptionsActivity). Hence, some wiring needs to be established to render the toolbar internally or externally conditionally.
…n host

ScheduleReminders can be hosted in multiple places, each of which presents their own unique UI challenges:

1. Long-pressing a deck from DeckPicker: On small screens, there is no suitable activity currently available, and so we should launch one to host ScheduleRemindersFragment in the form of SingleFragmentActivity. On large screens, there MAY be a right-side panel available (it is hidden in the edge case where the collection is empty); the UI looks cleanest if it is used.
2. Clicking on the "bell" icon from StudyOptionsFragment: On small screens, StudyOptionsActivity is currently active, and so it should be used as the host rather than launching a new activity. However, it manages an external toolbar and so using an internal toolbar would not work. We need to latch onto the external support action bar and modify it. On large screens, the right-side panel is available similar to option 1 if the collection is non-empty.
3. The screen may be launched from Settings, in which case the user is inspecting all reminders across all decks. Here, it should match the style of the other Settings Preferences screens, i.e. a collapsing toolbar, and should align whether on a small screen or large screen.

In my opinion, the cleanest way to handle this is to enumerate the possible hosts ScheduleReminders can have via FragmentHost, define what the ToolbarType should be for each host, and then modify the toolbar and styling appropriately. This keeps all logic centralized within ScheduleRemindersFragment and maintains a single source of truth.

Additionally, due to an issue with `fitsSystemWindows`, we sometimes need to set the upper padding programmatically. See the TODO comment in this commit.

Proper launching of ReminderTroubleshootingFragment is also implemented. A subtitle style is added.
Adds a FragmentManager.showDialogFragment extension function. The normal showDialogFragment function is an extension on FragmentActivity and attaches the dialog to the supportFragmentManager, which is activity-scoped. This:

1. Causes issues when ScheduleRemindersFragment is hosted within Settings, as Preferences.kt launches its children within its childFragmentManager, meaning that AddEditReminderDialog's setFragmentResultListener needs to be changed to `requireActivity().supportFragmentManager.setFragmentResultListener`.
2. However, even though the above is implementable and works (I tried it), it is kind of bad because we've attached the listener to the entire activity. If the ScheduleRemindersFragment dies and thus there is no "correct" place for AddEditReminderDialog to return, the listener is technically still alive on the activity. This feels wrong.

A better solution in my opinion is to attach the AddEditReminderDialog result listeners to the childFragmentManager of ScheduleRemindersFragment. While this can be done via a direct call to showDialogFragmentImpl, I thought calling a function with the word "Impl" in it was a bit ugly and so created an extension function.
Deletes old "search" override code in the Settings screen. Adds a new preferences XML file solely for indexing purposes, but directs the HeaderFragment to simply open ScheduleRemindersFragment on click.
… StudyOptionsFragment

Adds logic for opening ScheduleRemindersFragment in the correct fragment container hosts in DeckPicker and StudyOptionsFragment. Mirrors `openStudyOptions` and `tryShowStudyOptionsPanel` by adding `openScheduleReminders` and `tryShowScheduleRemindersPanel`. Reloads the StudyOptionsFragment and removes ScheduleRemindersFragment if an appbar menu button is clicked while the fragment is open on large screens to prevent stale state from showing.
Yanks the troubleshooting snackbar setup code into a helper function to declutter `onViewCreated` a bit.
@ericli3690 ericli3690 force-pushed the ericli3690-schedule-reminders-frag-rework branch from 59c7f71 to 3774c60 Compare May 25, 2026 05:32
.withTitle("Review reminders")
.withResId(R.xml.preference_headers)
.withResId(R.xml.preferences_review_reminders)
.withSummary("Notifications")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If the user searches for "notif" or "notification" in the search bar, I want them to be able to find this preference. Hence this withSummary.

Comment on lines +310 to +312
* TODO: Split SingleFragmentActivity into two activities
* One with `android:configChanges="orientation"` for hosting WebView fragments
* and one without for hosting non-WebView fragments like this one.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Should I make an issue for this?

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.

ConfigAwareSingleFragmentActivity

Comment on lines +141 to 142
(arguments ?: bundleOf()).getParcelableCompat<ReviewReminderScope>(ARGS_SCOPE)
?: ReviewReminderScope.Global
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This "soft-failure" defaulting is actually a used codepath, as it's tricky to pass arguments to ScheduleRemindersFragment when the Preference is clicked in Settings. See preference_headers.xml:

    <com.ichi2.preferences.HeaderPreference
        android:fragment="com.ichi2.anki.reviewreminders.ScheduleRemindersFragment"

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.

Comment that it's not dead code.

Is there a reason you didn't set a click handler on the Header?

Comment on lines +150 to +151
(arguments ?: bundleOf()).getParcelableCompat<FragmentHost>(ARGS_HOST)
?: FragmentHost.SETTINGS
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Similarly here.

launchCatchingTask {
binding.toolbar.subtitle = scope.getDeckName()
override fun onDestroyView() {
troubleshootingSnackbar?.dismiss()
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is necessary if, for example, the user navigates back from the ScheduleRemindersFragment to the StudyOptionsFragment. Since ScheduleRemindersFragment is no longer its own activity, we need to dismiss the snackbar before relinquishing control.

* Sets up the troubleshooting snackbar which is shown persistently when checks find a warning/error.
* Tapping "Fix" opens the full troubleshooting screen.
*/
private suspend fun setupTroubleshootingSnackbar() {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Nothing was changed inside this method, all I did was extract it out to clean up onViewCreated.

Comment on lines +317 to +320
* TODO: Implement edge-to-edge for both [SingleFragmentActivity] and its child, PreferencesActivity
* After doing so, this insets-handling logic and the use of fitsSystemWindows in the layout file
* can be re-evaluated. UI and the collapsing toolbar should be tested on both small and wide screens
* with all app display themes from all possible locations this fragment can be opened from.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Should I create an issue for this?

Comment on lines 910 to +911
dismissAllDialogFragments()
openScheduleReminders(deckId)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The order of these needed to be reversed or else the opened scheduled reminders screen would be immediately popped by the dialog fragment dismissal, which pops every fragment added between it and the dialog fragment, inclusive.


private fun tryShowScheduleRemindersPanel(deckId: DeckId): Boolean {
val sidePanel = binding.studyoptionsFragment ?: return false
if (!sidePanel.isVisible) return false
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This early return is necessary in the scenario where the collection is empty and the side panel is hidden.

Comment on lines +129 to +131
if (!fragmented) {
requireAnkiActivity().setToolbarText(R.string.empty_string)
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Necessary because otherwise on narrow screens, the ScheduleRemindersFragment text will persist once we press back and return to StudyOptionsFragment if we are hosted within StudyOptionsActivity.

Should not be done on wide screens because otherwise the DeckPicker title gets deleted.


<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:id="@+id/troubleshooting_toolbar"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done because of a quirk where the Settings screen manually hides all toolbars on wide screens for stylistic purposes. However, it's better UX to have it for the nested troubleshooting screen. The simplest quick fix is to just change the id.

android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="?collapsingToolbarLayoutMediumSize"
app:expandedTitleMarginTop="80dp"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

expandedTitleMarginTop is required to give the deck name subtitle a bit more room to breathe.

```
DeckPickerTest > [1] > deckPickerOpensWithHelpMakeAnkiDroidBetterDialog[1] FAILED
    java.lang.IllegalStateException: FragmentManager has been destroyed
        at androidx.fragment.app.FragmentManager.enqueueAction(FragmentManager.java:1896)
        at androidx.fragment.app.FragmentManager.popBackStack(FragmentManager.java:1015)
        at com.ichi2.anki.DeckPicker.tryShowStudyOptionsPanel(DeckPicker.kt:1878)
```
@ericli3690 ericli3690 marked this pull request as ready for review May 25, 2026 06:51
@david-allison
Copy link
Copy Markdown
Member

I partially edited the description to bring Brayan's message into the issue description. Discord may not be long-term stable

Comment on lines +310 to +312
* TODO: Split SingleFragmentActivity into two activities
* One with `android:configChanges="orientation"` for hosting WebView fragments
* and one without for hosting non-WebView fragments like this one.
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.

ConfigAwareSingleFragmentActivity

Copy link
Copy Markdown
Member

@david-allison david-allison left a comment

Choose a reason for hiding this comment

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

Wow, LGTM, extremely well-designed

*/
private val scheduleRemindersScope: ReviewReminderScope by lazy {
requireArguments().getParcelableCompat<ReviewReminderScope>(ARGS_SCOPE)
(arguments ?: bundleOf()).getParcelableCompat<ReviewReminderScope>(ARGS_SCOPE)
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.

bundleOf is deprecated, use Bundle()

https://issuetracker.google.com/issues/434825212

Comment on lines +310 to +312
* TODO: Split SingleFragmentActivity into two activities
* One with `android:configChanges="orientation"` for hosting WebView fragments
* and one without for hosting non-WebView fragments like this one.
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.

ConfigAwareSingleFragmentActivity

Comment on lines +141 to 142
(arguments ?: bundleOf()).getParcelableCompat<ReviewReminderScope>(ARGS_SCOPE)
?: ReviewReminderScope.Global
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.

Comment that it's not dead code.

Is there a reason you didn't set a click handler on the Header?

Comment on lines +3 to +6
~ This file exists solely to provide a stable @XmlRes resource ID used as a routing key
~ in the preference search infrastructure (HeaderFragment + getFragmentFromXmlRes).
~ ScheduleRemindersFragment is not a PreferenceFragmentCompat, so there are no
~ preferences to index here.
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.

I feel the intent: "exists for search" is a little lost in the explanation.

Comment on lines 102 to 111
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.activity_study_options, menu)
val undoMenuItem = menu.findItem(R.id.action_undo)
val undoActionProvider = MenuItemCompat.getActionProvider(undoMenuItem) as? RtlCompliantActionProvider
// Set the proper click target for the undo button's ActionProvider
undoActionProvider?.clickHandler = { _, menuItem -> onOptionsItemSelected(menuItem) }
undoMenuItem.isVisible = undoState.hasAction
undoMenuItem.isVisible = undoState.hasAction && (currentFragment is StudyOptionsFragment)
undoMenuItem.title = undoState.label
return true
}
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.

Optional/for a TODO/ignore this

Take a look at CardBrowser + CardBrowserFragment's use of MenuProvider

Would this simplify the logic? Make one provider for each state: fragmented and non-fragmented, and the fragments control their menus

// Update the menu for a fragmented state
// Added last so all changes take priority
onAllFragmentsLoaded {
addPrepareMenuProvider { menu ->
if (!fragmented) return@addPrepareMenuProvider
/** Return the menu item with a particular identifier or `null` */
operator fun Menu.get(id: Int): MenuItem? = this.findItem(id)
// NoteEditorFragment: Remove save/preview note options if there are no notes
if (viewModel.rowCount == 0) {
menu[R.id.action_save]?.isVisible = false
menu[R.id.action_preview]?.isVisible = false
}
menu[R.id.action_edit_note]?.isVisible = false
// TODO: https://github.com/ankidroid/Anki-Android/issues/20206
// This blocks a user from previewing all cards
menu[R.id.action_preview_many]?.isVisible = false
}

Comment on lines +221 to +226
parentFragmentManager.setFragmentResult(
REQUEST_STUDY_OPTIONS_REVIEW_REMINDERS,
bundleOf(
KEY_REVIEW_REMINDERS_DECK_ID to col!!.decks.current().id,
),
)
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.

Optional: consider using this pattern for strongly typed listeners

fun FragmentManager.setDeckPickerContextMenuResult(result: DeckPickerContextMenuResult) {
setFragmentResult(DeckPickerContextMenuResult.REQUEST_KEY, result.toBundle())
}
fun FragmentActivity.setDeckPickerContextMenuResultListener(listener: (DeckPickerContextMenuResult) -> Unit) {
setFragmentResultListener(DeckPickerContextMenuResult.REQUEST_KEY) { _, bundle ->
listener(DeckPickerContextMenuResult.fromBundle(bundle))
}
}

* Tapping "Fix" opens the full troubleshooting screen.
*/
private suspend fun setupTroubleshootingSnackbar() {
troubleshootingViewModel.state
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.

Optional: launchCollectionInLifecycleScope simplifies this a little

this@launchCollectionInLifecycleScope.collect {
if (isRobolectric) {
HandlerUtils.postOnNewHandler { runBlocking { block(it) } }
val lifecycle = fragment.lifecycle
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.

If this is a test fix, it should be squashed into when the test failure started, otherwise we have commits which may cause git bisect to produce a bad result

@ericli3690 ericli3690 marked this pull request as draft May 29, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants