Explorar o código

Add button to reorder categories alphabetically (#9369)

Closes #6459

Co-authored-by: arkon <[email protected]>
Pauline hai 1 ano
pai
achega
77ebc362f6

+ 36 - 3
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,
             )
         },

+ 29 - 0
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<CheckboxState<Category>>,

+ 8 - 0
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) {

+ 10 - 0
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
 }

+ 21 - 0
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

+ 2 - 0
i18n/src/main/res/values/strings.xml

@@ -91,6 +91,8 @@
     <string name="action_move_category">Set categories</string>
     <string name="delete_category_confirmation">Do you wish to delete the category \"%s\"?</string>
     <string name="delete_category">Delete category</string>
+    <string name="action_sort_category">Sort categories</string>
+    <string name="sort_category_confirmation">Would you like to sort the categories alphabetically?</string>
     <string name="action_edit_cover">Edit cover</string>
     <string name="action_view_chapters">View chapters</string>
     <string name="action_pause">Pause</string>