feat(update-errors): Allow manually delete update errors (#916)
* Allow manually delete error(s) * remember swipe action & correct Modifier * Simplify LibraryUpdateError data structure and separate SourceManager from compose UI * Add badge count errors * using SwipeToDismiss * correct Modifier & StringResource * remove confirmValueChange when Settle
This commit is contained in:
parent
bc33a75b6b
commit
2024cdf168
13 changed files with 225 additions and 84 deletions
|
|
@ -14,6 +14,7 @@ import androidx.compose.foundation.shape.ZeroCornerSize
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowDownward
|
||||
import androidx.compose.material.icons.outlined.ArrowUpward
|
||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
||||
import androidx.compose.material.icons.outlined.FindReplace
|
||||
import androidx.compose.material.icons.outlined.FlipToBack
|
||||
import androidx.compose.material.icons.outlined.SelectAll
|
||||
|
|
@ -63,6 +64,8 @@ fun LibraryUpdateErrorScreen(
|
|||
onMultiMigrateClicked: (() -> Unit),
|
||||
onSelectAll: (Boolean) -> Unit,
|
||||
onInvertSelection: () -> Unit,
|
||||
onErrorsDelete: () -> Unit,
|
||||
onErrorDelete: (Long) -> Unit,
|
||||
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean, Boolean) -> Unit,
|
||||
navigateUp: () -> Unit,
|
||||
) {
|
||||
|
|
@ -112,6 +115,7 @@ fun LibraryUpdateErrorScreen(
|
|||
onClickUnselectAll = { onSelectAll(false) },
|
||||
onClickSelectAll = { onSelectAll(true) },
|
||||
onClickInvertSelection = onInvertSelection,
|
||||
onClickDeleteErrors = onErrorsDelete,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
|
|
@ -173,6 +177,7 @@ fun LibraryUpdateErrorScreen(
|
|||
onErrorSelected = onErrorSelected,
|
||||
onClick = onClick,
|
||||
onClickCover = onClickCover,
|
||||
onDelete = onErrorDelete,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -303,6 +308,7 @@ private fun LibraryUpdateErrorAppBar(
|
|||
onClickUnselectAll: () -> Unit,
|
||||
onClickSelectAll: () -> Unit,
|
||||
onClickInvertSelection: () -> Unit,
|
||||
onClickDeleteErrors: () -> Unit,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
) {
|
||||
AppBar(
|
||||
|
|
@ -326,6 +332,11 @@ private fun LibraryUpdateErrorAppBar(
|
|||
actionModeActions = {
|
||||
AppBarActions(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(MR.strings.action_delete),
|
||||
icon = Icons.Outlined.DeleteOutline,
|
||||
onClick = onClickDeleteErrors,
|
||||
),
|
||||
AppBar.Action(
|
||||
title = stringResource(MR.strings.action_select_all),
|
||||
icon = Icons.Outlined.SelectAll,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
package eu.kanade.presentation.libraryUpdateError.components
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SwipeToDismissBox
|
||||
import androidx.compose.material3.SwipeToDismissBoxState
|
||||
import androidx.compose.material3.SwipeToDismissBoxValue.EndToStart
|
||||
import androidx.compose.material3.SwipeToDismissBoxValue.Settled
|
||||
import androidx.compose.material3.SwipeToDismissBoxValue.StartToEnd
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberSwipeToDismissBoxState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
|
|
@ -19,14 +33,13 @@ import eu.kanade.presentation.manga.components.MangaCover
|
|||
import eu.kanade.presentation.util.animateItemFastScroll
|
||||
import eu.kanade.tachiyomi.ui.libraryUpdateError.LibraryUpdateErrorItem
|
||||
import tachiyomi.domain.libraryUpdateError.model.LibraryUpdateErrorWithRelations
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.ListGroupHeader
|
||||
import tachiyomi.presentation.core.components.Scroller.STICKY_HEADER_KEY_PREFIX
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import tachiyomi.presentation.core.util.selectedBackground
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
internal fun LazyListScope.libraryUpdateErrorUiItems(
|
||||
uiModels: List<LibraryUpdateErrorUiModel>,
|
||||
|
|
@ -34,6 +47,7 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
|||
onErrorSelected: (LibraryUpdateErrorItem, Boolean, Boolean, Boolean) -> Unit,
|
||||
onClick: (LibraryUpdateErrorItem) -> Unit,
|
||||
onClickCover: (LibraryUpdateErrorItem) -> Unit,
|
||||
onDelete: (Long) -> Unit,
|
||||
) {
|
||||
uiModels.forEach { uiModel ->
|
||||
when (uiModel) {
|
||||
|
|
@ -46,6 +60,7 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
|||
modifier = Modifier.animateItemFastScroll(),
|
||||
text = uiModel.errorMessage,
|
||||
tonalElevation = 1.dp,
|
||||
count = uiModel.count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -58,6 +73,8 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
|||
LibraryUpdateErrorUiItem(
|
||||
modifier = Modifier.animateItemFastScroll(),
|
||||
error = libraryUpdateErrorItem.error,
|
||||
mangaCover = libraryUpdateErrorItem.mangaCover,
|
||||
sourceName = libraryUpdateErrorItem.sourceName,
|
||||
selected = libraryUpdateErrorItem.selected,
|
||||
onClick = {
|
||||
when {
|
||||
|
|
@ -80,6 +97,7 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
|||
)
|
||||
},
|
||||
onClickCover = { onClickCover(libraryUpdateErrorItem) }.takeIf { !selectionMode },
|
||||
onSwipe = { onDelete(libraryUpdateErrorItem.error.errorId) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -91,15 +109,37 @@ internal fun LazyListScope.libraryUpdateErrorUiItems(
|
|||
private fun LibraryUpdateErrorUiItem(
|
||||
modifier: Modifier,
|
||||
error: LibraryUpdateErrorWithRelations,
|
||||
mangaCover: tachiyomi.domain.manga.model.MangaCover,
|
||||
sourceName: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: () -> Unit,
|
||||
onClickCover: (() -> Unit)?,
|
||||
onSwipe: () -> Unit,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
|
||||
val dismissState = rememberSwipeToDismissBoxState(
|
||||
confirmValueChange = {
|
||||
when (it) {
|
||||
StartToEnd -> onSwipe()
|
||||
EndToStart -> onSwipe()
|
||||
else -> {}
|
||||
}
|
||||
return@rememberSwipeToDismissBoxState true
|
||||
},
|
||||
// Set threshold to 25% of the width
|
||||
positionalThreshold = { totalDistance -> totalDistance * 0.25f },
|
||||
)
|
||||
|
||||
SwipeToDismissBox(
|
||||
state = dismissState,
|
||||
modifier = modifier,
|
||||
backgroundContent = { DismissBackground(dismissState) },
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.selectedBackground(selected)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
|
|
@ -115,7 +155,7 @@ private fun LibraryUpdateErrorUiItem(
|
|||
modifier = Modifier
|
||||
.padding(vertical = 6.dp)
|
||||
.height(48.dp),
|
||||
data = error.mangaCover,
|
||||
data = mangaCover,
|
||||
onClick = onClickCover,
|
||||
)
|
||||
|
||||
|
|
@ -132,7 +172,7 @@ private fun LibraryUpdateErrorUiItem(
|
|||
|
||||
Row(modifier = Modifier.padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = Injekt.get<SourceManager>().getOrStub(error.mangaSource).name,
|
||||
text = sourceName,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
overflow = TextOverflow.Visible,
|
||||
maxLines = 1,
|
||||
|
|
@ -143,11 +183,50 @@ private fun LibraryUpdateErrorUiItem(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DismissBackground(dismissState: SwipeToDismissBoxState) {
|
||||
val direction = dismissState.dismissDirection
|
||||
val targetState = dismissState.targetValue
|
||||
|
||||
val backgroundColor by animateColorAsState(
|
||||
when (direction) {
|
||||
Settled ->
|
||||
MaterialTheme.colorScheme.surface
|
||||
StartToEnd ->
|
||||
MaterialTheme.colorScheme.errorContainer
|
||||
.copy(alpha = if (targetState == Settled) 0.45f else 1f)
|
||||
EndToStart ->
|
||||
MaterialTheme.colorScheme.errorContainer
|
||||
.copy(alpha = if (targetState == Settled) 0.45f else 1f)
|
||||
},
|
||||
)
|
||||
val alignment = when (direction) {
|
||||
StartToEnd -> Alignment.CenterStart
|
||||
EndToStart -> Alignment.CenterEnd
|
||||
else -> Alignment.Center
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(backgroundColor)
|
||||
.padding(horizontal = 20.dp),
|
||||
contentAlignment = alignment,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Delete,
|
||||
contentDescription = stringResource(MR.strings.action_delete),
|
||||
tint = MaterialTheme.colorScheme.onErrorContainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class LibraryUpdateErrorUiModel {
|
||||
|
||||
data class Header(val errorMessage: String) : LibraryUpdateErrorUiModel()
|
||||
data class Header(val errorMessage: String, val count: Int) : LibraryUpdateErrorUiModel()
|
||||
|
||||
data class Item(val item: LibraryUpdateErrorItem) : LibraryUpdateErrorUiModel()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,14 +96,14 @@ fun MangaChapterListItem(
|
|||
}
|
||||
|
||||
SwipeableActionsBox(
|
||||
modifier = Modifier.clipToBounds(),
|
||||
modifier = modifier.clipToBounds(),
|
||||
startActions = listOfNotNull(swipeStart),
|
||||
endActions = listOfNotNull(swipeEnd),
|
||||
swipeThreshold = swipeActionThreshold,
|
||||
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.selectedBackground(selected)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
|
|
@ -244,7 +244,7 @@ internal fun getSwipeAction(
|
|||
}
|
||||
}
|
||||
|
||||
private fun swipeAction(
|
||||
internal fun swipeAction(
|
||||
onSwipe: () -> Unit,
|
||||
icon: ImageVector,
|
||||
background: Color,
|
||||
|
|
|
|||
|
|
@ -655,7 +655,7 @@ class LibraryUpdateJob(private val context: Context, private val workerParams: W
|
|||
|
||||
// KMK -->
|
||||
private suspend fun clearErrorFromDB(mangaId: Long) {
|
||||
deleteLibraryUpdateErrors.deleteMangaError(mangaId = mangaId)
|
||||
deleteLibraryUpdateErrors.deleteMangaError(mangaIds = listOf(mangaId))
|
||||
}
|
||||
|
||||
private suspend fun writeErrorToDB(error: Pair<Manga, String?>) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ class LibraryUpdateErrorScreen : Screen() {
|
|||
},
|
||||
onSelectAll = screenModel::toggleAllSelection,
|
||||
onInvertSelection = screenModel::invertSelection,
|
||||
onErrorsDelete = screenModel::deleteSelected,
|
||||
onErrorDelete = screenModel::delete,
|
||||
onErrorSelected = screenModel::toggleSelection,
|
||||
navigateUp = navigator::pop,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,19 +5,26 @@ import cafe.adriel.voyager.core.model.StateScreenModel
|
|||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.core.util.addOrRemove
|
||||
import eu.kanade.presentation.libraryUpdateError.components.LibraryUpdateErrorUiModel
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.common.util.lang.launchIO
|
||||
import tachiyomi.core.common.util.lang.withUIContext
|
||||
import tachiyomi.domain.libraryUpdateError.interactor.DeleteLibraryUpdateErrors
|
||||
import tachiyomi.domain.libraryUpdateError.interactor.GetLibraryUpdateErrorWithRelations
|
||||
import tachiyomi.domain.libraryUpdateError.model.LibraryUpdateErrorWithRelations
|
||||
import tachiyomi.domain.libraryUpdateErrorMessage.interactor.GetLibraryUpdateErrorMessages
|
||||
import tachiyomi.domain.libraryUpdateErrorMessage.model.LibraryUpdateErrorMessage
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class LibraryUpdateErrorScreenModel(
|
||||
private val getLibraryUpdateErrorWithRelations: GetLibraryUpdateErrorWithRelations = Injekt.get(),
|
||||
private val getLibraryUpdateErrorMessages: GetLibraryUpdateErrorMessages = Injekt.get(),
|
||||
private val deleteLibraryUpdateErrors: DeleteLibraryUpdateErrors = Injekt.get(),
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
) : StateScreenModel<LibraryUpdateErrorScreenState>(LibraryUpdateErrorScreenState()) {
|
||||
|
||||
// First and last selected index in list
|
||||
|
|
@ -44,6 +51,7 @@ class LibraryUpdateErrorScreenModel(
|
|||
return map { error ->
|
||||
LibraryUpdateErrorItem(
|
||||
error = error,
|
||||
sourceName = sourceManager.getOrStub(error.mangaSource).name,
|
||||
selected = error.errorId in selectedErrorIds,
|
||||
)
|
||||
}
|
||||
|
|
@ -139,6 +147,26 @@ class LibraryUpdateErrorScreenModel(
|
|||
selectedPositions[0] = -1
|
||||
selectedPositions[1] = -1
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun deleteSelected() {
|
||||
launchIO {
|
||||
deleteLibraryUpdateErrors.delete(selectedErrorIds.toList())
|
||||
withUIContext {
|
||||
selectedErrorIds.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun delete(errorId: Long) {
|
||||
launchIO {
|
||||
deleteLibraryUpdateErrors.delete(listOf(errorId))
|
||||
withUIContext {
|
||||
selectedErrorIds.remove(errorId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
|
|
@ -156,7 +184,7 @@ data class LibraryUpdateErrorScreenState(
|
|||
val errorMap = items.groupBy { it.error.messageId }
|
||||
errorMap.forEach { (messageId, errors) ->
|
||||
val message = messages.find { it.id == messageId }
|
||||
uiModels.add(LibraryUpdateErrorUiModel.Header(message!!.message))
|
||||
uiModels.add(LibraryUpdateErrorUiModel.Header(message!!.message, errors.size))
|
||||
uiModels.addAll(errors.map { LibraryUpdateErrorUiModel.Item(it) })
|
||||
}
|
||||
return uiModels
|
||||
|
|
@ -171,5 +199,14 @@ data class LibraryUpdateErrorScreenState(
|
|||
@Immutable
|
||||
data class LibraryUpdateErrorItem(
|
||||
val error: LibraryUpdateErrorWithRelations,
|
||||
val sourceName: String,
|
||||
val selected: Boolean,
|
||||
)
|
||||
) {
|
||||
val mangaCover = MangaCover(
|
||||
mangaId = error.mangaId,
|
||||
sourceId = error.mangaSource,
|
||||
isMangaFavorite = error.favorite,
|
||||
ogUrl = error.mangaThumbnail,
|
||||
lastModified = error.coverLastModified,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,17 +25,15 @@ class LibraryUpdateErrorRepositoryImpl(
|
|||
return handler.await { libraryUpdateErrorQueries.deleteAllErrors() }
|
||||
}
|
||||
|
||||
override suspend fun delete(errorId: Long) {
|
||||
override suspend fun delete(errorIds: List<Long>) {
|
||||
return handler.await {
|
||||
libraryUpdateErrorQueries.deleteError(
|
||||
_id = errorId,
|
||||
)
|
||||
libraryUpdateErrorQueries.deleteErrors(_ids = errorIds)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteMangaError(mangaId: Long) {
|
||||
override suspend fun deleteMangaError(mangaIds: List<Long>) {
|
||||
return handler.await {
|
||||
libraryUpdateErrorQueries.deleteMangaError(mangaId = mangaId)
|
||||
libraryUpdateErrorQueries.deleteMangaErrors(mangaIds = mangaIds)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package tachiyomi.data.libraryUpdateError
|
||||
|
||||
import tachiyomi.domain.libraryUpdateError.model.LibraryUpdateErrorWithRelations
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
|
||||
val libraryUpdateErrorWithRelationsMapper:
|
||||
(Long, String, Long, Boolean, String?, Long, Long, Long, Long) -> LibraryUpdateErrorWithRelations =
|
||||
|
|
@ -10,13 +9,9 @@ val libraryUpdateErrorWithRelationsMapper:
|
|||
mangaId = mangaId,
|
||||
mangaTitle = mangaTitle,
|
||||
mangaSource = mangaSource,
|
||||
mangaCover = MangaCover(
|
||||
mangaId = mangaId,
|
||||
sourceId = mangaSource,
|
||||
isMangaFavorite = favorite,
|
||||
ogUrl = mangaThumbnail,
|
||||
lastModified = coverLastModified,
|
||||
),
|
||||
favorite = favorite,
|
||||
mangaThumbnail = mangaThumbnail,
|
||||
coverLastModified = coverLastModified,
|
||||
errorId = errorId,
|
||||
messageId = messageId,
|
||||
lastUpdate = lastUpdate,
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ WHERE manga_id = :mangaId;
|
|||
deleteAllErrors:
|
||||
DELETE FROM libraryUpdateError;
|
||||
|
||||
deleteError:
|
||||
deleteErrors:
|
||||
DELETE FROM libraryUpdateError
|
||||
WHERE _id = :_id;
|
||||
WHERE _id IN :_ids;
|
||||
|
||||
deleteMangaError:
|
||||
deleteMangaErrors:
|
||||
DELETE FROM libraryUpdateError
|
||||
WHERE manga_id = :mangaId;
|
||||
WHERE manga_id IN :mangaIds;
|
||||
|
||||
cleanUnrelevantMangaErrors:
|
||||
DELETE FROM libraryUpdateError
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class DeleteLibraryUpdateErrors(
|
|||
private val libraryUpdateErrorRepository: LibraryUpdateErrorRepository,
|
||||
) {
|
||||
|
||||
suspend fun await() = withNonCancellableContext {
|
||||
suspend fun deleteAll() = withNonCancellableContext {
|
||||
try {
|
||||
libraryUpdateErrorRepository.deleteAll()
|
||||
Result.Success
|
||||
|
|
@ -19,9 +19,9 @@ class DeleteLibraryUpdateErrors(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun await(errorId: Long) = withNonCancellableContext {
|
||||
suspend fun delete(errorIds: List<Long>) = withNonCancellableContext {
|
||||
try {
|
||||
libraryUpdateErrorRepository.delete(errorId)
|
||||
libraryUpdateErrorRepository.delete(errorIds)
|
||||
Result.Success
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
|
|
@ -29,9 +29,9 @@ class DeleteLibraryUpdateErrors(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun deleteMangaError(mangaId: Long) = withNonCancellableContext {
|
||||
suspend fun deleteMangaError(mangaIds: List<Long>) = withNonCancellableContext {
|
||||
try {
|
||||
libraryUpdateErrorRepository.deleteMangaError(mangaId)
|
||||
libraryUpdateErrorRepository.deleteMangaError(mangaIds)
|
||||
Result.Success
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
package tachiyomi.domain.libraryUpdateError.model
|
||||
|
||||
import tachiyomi.domain.manga.model.MangaCover
|
||||
|
||||
data class LibraryUpdateErrorWithRelations(
|
||||
val mangaId: Long,
|
||||
val mangaTitle: String,
|
||||
val mangaSource: Long,
|
||||
val mangaCover: MangaCover,
|
||||
val favorite: Boolean,
|
||||
val mangaThumbnail: String?,
|
||||
val coverLastModified: Long,
|
||||
val errorId: Long,
|
||||
val messageId: Long,
|
||||
val lastUpdate: Long,
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ interface LibraryUpdateErrorRepository {
|
|||
|
||||
suspend fun deleteAll()
|
||||
|
||||
suspend fun delete(errorId: Long)
|
||||
suspend fun delete(errorIds: List<Long>)
|
||||
|
||||
suspend fun deleteMangaError(mangaId: Long)
|
||||
suspend fun deleteMangaError(mangaIds: List<Long>)
|
||||
|
||||
suspend fun cleanUnrelevantMangaErrors()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package tachiyomi.presentation.core.components
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Badge
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
|
@ -18,6 +21,7 @@ fun ListGroupHeader(
|
|||
modifier: Modifier = Modifier,
|
||||
// KMK -->
|
||||
tonalElevation: Dp = 0.dp,
|
||||
count: Int? = null,
|
||||
// KMK <--
|
||||
) {
|
||||
// KMK -->
|
||||
|
|
@ -25,6 +29,10 @@ fun ListGroupHeader(
|
|||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
tonalElevation = tonalElevation,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
// KMK <--
|
||||
Text(
|
||||
|
|
@ -38,5 +46,16 @@ fun ListGroupHeader(
|
|||
fontWeight = FontWeight.SemiBold,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
// KMK -->
|
||||
if (count != null) {
|
||||
Badge(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
) {
|
||||
Text("$count")
|
||||
}
|
||||
}
|
||||
// KMK <--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue