Add Stable interface for Category state (#7539)

This commit is contained in:
Andreas 2022-07-15 23:35:19 +02:00 committed by GitHub
parent 83e193f1ab
commit a21aa8125e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 34 deletions

View File

@ -7,7 +7,6 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarScrollState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@ -19,6 +18,7 @@ import eu.kanade.presentation.category.components.CategoryFloatingActionButton
import eu.kanade.presentation.category.components.CategoryRenameDialog
import eu.kanade.presentation.category.components.CategoryTopAppBar
import eu.kanade.presentation.components.EmptyScreen
import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.util.horizontalPadding
import eu.kanade.presentation.util.plus
@ -50,25 +50,25 @@ fun CategoryScreen(
floatingActionButton = {
CategoryFloatingActionButton(
lazyListState = lazyListState,
onCreate = { presenter.dialog = CategoryPresenter.Dialog.Create },
onCreate = { presenter.dialog = Dialog.Create },
)
},
) { paddingValues ->
val context = LocalContext.current
val categories by presenter.categories.collectAsState(initial = emptyList())
if (categories.isEmpty()) {
EmptyScreen(textResource = R.string.information_empty_category)
} else {
when {
presenter.isLoading -> LoadingScreen()
presenter.isEmpty -> EmptyScreen(textResource = R.string.information_empty_category)
else -> {
CategoryContent(
categories = categories,
state = presenter,
lazyListState = lazyListState,
paddingValues = paddingValues + topPaddingValues + PaddingValues(horizontal = horizontalPadding),
onMoveUp = { presenter.moveUp(it) },
onMoveDown = { presenter.moveDown(it) },
onRename = { presenter.dialog = Dialog.Rename(it) },
onDelete = { presenter.dialog = Dialog.Delete(it) },
)
}
}
val onDismissRequest = { presenter.dialog = null }
when (val dialog = presenter.dialog) {
Dialog.Create -> {

View File

@ -0,0 +1,28 @@
package eu.kanade.presentation.category
import androidx.compose.runtime.Stable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import eu.kanade.domain.category.model.Category
import eu.kanade.tachiyomi.ui.category.CategoryPresenter
@Stable
interface CategoryState {
val isLoading: Boolean
var dialog: CategoryPresenter.Dialog?
val categories: List<Category>
val isEmpty: Boolean
}
fun CategoryState(): CategoryState {
return CategoryStateImpl()
}
class CategoryStateImpl : CategoryState {
override var isLoading: Boolean by mutableStateOf(true)
override var dialog: CategoryPresenter.Dialog? by mutableStateOf(null)
override var categories: List<Category> by mutableStateOf(emptyList())
override val isEmpty: Boolean by derivedStateOf { categories.isEmpty() }
}

View File

@ -5,34 +5,40 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import eu.kanade.domain.category.model.Category
import eu.kanade.presentation.category.CategoryState
import eu.kanade.presentation.components.LazyColumn
import eu.kanade.tachiyomi.ui.category.CategoryPresenter.Dialog
@Composable
fun CategoryContent(
categories: List<Category>,
state: CategoryState,
lazyListState: LazyListState,
paddingValues: PaddingValues,
onMoveUp: (Category) -> Unit,
onMoveDown: (Category) -> Unit,
onRename: (Category) -> Unit,
onDelete: (Category) -> Unit,
) {
val categories = state.categories
LazyColumn(
state = lazyListState,
contentPadding = paddingValues,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
itemsIndexed(categories) { index, category ->
itemsIndexed(
items = categories,
key = { _, category -> category.id },
) { index, category ->
CategoryListItem(
modifier = Modifier.animateItemPlacement(),
category = category,
canMoveUp = index != 0,
canMoveDown = index != categories.lastIndex,
onMoveUp = onMoveUp,
onMoveDown = onMoveDown,
onRename = onRename,
onDelete = onDelete,
onRename = { state.dialog = Dialog.Rename(category) },
onDelete = { state.dialog = Dialog.Delete(category) },
)
}
}

View File

@ -21,15 +21,18 @@ import eu.kanade.presentation.util.horizontalPadding
@Composable
fun CategoryListItem(
modifier: Modifier = Modifier,
category: Category,
canMoveUp: Boolean,
canMoveDown: Boolean,
onMoveUp: (Category) -> Unit,
onMoveDown: (Category) -> Unit,
onRename: (Category) -> Unit,
onDelete: (Category) -> Unit,
onRename: () -> Unit,
onDelete: () -> Unit,
) {
ElevatedCard(
modifier = modifier,
) {
ElevatedCard {
Row(
modifier = Modifier
.padding(start = horizontalPadding, top = horizontalPadding, end = horizontalPadding),
@ -52,10 +55,10 @@ fun CategoryListItem(
Icon(imageVector = Icons.Outlined.ArrowDropDown, contentDescription = "")
}
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = { onRename(category) }) {
IconButton(onClick = onRename) {
Icon(imageVector = Icons.Outlined.Edit, contentDescription = "")
}
IconButton(onClick = { onDelete(category) }) {
IconButton(onClick = onDelete) {
Icon(imageVector = Icons.Outlined.Delete, contentDescription = "")
}
}

View File

@ -1,36 +1,45 @@
package eu.kanade.tachiyomi.ui.category
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import android.os.Bundle
import eu.kanade.domain.category.interactor.CreateCategoryWithName
import eu.kanade.domain.category.interactor.DeleteCategory
import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.category.interactor.RenameCategory
import eu.kanade.domain.category.interactor.ReorderCategory
import eu.kanade.domain.category.model.Category
import eu.kanade.presentation.category.CategoryState
import eu.kanade.presentation.category.CategoryStateImpl
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.lang.launchIO
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.consumeAsFlow
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class CategoryPresenter(
private val state: CategoryStateImpl = CategoryState() as CategoryStateImpl,
private val getCategories: GetCategories = Injekt.get(),
private val createCategoryWithName: CreateCategoryWithName = Injekt.get(),
private val renameCategory: RenameCategory = Injekt.get(),
private val reorderCategory: ReorderCategory = Injekt.get(),
private val deleteCategory: DeleteCategory = Injekt.get(),
) : BasePresenter<CategoryController>() {
var dialog: Dialog? by mutableStateOf(null)
val categories = getCategories.subscribe()
) : BasePresenter<CategoryController>(), CategoryState by state {
private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
val events = _events.consumeAsFlow()
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
presenterScope.launchIO {
getCategories.subscribe()
.collectLatest {
state.isLoading = false
state.categories = it
}
}
}
fun createCategory(name: String) {
presenterScope.launchIO {
when (createCategoryWithName.await(name)) {