diff --git a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt index f7d699164f..3e3364d79d 100644 --- a/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/category/CategoryScreen.kt @@ -7,13 +7,22 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowBack +import androidx.compose.material.icons.outlined.SortByAlpha +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import eu.kanade.presentation.category.components.CategoryFloatingActionButton import eu.kanade.presentation.category.components.CategoryListItem import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.components.AppBarActions import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.category.CategoryScreenState import tachiyomi.domain.category.model.Category @@ -27,6 +36,7 @@ import tachiyomi.presentation.core.util.plus fun CategoryScreen( state: CategoryScreenState.Success, onClickCreate: () -> Unit, + onClickSortAlphabetically: () -> Unit, onClickRename: (Category) -> Unit, onClickDelete: (Category) -> Unit, onClickMoveUp: (Category) -> Unit, @@ -36,9 +46,32 @@ fun CategoryScreen( val lazyListState = rememberLazyListState() Scaffold( topBar = { scrollBehavior -> - AppBar( - title = stringResource(R.string.action_edit_categories), - navigateUp = navigateUp, + TopAppBar( + title = { + Text( + text = stringResource(R.string.action_edit_categories), + modifier = Modifier.padding(start = 8.dp), + ) + }, + navigationIcon = { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.Outlined.ArrowBack, + contentDescription = stringResource(R.string.abc_action_bar_up_description), + ) + } + }, + actions = { + AppBarActions( + listOf( + AppBar.Action( + title = stringResource(R.string.action_sort), + icon = Icons.Outlined.SortByAlpha, + onClick = onClickSortAlphabetically, + ), + ), + ) + }, scrollBehavior = scrollBehavior, ) }, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt index 0e99d26c16..ad30e4e2d1 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt @@ -180,6 +180,35 @@ fun CategoryDeleteDialog( ) } +@Composable +fun CategorySortAlphabeticallyDialog( + onDismissRequest: () -> Unit, + onSort: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = { + onSort() + onDismissRequest() + }) { + Text(text = stringResource(R.string.action_ok)) + } + }, + dismissButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.action_cancel)) + } + }, + title = { + Text(text = stringResource(R.string.action_sort_category)) + }, + text = { + Text(text = stringResource(R.string.sort_category_confirmation)) + }, + ) +} + @Composable fun ChangeCategoryDialog( initialSelection: List>, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt index 77628a4156..bc9fbd4a5e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt @@ -12,6 +12,7 @@ import eu.kanade.presentation.category.CategoryScreen import eu.kanade.presentation.category.components.CategoryCreateDialog import eu.kanade.presentation.category.components.CategoryDeleteDialog import eu.kanade.presentation.category.components.CategoryRenameDialog +import eu.kanade.presentation.category.components.CategorySortAlphabeticallyDialog import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.flow.collectLatest @@ -37,6 +38,7 @@ class CategoryScreen : Screen() { CategoryScreen( state = successState, onClickCreate = { screenModel.showDialog(CategoryDialog.Create) }, + onClickSortAlphabetically = { screenModel.showDialog(CategoryDialog.SortAlphabetically) }, onClickRename = { screenModel.showDialog(CategoryDialog.Rename(it)) }, onClickDelete = { screenModel.showDialog(CategoryDialog.Delete(it)) }, onClickMoveUp = screenModel::moveUp, @@ -68,6 +70,12 @@ class CategoryScreen : Screen() { category = dialog.category, ) } + is CategoryDialog.SortAlphabetically -> { + CategorySortAlphabeticallyDialog( + onDismissRequest = screenModel::dismissDialog, + onSort = { screenModel.sortAlphabetically() }, + ) + } } LaunchedEffect(Unit) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt index 45fbdcb4af..3a04a34750 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreenModel.kt @@ -61,6 +61,15 @@ class CategoryScreenModel( } } + fun sortAlphabetically() { + coroutineScope.launch { + when (reorderCategory.sortAlphabetically()) { + is ReorderCategory.Result.InternalError -> _events.send(CategoryEvent.InternalError) + else -> {} + } + } + } + fun moveUp(category: Category) { coroutineScope.launch { when (reorderCategory.moveUp(category)) { @@ -109,6 +118,7 @@ class CategoryScreenModel( sealed interface CategoryDialog { data object Create : CategoryDialog + data object SortAlphabetically : CategoryDialog data class Rename(val category: Category) : CategoryDialog data class Delete(val category: Category) : CategoryDialog } diff --git a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt index b29cfd0934..7561f52c84 100644 --- a/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/interactor/ReorderCategory.kt @@ -55,6 +55,27 @@ class ReorderCategory( } } + suspend fun sortAlphabetically() = withNonCancellableContext { + mutex.withLock { + val updates = categoryRepository.getAll() + .sortedBy { category -> category.name } + .mapIndexed { index, category -> + CategoryUpdate( + id = category.id, + order = index.toLong(), + ) + } + + try { + categoryRepository.updatePartial(updates) + Result.Success + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) + Result.InternalError(e) + } + } + } + sealed interface Result { data object Success : Result data object Unchanged : Result diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 41d216db55..aca17a1224 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -91,6 +91,8 @@ Set categories Do you wish to delete the category \"%s\"? Delete category + Sort categories + Would you like to sort the categories alphabetically? Edit cover View chapters Pause