MAL has a concept of "titles waiting for approval". These titles
cannot be added to user lists, but they do show up on the website and
crucially, in search results.
However, trying to add such an "unapproved" title will return a 400
error response with the error "invalid_content".
Previously, the awaitSuccess() call would mean the generic "HTTP 400"
toast would be shown. Now, a dedicated informative error message is
shown instead.
# Conflicts:
# CHANGELOG.md
* Use plural forms for update error notification
Replace the hardcoded 'X update(s) failed' string with Android
plural resources so the notification correctly shows '1 update failed'
vs '2 updates failed', enabling proper localization.
Fixes#3051
* Address review: rename plural key and remove comment
Rename plural key to notification_update_errors to avoid potential
conflicts with existing translated string keys. Remove leftover
comment from strings.xml.
* Revert key rename per review
Apparently, this is all that's needed to replace the forbidden
`Task.project` accessor, which would be an error in Gradle v10 (it's
been deprecated for a while)
This will also allow us to use the Configuration Cache if we wanted
to.
* feat(sync): prevent deleted "ghost chapters" from reappearing during sync.
- Pass lastSyncTime down to mergeChapters in SyncService.kt.
- Apply timestamp-based tombstoning logic to chapter merging. When a chapter is missing from either the local or remote backup, its `lastModifiedAt` timestamp is checked against the device's last sync time.
- Ensure that chapters deleted on one device (or removed by a source) are recognized as deletions and dropped from the merged backup, rather than being erroneously restored as "new" chapters on subsequent syncs.
* chore: change timestamp to use duration-based calculations
* chore: spotless
* fix(delegate): migrate NH to the v2 api
* remove extra comment
* remove redundant data
* linting
* Code cleanup
---------
Co-authored-by: Jobobby04 <jobobby04@users.noreply.github.com>
* feat: Add versioning to categories
* feat: use random UID for categories.
For legacy and migration we should assign uid on insert, and modify existing one as well in the migration.
* feat: sync category metadata
Add version, uid and lastModifiedAt fields to Category model to allow syncing.
* chore: fix category merging logic
Improve the category merging logic by matching using UIDs first, with a fallback to matching by name for legacy remote categories.
Previously, categories were only matched by name, which could lead to incorrect merges if names were changed. This change ensures more accurate synchronization by prioritizing the unique identifier. Conflict resolution is now based on the `version` field, and logging has been added for better visibility into the merging process.
* refactor: prioritize UID when restoring categories
If a category with the same UID exists, update it instead of creating a new one. Fallback to matching by name if no UID match is found.
* chore: add isSyncing flag like before.
This make sure the version is consistent, and it's not accidentally appended by the trigger, if it does then one device will always be ahead, than previous, and they need to make multiple changes to increase the version.
* Apply suggestion from @jobobby04
Use SY specific numbers(601, 602 for now)
Co-authored-by: jobobby04 <jobobby04@users.noreply.github.com>
* chore: commit review, re-order.
* chore: surround changes in // SY --> // SY <--
* refactor: fallback to existing category UID if backup UID is 0 during restore.
when dealing with old backups (backups created before we added UIDs). In those old backups, backupCategory.uid defaults to 0.
If a user restored an old backup, it would match by name, and then overwrite the newly generated local UID with 0. This would break the synchronization.
* refactor: change to 6xx
* feat: improve sync reliability for categories and settings
- Refactor `mergeCategoriesLists` to correctly match categories by name when UID matching fails, ensuring better reconciliation across devices.
- Fix a bug in category merging where multiple categories with UID 0 (common for non-synced items) caused data loss.
- Update `SyncManager` to detect changes in categories, sources, preferences, saved searches, and extension repos, ensuring they synchronize even when the library favorites haven't changed.
- Convert `BackupCategory` and `BackupExtensionRepos` to data classes to support robust content-aware comparison during the sync process.
- Fix data loss in `mergeSourcesLists`, `mergePreferencesLists`, and `mergeSavedSearchesLists` by retaining local versions when conflicting with remote data.
* fix(sync): properly sync category deletions across devices
Previously, the sync system could not distinguish between a category that was deleted locally and a new category created on another device, causing deleted categories to be restored from the remote backup.
- Update `SyncService` to use `lastSyncTimestamp` to deduce if a missing local category was deleted (if modified before last sync) or newly created remotely (if modified after).
- Update `SyncManager` to explicitly delete local categories that are absent from the merged remote backup, propagating deletions to other devices.
- Fix `RestoreOptions` in `SyncManager` to respect the user's sync preferences instead of hardcoding `categories = true`.
* chore: change it to 6xx and not 600.
* chore: don't need to change this.
* chore: use kotlin time duration units
---------
Co-authored-by: jobobby04 <jobobby04@users.noreply.github.com>