MangaChapterListItem: Increase swipe action touch slop (#9598)

This commit is contained in:
Ivan Iskandar 2023-06-10 23:48:03 +07:00 committed by GitHub
parent cf777d9893
commit 9ec8d770ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -32,6 +32,7 @@ import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@ -43,6 +44,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -74,201 +77,209 @@ fun MangaChapterListItem(
onDownloadClick: ((ChapterDownloadAction) -> Unit)?, onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit, onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
) { ) {
val textAlpha = if (read) ReadItemAlpha else 1f // Increase touch slop of swipe action to reduce accidental trigger
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha val configuration = LocalViewConfiguration.current
CompositionLocalProvider(
val chapterSwipeStartEnabled = chapterSwipeStartAction != LibraryPreferences.ChapterSwipeAction.Disabled LocalViewConfiguration provides object : ViewConfiguration by configuration {
val chapterSwipeEndEnabled = chapterSwipeEndAction != LibraryPreferences.ChapterSwipeAction.Disabled override val touchSlop: Float = configuration.touchSlop * 3f
val dismissState = rememberDismissState()
val dismissDirections = remember { mutableSetOf<DismissDirection>() }
var lastDismissDirection: DismissDirection? by remember { mutableStateOf(null) }
if (lastDismissDirection == null) {
if (chapterSwipeStartEnabled) {
dismissDirections.add(DismissDirection.EndToStart)
}
if (chapterSwipeEndEnabled) {
dismissDirections.add(DismissDirection.StartToEnd)
}
}
val animateDismissContentAlpha by animateFloatAsState(
label = "animateDismissContentAlpha",
targetValue = if (lastDismissDirection != null) 1f else 0f,
animationSpec = tween(durationMillis = if (lastDismissDirection != null) 500 else 0),
finishedListener = {
lastDismissDirection = null
}, },
) ) {
val dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f val textAlpha = if (read) ReadItemAlpha else 1f
val backgroundColor = if (chapterSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) { val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
MaterialTheme.colorScheme.primary
} else if (chapterSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
MaterialTheme.colorScheme.primary
} else {
Color.Unspecified
}
LaunchedEffect(dismissState.currentValue) { val chapterSwipeStartEnabled = chapterSwipeStartAction != LibraryPreferences.ChapterSwipeAction.Disabled
when (dismissState.currentValue) { val chapterSwipeEndEnabled = chapterSwipeEndAction != LibraryPreferences.ChapterSwipeAction.Disabled
DismissValue.DismissedToEnd -> {
lastDismissDirection = DismissDirection.StartToEnd val dismissState = rememberDismissState()
val dismissDirectionsCopy = dismissDirections.toSet() val dismissDirections = remember { mutableSetOf<DismissDirection>() }
dismissDirections.clear() var lastDismissDirection: DismissDirection? by remember { mutableStateOf(null) }
onChapterSwipe(chapterSwipeEndAction) if (lastDismissDirection == null) {
dismissState.snapTo(DismissValue.Default) if (chapterSwipeStartEnabled) {
dismissDirections.addAll(dismissDirectionsCopy) dismissDirections.add(DismissDirection.EndToStart)
} }
DismissValue.DismissedToStart -> { if (chapterSwipeEndEnabled) {
lastDismissDirection = DismissDirection.EndToStart dismissDirections.add(DismissDirection.StartToEnd)
val dismissDirectionsCopy = dismissDirections.toSet()
dismissDirections.clear()
onChapterSwipe(chapterSwipeStartAction)
dismissState.snapTo(DismissValue.Default)
dismissDirections.addAll(dismissDirectionsCopy)
} }
DismissValue.Default -> { }
} }
} val animateDismissContentAlpha by animateFloatAsState(
label = "animateDismissContentAlpha",
targetValue = if (lastDismissDirection != null) 1f else 0f,
animationSpec = tween(durationMillis = if (lastDismissDirection != null) 500 else 0),
finishedListener = {
lastDismissDirection = null
},
)
val dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f
val backgroundColor = if (chapterSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
MaterialTheme.colorScheme.primary
} else if (chapterSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
MaterialTheme.colorScheme.primary
} else {
Color.Unspecified
}
SwipeToDismiss( LaunchedEffect(dismissState.currentValue) {
state = dismissState, when (dismissState.currentValue) {
directions = dismissDirections, DismissValue.DismissedToEnd -> {
background = { lastDismissDirection = DismissDirection.StartToEnd
Box( val dismissDirectionsCopy = dismissDirections.toSet()
modifier = Modifier dismissDirections.clear()
.fillMaxSize() onChapterSwipe(chapterSwipeEndAction)
.background(backgroundColor), dismissState.snapTo(DismissValue.Default)
) { dismissDirections.addAll(dismissDirectionsCopy)
if (dismissState.dismissDirection in dismissDirections) {
val downloadState = downloadStateProvider()
SwipeBackgroundIcon(
modifier = Modifier
.padding(start = 16.dp)
.align(Alignment.CenterStart)
.alpha(
if (dismissState.dismissDirection == DismissDirection.StartToEnd) 1f else 0f,
),
tint = contentColorFor(backgroundColor),
swipeAction = chapterSwipeEndAction,
read = read,
bookmark = bookmark,
downloadState = downloadState,
)
SwipeBackgroundIcon(
modifier = Modifier
.padding(end = 16.dp)
.align(Alignment.CenterEnd)
.alpha(
if (dismissState.dismissDirection == DismissDirection.EndToStart) 1f else 0f,
),
tint = contentColorFor(backgroundColor),
swipeAction = chapterSwipeStartAction,
read = read,
bookmark = bookmark,
downloadState = downloadState,
)
} }
DismissValue.DismissedToStart -> {
lastDismissDirection = DismissDirection.EndToStart
val dismissDirectionsCopy = dismissDirections.toSet()
dismissDirections.clear()
onChapterSwipe(chapterSwipeStartAction)
dismissState.snapTo(DismissValue.Default)
dismissDirections.addAll(dismissDirectionsCopy)
}
DismissValue.Default -> { }
} }
}, }
dismissContent = {
Row( SwipeToDismiss(
modifier = modifier state = dismissState,
.background( directions = dismissDirections,
MaterialTheme.colorScheme.background.copy(dismissContentAlpha), background = {
) Box(
.selectedBackground(selected) modifier = Modifier
.alpha(dismissContentAlpha) .fillMaxSize()
.combinedClickable( .background(backgroundColor),
onClick = onClick,
onLongClick = onLongClick,
)
.padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp),
) {
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(6.dp),
) { ) {
Row( if (dismissState.dismissDirection in dismissDirections) {
horizontalArrangement = Arrangement.spacedBy(2.dp), val downloadState = downloadStateProvider()
verticalAlignment = Alignment.CenterVertically, SwipeBackgroundIcon(
) { modifier = Modifier
var textHeight by remember { mutableIntStateOf(0) } .padding(start = 16.dp)
if (!read) { .align(Alignment.CenterStart)
Icon( .alpha(
imageVector = Icons.Filled.Circle, if (dismissState.dismissDirection == DismissDirection.StartToEnd) 1f else 0f,
contentDescription = stringResource(R.string.unread), ),
modifier = Modifier tint = contentColorFor(backgroundColor),
.height(8.dp) swipeAction = chapterSwipeEndAction,
.padding(end = 4.dp), read = read,
tint = MaterialTheme.colorScheme.primary, bookmark = bookmark,
) downloadState = downloadState,
} )
if (bookmark) { SwipeBackgroundIcon(
Icon( modifier = Modifier
imageVector = Icons.Filled.Bookmark, .padding(end = 16.dp)
contentDescription = stringResource(R.string.action_filter_bookmarked), .align(Alignment.CenterEnd)
modifier = Modifier .alpha(
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }), if (dismissState.dismissDirection == DismissDirection.EndToStart) 1f else 0f,
tint = MaterialTheme.colorScheme.primary, ),
) tint = contentColorFor(backgroundColor),
} swipeAction = chapterSwipeStartAction,
Text( read = read,
text = title, bookmark = bookmark,
style = MaterialTheme.typography.bodyMedium, downloadState = downloadState,
color = LocalContentColor.current.copy(alpha = textAlpha),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
onTextLayout = { textHeight = it.size.height },
) )
} }
}
Row { },
ProvideTextStyle( dismissContent = {
value = MaterialTheme.typography.bodyMedium.copy( Row(
fontSize = 12.sp, modifier = modifier
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha), .background(
), MaterialTheme.colorScheme.background.copy(dismissContentAlpha),
)
.selectedBackground(selected)
.alpha(dismissContentAlpha)
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick,
)
.padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp),
) {
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
Row(
horizontalArrangement = Arrangement.spacedBy(2.dp),
verticalAlignment = Alignment.CenterVertically,
) { ) {
if (date != null) { var textHeight by remember { mutableIntStateOf(0) }
Text( if (!read) {
text = date, Icon(
maxLines = 1, imageVector = Icons.Filled.Circle,
overflow = TextOverflow.Ellipsis, contentDescription = stringResource(R.string.unread),
modifier = Modifier
.height(8.dp)
.padding(end = 4.dp),
tint = MaterialTheme.colorScheme.primary,
) )
if (readProgress != null || scanlator != null) DotSeparatorText()
} }
if (readProgress != null) { if (bookmark) {
Text( Icon(
text = readProgress, imageVector = Icons.Filled.Bookmark,
maxLines = 1, contentDescription = stringResource(R.string.action_filter_bookmarked),
overflow = TextOverflow.Ellipsis, modifier = Modifier
modifier = Modifier.alpha(ReadItemAlpha), .sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
tint = MaterialTheme.colorScheme.primary,
) )
if (scanlator != null) DotSeparatorText()
} }
if (scanlator != null) { Text(
Text( text = title,
text = scanlator, style = MaterialTheme.typography.bodyMedium,
maxLines = 1, color = LocalContentColor.current.copy(alpha = textAlpha),
overflow = TextOverflow.Ellipsis, maxLines = 1,
) overflow = TextOverflow.Ellipsis,
onTextLayout = { textHeight = it.size.height },
)
}
Row {
ProvideTextStyle(
value = MaterialTheme.typography.bodyMedium.copy(
fontSize = 12.sp,
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha),
),
) {
if (date != null) {
Text(
text = date,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (readProgress != null || scanlator != null) DotSeparatorText()
}
if (readProgress != null) {
Text(
text = readProgress,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.alpha(ReadItemAlpha),
)
if (scanlator != null) DotSeparatorText()
}
if (scanlator != null) {
Text(
text = scanlator,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
} }
} }
} }
}
if (onDownloadClick != null) { if (onDownloadClick != null) {
ChapterDownloadIndicator( ChapterDownloadIndicator(
enabled = downloadIndicatorEnabled, enabled = downloadIndicatorEnabled,
modifier = Modifier.padding(start = 4.dp), modifier = Modifier.padding(start = 4.dp),
downloadStateProvider = downloadStateProvider, downloadStateProvider = downloadStateProvider,
downloadProgressProvider = downloadProgressProvider, downloadProgressProvider = downloadProgressProvider,
onClick = onDownloadClick, onClick = onDownloadClick,
) )
}
} }
} },
}, )
) }
} }
@Composable @Composable