Improve favorites sync statuses
This commit is contained in:
parent
3f8cce8a32
commit
76af3b59f0
@ -15,7 +15,6 @@ import androidx.compose.ui.window.DialogProperties
|
||||
import exh.favorites.FavoritesSyncStatus
|
||||
import kotlinx.coroutines.delay
|
||||
import tachiyomi.core.common.i18n.stringResource
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@ -23,7 +22,6 @@ import kotlin.time.Duration.Companion.seconds
|
||||
data class SyncFavoritesProgressProperties(
|
||||
val title: String,
|
||||
val text: String,
|
||||
val canDismiss: Boolean,
|
||||
val positiveButtonText: String? = null,
|
||||
val positiveButton: (() -> Unit)? = null,
|
||||
val negativeButtonText: String? = null,
|
||||
@ -34,18 +32,23 @@ data class SyncFavoritesProgressProperties(
|
||||
fun SyncFavoritesProgressDialog(
|
||||
status: FavoritesSyncStatus,
|
||||
setStatusIdle: () -> Unit,
|
||||
openManga: (Manga) -> Unit,
|
||||
openManga: (Long) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val properties by produceState<SyncFavoritesProgressProperties?>(initialValue = null, status) {
|
||||
when (status) {
|
||||
is FavoritesSyncStatus.BadLibraryState.MangaInMultipleCategories -> value = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_sync_error),
|
||||
text = context.stringResource(SYMR.strings.favorites_sync_bad_library_state, status.message),
|
||||
canDismiss = false,
|
||||
text = context.stringResource(
|
||||
SYMR.strings.favorites_sync_bad_library_state,
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_gallery_in_multiple_categories, status.mangaTitle,
|
||||
status.categories.joinToString(),
|
||||
),
|
||||
),
|
||||
positiveButtonText = context.stringResource(SYMR.strings.show_gallery),
|
||||
positiveButton = {
|
||||
openManga(status.manga)
|
||||
openManga(status.mangaId)
|
||||
setStatusIdle()
|
||||
},
|
||||
negativeButtonText = context.stringResource(MR.strings.action_ok),
|
||||
@ -53,31 +56,122 @@ fun SyncFavoritesProgressDialog(
|
||||
)
|
||||
is FavoritesSyncStatus.CompleteWithErrors -> value = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_sync_done_errors),
|
||||
text = context.stringResource(SYMR.strings.favorites_sync_done_errors_message, status.message),
|
||||
canDismiss = false,
|
||||
positiveButtonText = context.stringResource(MR.strings.action_ok),
|
||||
positiveButton = setStatusIdle,
|
||||
text = context.stringResource(
|
||||
SYMR.strings.favorites_sync_done_errors_message,
|
||||
status.messages.joinToString(separator = "\n") {
|
||||
when (it) {
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.GalleryAddFail ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_failed_to_add_to_local) +
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_error, it.title, it.reason,
|
||||
)
|
||||
is FavoritesSyncStatus.Error -> value = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_sync_error),
|
||||
text = context.stringResource(SYMR.strings.favorites_sync_error_string, status.message),
|
||||
canDismiss = false,
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.InvalidGalleryFail ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_failed_to_add_to_local) +
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_unknown_type, it.title, it.url,
|
||||
)
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.UnableToAddGalleryToRemote ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_unable_to_add_to_remote, it.title, it.gid)
|
||||
FavoritesSyncStatus.SyncError.GallerySyncError.UnableToDeleteFromRemote ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_unable_to_delete)
|
||||
}
|
||||
}
|
||||
),
|
||||
positiveButtonText = context.stringResource(MR.strings.action_ok),
|
||||
positiveButton = setStatusIdle,
|
||||
)
|
||||
is FavoritesSyncStatus.Idle -> value = null
|
||||
is FavoritesSyncStatus.Initializing, is FavoritesSyncStatus.Processing -> {
|
||||
is FavoritesSyncStatus.Initializing -> {
|
||||
value = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_syncing),
|
||||
text = status.message,
|
||||
canDismiss = false,
|
||||
text = context.stringResource(SYMR.strings.favorites_sync_initializing),
|
||||
)
|
||||
if (status is FavoritesSyncStatus.Processing && status.title != null) {
|
||||
delay(5.seconds)
|
||||
value = SyncFavoritesProgressProperties(
|
||||
}
|
||||
|
||||
is FavoritesSyncStatus.SyncError -> value = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_sync_error),
|
||||
text = context.stringResource(
|
||||
SYMR.strings.favorites_sync_error_string,
|
||||
when (status) {
|
||||
FavoritesSyncStatus.SyncError.NotLoggedInSyncError -> context.stringResource(SYMR.strings.please_login)
|
||||
FavoritesSyncStatus.SyncError.FailedToFetchFavorites ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_failed_to_featch)
|
||||
is FavoritesSyncStatus.SyncError.UnknownSyncError ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_unknown_error, status.message)
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.GalleryAddFail ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_failed_to_add_to_local) +
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_error, status.title, status.reason,
|
||||
)
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.InvalidGalleryFail ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_failed_to_add_to_local) +
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_unknown_type, status.title, status.url,
|
||||
)
|
||||
is FavoritesSyncStatus.SyncError.GallerySyncError.UnableToAddGalleryToRemote ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_unable_to_add_to_remote, status.title, status.gid)
|
||||
FavoritesSyncStatus.SyncError.GallerySyncError.UnableToDeleteFromRemote ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_unable_to_delete)
|
||||
}
|
||||
),
|
||||
positiveButtonText = context.stringResource(MR.strings.action_ok),
|
||||
positiveButton = setStatusIdle,
|
||||
)
|
||||
is FavoritesSyncStatus.Processing -> {
|
||||
val properties = SyncFavoritesProgressProperties(
|
||||
title = context.stringResource(SYMR.strings.favorites_syncing),
|
||||
text = status.delayedMessage ?: status.message,
|
||||
canDismiss = false,
|
||||
text = when (status) {
|
||||
FavoritesSyncStatus.Processing.VerifyingLibrary ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_verifying_library)
|
||||
FavoritesSyncStatus.Processing.DownloadingFavorites ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_downloading)
|
||||
FavoritesSyncStatus.Processing.CalculatingRemoteChanges ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_calculating_remote_changes)
|
||||
FavoritesSyncStatus.Processing.CalculatingLocalChanges ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_calculating_local_changes)
|
||||
FavoritesSyncStatus.Processing.SyncingCategoryNames ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_syncing_category_names)
|
||||
is FavoritesSyncStatus.Processing.RemovingRemoteGalleries ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_removing_galleries, status.galleryCount)
|
||||
is FavoritesSyncStatus.Processing.AddingGalleryToRemote ->
|
||||
if (status.isThrottling) {
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_processing_throttle,
|
||||
context.stringResource(SYMR.strings.favorites_sync_adding_to_remote, status.index, status.total)
|
||||
)
|
||||
} else {
|
||||
context.stringResource(SYMR.strings.favorites_sync_adding_to_remote, status.index, status.total)
|
||||
}
|
||||
is FavoritesSyncStatus.Processing.RemovingGalleryFromLocal ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_remove_from_local, status.index, status.total)
|
||||
is FavoritesSyncStatus.Processing.AddingGalleryToLocal ->
|
||||
if (status.isThrottling) {
|
||||
context.stringResource(
|
||||
SYMR.strings.favorites_sync_processing_throttle,
|
||||
context.stringResource(SYMR.strings.favorites_sync_add_to_local, status.index, status.total)
|
||||
)
|
||||
} else {
|
||||
context.stringResource(SYMR.strings.favorites_sync_add_to_local, status.index, status.total)
|
||||
}
|
||||
|
||||
FavoritesSyncStatus.Processing.CleaningUp ->
|
||||
context.stringResource(SYMR.strings.favorites_sync_cleaning_up)
|
||||
},
|
||||
)
|
||||
value = properties
|
||||
if (
|
||||
status is FavoritesSyncStatus.Processing.AddingGalleryToRemote ||
|
||||
status is FavoritesSyncStatus.Processing.AddingGalleryToLocal
|
||||
) {
|
||||
delay(5.seconds)
|
||||
value = properties.copy(
|
||||
text = when (status) {
|
||||
is FavoritesSyncStatus.Processing.AddingGalleryToRemote ->
|
||||
properties.text + "\n\n" + status.title
|
||||
is FavoritesSyncStatus.Processing.AddingGalleryToLocal ->
|
||||
properties.text + "\n\n" + status.title
|
||||
else -> properties.text
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -112,8 +206,8 @@ fun SyncFavoritesProgressDialog(
|
||||
}
|
||||
},
|
||||
properties = DialogProperties(
|
||||
dismissOnClickOutside = dialog.canDismiss,
|
||||
dismissOnBackPress = dialog.canDismiss,
|
||||
dismissOnClickOutside = false,
|
||||
dismissOnBackPress = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ data object LibraryTab : Tab {
|
||||
SyncFavoritesProgressDialog(
|
||||
status = screenModel.favoritesSync.status.collectAsState().value,
|
||||
setStatusIdle = { screenModel.favoritesSync.status.value = FavoritesSyncStatus.Idle(context) },
|
||||
openManga = { navigator.push(MangaScreen(it.id)) },
|
||||
openManga = { navigator.push(MangaScreen(it)) },
|
||||
)
|
||||
// SY <--
|
||||
|
||||
|
@ -64,18 +64,18 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
?: EHentai(0, true, context)
|
||||
}
|
||||
|
||||
private val storage = LocalFavoritesStorage()
|
||||
private val storage by lazy { LocalFavoritesStorage() }
|
||||
|
||||
private val galleryAdder = GalleryAdder()
|
||||
private val galleryAdder by lazy { GalleryAdder() }
|
||||
|
||||
private val throttleManager = EHentaiThrottleManager()
|
||||
private val throttleManager by lazy { EHentaiThrottleManager() }
|
||||
|
||||
private var wifiLock: WifiManager.WifiLock? = null
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
|
||||
private val logger = xLog()
|
||||
private val logger by lazy { xLog() }
|
||||
|
||||
val status: MutableStateFlow<FavoritesSyncStatus> = MutableStateFlow(FavoritesSyncStatus.Idle(context))
|
||||
val status: MutableStateFlow<FavoritesSyncStatus> = MutableStateFlow(FavoritesSyncStatus.Idle)
|
||||
|
||||
@Synchronized
|
||||
fun runSync(scope: CoroutineScope) {
|
||||
@ -83,7 +83,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
return
|
||||
}
|
||||
|
||||
status.value = FavoritesSyncStatus.Initializing(context)
|
||||
status.value = FavoritesSyncStatus.Initializing
|
||||
|
||||
scope.launch(Dispatchers.IO) { beginSync() }
|
||||
}
|
||||
@ -91,13 +91,12 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
private suspend fun beginSync() {
|
||||
// Check if logged in
|
||||
if (!prefs.enableExhentai().get()) {
|
||||
status.value = FavoritesSyncStatus.Error(context.stringResource(SYMR.strings.please_login))
|
||||
status.value = FavoritesSyncStatus.SyncError.NotLoggedInSyncError
|
||||
return
|
||||
}
|
||||
|
||||
// Validate library state
|
||||
status.value =
|
||||
FavoritesSyncStatus.Processing(context.stringResource(SYMR.strings.favorites_sync_verifying_library))
|
||||
status.value = FavoritesSyncStatus.Processing.VerifyingLibrary
|
||||
val libraryManga = getLibraryManga.await()
|
||||
val seenManga = HashSet<Long>(libraryManga.size)
|
||||
libraryManga.forEach { (manga) ->
|
||||
@ -106,7 +105,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
if (manga.id in seenManga) {
|
||||
val inCategories = getCategories.await(manga.id)
|
||||
status.value = FavoritesSyncStatus.BadLibraryState
|
||||
.MangaInMultipleCategories(manga, inCategories, context)
|
||||
.MangaInMultipleCategories(manga.id, manga.title, inCategories.map { it.name })
|
||||
|
||||
logger.w(context.stringResource(SYMR.strings.favorites_sync_gallery_multiple_categories_error, manga.id))
|
||||
return
|
||||
@ -117,17 +116,15 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
|
||||
// Download remote favorites
|
||||
val favorites = try {
|
||||
status.value =
|
||||
FavoritesSyncStatus.Processing(context.stringResource(SYMR.strings.favorites_sync_downloading))
|
||||
status.value = FavoritesSyncStatus.Processing.DownloadingFavorites
|
||||
exh.fetchFavorites()
|
||||
} catch (e: Exception) {
|
||||
status.value =
|
||||
FavoritesSyncStatus.Error(context.stringResource(SYMR.strings.favorites_sync_failed_to_featch))
|
||||
status.value = FavoritesSyncStatus.SyncError.FailedToFetchFavorites
|
||||
logger.e(context.stringResource(SYMR.strings.favorites_sync_could_not_fetch), e)
|
||||
return
|
||||
}
|
||||
|
||||
val errorList = mutableListOf<String>()
|
||||
val errorList = mutableListOf<FavoritesSyncStatus.SyncError.GallerySyncError>()
|
||||
|
||||
try {
|
||||
// Take wake + wifi locks
|
||||
@ -157,23 +154,17 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
// Do not update galleries while syncing favorites
|
||||
EHentaiUpdateWorker.cancelBackground(context)
|
||||
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
context.stringResource(SYMR.strings.favorites_sync_calculating_remote_changes),
|
||||
)
|
||||
status.value = FavoritesSyncStatus.Processing.CalculatingRemoteChanges
|
||||
val remoteChanges = storage.getChangedRemoteEntries(favorites.first)
|
||||
val localChanges = if (prefs.exhReadOnlySync().get()) {
|
||||
null // Do not build local changes if they are not going to be applied
|
||||
} else {
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
context.stringResource(SYMR.strings.favorites_sync_calculating_local_changes),
|
||||
)
|
||||
status.value = FavoritesSyncStatus.Processing.CalculatingLocalChanges
|
||||
storage.getChangedDbEntries()
|
||||
}
|
||||
|
||||
// Apply remote categories
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
context.stringResource(SYMR.strings.favorites_sync_syncing_category_names),
|
||||
)
|
||||
status.value = FavoritesSyncStatus.Processing.SyncingCategoryNames
|
||||
applyRemoteCategories(favorites.second)
|
||||
|
||||
// Apply change sets
|
||||
@ -182,8 +173,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
applyChangeSetToRemote(errorList, localChanges)
|
||||
}
|
||||
|
||||
status.value =
|
||||
FavoritesSyncStatus.Processing(context.stringResource(SYMR.strings.favorites_sync_cleaning_up))
|
||||
status.value = FavoritesSyncStatus.Processing.CleaningUp
|
||||
storage.snapshotEntries()
|
||||
|
||||
withUIContext {
|
||||
@ -194,9 +184,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
logger.w(context.stringResource(SYMR.strings.favorites_sync_ignoring_exception), e)
|
||||
return
|
||||
} catch (e: Exception) {
|
||||
status.value = FavoritesSyncStatus.Error(
|
||||
context.stringResource(SYMR.strings.favorites_sync_unknown_error, e.message.orEmpty()),
|
||||
)
|
||||
status.value = FavoritesSyncStatus.SyncError.UnknownSyncError(e.message.orEmpty())
|
||||
logger.e(context.stringResource(SYMR.strings.favorites_sync_sync_error), e)
|
||||
return
|
||||
} finally {
|
||||
@ -215,7 +203,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
}
|
||||
|
||||
if (errorList.isEmpty()) {
|
||||
status.value = FavoritesSyncStatus.Idle(context)
|
||||
status.value = FavoritesSyncStatus.Idle
|
||||
} else {
|
||||
status.value = FavoritesSyncStatus.CompleteWithErrors(errorList)
|
||||
}
|
||||
@ -249,7 +237,7 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun addGalleryRemote(errorList: MutableList<String>, gallery: FavoriteEntry) {
|
||||
private suspend fun addGalleryRemote(errorList: MutableList<FavoritesSyncStatus.SyncError.GallerySyncError>, gallery: FavoriteEntry) {
|
||||
val url = "${exh.baseUrl}/gallerypopups.php?gid=${gallery.gid}&t=${gallery.token}&act=addfav"
|
||||
|
||||
val request = POST(
|
||||
@ -263,13 +251,16 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
)
|
||||
|
||||
if (!explicitlyRetryExhRequest(10, request)) {
|
||||
val errorString = "Unable to add gallery to remote server: '${gallery.title}' (GID: ${gallery.gid})!"
|
||||
val error = FavoritesSyncStatus.SyncError.GallerySyncError.UnableToAddGalleryToRemote(
|
||||
gallery.title,
|
||||
gallery.gid
|
||||
)
|
||||
|
||||
if (prefs.exhLenientSync().get()) {
|
||||
errorList += errorString
|
||||
errorList += error
|
||||
} else {
|
||||
status.value = FavoritesSyncStatus.Error(errorString)
|
||||
throw IgnoredException(errorString)
|
||||
status.value = error
|
||||
throw IgnoredException(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,12 +284,13 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
return success
|
||||
}
|
||||
|
||||
private suspend fun applyChangeSetToRemote(errorList: MutableList<String>, changeSet: ChangeSet) {
|
||||
private suspend fun applyChangeSetToRemote(
|
||||
errorList: MutableList<FavoritesSyncStatus.SyncError.GallerySyncError>,
|
||||
changeSet: ChangeSet,
|
||||
) {
|
||||
// Apply removals
|
||||
if (changeSet.removed.isNotEmpty()) {
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
context.stringResource(SYMR.strings.favorites_sync_removing_galleries, changeSet.removed.size),
|
||||
)
|
||||
status.value = FavoritesSyncStatus.Processing.RemovingRemoteGalleries(changeSet.removed.size)
|
||||
|
||||
val formBody = FormBody.Builder()
|
||||
.add("ddact", "delete")
|
||||
@ -315,13 +307,11 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
)
|
||||
|
||||
if (!explicitlyRetryExhRequest(10, request)) {
|
||||
val errorString = context.stringResource(SYMR.strings.favorites_sync_unable_to_delete)
|
||||
|
||||
if (prefs.exhLenientSync().get()) {
|
||||
errorList += errorString
|
||||
errorList += FavoritesSyncStatus.SyncError.GallerySyncError.UnableToDeleteFromRemote
|
||||
} else {
|
||||
status.value = FavoritesSyncStatus.Error(errorString)
|
||||
throw IgnoredException(errorString)
|
||||
status.value = FavoritesSyncStatus.SyncError.GallerySyncError.UnableToDeleteFromRemote
|
||||
throw IgnoredException(FavoritesSyncStatus.SyncError.GallerySyncError.UnableToDeleteFromRemote)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,10 +319,10 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
// Apply additions
|
||||
throttleManager.resetThrottle()
|
||||
changeSet.added.forEachIndexed { index, it ->
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
message = context.stringResource(SYMR.strings.favorites_sync_adding_to_remote, index + 1, changeSet.added.size),
|
||||
isThrottle = needWarnThrottle(),
|
||||
context = context,
|
||||
status.value = FavoritesSyncStatus.Processing.AddingGalleryToRemote(
|
||||
index = index + 1,
|
||||
total = changeSet.added.size,
|
||||
isThrottling = needWarnThrottle(),
|
||||
title = it.title,
|
||||
)
|
||||
|
||||
@ -342,14 +332,17 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun applyChangeSetToLocal(errorList: MutableList<String>, changeSet: ChangeSet) {
|
||||
private suspend fun applyChangeSetToLocal(
|
||||
errorList: MutableList<FavoritesSyncStatus.SyncError.GallerySyncError>,
|
||||
changeSet: ChangeSet,
|
||||
) {
|
||||
val removedManga = mutableListOf<Manga>()
|
||||
|
||||
// Apply removals
|
||||
changeSet.removed.forEachIndexed { index, it ->
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
context.stringResource(SYMR.strings.favorites_sync_remove_from_local, index + 1, changeSet.removed.size),
|
||||
title = it.title,
|
||||
status.value = FavoritesSyncStatus.Processing.RemovingGalleryFromLocal(
|
||||
index = index + 1,
|
||||
total = changeSet.removed.size,
|
||||
)
|
||||
val url = it.getUrl()
|
||||
|
||||
@ -379,10 +372,10 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
// Apply additions
|
||||
throttleManager.resetThrottle()
|
||||
changeSet.added.forEachIndexed { index, it ->
|
||||
status.value = FavoritesSyncStatus.Processing(
|
||||
message = context.stringResource(SYMR.strings.favorites_sync_add_to_local, index + 1, changeSet.added.size),
|
||||
isThrottle = needWarnThrottle(),
|
||||
context = context,
|
||||
status.value = FavoritesSyncStatus.Processing.AddingGalleryToLocal(
|
||||
index = index + 1,
|
||||
total = changeSet.added.size,
|
||||
isThrottling = needWarnThrottle(),
|
||||
title = it.title,
|
||||
)
|
||||
|
||||
@ -405,24 +398,23 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
val errorString = context.stringResource(SYMR.strings.favorites_sync_failed_to_add_to_local) +
|
||||
when (result) {
|
||||
is GalleryAddEvent.Fail.Error -> context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_error, it.title, result.logMessage,
|
||||
val error = when (result) {
|
||||
is GalleryAddEvent.Fail.Error -> FavoritesSyncStatus.SyncError.GallerySyncError.GalleryAddFail(
|
||||
it.title, result.logMessage,
|
||||
)
|
||||
is GalleryAddEvent.Fail.UnknownType -> context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl,
|
||||
is GalleryAddEvent.Fail.UnknownType -> FavoritesSyncStatus.SyncError.GallerySyncError.InvalidGalleryFail(
|
||||
it.title, result.galleryUrl,
|
||||
)
|
||||
is GalleryAddEvent.Fail.UnknownSource -> context.stringResource(
|
||||
SYMR.strings.favorites_sync_failed_to_add_to_local_unknown_type, it.title, result.galleryUrl,
|
||||
is GalleryAddEvent.Fail.UnknownSource -> FavoritesSyncStatus.SyncError.GallerySyncError.InvalidGalleryFail(
|
||||
it.title, result.galleryUrl,
|
||||
)
|
||||
}
|
||||
|
||||
if (prefs.exhLenientSync().get()) {
|
||||
errorList += errorString
|
||||
errorList += error
|
||||
} else {
|
||||
status.value = FavoritesSyncStatus.Error(errorString)
|
||||
throw IgnoredException(errorString)
|
||||
status.value = error
|
||||
throw IgnoredException(error)
|
||||
}
|
||||
} else if (result is GalleryAddEvent.Success) {
|
||||
insertedMangaCategories += categories[it.category].id to result.manga
|
||||
@ -438,59 +430,74 @@ class FavoritesSyncHelper(val context: Context) {
|
||||
private fun needWarnThrottle() =
|
||||
throttleManager.throttleTime >= THROTTLE_WARN
|
||||
|
||||
class IgnoredException(message: String) : RuntimeException(message)
|
||||
class IgnoredException(message: FavoritesSyncStatus.SyncError.GallerySyncError) : RuntimeException(message.toString())
|
||||
|
||||
companion object {
|
||||
private val THROTTLE_WARN = 1.seconds
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class FavoritesSyncStatus {
|
||||
abstract val message: String
|
||||
|
||||
data class Error(override val message: String) : FavoritesSyncStatus()
|
||||
data class Idle(override val message: String) : FavoritesSyncStatus() {
|
||||
constructor(context: Context) : this(context.stringResource(SYMR.strings.favorites_sync_waiting_for_start))
|
||||
@Serializable
|
||||
sealed class SyncError : FavoritesSyncStatus() {
|
||||
@Serializable
|
||||
data object NotLoggedInSyncError : SyncError()
|
||||
@Serializable
|
||||
data object FailedToFetchFavorites : SyncError()
|
||||
@Serializable
|
||||
data class UnknownSyncError(val message: String) : SyncError()
|
||||
@Serializable
|
||||
sealed class GallerySyncError : SyncError() {
|
||||
@Serializable
|
||||
data class UnableToAddGalleryToRemote(val title: String, val gid: String): GallerySyncError()
|
||||
@Serializable
|
||||
data object UnableToDeleteFromRemote : GallerySyncError()
|
||||
@Serializable
|
||||
data class GalleryAddFail(val title: String, val reason: String): GallerySyncError()
|
||||
@Serializable
|
||||
data class InvalidGalleryFail(val title: String, val url: String): GallerySyncError()
|
||||
}
|
||||
}
|
||||
@Serializable
|
||||
data object Idle : FavoritesSyncStatus()
|
||||
@Serializable
|
||||
sealed class BadLibraryState : FavoritesSyncStatus() {
|
||||
@Serializable
|
||||
data class MangaInMultipleCategories(
|
||||
val manga: Manga,
|
||||
val categories: List<Category>,
|
||||
override val message: String,
|
||||
) : BadLibraryState() {
|
||||
constructor(manga: Manga, categories: List<Category>, context: Context) :
|
||||
this(
|
||||
manga = manga,
|
||||
categories = categories,
|
||||
message = context.stringResource(
|
||||
SYMR.strings.favorites_sync_gallery_in_multiple_categories, manga.title,
|
||||
categories.joinToString {
|
||||
it.name
|
||||
},
|
||||
),
|
||||
)
|
||||
val mangaId: Long,
|
||||
val mangaTitle: String,
|
||||
val categories: List<String>,
|
||||
) : BadLibraryState()
|
||||
}
|
||||
@Serializable
|
||||
data object Initializing : FavoritesSyncStatus()
|
||||
@Serializable
|
||||
sealed class Processing : FavoritesSyncStatus() {
|
||||
data object VerifyingLibrary : Processing()
|
||||
data object DownloadingFavorites : Processing()
|
||||
data object CalculatingRemoteChanges : Processing()
|
||||
data object CalculatingLocalChanges : Processing()
|
||||
data object SyncingCategoryNames : Processing()
|
||||
data class RemovingRemoteGalleries(val galleryCount: Int) : Processing()
|
||||
data class AddingGalleryToRemote(
|
||||
val index: Int,
|
||||
val total: Int,
|
||||
val isThrottling: Boolean,
|
||||
val title: String,
|
||||
) : Processing()
|
||||
data class RemovingGalleryFromLocal(
|
||||
val index: Int,
|
||||
val total: Int,
|
||||
) : Processing()
|
||||
data class AddingGalleryToLocal(
|
||||
val index: Int,
|
||||
val total: Int,
|
||||
val isThrottling: Boolean,
|
||||
val title: String,
|
||||
) : Processing()
|
||||
data object CleaningUp : Processing()
|
||||
}
|
||||
data class Initializing(override val message: String) : FavoritesSyncStatus() {
|
||||
constructor(context: Context) : this(context.stringResource(SYMR.strings.favorites_sync_initializing))
|
||||
}
|
||||
data class Processing(
|
||||
override val message: String,
|
||||
val title: String? = null,
|
||||
) : FavoritesSyncStatus() {
|
||||
constructor(message: String, isThrottle: Boolean, context: Context, title: String?) :
|
||||
this(
|
||||
if (isThrottle) {
|
||||
context.stringResource(SYMR.strings.favorites_sync_processing_throttle, message)
|
||||
} else {
|
||||
message
|
||||
},
|
||||
title,
|
||||
)
|
||||
|
||||
val delayedMessage get() = if (title != null) this.message + "\n\n" + title else null
|
||||
}
|
||||
data class CompleteWithErrors(val messages: List<String>) : FavoritesSyncStatus() {
|
||||
override val message: String = messages.joinToString("\n")
|
||||
}
|
||||
@Serializable
|
||||
data class CompleteWithErrors(val messages: List<SyncError.GallerySyncError>) : FavoritesSyncStatus()
|
||||
}
|
||||
|
@ -515,6 +515,7 @@
|
||||
<string name="favorites_sync_removing_galleries">Removing %1$d galleries from remote server</string>
|
||||
<string name="favorites_sync_unable_to_delete">Unable to delete galleries from the remote servers!</string>
|
||||
<string name="favorites_sync_adding_to_remote">Adding gallery %1$d of %2$d to remote server</string>
|
||||
<string name="favorites_sync_unable_to_add_to_remote">Unable to add gallery to remote server: '%1$s' (GID: %2$s)!</string>
|
||||
<string name="favorites_sync_remove_from_local">Removing gallery %1$d of %2$d from local library</string>
|
||||
<string name="favorites_sync_add_to_local">Adding gallery %1$d of %2$d to local library</string>
|
||||
<string name="favorites_sync_remote_not_exist">Remote gallery does not exist, skipping: %1$s!</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user