ChapterDownloadIndicator: Fixes and improvements (#7485)

* Increased touch target
* Fix downloaded icon smaller than other states
* Deferred state reads to minimize recompose works
* Move things around to eliminate unnecessary elements
This commit is contained in:
Ivan Iskandar 2022-07-09 23:38:33 +07:00 committed by GitHub
parent 34906a7425
commit e56f6c1017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 109 deletions

View File

@ -1,21 +1,22 @@
package eu.kanade.presentation.components package eu.kanade.presentation.components
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowDownward
import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalMinimumTouchTargetEnforcement
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -24,6 +25,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.manga.ChapterDownloadAction import eu.kanade.presentation.manga.ChapterDownloadAction
import eu.kanade.presentation.util.secondaryItemAlpha import eu.kanade.presentation.util.secondaryItemAlpha
@ -33,23 +35,18 @@ import eu.kanade.tachiyomi.data.download.model.Download
@Composable @Composable
fun ChapterDownloadIndicator( fun ChapterDownloadIndicator(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
downloadState: Download.State, downloadStateProvider: () -> Download.State,
downloadProgress: Int, downloadProgressProvider: () -> Int,
onClick: (ChapterDownloadAction) -> Unit, onClick: (ChapterDownloadAction) -> Unit,
) { ) {
Box(modifier = modifier, contentAlignment = Alignment.Center) { val downloadState = downloadStateProvider()
CompositionLocalProvider(LocalMinimumTouchTargetEnforcement provides false) {
val isDownloaded = downloadState == Download.State.DOWNLOADED val isDownloaded = downloadState == Download.State.DOWNLOADED
val isDownloading = downloadState != Download.State.NOT_DOWNLOADED val isDownloading = downloadState != Download.State.NOT_DOWNLOADED
var isMenuExpanded by remember(downloadState) { mutableStateOf(false) } var isMenuExpanded by remember(downloadState) { mutableStateOf(false) }
IconButton( Box(
onClick = { modifier = modifier
if (isDownloaded || isDownloading) { .size(IconButtonTokens.StateLayerSize)
isMenuExpanded = true .combinedClickable(
} else {
onClick(ChapterDownloadAction.START)
}
},
onLongClick = { onLongClick = {
val chapterDownloadAction = when { val chapterDownloadAction = when {
isDownloaded -> ChapterDownloadAction.DELETE isDownloaded -> ChapterDownloadAction.DELETE
@ -58,15 +55,27 @@ fun ChapterDownloadIndicator(
} }
onClick(chapterDownloadAction) onClick(chapterDownloadAction)
}, },
onClick = {
if (isDownloaded || isDownloading) {
isMenuExpanded = true
} else {
onClick(ChapterDownloadAction.START)
}
},
role = Role.Button,
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(
bounded = false,
radius = IconButtonTokens.StateLayerSize / 2,
),
),
contentAlignment = Alignment.Center,
) { ) {
val indicatorModifier = Modifier
.size(IndicatorSize)
.padding(IndicatorPadding)
if (isDownloaded) { if (isDownloaded) {
Icon( Icon(
imageVector = Icons.Default.CheckCircle, imageVector = Icons.Default.CheckCircle,
contentDescription = null, contentDescription = null,
modifier = indicatorModifier, modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.onSurfaceVariant, tint = MaterialTheme.colorScheme.onSurfaceVariant,
) )
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) { DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
@ -80,18 +89,16 @@ fun ChapterDownloadIndicator(
} }
} else { } else {
val inactiveAlphaModifier = if (!isDownloading) Modifier.secondaryItemAlpha() else Modifier val inactiveAlphaModifier = if (!isDownloading) Modifier.secondaryItemAlpha() else Modifier
val arrowModifier = Modifier
.size(IndicatorSize - 7.dp)
.then(inactiveAlphaModifier)
val arrowColor: Color val arrowColor: Color
val strokeColor = MaterialTheme.colorScheme.onSurfaceVariant val strokeColor = MaterialTheme.colorScheme.onSurfaceVariant
if (isDownloading) { if (isDownloading) {
val downloadProgress = downloadProgressProvider()
val indeterminate = downloadState == Download.State.QUEUE || val indeterminate = downloadState == Download.State.QUEUE ||
(downloadState == Download.State.DOWNLOADING && downloadProgress == 0) (downloadState == Download.State.DOWNLOADING && downloadProgress == 0)
if (indeterminate) { if (indeterminate) {
arrowColor = strokeColor arrowColor = strokeColor
CircularProgressIndicator( CircularProgressIndicator(
modifier = indicatorModifier, modifier = IndicatorModifier,
color = strokeColor, color = strokeColor,
strokeWidth = IndicatorStrokeWidth, strokeWidth = IndicatorStrokeWidth,
) )
@ -107,26 +114,11 @@ fun ChapterDownloadIndicator(
} }
CircularProgressIndicator( CircularProgressIndicator(
progress = animatedProgress, progress = animatedProgress,
modifier = indicatorModifier, modifier = IndicatorModifier,
color = strokeColor, color = strokeColor,
strokeWidth = IndicatorSize / 2, strokeWidth = IndicatorSize / 2,
) )
} }
} else {
arrowColor = strokeColor
CircularProgressIndicator(
progress = 1f,
modifier = indicatorModifier.then(inactiveAlphaModifier),
color = strokeColor,
strokeWidth = IndicatorStrokeWidth,
)
}
Icon(
imageVector = Icons.Default.ArrowDownward,
contentDescription = null,
modifier = arrowModifier,
tint = arrowColor,
)
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) { DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
DropdownMenuItem( DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_start_downloading_now)) }, text = { Text(text = stringResource(R.string.action_start_downloading_now)) },
@ -143,8 +135,21 @@ fun ChapterDownloadIndicator(
}, },
) )
} }
} else {
arrowColor = strokeColor
CircularProgressIndicator(
progress = 1f,
modifier = IndicatorModifier.then(inactiveAlphaModifier),
color = strokeColor,
strokeWidth = IndicatorStrokeWidth,
)
} }
} Icon(
imageVector = Icons.Default.ArrowDownward,
contentDescription = null,
modifier = ArrowModifier.then(inactiveAlphaModifier),
tint = arrowColor,
)
} }
} }
} }
@ -154,3 +159,9 @@ private val IndicatorPadding = 2.dp
// To match composable parameter name when used later // To match composable parameter name when used later
private val IndicatorStrokeWidth = IndicatorPadding private val IndicatorStrokeWidth = IndicatorPadding
private val IndicatorModifier = Modifier
.size(IndicatorSize)
.padding(IndicatorPadding)
private val ArrowModifier = Modifier
.size(IndicatorSize - 7.dp)

