mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-21 20:27:06 +03:00
parent
184804f62e
commit
59b4404c11
27 changed files with 442 additions and 539 deletions
13
.github/renovate.json
vendored
13
.github/renovate.json
vendored
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"schedule": ["every sunday"],
|
||||
"packageRules": [
|
||||
{
|
||||
"managers": ["maven"],
|
||||
"packageNames": ["com.google.guava:guava"],
|
||||
"versionScheme": "docker"
|
||||
}
|
||||
]
|
||||
}
|
22
.github/renovate.json5
vendored
Normal file
22
.github/renovate.json5
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"schedule": ["every sunday"],
|
||||
"packageRules": [
|
||||
{
|
||||
"managers": ["maven"],
|
||||
"packageNames": ["com.google.guava:guava"],
|
||||
"versionScheme": "docker"
|
||||
},
|
||||
{
|
||||
// Compiler plugins are tightly coupled to Kotlin version
|
||||
"groupName": "Kotlin",
|
||||
"matchPackagePrefixes": [
|
||||
"androidx.compose.compiler",
|
||||
"org.jetbrains.kotlin",
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
|
@ -247,6 +247,7 @@ dependencies {
|
|||
implementation(libs.bundles.voyager)
|
||||
implementation(libs.compose.materialmotion)
|
||||
implementation(libs.compose.simpleicons)
|
||||
implementation(libs.swipe)
|
||||
|
||||
// Logging
|
||||
implementation(libs.logcat)
|
||||
|
|
|
@ -100,8 +100,8 @@ fun AnimeScreen(
|
|||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
isTabletUi: Boolean,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
showNextEpisodeAirTime: Boolean,
|
||||
alwaysUseExternalPlayer: Boolean,
|
||||
onBackClicked: () -> Unit,
|
||||
|
@ -162,8 +162,8 @@ fun AnimeScreen(
|
|||
snackbarHostState = snackbarHostState,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
||||
onBackClicked = onBackClicked,
|
||||
|
@ -200,8 +200,8 @@ fun AnimeScreen(
|
|||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
||||
dateFormat = dateFormat,
|
||||
|
@ -244,8 +244,8 @@ private fun AnimeScreenSmallImpl(
|
|||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
showNextEpisodeAirTime: Boolean,
|
||||
alwaysUseExternalPlayer: Boolean,
|
||||
onBackClicked: () -> Unit,
|
||||
|
@ -490,8 +490,8 @@ private fun AnimeScreenSmallImpl(
|
|||
episodes = episodes,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
onEpisodeClicked = onEpisodeClicked,
|
||||
onDownloadEpisode = onDownloadEpisode,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
|
@ -510,8 +510,8 @@ fun AnimeScreenLargeImpl(
|
|||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
showNextEpisodeAirTime: Boolean,
|
||||
alwaysUseExternalPlayer: Boolean,
|
||||
onBackClicked: () -> Unit,
|
||||
|
@ -747,8 +747,8 @@ fun AnimeScreenLargeImpl(
|
|||
episodes = episodes,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
onEpisodeClicked = onEpisodeClicked,
|
||||
onDownloadEpisode = onDownloadEpisode,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
|
@ -818,8 +818,8 @@ private fun LazyListScope.sharedEpisodeItems(
|
|||
episodes: List<EpisodeItem>,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
onEpisodeClicked: (Episode, Boolean) -> Unit,
|
||||
onDownloadEpisode: ((List<EpisodeItem>, EpisodeDownloadAction) -> Unit)?,
|
||||
onEpisodeSelected: (EpisodeItem, Boolean, Boolean, Boolean) -> Unit,
|
||||
|
@ -867,8 +867,8 @@ private fun LazyListScope.sharedEpisodeItems(
|
|||
downloadIndicatorEnabled = episodes.fastAll { !it.selected },
|
||||
downloadStateProvider = { episodeItem.downloadState },
|
||||
downloadProgressProvider = { episodeItem.downloadProgress },
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||
onLongClick = {
|
||||
onEpisodeSelected(episodeItem, !episodeItem.selected, true, true)
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
package eu.kanade.presentation.entries.anime.components
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material.DismissDirection
|
||||
import androidx.compose.material.DismissValue
|
||||
import androidx.compose.material.SwipeToDismiss
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Bookmark
|
||||
import androidx.compose.material.icons.filled.Circle
|
||||
|
@ -26,7 +19,6 @@ import androidx.compose.material.icons.outlined.Done
|
|||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material.icons.outlined.FileDownloadOff
|
||||
import androidx.compose.material.icons.outlined.RemoveDone
|
||||
import androidx.compose.material.rememberDismissState
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -38,14 +30,18 @@ import androidx.compose.runtime.CompositionLocalProvider
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||
import androidx.compose.ui.platform.ViewConfiguration
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -55,10 +51,13 @@ import androidx.compose.ui.unit.sp
|
|||
import eu.kanade.presentation.entries.DotSeparatorText
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.anime.model.AnimeDownload
|
||||
import me.saket.swipe.SwipeableActionsBox
|
||||
import me.saket.swipe.rememberSwipeableActionsState
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
||||
import tachiyomi.presentation.core.util.selectedBackground
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
fun AnimeEpisodeListItem(
|
||||
|
@ -73,13 +72,19 @@ fun AnimeEpisodeListItem(
|
|||
downloadIndicatorEnabled: Boolean,
|
||||
downloadStateProvider: () -> AnimeDownload.State,
|
||||
downloadProgressProvider: () -> Int,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
onLongClick: () -> Unit,
|
||||
onClick: () -> Unit,
|
||||
onDownloadClick: ((EpisodeDownloadAction) -> Unit)?,
|
||||
onEpisodeSwipe: (LibraryPreferences.EpisodeSwipeAction) -> Unit,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val density = LocalDensity.current
|
||||
|
||||
val textAlpha = if (seen) ReadItemAlpha else 1f
|
||||
val textSubtitleAlpha = if (seen) ReadItemAlpha else SecondaryItemAlpha
|
||||
|
||||
// Increase touch slop of swipe action to reduce accidental trigger
|
||||
val configuration = LocalViewConfiguration.current
|
||||
CompositionLocalProvider(
|
||||
|
@ -87,248 +92,166 @@ fun AnimeEpisodeListItem(
|
|||
override val touchSlop: Float = configuration.touchSlop * 3f
|
||||
},
|
||||
) {
|
||||
val textAlpha = if (seen) ReadItemAlpha else 1f
|
||||
val textSubtitleAlpha = if (seen) ReadItemAlpha else SecondaryItemAlpha
|
||||
|
||||
val episodeSwipeStartEnabled = episodeSwipeStartAction != LibraryPreferences.EpisodeSwipeAction.Disabled
|
||||
val episodeSwipeEndEnabled = episodeSwipeEndAction != LibraryPreferences.EpisodeSwipeAction.Disabled
|
||||
|
||||
val dismissState = rememberDismissState()
|
||||
val dismissDirections = remember { mutableSetOf<DismissDirection>() }
|
||||
var lastDismissDirection: DismissDirection? by remember { mutableStateOf(null) }
|
||||
if (lastDismissDirection == null) {
|
||||
if (episodeSwipeStartEnabled) {
|
||||
dismissDirections.add(DismissDirection.EndToStart)
|
||||
}
|
||||
if (episodeSwipeEndEnabled) {
|
||||
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 start = getSwipeAction(
|
||||
action = episodeSwipeStartAction,
|
||||
seen = seen,
|
||||
bookmark = bookmark,
|
||||
downloadState = downloadStateProvider(),
|
||||
background = MaterialTheme.colorScheme.primaryContainer,
|
||||
onSwipe = { onEpisodeSwipe(episodeSwipeStartAction) },
|
||||
)
|
||||
val dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
||||
val backgroundColor = if (episodeSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else if (episodeSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
Color.Unspecified
|
||||
val end = getSwipeAction(
|
||||
action = episodeSwipeEndAction,
|
||||
seen = seen,
|
||||
bookmark = bookmark,
|
||||
downloadState = downloadStateProvider(),
|
||||
background = MaterialTheme.colorScheme.primaryContainer,
|
||||
onSwipe = { onEpisodeSwipe(episodeSwipeEndAction) },
|
||||
)
|
||||
|
||||
val swipeableActionsState = rememberSwipeableActionsState()
|
||||
LaunchedEffect(Unit) {
|
||||
// Haptic effect when swipe over threshold
|
||||
val swipeActionThresholdPx = with(density) { swipeActionThreshold.toPx() }
|
||||
snapshotFlow { swipeableActionsState.offset.value.absoluteValue > swipeActionThresholdPx }
|
||||
.collect { if (it) haptic.performHapticFeedback(HapticFeedbackType.LongPress) }
|
||||
}
|
||||
|
||||
LaunchedEffect(dismissState.currentValue) {
|
||||
when (dismissState.currentValue) {
|
||||
DismissValue.DismissedToEnd -> {
|
||||
lastDismissDirection = DismissDirection.StartToEnd
|
||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
||||
dismissDirections.clear()
|
||||
onEpisodeSwipe(episodeSwipeEndAction)
|
||||
dismissState.snapTo(DismissValue.Default)
|
||||
dismissDirections.addAll(dismissDirectionsCopy)
|
||||
}
|
||||
DismissValue.DismissedToStart -> {
|
||||
lastDismissDirection = DismissDirection.EndToStart
|
||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
||||
dismissDirections.clear()
|
||||
onEpisodeSwipe(episodeSwipeStartAction)
|
||||
dismissState.snapTo(DismissValue.Default)
|
||||
dismissDirections.addAll(dismissDirectionsCopy)
|
||||
}
|
||||
DismissValue.Default -> { }
|
||||
}
|
||||
}
|
||||
|
||||
SwipeToDismiss(
|
||||
state = dismissState,
|
||||
directions = dismissDirections,
|
||||
background = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(backgroundColor),
|
||||
SwipeableActionsBox(
|
||||
modifier = Modifier.clipToBounds(),
|
||||
state = swipeableActionsState,
|
||||
startActions = listOfNotNull(start),
|
||||
endActions = listOfNotNull(end),
|
||||
swipeThreshold = swipeActionThreshold,
|
||||
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.selectedBackground(selected)
|
||||
.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),
|
||||
) {
|
||||
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 = episodeSwipeEndAction,
|
||||
seen = seen,
|
||||
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 = episodeSwipeStartAction,
|
||||
seen = seen,
|
||||
bookmark = bookmark,
|
||||
downloadState = downloadState,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
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,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
var textHeight by remember { mutableIntStateOf(0) }
|
||||
if (!seen) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Circle,
|
||||
contentDescription = stringResource(R.string.unseen),
|
||||
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 },
|
||||
var textHeight by remember { mutableIntStateOf(0) }
|
||||
if (!seen) {
|
||||
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 },
|
||||
)
|
||||
}
|
||||
|
||||
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 (watchProgress != null || scanlator != null) DotSeparatorText()
|
||||
}
|
||||
if (watchProgress != null) {
|
||||
Text(
|
||||
text = watchProgress,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.alpha(ReadItemAlpha),
|
||||
)
|
||||
if (scanlator != null) DotSeparatorText()
|
||||
}
|
||||
if (scanlator != null) {
|
||||
Text(
|
||||
text = scanlator,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
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 (watchProgress != null || scanlator != null) DotSeparatorText()
|
||||
}
|
||||
if (watchProgress != null) {
|
||||
Text(
|
||||
text = watchProgress,
|
||||
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) {
|
||||
EpisodeDownloadIndicator(
|
||||
enabled = downloadIndicatorEnabled,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
downloadStateProvider = downloadStateProvider,
|
||||
downloadProgressProvider = downloadProgressProvider,
|
||||
onClick = onDownloadClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (onDownloadClick != null) {
|
||||
EpisodeDownloadIndicator(
|
||||
enabled = downloadIndicatorEnabled,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
downloadStateProvider = downloadStateProvider,
|
||||
downloadProgressProvider = downloadProgressProvider,
|
||||
onClick = onDownloadClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SwipeBackgroundIcon(
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color,
|
||||
swipeAction: LibraryPreferences.EpisodeSwipeAction,
|
||||
private fun getSwipeAction(
|
||||
action: LibraryPreferences.EpisodeSwipeAction,
|
||||
seen: Boolean,
|
||||
bookmark: Boolean,
|
||||
downloadState: AnimeDownload.State,
|
||||
) {
|
||||
val imageVector = when (swipeAction) {
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleSeen -> {
|
||||
if (!seen) {
|
||||
Icons.Outlined.Done
|
||||
} else {
|
||||
Icons.Outlined.RemoveDone
|
||||
}
|
||||
}
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark -> {
|
||||
if (!bookmark) {
|
||||
Icons.Outlined.BookmarkAdd
|
||||
} else {
|
||||
Icons.Outlined.BookmarkRemove
|
||||
}
|
||||
}
|
||||
LibraryPreferences.EpisodeSwipeAction.Download -> {
|
||||
when (downloadState) {
|
||||
AnimeDownload.State.NOT_DOWNLOADED,
|
||||
AnimeDownload.State.ERROR,
|
||||
-> { Icons.Outlined.Download }
|
||||
AnimeDownload.State.QUEUE,
|
||||
AnimeDownload.State.DOWNLOADING,
|
||||
-> { Icons.Outlined.FileDownloadOff }
|
||||
AnimeDownload.State.DOWNLOADED -> { Icons.Outlined.Delete }
|
||||
}
|
||||
}
|
||||
LibraryPreferences.EpisodeSwipeAction.Disabled -> null
|
||||
}
|
||||
imageVector?.let {
|
||||
Icon(
|
||||
modifier = modifier,
|
||||
imageVector = imageVector,
|
||||
tint = tint,
|
||||
contentDescription = null,
|
||||
background: Color,
|
||||
onSwipe: () -> Unit,
|
||||
): me.saket.swipe.SwipeAction? {
|
||||
return when (action) {
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleSeen -> swipeAction(
|
||||
icon = if (!seen) Icons.Outlined.Done else Icons.Outlined.RemoveDone,
|
||||
background = background,
|
||||
isUndo = seen,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark -> swipeAction(
|
||||
icon = if (!bookmark) Icons.Outlined.BookmarkAdd else Icons.Outlined.BookmarkRemove,
|
||||
background = background,
|
||||
isUndo = bookmark,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.EpisodeSwipeAction.Download -> swipeAction(
|
||||
icon = when (downloadState) {
|
||||
AnimeDownload.State.NOT_DOWNLOADED, AnimeDownload.State.ERROR -> Icons.Outlined.Download
|
||||
AnimeDownload.State.QUEUE, AnimeDownload.State.DOWNLOADING -> Icons.Outlined.FileDownloadOff
|
||||
AnimeDownload.State.DOWNLOADED -> Icons.Outlined.Delete
|
||||
},
|
||||
background = background,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.EpisodeSwipeAction.Disabled -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,3 +293,26 @@ fun NextEpisodeAiringListItem(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun swipeAction(
|
||||
onSwipe: () -> Unit,
|
||||
icon: ImageVector,
|
||||
background: Color,
|
||||
isUndo: Boolean = false,
|
||||
): me.saket.swipe.SwipeAction {
|
||||
return me.saket.swipe.SwipeAction(
|
||||
icon = {
|
||||
Icon(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
imageVector = icon,
|
||||
tint = contentColorFor(background),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
background = background,
|
||||
onSwipe = onSwipe,
|
||||
isUndo = isUndo,
|
||||
)
|
||||
}
|
||||
|
||||
private val swipeActionThreshold = 56.dp
|
||||
|
|
|
@ -93,8 +93,8 @@ fun MangaScreen(
|
|||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
isTabletUi: Boolean,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onBackClicked: () -> Unit,
|
||||
onChapterClicked: (Chapter) -> Unit,
|
||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||
|
@ -152,8 +152,8 @@ fun MangaScreen(
|
|||
snackbarHostState = snackbarHostState,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
onBackClicked = onBackClicked,
|
||||
onChapterClicked = onChapterClicked,
|
||||
onDownloadChapter = onDownloadChapter,
|
||||
|
@ -187,8 +187,8 @@ fun MangaScreen(
|
|||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
dateFormat = dateFormat,
|
||||
onBackClicked = onBackClicked,
|
||||
onChapterClicked = onChapterClicked,
|
||||
|
@ -227,8 +227,8 @@ private fun MangaScreenSmallImpl(
|
|||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onBackClicked: () -> Unit,
|
||||
onChapterClicked: (Chapter) -> Unit,
|
||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||
|
@ -439,8 +439,8 @@ private fun MangaScreenSmallImpl(
|
|||
chapters = chapters,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
onChapterClicked = onChapterClicked,
|
||||
onDownloadChapter = onDownloadChapter,
|
||||
onChapterSelected = onChapterSelected,
|
||||
|
@ -458,8 +458,8 @@ fun MangaScreenLargeImpl(
|
|||
snackbarHostState: SnackbarHostState,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onBackClicked: () -> Unit,
|
||||
onChapterClicked: (Chapter) -> Unit,
|
||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||
|
@ -664,8 +664,8 @@ fun MangaScreenLargeImpl(
|
|||
chapters = chapters,
|
||||
dateRelativeTime = dateRelativeTime,
|
||||
dateFormat = dateFormat,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
onChapterClicked = onChapterClicked,
|
||||
onDownloadChapter = onDownloadChapter,
|
||||
onChapterSelected = onChapterSelected,
|
||||
|
@ -727,8 +727,8 @@ private fun LazyListScope.sharedChapterItems(
|
|||
chapters: List<ChapterItem>,
|
||||
dateRelativeTime: Int,
|
||||
dateFormat: DateFormat,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onChapterClicked: (Chapter) -> Unit,
|
||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
|
||||
|
@ -775,8 +775,8 @@ private fun LazyListScope.sharedChapterItems(
|
|||
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
||||
downloadStateProvider = { chapterItem.downloadState },
|
||||
downloadProgressProvider = { chapterItem.downloadProgress },
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||
onLongClick = {
|
||||
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
package eu.kanade.presentation.entries.manga.components
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material.DismissDirection
|
||||
import androidx.compose.material.DismissValue
|
||||
import androidx.compose.material.SwipeToDismiss
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Bookmark
|
||||
import androidx.compose.material.icons.filled.Circle
|
||||
|
@ -25,7 +18,6 @@ import androidx.compose.material.icons.outlined.Done
|
|||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material.icons.outlined.FileDownloadOff
|
||||
import androidx.compose.material.icons.outlined.RemoveDone
|
||||
import androidx.compose.material.rememberDismissState
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -37,14 +29,18 @@ import androidx.compose.runtime.CompositionLocalProvider
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||
import androidx.compose.ui.platform.ViewConfiguration
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -54,10 +50,13 @@ import androidx.compose.ui.unit.sp
|
|||
import eu.kanade.presentation.entries.DotSeparatorText
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.manga.model.MangaDownload
|
||||
import me.saket.swipe.SwipeableActionsBox
|
||||
import me.saket.swipe.rememberSwipeableActionsState
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
||||
import tachiyomi.presentation.core.util.selectedBackground
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
fun MangaChapterListItem(
|
||||
|
@ -72,13 +71,19 @@ fun MangaChapterListItem(
|
|||
downloadIndicatorEnabled: Boolean,
|
||||
downloadStateProvider: () -> MangaDownload.State,
|
||||
downloadProgressProvider: () -> Int,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||
onLongClick: () -> Unit,
|
||||
onClick: () -> Unit,
|
||||
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
|
||||
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val density = LocalDensity.current
|
||||
|
||||
val textAlpha = if (read) ReadItemAlpha else 1f
|
||||
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
|
||||
|
||||
// Increase touch slop of swipe action to reduce accidental trigger
|
||||
val configuration = LocalViewConfiguration.current
|
||||
CompositionLocalProvider(
|
||||
|
@ -86,254 +91,187 @@ fun MangaChapterListItem(
|
|||
override val touchSlop: Float = configuration.touchSlop * 3f
|
||||
},
|
||||
) {
|
||||
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
|
||||
},
|
||||
val start = getSwipeAction(
|
||||
action = chapterSwipeStartAction,
|
||||
read = read,
|
||||
bookmark = bookmark,
|
||||
downloadState = downloadStateProvider(),
|
||||
background = MaterialTheme.colorScheme.primaryContainer,
|
||||
onSwipe = { onChapterSwipe(chapterSwipeStartAction) },
|
||||
)
|
||||
val end = getSwipeAction(
|
||||
action = chapterSwipeEndAction,
|
||||
read = read,
|
||||
bookmark = bookmark,
|
||||
downloadState = downloadStateProvider(),
|
||||
background = MaterialTheme.colorScheme.primaryContainer,
|
||||
onSwipe = { onChapterSwipe(chapterSwipeEndAction) },
|
||||
)
|
||||
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
|
||||
}
|
||||
|
||||
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 -> {}
|
||||
}
|
||||
val swipeableActionsState = rememberSwipeableActionsState()
|
||||
LaunchedEffect(Unit) {
|
||||
// Haptic effect when swipe over threshold
|
||||
val swipeActionThresholdPx = with(density) { swipeActionThreshold.toPx() }
|
||||
snapshotFlow { swipeableActionsState.offset.value.absoluteValue > swipeActionThresholdPx }
|
||||
.collect { if (it) haptic.performHapticFeedback(HapticFeedbackType.LongPress) }
|
||||
}
|
||||
|
||||
SwipeToDismiss(
|
||||
state = dismissState,
|
||||
directions = dismissDirections,
|
||||
background = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(backgroundColor),
|
||||
SwipeableActionsBox(
|
||||
modifier = Modifier.clipToBounds(),
|
||||
state = swipeableActionsState,
|
||||
startActions = listOfNotNull(start),
|
||||
endActions = listOfNotNull(end),
|
||||
swipeThreshold = swipeActionThreshold,
|
||||
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.selectedBackground(selected)
|
||||
.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),
|
||||
) {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
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,
|
||||
) {
|
||||
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 },
|
||||
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 },
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
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) {
|
||||
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
|
||||
private fun SwipeBackgroundIcon(
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color,
|
||||
swipeAction: LibraryPreferences.ChapterSwipeAction,
|
||||
private fun getSwipeAction(
|
||||
action: LibraryPreferences.ChapterSwipeAction,
|
||||
read: Boolean,
|
||||
bookmark: Boolean,
|
||||
downloadState: MangaDownload.State,
|
||||
) {
|
||||
val imageVector = when (swipeAction) {
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
|
||||
if (!read) {
|
||||
Icons.Outlined.Done
|
||||
} else {
|
||||
Icons.Outlined.RemoveDone
|
||||
}
|
||||
}
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
|
||||
if (!bookmark) {
|
||||
Icons.Outlined.BookmarkAdd
|
||||
} else {
|
||||
Icons.Outlined.BookmarkRemove
|
||||
}
|
||||
}
|
||||
LibraryPreferences.ChapterSwipeAction.Download -> {
|
||||
when (downloadState) {
|
||||
MangaDownload.State.NOT_DOWNLOADED,
|
||||
MangaDownload.State.ERROR,
|
||||
-> { Icons.Outlined.Download }
|
||||
MangaDownload.State.QUEUE,
|
||||
MangaDownload.State.DOWNLOADING,
|
||||
-> { Icons.Outlined.FileDownloadOff }
|
||||
MangaDownload.State.DOWNLOADED -> { Icons.Outlined.Delete }
|
||||
}
|
||||
}
|
||||
background: Color,
|
||||
onSwipe: () -> Unit,
|
||||
): me.saket.swipe.SwipeAction? {
|
||||
return when (action) {
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleRead -> swipeAction(
|
||||
icon = if (!read) Icons.Outlined.Done else Icons.Outlined.RemoveDone,
|
||||
background = background,
|
||||
isUndo = read,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> swipeAction(
|
||||
icon = if (!bookmark) Icons.Outlined.BookmarkAdd else Icons.Outlined.BookmarkRemove,
|
||||
background = background,
|
||||
isUndo = bookmark,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.ChapterSwipeAction.Download -> swipeAction(
|
||||
icon = when (downloadState) {
|
||||
MangaDownload.State.NOT_DOWNLOADED, MangaDownload.State.ERROR -> Icons.Outlined.Download
|
||||
MangaDownload.State.QUEUE, MangaDownload.State.DOWNLOADING -> Icons.Outlined.FileDownloadOff
|
||||
MangaDownload.State.DOWNLOADED -> Icons.Outlined.Delete
|
||||
},
|
||||
background = background,
|
||||
onSwipe = onSwipe,
|
||||
)
|
||||
LibraryPreferences.ChapterSwipeAction.Disabled -> null
|
||||
}
|
||||
imageVector?.let {
|
||||
Icon(
|
||||
modifier = modifier,
|
||||
imageVector = imageVector,
|
||||
tint = tint,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun swipeAction(
|
||||
onSwipe: () -> Unit,
|
||||
icon: ImageVector,
|
||||
background: Color,
|
||||
isUndo: Boolean = false,
|
||||
): me.saket.swipe.SwipeAction {
|
||||
return me.saket.swipe.SwipeAction(
|
||||
icon = {
|
||||
Icon(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
imageVector = icon,
|
||||
tint = contentColorFor(background),
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
background = background,
|
||||
onSwipe = onSwipe,
|
||||
isUndo = isUndo,
|
||||
)
|
||||
}
|
||||
|
||||
private val swipeActionThreshold = 56.dp
|
||||
|
|
|
@ -30,6 +30,8 @@ import eu.kanade.domain.base.BasePreferences
|
|||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.source.service.SourcePreferences.DataSaver
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.screen.advanced.ClearAnimeDatabaseScreen
|
||||
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
||||
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
||||
import eu.kanade.presentation.util.collectAsState
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
|
|
@ -394,7 +394,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||
preferenceItems = listOf(
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = libraryPreferences.swipeChapterStartAction(),
|
||||
title = stringResource(R.string.pref_chapter_swipe_start),
|
||||
title = stringResource(R.string.pref_chapter_swipe_end),
|
||||
entries = mapOf(
|
||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||
|
@ -404,7 +404,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = libraryPreferences.swipeChapterEndAction(),
|
||||
title = stringResource(R.string.pref_chapter_swipe_end),
|
||||
title = stringResource(R.string.pref_chapter_swipe_start),
|
||||
entries = mapOf(
|
||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||
|
@ -425,7 +425,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||
preferenceItems = listOf(
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = libraryPreferences.swipeEpisodeStartAction(),
|
||||
title = stringResource(R.string.pref_episode_swipe_start),
|
||||
title = stringResource(R.string.pref_episode_swipe_end),
|
||||
entries = mapOf(
|
||||
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark_episode),
|
||||
|
@ -435,7 +435,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = libraryPreferences.swipeEpisodeEndAction(),
|
||||
title = stringResource(R.string.pref_episode_swipe_end),
|
||||
title = stringResource(R.string.pref_episode_swipe_start),
|
||||
entries = mapOf(
|
||||
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark_episode),
|
||||
|
|
|
@ -45,6 +45,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
|||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.UpIcon
|
||||
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||
import eu.kanade.presentation.util.LocalBackPress
|
||||
import eu.kanade.presentation.util.Screen
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -39,12 +38,14 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
|
@ -52,7 +53,6 @@ import eu.kanade.presentation.components.UpIcon
|
|||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.isLTR
|
||||
import tachiyomi.presentation.core.components.material.Divider
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
|
@ -164,6 +164,8 @@ private fun SearchResult(
|
|||
) {
|
||||
if (searchKey.isEmpty()) return
|
||||
|
||||
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
||||
|
||||
val index = getIndex()
|
||||
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
|
||||
value = index.asSequence()
|
||||
|
@ -199,7 +201,7 @@ private fun SearchResult(
|
|||
SearchResultItem(
|
||||
route = settingsData.route,
|
||||
title = p.title,
|
||||
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle),
|
||||
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle, isLtr = isLtr),
|
||||
highlightKey = p.title,
|
||||
)
|
||||
}
|
||||
|
@ -264,11 +266,11 @@ private fun getIndex() = settingScreens
|
|||
)
|
||||
}
|
||||
|
||||
private fun getLocalizedBreadcrumb(path: String, node: String?): String {
|
||||
private fun getLocalizedBreadcrumb(path: String, node: String?, isLtr: Boolean): String {
|
||||
return if (node == null) {
|
||||
path
|
||||
} else {
|
||||
if (Resources.getSystem().isLTR) {
|
||||
if (isLtr) {
|
||||
// This locale reads left to right.
|
||||
"$path > $node"
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
package eu.kanade.presentation.more.settings.screen.about
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.AnimatedVisibility
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
package eu.kanade.presentation.more.settings.screen.about
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
package eu.kanade.presentation.more.settings.screen.about
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
package eu.kanade.presentation.more.settings.screen.advanced
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
package eu.kanade.presentation.more.settings.screen.advanced
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
|
@ -12,7 +12,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
||||
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
||||
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
|
|
|
@ -106,8 +106,8 @@ class AnimeScreen(
|
|||
dateRelativeTime = screenModel.relativeTime,
|
||||
dateFormat = screenModel.dateFormat,
|
||||
isTabletUi = isTabletUi(),
|
||||
episodeSwipeEndAction = screenModel.episodeSwipeEndAction,
|
||||
episodeSwipeStartAction = screenModel.episodeSwipeStartAction,
|
||||
episodeSwipeEndAction = screenModel.episodeSwipeEndAction,
|
||||
showNextEpisodeAirTime = screenModel.showNextEpisodeAirTime,
|
||||
alwaysUseExternalPlayer = screenModel.alwaysUseExternalPlayer,
|
||||
onBackClicked = navigator::pop,
|
||||
|
|
|
@ -126,8 +126,8 @@ class AnimeInfoScreenModel(
|
|||
private val processedEpisodes: List<EpisodeItem>?
|
||||
get() = successState?.processedEpisodes
|
||||
|
||||
val episodeSwipeEndAction = libraryPreferences.swipeEpisodeEndAction().get()
|
||||
val episodeSwipeStartAction = libraryPreferences.swipeEpisodeStartAction().get()
|
||||
val episodeSwipeStartAction = libraryPreferences.swipeEpisodeEndAction().get()
|
||||
val episodeSwipeEndAction = libraryPreferences.swipeEpisodeStartAction().get()
|
||||
|
||||
val showNextEpisodeAirTime = trackPreferences.showNextEpisodeAiringTime().get()
|
||||
val alwaysUseExternalPlayer = playerPreferences.alwaysUseExternalPlayer().get()
|
||||
|
|
|
@ -102,8 +102,8 @@ class MangaScreen(
|
|||
dateRelativeTime = screenModel.relativeTime,
|
||||
dateFormat = screenModel.dateFormat,
|
||||
isTabletUi = isTabletUi(),
|
||||
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
||||
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
||||
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
||||
onBackClicked = navigator::pop,
|
||||
onChapterClicked = { openChapter(context, it) },
|
||||
onDownloadChapter = screenModel::runChapterDownloadActions.takeIf { !successState.source.isLocalOrStub() },
|
||||
|
|
|
@ -124,8 +124,8 @@ class MangaInfoScreenModel(
|
|||
private val filteredChapters: List<ChapterItem>?
|
||||
get() = successState?.processedChapters
|
||||
|
||||
val chapterSwipeEndAction = libraryPreferences.swipeChapterEndAction().get()
|
||||
val chapterSwipeStartAction = libraryPreferences.swipeChapterStartAction().get()
|
||||
val chapterSwipeStartAction = libraryPreferences.swipeChapterEndAction().get()
|
||||
val chapterSwipeEndAction = libraryPreferences.swipeChapterStartAction().get()
|
||||
|
||||
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||
|
|
|
@ -109,6 +109,7 @@ class PlayerViewModel(
|
|||
val eventFlow = eventChannel.receiveAsFlow()
|
||||
|
||||
private val incognitoMode = basePreferences.incognitoMode().get()
|
||||
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileWatching().get()
|
||||
|
||||
internal val relativeTime = uiPreferences.relativeTime().get()
|
||||
internal val dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get())
|
||||
|
@ -349,9 +350,9 @@ class PlayerViewModel(
|
|||
}
|
||||
|
||||
private fun downloadNextEpisodes() {
|
||||
if (downloadAheadAmount == 0) return
|
||||
val anime = currentAnime ?: return
|
||||
val amount = downloadPreferences.autoDownloadWhileWatching().get()
|
||||
if (amount == 0 || !anime.favorite) return
|
||||
|
||||
// Only download ahead if current + next episode is already downloaded too to avoid jank
|
||||
if (getCurrentEpisodeIndex() == this.currentPlaylist.lastIndex) return
|
||||
val currentEpisode = currentEpisode ?: return
|
||||
|
@ -366,7 +367,7 @@ class PlayerViewModel(
|
|||
return@launchIO
|
||||
}
|
||||
val episodesToDownload = getNextEpisodes.await(anime.id, nextEpisode.id!!)
|
||||
.take(amount)
|
||||
.take(downloadAheadAmount)
|
||||
downloadManager.downloadEpisodes(anime, episodesToDownload)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
|
@ -204,6 +205,7 @@ class ReaderViewModel(
|
|||
}
|
||||
|
||||
private val incognitoMode = preferences.incognitoMode().get()
|
||||
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileReading().get()
|
||||
|
||||
init {
|
||||
// To save state
|
||||
|
@ -444,12 +446,11 @@ class ReaderViewModel(
|
|||
}
|
||||
|
||||
private fun downloadNextChapters() {
|
||||
if (downloadAheadAmount == 0) return
|
||||
val manga = manga ?: return
|
||||
val amount = downloadPreferences.autoDownloadWhileReading().get()
|
||||
if (amount == 0 || !manga.favorite) return
|
||||
|
||||
// Only download ahead if current + next chapter is already downloaded too to avoid jank
|
||||
if (getCurrentChapter()?.pageLoader?.isLocal == true) return
|
||||
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
||||
val nextChapter = state.value.viewerChapters?.nextChapter?.chapter ?: return
|
||||
|
||||
viewModelScope.launchIO {
|
||||
|
@ -467,7 +468,7 @@ class ReaderViewModel(
|
|||
} else {
|
||||
this
|
||||
}
|
||||
}.take(amount)
|
||||
}.take(downloadAheadAmount)
|
||||
downloadManager.downloadChapters(
|
||||
manga,
|
||||
chaptersToDownload,
|
||||
|
|
|
@ -12,10 +12,10 @@ import androidx.compose.ui.Modifier
|
|||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
||||
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen
|
||||
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
||||
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
||||
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||
import eu.kanade.presentation.util.LocalBackPress
|
||||
import eu.kanade.presentation.util.Screen
|
||||
|
|
|
@ -261,22 +261,22 @@ class LibraryPreferences(
|
|||
|
||||
// region Swipe Actions
|
||||
|
||||
fun swipeEpisodeStartAction() =
|
||||
preferenceStore.getEnum("pref_episode_swipe_end_action", EpisodeSwipeAction.ToggleSeen)
|
||||
|
||||
fun swipeEpisodeEndAction() = preferenceStore.getEnum(
|
||||
"pref_episode_swipe_start_action",
|
||||
EpisodeSwipeAction.ToggleBookmark,
|
||||
)
|
||||
|
||||
fun swipeEpisodeStartAction() =
|
||||
preferenceStore.getEnum("pref_episode_swipe_end_action", EpisodeSwipeAction.ToggleSeen)
|
||||
fun swipeChapterStartAction() =
|
||||
preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleRead)
|
||||
|
||||
fun swipeChapterEndAction() = preferenceStore.getEnum(
|
||||
"pref_chapter_swipe_start_action",
|
||||
ChapterSwipeAction.ToggleBookmark,
|
||||
)
|
||||
|
||||
fun swipeChapterStartAction() =
|
||||
preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleRead)
|
||||
|
||||
// endregion
|
||||
|
||||
enum class EpisodeSwipeAction {
|
||||
|
|
|
@ -19,7 +19,7 @@ flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4"
|
|||
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" }
|
||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp_version" }
|
||||
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" }
|
||||
okio = "com.squareup.okio:okio:3.3.0"
|
||||
okio = "com.squareup.okio:okio:3.4.0"
|
||||
|
||||
conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2"
|
||||
|
||||
|
@ -60,6 +60,8 @@ insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
|||
compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.3"
|
||||
compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0"
|
||||
|
||||
swipe = "me.saket.swipe:swipe:1.2.0"
|
||||
|
||||
logcat = "com.squareup.logcat:logcat:0.1"
|
||||
|
||||
acra-http = "ch.acra:acra-http:5.10.1"
|
||||
|
|
|
@ -463,7 +463,7 @@
|
|||
<item quantity="one">Next unread chapter</item>
|
||||
<item quantity="other">Next %d unread chapters</item>
|
||||
</plurals>
|
||||
<string name="download_ahead_info">Only works on entries in library and if the current chapter plus the next one are already downloaded</string>
|
||||
<string name="download_ahead_info">Only works if the current chapter/episode + the next one are already downloaded.</string>
|
||||
<string name="save_chapter_as_cbz">Save as CBZ archive</string>
|
||||
<string name="split_tall_images">Split tall images</string>
|
||||
<string name="split_tall_images_summary">Improves reader performance</string>
|
||||
|
|
Loading…
Reference in a new issue