mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-24 21:58:34 +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.bundles.voyager)
|
||||||
implementation(libs.compose.materialmotion)
|
implementation(libs.compose.materialmotion)
|
||||||
implementation(libs.compose.simpleicons)
|
implementation(libs.compose.simpleicons)
|
||||||
|
implementation(libs.swipe)
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.logcat)
|
implementation(libs.logcat)
|
||||||
|
|
|
@ -100,8 +100,8 @@ fun AnimeScreen(
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
isTabletUi: Boolean,
|
isTabletUi: Boolean,
|
||||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
|
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
showNextEpisodeAirTime: Boolean,
|
showNextEpisodeAirTime: Boolean,
|
||||||
alwaysUseExternalPlayer: Boolean,
|
alwaysUseExternalPlayer: Boolean,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
|
@ -162,8 +162,8 @@ fun AnimeScreen(
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||||
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
|
@ -200,8 +200,8 @@ fun AnimeScreen(
|
||||||
state = state,
|
state = state,
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||||
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
showNextEpisodeAirTime = showNextEpisodeAirTime,
|
||||||
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
alwaysUseExternalPlayer = alwaysUseExternalPlayer,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
|
@ -244,8 +244,8 @@ private fun AnimeScreenSmallImpl(
|
||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
|
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
showNextEpisodeAirTime: Boolean,
|
showNextEpisodeAirTime: Boolean,
|
||||||
alwaysUseExternalPlayer: Boolean,
|
alwaysUseExternalPlayer: Boolean,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
|
@ -490,8 +490,8 @@ private fun AnimeScreenSmallImpl(
|
||||||
episodes = episodes,
|
episodes = episodes,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||||
onEpisodeClicked = onEpisodeClicked,
|
onEpisodeClicked = onEpisodeClicked,
|
||||||
onDownloadEpisode = onDownloadEpisode,
|
onDownloadEpisode = onDownloadEpisode,
|
||||||
onEpisodeSelected = onEpisodeSelected,
|
onEpisodeSelected = onEpisodeSelected,
|
||||||
|
@ -510,8 +510,8 @@ fun AnimeScreenLargeImpl(
|
||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
|
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
showNextEpisodeAirTime: Boolean,
|
showNextEpisodeAirTime: Boolean,
|
||||||
alwaysUseExternalPlayer: Boolean,
|
alwaysUseExternalPlayer: Boolean,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
|
@ -747,8 +747,8 @@ fun AnimeScreenLargeImpl(
|
||||||
episodes = episodes,
|
episodes = episodes,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||||
onEpisodeClicked = onEpisodeClicked,
|
onEpisodeClicked = onEpisodeClicked,
|
||||||
onDownloadEpisode = onDownloadEpisode,
|
onDownloadEpisode = onDownloadEpisode,
|
||||||
onEpisodeSelected = onEpisodeSelected,
|
onEpisodeSelected = onEpisodeSelected,
|
||||||
|
@ -818,8 +818,8 @@ private fun LazyListScope.sharedEpisodeItems(
|
||||||
episodes: List<EpisodeItem>,
|
episodes: List<EpisodeItem>,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
|
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
onEpisodeClicked: (Episode, Boolean) -> Unit,
|
onEpisodeClicked: (Episode, Boolean) -> Unit,
|
||||||
onDownloadEpisode: ((List<EpisodeItem>, EpisodeDownloadAction) -> Unit)?,
|
onDownloadEpisode: ((List<EpisodeItem>, EpisodeDownloadAction) -> Unit)?,
|
||||||
onEpisodeSelected: (EpisodeItem, Boolean, Boolean, Boolean) -> Unit,
|
onEpisodeSelected: (EpisodeItem, Boolean, Boolean, Boolean) -> Unit,
|
||||||
|
@ -867,8 +867,8 @@ private fun LazyListScope.sharedEpisodeItems(
|
||||||
downloadIndicatorEnabled = episodes.fastAll { !it.selected },
|
downloadIndicatorEnabled = episodes.fastAll { !it.selected },
|
||||||
downloadStateProvider = { episodeItem.downloadState },
|
downloadStateProvider = { episodeItem.downloadState },
|
||||||
downloadProgressProvider = { episodeItem.downloadProgress },
|
downloadProgressProvider = { episodeItem.downloadProgress },
|
||||||
episodeSwipeEndAction = episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = episodeSwipeStartAction,
|
episodeSwipeStartAction = episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = episodeSwipeEndAction,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
onEpisodeSelected(episodeItem, !episodeItem.selected, true, true)
|
onEpisodeSelected(episodeItem, !episodeItem.selected, true, true)
|
||||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
|
|
@ -1,21 +1,14 @@
|
||||||
package eu.kanade.presentation.entries.anime.components
|
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.background
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
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.Icons
|
||||||
import androidx.compose.material.icons.filled.Bookmark
|
import androidx.compose.material.icons.filled.Bookmark
|
||||||
import androidx.compose.material.icons.filled.Circle
|
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.Download
|
||||||
import androidx.compose.material.icons.outlined.FileDownloadOff
|
import androidx.compose.material.icons.outlined.FileDownloadOff
|
||||||
import androidx.compose.material.icons.outlined.RemoveDone
|
import androidx.compose.material.icons.outlined.RemoveDone
|
||||||
import androidx.compose.material.rememberDismissState
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
@ -38,14 +30,18 @@ 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
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.graphics.Color
|
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.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
import androidx.compose.ui.platform.ViewConfiguration
|
import androidx.compose.ui.platform.ViewConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
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.presentation.entries.DotSeparatorText
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.anime.model.AnimeDownload
|
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.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||||
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
||||||
import tachiyomi.presentation.core.util.selectedBackground
|
import tachiyomi.presentation.core.util.selectedBackground
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnimeEpisodeListItem(
|
fun AnimeEpisodeListItem(
|
||||||
|
@ -73,13 +72,19 @@ fun AnimeEpisodeListItem(
|
||||||
downloadIndicatorEnabled: Boolean,
|
downloadIndicatorEnabled: Boolean,
|
||||||
downloadStateProvider: () -> AnimeDownload.State,
|
downloadStateProvider: () -> AnimeDownload.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
episodeSwipeStartAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
|
episodeSwipeEndAction: LibraryPreferences.EpisodeSwipeAction,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onDownloadClick: ((EpisodeDownloadAction) -> Unit)?,
|
onDownloadClick: ((EpisodeDownloadAction) -> Unit)?,
|
||||||
onEpisodeSwipe: (LibraryPreferences.EpisodeSwipeAction) -> 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
|
// Increase touch slop of swipe action to reduce accidental trigger
|
||||||
val configuration = LocalViewConfiguration.current
|
val configuration = LocalViewConfiguration.current
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
@ -87,110 +92,42 @@ fun AnimeEpisodeListItem(
|
||||||
override val touchSlop: Float = configuration.touchSlop * 3f
|
override val touchSlop: Float = configuration.touchSlop * 3f
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
val textAlpha = if (seen) ReadItemAlpha else 1f
|
val start = getSwipeAction(
|
||||||
val textSubtitleAlpha = if (seen) ReadItemAlpha else SecondaryItemAlpha
|
action = episodeSwipeStartAction,
|
||||||
|
seen = seen,
|
||||||
val episodeSwipeStartEnabled = episodeSwipeStartAction != LibraryPreferences.EpisodeSwipeAction.Disabled
|
bookmark = bookmark,
|
||||||
val episodeSwipeEndEnabled = episodeSwipeEndAction != LibraryPreferences.EpisodeSwipeAction.Disabled
|
downloadState = downloadStateProvider(),
|
||||||
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
val dismissState = rememberDismissState()
|
onSwipe = { onEpisodeSwipe(episodeSwipeStartAction) },
|
||||||
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 dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
val end = getSwipeAction(
|
||||||
val backgroundColor = if (episodeSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
|
action = episodeSwipeEndAction,
|
||||||
MaterialTheme.colorScheme.primary
|
seen = seen,
|
||||||
} else if (episodeSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
|
bookmark = bookmark,
|
||||||
MaterialTheme.colorScheme.primary
|
downloadState = downloadStateProvider(),
|
||||||
} else {
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
Color.Unspecified
|
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) {
|
SwipeableActionsBox(
|
||||||
when (dismissState.currentValue) {
|
modifier = Modifier.clipToBounds(),
|
||||||
DismissValue.DismissedToEnd -> {
|
state = swipeableActionsState,
|
||||||
lastDismissDirection = DismissDirection.StartToEnd
|
startActions = listOfNotNull(start),
|
||||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
endActions = listOfNotNull(end),
|
||||||
dismissDirections.clear()
|
swipeThreshold = swipeActionThreshold,
|
||||||
onEpisodeSwipe(episodeSwipeEndAction)
|
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||||
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),
|
|
||||||
) {
|
) {
|
||||||
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(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
|
||||||
MaterialTheme.colorScheme.background.copy(dismissContentAlpha),
|
|
||||||
)
|
|
||||||
.selectedBackground(selected)
|
.selectedBackground(selected)
|
||||||
.alpha(dismissContentAlpha)
|
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
|
@ -209,7 +146,7 @@ fun AnimeEpisodeListItem(
|
||||||
if (!seen) {
|
if (!seen) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Circle,
|
imageVector = Icons.Filled.Circle,
|
||||||
contentDescription = stringResource(R.string.unseen),
|
contentDescription = stringResource(R.string.unread),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(8.dp)
|
.height(8.dp)
|
||||||
.padding(end = 4.dp),
|
.padding(end = 4.dp),
|
||||||
|
@ -280,55 +217,41 @@ fun AnimeEpisodeListItem(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
private fun getSwipeAction(
|
||||||
private fun SwipeBackgroundIcon(
|
action: LibraryPreferences.EpisodeSwipeAction,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
tint: Color,
|
|
||||||
swipeAction: LibraryPreferences.EpisodeSwipeAction,
|
|
||||||
seen: Boolean,
|
seen: Boolean,
|
||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
downloadState: AnimeDownload.State,
|
downloadState: AnimeDownload.State,
|
||||||
) {
|
background: Color,
|
||||||
val imageVector = when (swipeAction) {
|
onSwipe: () -> Unit,
|
||||||
LibraryPreferences.EpisodeSwipeAction.ToggleSeen -> {
|
): me.saket.swipe.SwipeAction? {
|
||||||
if (!seen) {
|
return when (action) {
|
||||||
Icons.Outlined.Done
|
LibraryPreferences.EpisodeSwipeAction.ToggleSeen -> swipeAction(
|
||||||
} else {
|
icon = if (!seen) Icons.Outlined.Done else Icons.Outlined.RemoveDone,
|
||||||
Icons.Outlined.RemoveDone
|
background = background,
|
||||||
}
|
isUndo = seen,
|
||||||
}
|
onSwipe = onSwipe,
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
|
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,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
isTabletUi: Boolean,
|
isTabletUi: Boolean,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
|
@ -152,8 +152,8 @@ fun MangaScreen(
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
|
@ -187,8 +187,8 @@ fun MangaScreen(
|
||||||
state = state,
|
state = state,
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
|
@ -227,8 +227,8 @@ private fun MangaScreenSmallImpl(
|
||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
|
@ -439,8 +439,8 @@ private fun MangaScreenSmallImpl(
|
||||||
chapters = chapters,
|
chapters = chapters,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
onChapterSelected = onChapterSelected,
|
onChapterSelected = onChapterSelected,
|
||||||
|
@ -458,8 +458,8 @@ fun MangaScreenLargeImpl(
|
||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
|
@ -664,8 +664,8 @@ fun MangaScreenLargeImpl(
|
||||||
chapters = chapters,
|
chapters = chapters,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
onChapterSelected = onChapterSelected,
|
onChapterSelected = onChapterSelected,
|
||||||
|
@ -727,8 +727,8 @@ private fun LazyListScope.sharedChapterItems(
|
||||||
chapters: List<ChapterItem>,
|
chapters: List<ChapterItem>,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
|
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
|
||||||
|
@ -775,8 +775,8 @@ private fun LazyListScope.sharedChapterItems(
|
||||||
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
||||||
downloadStateProvider = { chapterItem.downloadState },
|
downloadStateProvider = { chapterItem.downloadState },
|
||||||
downloadProgressProvider = { chapterItem.downloadProgress },
|
downloadProgressProvider = { chapterItem.downloadProgress },
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
|
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
|
||||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
|
|
@ -1,20 +1,13 @@
|
||||||
package eu.kanade.presentation.entries.manga.components
|
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.background
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
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.Icons
|
||||||
import androidx.compose.material.icons.filled.Bookmark
|
import androidx.compose.material.icons.filled.Bookmark
|
||||||
import androidx.compose.material.icons.filled.Circle
|
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.Download
|
||||||
import androidx.compose.material.icons.outlined.FileDownloadOff
|
import androidx.compose.material.icons.outlined.FileDownloadOff
|
||||||
import androidx.compose.material.icons.outlined.RemoveDone
|
import androidx.compose.material.icons.outlined.RemoveDone
|
||||||
import androidx.compose.material.rememberDismissState
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
@ -37,14 +29,18 @@ 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
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.graphics.Color
|
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.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
import androidx.compose.ui.platform.ViewConfiguration
|
import androidx.compose.ui.platform.ViewConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
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.presentation.entries.DotSeparatorText
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.manga.model.MangaDownload
|
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.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||||
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
||||||
import tachiyomi.presentation.core.util.selectedBackground
|
import tachiyomi.presentation.core.util.selectedBackground
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaChapterListItem(
|
fun MangaChapterListItem(
|
||||||
|
@ -72,13 +71,19 @@ fun MangaChapterListItem(
|
||||||
downloadIndicatorEnabled: Boolean,
|
downloadIndicatorEnabled: Boolean,
|
||||||
downloadStateProvider: () -> MangaDownload.State,
|
downloadStateProvider: () -> MangaDownload.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
|
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
|
||||||
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> 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
|
// Increase touch slop of swipe action to reduce accidental trigger
|
||||||
val configuration = LocalViewConfiguration.current
|
val configuration = LocalViewConfiguration.current
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
@ -86,117 +91,42 @@ fun MangaChapterListItem(
|
||||||
override val touchSlop: Float = configuration.touchSlop * 3f
|
override val touchSlop: Float = configuration.touchSlop * 3f
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
val textAlpha = if (read) ReadItemAlpha else 1f
|
val start = getSwipeAction(
|
||||||
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
|
action = chapterSwipeStartAction,
|
||||||
|
read = read,
|
||||||
val chapterSwipeStartEnabled =
|
bookmark = bookmark,
|
||||||
chapterSwipeStartAction != LibraryPreferences.ChapterSwipeAction.Disabled
|
downloadState = downloadStateProvider(),
|
||||||
val chapterSwipeEndEnabled =
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
chapterSwipeEndAction != LibraryPreferences.ChapterSwipeAction.Disabled
|
onSwipe = { onChapterSwipe(chapterSwipeStartAction) },
|
||||||
|
|
||||||
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 =
|
val end = getSwipeAction(
|
||||||
if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
action = chapterSwipeEndAction,
|
||||||
val backgroundColor =
|
read = read,
|
||||||
if (chapterSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
|
bookmark = bookmark,
|
||||||
MaterialTheme.colorScheme.primary
|
downloadState = downloadStateProvider(),
|
||||||
} else if (chapterSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
MaterialTheme.colorScheme.primary
|
onSwipe = { onChapterSwipe(chapterSwipeEndAction) },
|
||||||
} else {
|
)
|
||||||
Color.Unspecified
|
|
||||||
|
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) {
|
SwipeableActionsBox(
|
||||||
when (dismissState.currentValue) {
|
modifier = Modifier.clipToBounds(),
|
||||||
DismissValue.DismissedToEnd -> {
|
state = swipeableActionsState,
|
||||||
lastDismissDirection = DismissDirection.StartToEnd
|
startActions = listOfNotNull(start),
|
||||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
endActions = listOfNotNull(end),
|
||||||
dismissDirections.clear()
|
swipeThreshold = swipeActionThreshold,
|
||||||
onChapterSwipe(chapterSwipeEndAction)
|
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||||
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 -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissContent = {
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
|
||||||
MaterialTheme.colorScheme.background.copy(dismissContentAlpha),
|
|
||||||
)
|
|
||||||
.selectedBackground(selected)
|
.selectedBackground(selected)
|
||||||
.alpha(dismissContentAlpha)
|
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
|
@ -263,7 +193,6 @@ fun MangaChapterListItem(
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.alpha(ReadItemAlpha),
|
modifier = Modifier.alpha(ReadItemAlpha),
|
||||||
)
|
)
|
||||||
if (scanlator != null) DotSeparatorText()
|
|
||||||
}
|
}
|
||||||
if (scanlator != null) {
|
if (scanlator != null) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -286,54 +215,63 @@ fun MangaChapterListItem(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
private fun getSwipeAction(
|
||||||
private fun SwipeBackgroundIcon(
|
action: LibraryPreferences.ChapterSwipeAction,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
tint: Color,
|
|
||||||
swipeAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
downloadState: MangaDownload.State,
|
downloadState: MangaDownload.State,
|
||||||
) {
|
background: Color,
|
||||||
val imageVector = when (swipeAction) {
|
onSwipe: () -> Unit,
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
|
): me.saket.swipe.SwipeAction? {
|
||||||
if (!read) {
|
return when (action) {
|
||||||
Icons.Outlined.Done
|
LibraryPreferences.ChapterSwipeAction.ToggleRead -> swipeAction(
|
||||||
} else {
|
icon = if (!read) Icons.Outlined.Done else Icons.Outlined.RemoveDone,
|
||||||
Icons.Outlined.RemoveDone
|
background = background,
|
||||||
}
|
isUndo = read,
|
||||||
}
|
onSwipe = onSwipe,
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
|
)
|
||||||
if (!bookmark) {
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> swipeAction(
|
||||||
Icons.Outlined.BookmarkAdd
|
icon = if (!bookmark) Icons.Outlined.BookmarkAdd else Icons.Outlined.BookmarkRemove,
|
||||||
} else {
|
background = background,
|
||||||
Icons.Outlined.BookmarkRemove
|
isUndo = bookmark,
|
||||||
}
|
onSwipe = onSwipe,
|
||||||
}
|
)
|
||||||
LibraryPreferences.ChapterSwipeAction.Download -> {
|
LibraryPreferences.ChapterSwipeAction.Download -> swipeAction(
|
||||||
when (downloadState) {
|
icon = when (downloadState) {
|
||||||
MangaDownload.State.NOT_DOWNLOADED,
|
MangaDownload.State.NOT_DOWNLOADED, MangaDownload.State.ERROR -> Icons.Outlined.Download
|
||||||
MangaDownload.State.ERROR,
|
MangaDownload.State.QUEUE, MangaDownload.State.DOWNLOADING -> Icons.Outlined.FileDownloadOff
|
||||||
-> { Icons.Outlined.Download }
|
MangaDownload.State.DOWNLOADED -> Icons.Outlined.Delete
|
||||||
MangaDownload.State.QUEUE,
|
},
|
||||||
MangaDownload.State.DOWNLOADING,
|
background = background,
|
||||||
-> { Icons.Outlined.FileDownloadOff }
|
onSwipe = onSwipe,
|
||||||
MangaDownload.State.DOWNLOADED -> { Icons.Outlined.Delete }
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled -> null
|
LibraryPreferences.ChapterSwipeAction.Disabled -> null
|
||||||
}
|
}
|
||||||
imageVector?.let {
|
}
|
||||||
|
|
||||||
|
private fun swipeAction(
|
||||||
|
onSwipe: () -> Unit,
|
||||||
|
icon: ImageVector,
|
||||||
|
background: Color,
|
||||||
|
isUndo: Boolean = false,
|
||||||
|
): me.saket.swipe.SwipeAction {
|
||||||
|
return me.saket.swipe.SwipeAction(
|
||||||
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = modifier,
|
modifier = Modifier.padding(16.dp),
|
||||||
imageVector = imageVector,
|
imageVector = icon,
|
||||||
tint = tint,
|
tint = contentColorFor(background),
|
||||||
contentDescription = null,
|
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
|
||||||
import eu.kanade.domain.source.service.SourcePreferences.DataSaver
|
import eu.kanade.domain.source.service.SourcePreferences.DataSaver
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
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.more.settings.screen.debug.DebugInfoScreen
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
|
@ -394,7 +394,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeChapterStartAction(),
|
pref = libraryPreferences.swipeChapterStartAction(),
|
||||||
title = stringResource(R.string.pref_chapter_swipe_start),
|
title = stringResource(R.string.pref_chapter_swipe_end),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||||
|
@ -404,7 +404,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeChapterEndAction(),
|
pref = libraryPreferences.swipeChapterEndAction(),
|
||||||
title = stringResource(R.string.pref_chapter_swipe_end),
|
title = stringResource(R.string.pref_chapter_swipe_start),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||||
|
@ -425,7 +425,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeEpisodeStartAction(),
|
pref = libraryPreferences.swipeEpisodeStartAction(),
|
||||||
title = stringResource(R.string.pref_episode_swipe_start),
|
title = stringResource(R.string.pref_episode_swipe_end),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark_episode),
|
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark_episode),
|
||||||
|
@ -435,7 +435,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeEpisodeEndAction(),
|
pref = libraryPreferences.swipeEpisodeEndAction(),
|
||||||
title = stringResource(R.string.pref_episode_swipe_end),
|
title = stringResource(R.string.pref_episode_swipe_start),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
LibraryPreferences.EpisodeSwipeAction.Disabled to stringResource(R.string.action_disable),
|
||||||
LibraryPreferences.EpisodeSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark_episode),
|
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.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
import eu.kanade.presentation.components.UpIcon
|
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.more.settings.widget.TextPreferenceWidget
|
||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
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.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
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.more.settings.Preference
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
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.Divider
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||||
|
@ -164,6 +164,8 @@ private fun SearchResult(
|
||||||
) {
|
) {
|
||||||
if (searchKey.isEmpty()) return
|
if (searchKey.isEmpty()) return
|
||||||
|
|
||||||
|
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
||||||
|
|
||||||
val index = getIndex()
|
val index = getIndex()
|
||||||
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
|
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
|
||||||
value = index.asSequence()
|
value = index.asSequence()
|
||||||
|
@ -199,7 +201,7 @@ private fun SearchResult(
|
||||||
SearchResultItem(
|
SearchResultItem(
|
||||||
route = settingsData.route,
|
route = settingsData.route,
|
||||||
title = p.title,
|
title = p.title,
|
||||||
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle),
|
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle, isLtr = isLtr),
|
||||||
highlightKey = p.title,
|
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) {
|
return if (node == null) {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
if (Resources.getSystem().isLTR) {
|
if (isLtr) {
|
||||||
// This locale reads left to right.
|
// This locale reads left to right.
|
||||||
"$path > $node"
|
"$path > $node"
|
||||||
} else {
|
} 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 android.content.Context
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
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.Column
|
||||||
import androidx.compose.foundation.layout.padding
|
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.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
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.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
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.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
|
@ -12,7 +12,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
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.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
|
|
|
@ -106,8 +106,8 @@ class AnimeScreen(
|
||||||
dateRelativeTime = screenModel.relativeTime,
|
dateRelativeTime = screenModel.relativeTime,
|
||||||
dateFormat = screenModel.dateFormat,
|
dateFormat = screenModel.dateFormat,
|
||||||
isTabletUi = isTabletUi(),
|
isTabletUi = isTabletUi(),
|
||||||
episodeSwipeEndAction = screenModel.episodeSwipeEndAction,
|
|
||||||
episodeSwipeStartAction = screenModel.episodeSwipeStartAction,
|
episodeSwipeStartAction = screenModel.episodeSwipeStartAction,
|
||||||
|
episodeSwipeEndAction = screenModel.episodeSwipeEndAction,
|
||||||
showNextEpisodeAirTime = screenModel.showNextEpisodeAirTime,
|
showNextEpisodeAirTime = screenModel.showNextEpisodeAirTime,
|
||||||
alwaysUseExternalPlayer = screenModel.alwaysUseExternalPlayer,
|
alwaysUseExternalPlayer = screenModel.alwaysUseExternalPlayer,
|
||||||
onBackClicked = navigator::pop,
|
onBackClicked = navigator::pop,
|
||||||
|
|
|
@ -126,8 +126,8 @@ class AnimeInfoScreenModel(
|
||||||
private val processedEpisodes: List<EpisodeItem>?
|
private val processedEpisodes: List<EpisodeItem>?
|
||||||
get() = successState?.processedEpisodes
|
get() = successState?.processedEpisodes
|
||||||
|
|
||||||
val episodeSwipeEndAction = libraryPreferences.swipeEpisodeEndAction().get()
|
val episodeSwipeStartAction = libraryPreferences.swipeEpisodeEndAction().get()
|
||||||
val episodeSwipeStartAction = libraryPreferences.swipeEpisodeStartAction().get()
|
val episodeSwipeEndAction = libraryPreferences.swipeEpisodeStartAction().get()
|
||||||
|
|
||||||
val showNextEpisodeAirTime = trackPreferences.showNextEpisodeAiringTime().get()
|
val showNextEpisodeAirTime = trackPreferences.showNextEpisodeAiringTime().get()
|
||||||
val alwaysUseExternalPlayer = playerPreferences.alwaysUseExternalPlayer().get()
|
val alwaysUseExternalPlayer = playerPreferences.alwaysUseExternalPlayer().get()
|
||||||
|
|
|
@ -102,8 +102,8 @@ class MangaScreen(
|
||||||
dateRelativeTime = screenModel.relativeTime,
|
dateRelativeTime = screenModel.relativeTime,
|
||||||
dateFormat = screenModel.dateFormat,
|
dateFormat = screenModel.dateFormat,
|
||||||
isTabletUi = isTabletUi(),
|
isTabletUi = isTabletUi(),
|
||||||
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
||||||
onBackClicked = navigator::pop,
|
onBackClicked = navigator::pop,
|
||||||
onChapterClicked = { openChapter(context, it) },
|
onChapterClicked = { openChapter(context, it) },
|
||||||
onDownloadChapter = screenModel::runChapterDownloadActions.takeIf { !successState.source.isLocalOrStub() },
|
onDownloadChapter = screenModel::runChapterDownloadActions.takeIf { !successState.source.isLocalOrStub() },
|
||||||
|
|
|
@ -124,8 +124,8 @@ class MangaInfoScreenModel(
|
||||||
private val filteredChapters: List<ChapterItem>?
|
private val filteredChapters: List<ChapterItem>?
|
||||||
get() = successState?.processedChapters
|
get() = successState?.processedChapters
|
||||||
|
|
||||||
val chapterSwipeEndAction = libraryPreferences.swipeChapterEndAction().get()
|
val chapterSwipeStartAction = libraryPreferences.swipeChapterEndAction().get()
|
||||||
val chapterSwipeStartAction = libraryPreferences.swipeChapterStartAction().get()
|
val chapterSwipeEndAction = libraryPreferences.swipeChapterStartAction().get()
|
||||||
|
|
||||||
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
||||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||||
|
|
|
@ -109,6 +109,7 @@ class PlayerViewModel(
|
||||||
val eventFlow = eventChannel.receiveAsFlow()
|
val eventFlow = eventChannel.receiveAsFlow()
|
||||||
|
|
||||||
private val incognitoMode = basePreferences.incognitoMode().get()
|
private val incognitoMode = basePreferences.incognitoMode().get()
|
||||||
|
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileWatching().get()
|
||||||
|
|
||||||
internal val relativeTime = uiPreferences.relativeTime().get()
|
internal val relativeTime = uiPreferences.relativeTime().get()
|
||||||
internal val dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get())
|
internal val dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get())
|
||||||
|
@ -349,9 +350,9 @@ class PlayerViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadNextEpisodes() {
|
private fun downloadNextEpisodes() {
|
||||||
|
if (downloadAheadAmount == 0) return
|
||||||
val anime = currentAnime ?: 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
|
// Only download ahead if current + next episode is already downloaded too to avoid jank
|
||||||
if (getCurrentEpisodeIndex() == this.currentPlaylist.lastIndex) return
|
if (getCurrentEpisodeIndex() == this.currentPlaylist.lastIndex) return
|
||||||
val currentEpisode = currentEpisode ?: return
|
val currentEpisode = currentEpisode ?: return
|
||||||
|
@ -366,7 +367,7 @@ class PlayerViewModel(
|
||||||
return@launchIO
|
return@launchIO
|
||||||
}
|
}
|
||||||
val episodesToDownload = getNextEpisodes.await(anime.id, nextEpisode.id!!)
|
val episodesToDownload = getNextEpisodes.await(anime.id, nextEpisode.id!!)
|
||||||
.take(amount)
|
.take(downloadAheadAmount)
|
||||||
downloadManager.downloadEpisodes(anime, episodesToDownload)
|
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.model.Page
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
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.InsertPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
|
@ -204,6 +205,7 @@ class ReaderViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val incognitoMode = preferences.incognitoMode().get()
|
private val incognitoMode = preferences.incognitoMode().get()
|
||||||
|
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileReading().get()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// To save state
|
// To save state
|
||||||
|
@ -444,12 +446,11 @@ class ReaderViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadNextChapters() {
|
private fun downloadNextChapters() {
|
||||||
|
if (downloadAheadAmount == 0) return
|
||||||
val manga = manga ?: 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
|
// 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
|
val nextChapter = state.value.viewerChapters?.nextChapter?.chapter ?: return
|
||||||
|
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
|
@ -467,7 +468,7 @@ class ReaderViewModel(
|
||||||
} else {
|
} else {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
}.take(amount)
|
}.take(downloadAheadAmount)
|
||||||
downloadManager.downloadChapters(
|
downloadManager.downloadChapters(
|
||||||
manga,
|
manga,
|
||||||
chaptersToDownload,
|
chaptersToDownload,
|
||||||
|
|
|
@ -12,10 +12,10 @@ import androidx.compose.ui.Modifier
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
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.SettingsAppearanceScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
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.DefaultNavigatorScreenTransition
|
||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
|
|
|
@ -261,22 +261,22 @@ class LibraryPreferences(
|
||||||
|
|
||||||
// region Swipe Actions
|
// region Swipe Actions
|
||||||
|
|
||||||
|
fun swipeEpisodeStartAction() =
|
||||||
|
preferenceStore.getEnum("pref_episode_swipe_end_action", EpisodeSwipeAction.ToggleSeen)
|
||||||
|
|
||||||
fun swipeEpisodeEndAction() = preferenceStore.getEnum(
|
fun swipeEpisodeEndAction() = preferenceStore.getEnum(
|
||||||
"pref_episode_swipe_start_action",
|
"pref_episode_swipe_start_action",
|
||||||
EpisodeSwipeAction.ToggleBookmark,
|
EpisodeSwipeAction.ToggleBookmark,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun swipeEpisodeStartAction() =
|
fun swipeChapterStartAction() =
|
||||||
preferenceStore.getEnum("pref_episode_swipe_end_action", EpisodeSwipeAction.ToggleSeen)
|
preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleRead)
|
||||||
|
|
||||||
fun swipeChapterEndAction() = preferenceStore.getEnum(
|
fun swipeChapterEndAction() = preferenceStore.getEnum(
|
||||||
"pref_chapter_swipe_start_action",
|
"pref_chapter_swipe_start_action",
|
||||||
ChapterSwipeAction.ToggleBookmark,
|
ChapterSwipeAction.ToggleBookmark,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun swipeChapterStartAction() =
|
|
||||||
preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleRead)
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
enum class EpisodeSwipeAction {
|
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-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" }
|
||||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", 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" }
|
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"
|
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-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.3"
|
||||||
compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0"
|
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"
|
logcat = "com.squareup.logcat:logcat:0.1"
|
||||||
|
|
||||||
acra-http = "ch.acra:acra-http:5.10.1"
|
acra-http = "ch.acra:acra-http:5.10.1"
|
||||||
|
|
|
@ -463,7 +463,7 @@
|
||||||
<item quantity="one">Next unread chapter</item>
|
<item quantity="one">Next unread chapter</item>
|
||||||
<item quantity="other">Next %d unread chapters</item>
|
<item quantity="other">Next %d unread chapters</item>
|
||||||
</plurals>
|
</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="save_chapter_as_cbz">Save as CBZ archive</string>
|
||||||
<string name="split_tall_images">Split tall images</string>
|
<string name="split_tall_images">Split tall images</string>
|
||||||
<string name="split_tall_images_summary">Improves reader performance</string>
|
<string name="split_tall_images_summary">Improves reader performance</string>
|
||||||
|
|
Loading…
Reference in a new issue