-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
refactor(reminders): remove race conditions, simplify database interface #20755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,6 +161,9 @@ sealed class ReviewReminderScope : Parcelable { | |
| * reminders with invalid IDs are never created. This class is annotated | ||
| * with @ConsistentCopyVisibility to ensure copy() is private too and does not leak the constructor. | ||
| * | ||
| * Edits to instances of this class are not automatically persisted to SharedPreferences; | ||
| * that functionality is provided by [ReviewRemindersDatabase]. | ||
| * | ||
| * About the old schema migration process: | ||
| * | ||
| * To any developer who changes this class in the future, note that these review reminders are stored | ||
|
|
@@ -188,7 +191,7 @@ sealed class ReviewReminderScope : Parcelable { | |
| * multiple profiles might be active simultaneously. | ||
| * @param latestNotifTime The time at which this review reminder last attempted to fire a routine daily (non-snooze) | ||
| * notification, in epoch milliseconds, or the time at which it was created if no notification has ever been fired. | ||
| * See [shouldImmediatelyFire]. | ||
| * See [latestNotifDelivered]. | ||
| * @param onlyNotifyIfNoReviews If true, only notify the user if this scope has not been reviewed today yet. | ||
| */ | ||
| @Serializable | ||
|
|
@@ -239,11 +242,10 @@ data class ReviewReminder private constructor( | |
| } | ||
|
|
||
| /** | ||
| * Checks if this review reminder has tried to fire a routine daily (non-snooze) notification in the time between | ||
| * its latest scheduled firing time and now. If not, this method returns true, indicating that a notification | ||
| * should be immediately fired for this review reminder. | ||
| * Checks if this review reminder has successfully attempted to deliver a routine daily (non-snooze) | ||
| * notification in the time between its latest scheduled firing time and now. If so, this method returns true. | ||
| */ | ||
| fun shouldImmediatelyFire(): Boolean { | ||
| fun latestNotifDelivered(): Boolean { | ||
| val (hour, minute) = this.time | ||
|
|
||
| val currentTimestamp = TimeManager.time.calendar() | ||
|
|
@@ -257,7 +259,7 @@ data class ReviewReminder private constructor( | |
| } | ||
| } | ||
|
|
||
| return latestNotifTime < latestScheduledTimestamp.timeInMillis | ||
| return latestNotifTime >= latestScheduledTimestamp.timeInMillis | ||
| } | ||
|
Comment on lines
244
to
263
|
||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,11 @@ package com.ichi2.anki.reviewreminders | |
| import kotlinx.serialization.SerializationException | ||
| import kotlinx.serialization.json.Json | ||
|
|
||
| /** | ||
| * Convenience typealias for the mutation functions passed to editors of [ReviewReminderGroup]. | ||
| */ | ||
| typealias ReviewReminderGroupEditor = (ReviewReminderGroup) -> ReviewReminderGroup | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to top of file as requested by David |
||
|
|
||
| /** | ||
| * A group of review reminders, all for the same [ReviewReminderScope], | ||
| * persisted as a single JSON string in SharedPreferences. | ||
|
|
@@ -27,6 +32,9 @@ import kotlinx.serialization.json.Json | |
| * explicitly defined to restrict what can be done with the interface and to eliminate the | ||
| * need to verbosely type out "HashMap<ReviewReminderId, ReviewReminder>" everywhere. | ||
| * | ||
| * Edits to instances of this class are not automatically persisted to SharedPreferences; | ||
| * that functionality is provided by [ReviewRemindersDatabase]. | ||
| * | ||
| * A HashMap is used to allow for O(1) access to individual reminders by [ReviewReminderId]. | ||
| */ | ||
| class ReviewReminderGroup( | ||
|
|
@@ -39,9 +47,7 @@ class ReviewReminderGroup( | |
| /** | ||
| * Manually construct a [ReviewReminderGroup] from key-value pairs. | ||
| */ | ||
| constructor(vararg pairs: Pair<ReviewReminderId, ReviewReminder>) : this( | ||
| buildMap { pairs.forEach { put(it.first, it.second) } }, | ||
| ) | ||
| constructor(vararg pairs: Pair<ReviewReminderId, ReviewReminder>) : this(hashMapOf(*pairs)) | ||
|
david-allison marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Merge multiple [ReviewReminderGroup]s into one. | ||
|
|
@@ -87,8 +93,8 @@ class ReviewReminderGroup( | |
| underlyingMap.remove(id) | ||
| } | ||
|
|
||
| fun forEach(action: (ReviewReminderId, ReviewReminder) -> Unit) { | ||
| underlyingMap.forEach { (id, reminder) -> action(id, reminder) } | ||
| fun forEach(action: (Pair<ReviewReminderId, ReviewReminder>) -> Unit) { | ||
| underlyingMap.forEach { (id, reminder) -> action(id to reminder) } | ||
|
david-allison marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -112,8 +118,3 @@ class ReviewReminderGroup( | |
| * Convenience extension constructor for merging a list of [ReviewReminderGroup]s into one. | ||
| */ | ||
| fun List<ReviewReminderGroup>.mergeAll() = ReviewReminderGroup(*this.toTypedArray()) | ||
|
|
||
| /** | ||
| * Convenience typealias for the mutation functions passed to editors of [ReviewReminderGroup]. | ||
| */ | ||
| typealias ReviewReminderGroupEditor = (ReviewReminderGroup) -> ReviewReminderGroup | ||
Uh oh!
There was an error while loading. Please reload this page.