From 9ec8d770eaa364972b6a114fb788391db4e70806 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 10 Jun 2023 23:48:03 +0700 Subject: [PATCH] MangaChapterListItem: Increase swipe action touch slop (#9598) --- .../manga/components/MangaChapterListItem.kt | 359 +++++++++--------- 1 file changed, 185 insertions(+), 174 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt index 953f2c3d72..2360caaa70 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt @@ -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() } - 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() } + 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