View File

@ -685,8 +685,8 @@ private fun LazyListScope.sharedChapterItems(
read = chapter.read, read = chapter.read,
bookmark = chapter.bookmark, bookmark = chapter.bookmark,
selected = selected.contains(chapterItem), selected = selected.contains(chapterItem),
downloadState = downloadState, downloadStateProvider = { downloadState },
downloadProgress = downloadProgress, downloadProgressProvider = { downloadProgress },
onLongClick = { onLongClick = {
val dispatched = onChapterItemLongClick( val dispatched = onChapterItemLongClick(
chapterItem = chapterItem, chapterItem = chapterItem,

View File

@ -44,8 +44,8 @@ fun MangaChapterListItem(
read: Boolean, read: Boolean,
bookmark: Boolean, bookmark: Boolean,
selected: Boolean, selected: Boolean,
downloadState: Download.State, downloadStateProvider: () -> Download.State,
downloadProgress: Int, downloadProgressProvider: () -> Int,
onLongClick: () -> Unit, onLongClick: () -> Unit,
onClick: () -> Unit, onClick: () -> Unit,
onDownloadClick: ((ChapterDownloadAction) -> Unit)?, onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
@ -127,8 +127,8 @@ fun MangaChapterListItem(
if (onDownloadClick != null) { if (onDownloadClick != null) {
ChapterDownloadIndicator( ChapterDownloadIndicator(
modifier = Modifier.padding(start = 4.dp), modifier = Modifier.padding(start = 4.dp),
downloadState = downloadState, downloadStateProvider = downloadStateProvider,
downloadProgress = downloadProgress, downloadProgressProvider = downloadProgressProvider,
onClick = onDownloadClick, onClick = onDownloadClick,
) )
} }

View File

@ -27,8 +27,8 @@ class ChapterDownloadView @JvmOverloads constructor(
override fun Content() { override fun Content() {
TachiyomiTheme { TachiyomiTheme {
ChapterDownloadIndicator( ChapterDownloadIndicator(
downloadState = state, downloadStateProvider = { state },
downloadProgress = progress, downloadProgressProvider = { progress },
onClick = listener, onClick = listener,
) )
} }