Skip to content

Conversation

@ShaanNarendran
Copy link
Contributor

Purpose / Description

This changes the UI of existing progress dialogs (deprecated in api 26) to newer material ui progress circles.

Fixes

Approach

Created a new compat class ProgressCompat.kt to easily change all the existing progressdialogs to the new ones. We use this class in CoroutineHelpers.kt to change all the withProgress dialogs. The compat class uses regex to check for values like x/y and updates the dialog with a progress circle (defined in a new xml) automatically, if not we use an indeterminate spinner.

How Has This Been Tested?

Screen_recording_20251229_200048.webm
I struggled to test this normally, using one-way sync was the best way I found. If anyone has larger decks, or a better place to test, please let me know.

Learning (optional, can help others)

Referred:
https://developer.android.com/reference/android/app/ProgressDialog
ActionProviderCompat.kt for documentation help
https://m2.material.io/components/progress-indicators/android#circular-progress-indicators : for design (not sure if we want to use m3 since I believe it was still under discussion in the discord)

Checklist

Please, go through these checks before submitting the PR.

  • 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

@ShaanNarendran ShaanNarendran force-pushed the Progress-Bar branch 3 times, most recently from 9ac8ea1 to f94dfb1 Compare December 29, 2025 15:30
}
}

fun setMax(max: Int) = runOnUi { setMaxInternal(max) }
Copy link
Member

Choose a reason for hiding this comment

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

unused variable

circularIndicator?.max = max
}

fun setProgress(value: Int) = runOnUi { setProgressInternal(value) }
Copy link
Member

Choose a reason for hiding this comment

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

unused variable

}
}

fun incrementProgressBy(diff: Int) = runOnUi { setProgressInternal(progress + diff) }
Copy link
Member

Choose a reason for hiding this comment

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

unused variable


fun incrementProgressBy(diff: Int) = runOnUi { setProgressInternal(progress + diff) }

var isIndeterminate: Boolean
Copy link
Member

Choose a reason for hiding this comment

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

unused variable

}
}

private fun dismissDialogIfShowing(dialog: Dialog) {
Copy link
Member

Choose a reason for hiding this comment

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

unused function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason there's so many unused functions and variables is because I wanted it to be very similar to progressdialog since it is a compat wrapper. I thought this was best practice but if it's better to remove all the unused parts, I can

@ShaanNarendran
Copy link
Contributor Author

I implemented the changes which David had mentioned starting here:
https://discord.com/channels/368267295601983490/701922522836369498/1455239427247837297

I'm not sure if I understood it in the right way, so if I'm wrong do let me know

@david-allison
Copy link
Member

david-allison commented Jan 5, 2026

I struggled to test this normally, using one-way sync was the best way I found. If anyone has larger decks, or a better place to test, please let me know.

I'd consider an option in Developer options for UI samples?

@ShaanNarendran
Copy link
Contributor Author

I'd consider an option in Developer options for UI samples?

I did do some more comprehensive testing when I force pushed and it was working well, is there anything to change ui/code wise?

Copy link
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.

I've read the code and description a few times, and I don't understand the intention of this PR well enough.

It would help greatly if there was developer-level functionality to test this UI, as I don't have a 'reasonably slow' operation to try it with.

It doesn't fix the linked issue: optimizing parameters and checking database does not use a 'progress dialog with progress'

The Android deprecation on ProgressBar was introduced in order for developers to move away from a blocking progress bar in most cases. Instead, on-screen progress bars (such as the one we use in the CardBrowser) should be used. Removing the deprecation, whilst keeping the UX paradigm isn't how we should be tackling this.

We do have some operations which are 'truly' blocking: the pre-media sync being the main one.


ProgressDialogs have been in AnkiDroid for a long time, and they are a core concern of our code.

The default for 'wait for an operation' (normally a blocking operation) which anyone reaches for currently is withProgress { }. Android considers this to be bad UX

So:

  1. This new implementation should also be marked as @Deprecated by us (and suppressed appropriately)
    • Your code exists to add better progress notifications to the ProgressDialog, and this is useful
  2. We should use Material 3; Expressive if possble
  3. We should focus on the listed screens in the issue, and see if there's a better abstraction for 'progress bar with linear progress'
    • Maybe it looks something like this: #18341
  4. Ideally we should have a developer option to test this UI (maybe combine with the option I added for tts-voices)

@Suppress("Deprecation") // ProgressDialog deprecation
private fun ProgressContext.updateDialog(dialog: android.app.ProgressDialog) {
private fun ProgressContext.updateDialog(dialog: ProgressCompat) {
// ideally this would show a progress bar, but MaterialDialog does not support
Copy link
Member

Choose a reason for hiding this comment

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

Was this not fixed?

@ShaanNarendran
Copy link
Contributor Author

Honestly, I started with the intention of fixing the linked issue of course, which was to change the progress dialogs in the check database and full sync dialogs and so the idea I had was to just find a way to make one class that allows every progress dialog with a fixed x/y to be changed into a circular progress bar. This was when I took the route of making a compat wrapper for the progressdialogs, and it's on me for not actually marking that as deprecated but the idea is to use that for now to update the UI, and then move away from it as you said since its blocking.

  1. This new implementation should also be marked as @Deprecated by us (and suppressed appropriately)

    • Your code exists to add better progress notifications to the ProgressDialog, and this is useful
  2. We should use Material 3; Expressive if possble

  3. We should focus on the listed screens in the issue, and see if there's a better abstraction for 'progress bar with linear progress'

  4. Ideally we should have a developer option to test this UI (maybe combine with the option I added for tts-voices)

Based on the above, I think my plan for the pr will be to:

  1. Obviously mark the compat as deprecated.
  2. Swap to material3 implementation (I wasn't sure on this since I saw ongoing discussions in discord but I'll move to using it now)
  3. If possible, create the developer option to help test this.

As for the listed screens, the issue I'm having is that for database check, I can't even test it since it finishes instantly and for full sync, since there's no end value, I can't make it a progress bar. I think these for these indeterminate screens, I wouldn't want to tackle them in this pr and possibly leave it for someone else or come back to it later after more discussion.

I hope I understood everything and this isn't rambling, is it fine for me to go ahead with the plan I gave above?

@david-allison
Copy link
Member

That's great.

If you state that it fixes 'part of' an issue, then you've moved thing forward, most times in the right direction to solve the bigger picture.

It's even better when there's a task list of items which aren't yet fixed, so someone can come in and know where to

My current issue when reviewing is that I can't reliably test the dialog, as soon as we all have a 'good' measure for how to see it, I have a lot more confidence in the change.

We can then simulate unusual cases such as 'optimize all presets', which effectively have a 'dual layer' progress bar:

  • global progress: 5/40 presets are optimized
  • local progress: optimization is X% done on the current preset

@ShaanNarendran
Copy link
Contributor Author

My current issue when reviewing is that I can't reliably test the dialog, as soon as we all have a 'good' measure for how to see it, I have a lot more confidence in the change.

I'll see if I can get a developer option in place locally first that can help test this so that we can see how the change is reflecting, because even if I find it hard to see it except on a few dialogs, if that works should I commit to this pr with a new commit or open another issue and open it there?

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.

[UX] Show progress in percentage

4 participants