Albirew/tachiyomi
Archivé
1
0
Bifurcation 0

ChapterDownloadIndicator: Optimize further and reimplement error state (#7599)

In the context of a weaker device--remembering objects inside a list item
is expensive. So only do it when we really need to.

This also flattens the download button by drawing a single icon instead of using
separate icon and progress indicator.
Cette révision appartient à :
Ivan Iskandar 2022-07-24 21:27:00 +07:00 révisé par GitHub
Parent 6f94777530
révision aeffb5eeb8
Aucune clé n'a été trouvée pour cette signature dans la base de données
ID de la clé GPG: 4AEE18F83AFDEB23
2 fichiers modifiés avec 180 ajouts et 100 suppressions

Voir le fichier

@ -9,6 +9,7 @@ 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.icons.filled.ErrorOutline
import androidx.compose.material.ripple.rememberRipple 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
@ -23,7 +24,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -45,59 +48,62 @@ fun ChapterDownloadIndicator(
downloadProgressProvider: () -> Int, downloadProgressProvider: () -> Int,
onClick: (ChapterDownloadAction) -> Unit, onClick: (ChapterDownloadAction) -> Unit,
) { ) {
val downloadState = downloadStateProvider() when (val downloadState = downloadStateProvider()) {
val isDownloaded = downloadState == Download.State.DOWNLOADED Download.State.NOT_DOWNLOADED -> NotDownloadedIndicator(modifier = modifier, onClick = onClick)
val isDownloading = downloadState != Download.State.NOT_DOWNLOADED Download.State.QUEUE, Download.State.DOWNLOADING -> DownloadingIndicator(
var isMenuExpanded by remember(downloadState) { mutableStateOf(false) } modifier = modifier,
downloadState = downloadState,
downloadProgressProvider = downloadProgressProvider,
onClick = onClick,
)
Download.State.DOWNLOADED -> DownloadedIndicator(modifier = modifier, onClick = onClick)
Download.State.ERROR -> ErrorIndicator(modifier = modifier, onClick = onClick)
}
}
@Composable
private fun NotDownloadedIndicator(
modifier: Modifier = Modifier,
onClick: (ChapterDownloadAction) -> Unit,
) {
Box( Box(
modifier = modifier modifier = modifier
.size(IconButtonTokens.StateLayerSize) .size(IconButtonTokens.StateLayerSize)
.combinedClickable( .commonClickable(
onLongClick = { onLongClick = { onClick(ChapterDownloadAction.START_NOW) },
val chapterDownloadAction = when { onClick = { onClick(ChapterDownloadAction.START) },
isDownloaded -> ChapterDownloadAction.DELETE )
isDownloading -> ChapterDownloadAction.CANCEL .secondaryItemAlpha(),
else -> ChapterDownloadAction.START_NOW
}
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, contentAlignment = Alignment.Center,
) { ) {
if (isDownloaded) {
Icon( Icon(
imageVector = Icons.Default.CheckCircle, painter = painterResource(id = R.drawable.ic_download_chapter_24dp),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(IndicatorSize), modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.onSurfaceVariant, tint = MaterialTheme.colorScheme.onSurfaceVariant,
) )
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_delete)) },
onClick = {
onClick(ChapterDownloadAction.DELETE)
isMenuExpanded = false
},
)
} }
} else { }
val inactiveAlphaModifier = if (!isDownloading) Modifier.secondaryItemAlpha() else Modifier
@Composable
private fun DownloadingIndicator(
modifier: Modifier = Modifier,
downloadState: Download.State,
downloadProgressProvider: () -> Int,
onClick: (ChapterDownloadAction) -> Unit,
) {
var isMenuExpanded by remember { mutableStateOf(false) }
Box(
modifier = modifier
.size(IconButtonTokens.StateLayerSize)
.commonClickable(
onLongClick = { onClick(ChapterDownloadAction.CANCEL) },
onClick = { isMenuExpanded = true },
),
contentAlignment = Alignment.Center,
) {
val arrowColor: Color val arrowColor: Color
val strokeColor = MaterialTheme.colorScheme.onSurfaceVariant val strokeColor = MaterialTheme.colorScheme.onSurfaceVariant
if (isDownloading) {
val downloadProgress = downloadProgressProvider() 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)
@ -141,23 +147,85 @@ fun ChapterDownloadIndicator(
}, },
) )
} }
} else {
arrowColor = strokeColor
CircularProgressIndicator(
progress = 1f,
modifier = IndicatorModifier.then(inactiveAlphaModifier),
color = strokeColor,
strokeWidth = IndicatorStrokeWidth,
)
}
Icon( Icon(
imageVector = Icons.Default.ArrowDownward, imageVector = Icons.Default.ArrowDownward,
contentDescription = null, contentDescription = null,
modifier = ArrowModifier.then(inactiveAlphaModifier), modifier = ArrowModifier,
tint = arrowColor, tint = arrowColor,
) )
} }
} }
@Composable
private fun DownloadedIndicator(
modifier: Modifier = Modifier,
onClick: (ChapterDownloadAction) -> Unit,
) {
var isMenuExpanded by remember { mutableStateOf(false) }
Box(
modifier = modifier
.size(IconButtonTokens.StateLayerSize)
.commonClickable(
onLongClick = { onClick(ChapterDownloadAction.DELETE) },
onClick = { isMenuExpanded = true },
),
contentAlignment = Alignment.Center,
) {
Icon(
imageVector = Icons.Default.CheckCircle,
contentDescription = null,
modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_delete)) },
onClick = {
onClick(ChapterDownloadAction.DELETE)
isMenuExpanded = false
},
)
}
}
}
@Composable
private fun ErrorIndicator(
modifier: Modifier = Modifier,
onClick: (ChapterDownloadAction) -> Unit,
) {
Box(
modifier = modifier
.size(IconButtonTokens.StateLayerSize)
.commonClickable(
onLongClick = { onClick(ChapterDownloadAction.START) },
onClick = { onClick(ChapterDownloadAction.START) },
),
contentAlignment = Alignment.Center,
) {
Icon(
imageVector = Icons.Default.ErrorOutline,
contentDescription = null,
modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.error,
)
}
}
private fun Modifier.commonClickable(
onLongClick: () -> Unit,
onClick: () -> Unit,
) = composed {
this.combinedClickable(
onLongClick = onLongClick,
onClick = onClick,
role = Role.Button,
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(
bounded = false,
radius = IconButtonTokens.StateLayerSize / 2,
),
)
} }
private val IndicatorSize = 26.dp private val IndicatorSize = 26.dp

Voir le fichier

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M11.99,2C6.47,2 2,6.48 2,12C2,17.52 6.47,22 11.99,22C17.52,22 22,17.52 22,12C22,6.48 17.52,2 11.99,2zM12,4C16.42,4 20,7.58 20,12C20,16.42 16.42,20 12,20C7.58,20 4,16.42 4,12C4,7.58 7.58,4 12,4z"
android:fillColor="#000000"/>
<path
android:pathData="M18.041,12 L16.976,10.935 12.755,15.149L12.755,5.959L11.245,5.959L11.245,15.149L7.031,10.928 5.959,12l6.041,6.041z"
android:fillColor="#000000"/>
</vector>