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