mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-25 14:19:27 +03:00
parent
e99e4c2f41
commit
c62f86f6cc
28 changed files with 306 additions and 214 deletions
|
@ -34,7 +34,8 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -382,7 +383,7 @@ private fun AnimeScreenSmallImpl(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
onRefresh = onRefresh,
|
onRefresh = onRefresh,
|
||||||
enabled = episodes.fastAll { !it.selected },
|
enabled = episodes.fastAll { !it.selected },
|
||||||
indicatorPadding = contentPadding,
|
indicatorPadding = WindowInsets.systemBars.only(WindowInsetsSides.Top).asPaddingValues(),
|
||||||
) {
|
) {
|
||||||
val layoutDirection = LocalLayoutDirection.current
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
VerticalFastScroller(
|
VerticalFastScroller(
|
||||||
|
@ -465,7 +466,7 @@ private fun AnimeScreenSmallImpl(
|
||||||
contentType = EntryScreenItem.AIRING_TIME,
|
contentType = EntryScreenItem.AIRING_TIME,
|
||||||
) {
|
) {
|
||||||
// Handles the second by second countdown
|
// Handles the second by second countdown
|
||||||
var timer by remember { mutableStateOf(state.airingTime) }
|
var timer by remember { mutableLongStateOf(state.airingTime) }
|
||||||
LaunchedEffect(key1 = timer) {
|
LaunchedEffect(key1 = timer) {
|
||||||
if (timer > 0L) {
|
if (timer > 0L) {
|
||||||
delay(1000L)
|
delay(1000L)
|
||||||
|
@ -561,7 +562,7 @@ fun AnimeScreenLargeImpl(
|
||||||
val episodes = remember(state) { state.processedEpisodes.toList() }
|
val episodes = remember(state) { state.processedEpisodes.toList() }
|
||||||
|
|
||||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||||
var topBarHeight by remember { mutableStateOf(0) }
|
var topBarHeight by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
PullRefresh(
|
PullRefresh(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
|
@ -722,7 +723,7 @@ fun AnimeScreenLargeImpl(
|
||||||
contentType = EntryScreenItem.AIRING_TIME,
|
contentType = EntryScreenItem.AIRING_TIME,
|
||||||
) {
|
) {
|
||||||
// Handles the second by second countdown
|
// Handles the second by second countdown
|
||||||
var timer by remember { mutableStateOf(state.airingTime) }
|
var timer by remember { mutableLongStateOf(state.airingTime) }
|
||||||
LaunchedEffect(key1 = timer) {
|
LaunchedEffect(key1 = timer) {
|
||||||
if (timer > 0L) {
|
if (timer > 0L) {
|
||||||
delay(1000L)
|
delay(1000L)
|
||||||
|
|
|
@ -38,6 +38,7 @@ import androidx.compose.material3.contentColorFor
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.mutableStateOf
|
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
|
||||||
|
@ -214,7 +215,7 @@ fun AnimeEpisodeListItem(
|
||||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
if (!seen) {
|
if (!seen) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Circle,
|
imageVector = Icons.Filled.Circle,
|
||||||
|
@ -354,7 +355,7 @@ fun NextEpisodeAiringListItem(
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
|
|
@ -48,6 +48,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
@ -575,8 +576,8 @@ private fun AnimeSummary(
|
||||||
expanded: Boolean,
|
expanded: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
var expandedHeight by remember { mutableStateOf(0) }
|
var expandedHeight by remember { mutableIntStateOf(0) }
|
||||||
var shrunkHeight by remember { mutableStateOf(0) }
|
var shrunkHeight by remember { mutableIntStateOf(0) }
|
||||||
val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight }
|
val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight }
|
||||||
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
||||||
val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } }
|
val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } }
|
||||||
|
|
|
@ -32,7 +32,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -357,7 +357,7 @@ private fun MangaScreenSmallImpl(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
onRefresh = onRefresh,
|
onRefresh = onRefresh,
|
||||||
enabled = chapters.fastAll { !it.selected },
|
enabled = chapters.fastAll { !it.selected },
|
||||||
indicatorPadding = contentPadding,
|
indicatorPadding = WindowInsets.systemBars.only(WindowInsetsSides.Top).asPaddingValues(),
|
||||||
) {
|
) {
|
||||||
val layoutDirection = LocalLayoutDirection.current
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
VerticalFastScroller(
|
VerticalFastScroller(
|
||||||
|
@ -507,7 +507,7 @@ fun MangaScreenLargeImpl(
|
||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters.toList() }
|
||||||
|
|
||||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||||
var topBarHeight by remember { mutableStateOf(0) }
|
var topBarHeight by remember { mutableIntStateOf(0) }
|
||||||
PullRefresh(
|
PullRefresh(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
onRefresh = onRefresh,
|
onRefresh = onRefresh,
|
||||||
|
|
|
@ -12,7 +12,6 @@ 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.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.DismissDirection
|
import androidx.compose.material.DismissDirection
|
||||||
import androidx.compose.material.DismissValue
|
import androidx.compose.material.DismissValue
|
||||||
import androidx.compose.material.SwipeToDismiss
|
import androidx.compose.material.SwipeToDismiss
|
||||||
|
@ -26,8 +25,6 @@ import androidx.compose.material.icons.filled.FileDownloadOff
|
||||||
import androidx.compose.material.icons.filled.Visibility
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
import androidx.compose.material.icons.filled.VisibilityOff
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
import androidx.compose.material.rememberDismissState
|
import androidx.compose.material.rememberDismissState
|
||||||
import androidx.compose.material3.Card
|
|
||||||
import androidx.compose.material3.CardDefaults
|
|
||||||
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,6 +34,7 @@ import androidx.compose.material3.contentColorFor
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.mutableStateOf
|
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
|
||||||
|
@ -56,7 +54,6 @@ 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.min
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaChapterListItem(
|
fun MangaChapterListItem(
|
||||||
|
@ -103,6 +100,15 @@ fun MangaChapterListItem(
|
||||||
lastDismissDirection = null
|
lastDismissDirection = null
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
val dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
||||||
|
val backgroundColor = if (chapterSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
|
||||||
|
MaterialTheme.colorScheme.primary
|
||||||
|
} else if (chapterSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
|
||||||
|
MaterialTheme.colorScheme.primary
|
||||||
|
} else {
|
||||||
|
Color.Unspecified
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(dismissState.currentValue) {
|
LaunchedEffect(dismissState.currentValue) {
|
||||||
when (dismissState.currentValue) {
|
when (dismissState.currentValue) {
|
||||||
DismissValue.DismissedToEnd -> {
|
DismissValue.DismissedToEnd -> {
|
||||||
|
@ -126,17 +132,11 @@ fun MangaChapterListItem(
|
||||||
DismissValue.Default -> {}
|
DismissValue.Default -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SwipeToDismiss(
|
SwipeToDismiss(
|
||||||
state = dismissState,
|
state = dismissState,
|
||||||
directions = dismissDirections,
|
directions = dismissDirections,
|
||||||
background = {
|
background = {
|
||||||
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
|
|
||||||
}
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
@ -174,121 +174,102 @@ fun MangaChapterListItem(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissContent = {
|
dismissContent = {
|
||||||
val animateCornerRatio = if (dismissState.offset.value != 0f) {
|
Row(
|
||||||
min(
|
modifier = modifier
|
||||||
dismissState.progress.fraction / .075f,
|
.background(
|
||||||
1f,
|
MaterialTheme.colorScheme.background.copy(dismissContentAlpha),
|
||||||
)
|
)
|
||||||
} else {
|
.selectedBackground(selected)
|
||||||
0f
|
.alpha(dismissContentAlpha)
|
||||||
}
|
.combinedClickable(
|
||||||
val animateCornerShape = (8f * animateCornerRatio).dp
|
onClick = onClick,
|
||||||
val dismissContentAlpha =
|
onLongClick = onLongClick,
|
||||||
if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
)
|
||||||
Card(
|
.padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp),
|
||||||
modifier = modifier,
|
|
||||||
colors = CardDefaults.elevatedCardColors(
|
|
||||||
containerColor = Color.Transparent,
|
|
||||||
),
|
|
||||||
shape = RoundedCornerShape(animateCornerShape),
|
|
||||||
) {
|
) {
|
||||||
Row(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier.weight(1f),
|
||||||
.background(
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
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(
|
Row(
|
||||||
modifier = Modifier.weight(1f),
|
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Row(
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
if (!read) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
Icon(
|
||||||
) {
|
imageVector = Icons.Filled.Circle,
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
contentDescription = stringResource(R.string.unread),
|
||||||
if (!read) {
|
modifier = Modifier
|
||||||
Icon(
|
.height(8.dp)
|
||||||
imageVector = Icons.Filled.Circle,
|
.padding(end = 4.dp),
|
||||||
contentDescription = stringResource(R.string.unread),
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier
|
|
||||||
.height(8.dp)
|
|
||||||
.padding(end = 4.dp),
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (bookmark) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Bookmark,
|
|
||||||
contentDescription = stringResource(R.string.action_filter_bookmarked),
|
|
||||||
modifier = Modifier
|
|
||||||
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
color = LocalContentColor.current.copy(alpha = textAlpha),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
onTextLayout = { textHeight = it.size.height },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (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 {
|
Row {
|
||||||
ProvideTextStyle(
|
ProvideTextStyle(
|
||||||
value = MaterialTheme.typography.bodyMedium.copy(
|
value = MaterialTheme.typography.bodyMedium.copy(
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha),
|
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
Text(
|
Text(
|
||||||
text = date,
|
text = date,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
if (readProgress != null || scanlator != null) DotSeparatorText()
|
if (readProgress != null || scanlator != null) DotSeparatorText()
|
||||||
}
|
}
|
||||||
if (readProgress != null) {
|
if (readProgress != null) {
|
||||||
Text(
|
Text(
|
||||||
text = readProgress,
|
text = readProgress,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.alpha(ReadItemAlpha),
|
modifier = Modifier.alpha(ReadItemAlpha),
|
||||||
)
|
)
|
||||||
if (scanlator != null) DotSeparatorText()
|
if (scanlator != null) DotSeparatorText()
|
||||||
}
|
}
|
||||||
if (scanlator != null) {
|
if (scanlator != null) {
|
||||||
Text(
|
Text(
|
||||||
text = scanlator,
|
text = scanlator,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
@ -575,8 +576,8 @@ private fun MangaSummary(
|
||||||
expanded: Boolean,
|
expanded: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
var expandedHeight by remember { mutableStateOf(0) }
|
var expandedHeight by remember { mutableIntStateOf(0) }
|
||||||
var shrunkHeight by remember { mutableStateOf(0) }
|
var shrunkHeight by remember { mutableIntStateOf(0) }
|
||||||
val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight }
|
val heightDelta = remember(expandedHeight, shrunkHeight) { expandedHeight - shrunkHeight }
|
||||||
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
val animProgress by animateFloatAsState(if (expanded) 1f else 0f)
|
||||||
val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } }
|
val scrimHeight = with(LocalDensity.current) { remember { 24.sp.roundToPx() } }
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.pager.PagerState
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -61,7 +61,7 @@ fun AnimeLibraryPager(
|
||||||
|
|
||||||
remember(isLandscape) { getColumnsForOrientation(isLandscape) }
|
remember(isLandscape) { getColumnsForOrientation(isLandscape) }
|
||||||
} else {
|
} else {
|
||||||
remember { mutableStateOf(0) }
|
remember { mutableIntStateOf(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
when (displayMode) {
|
when (displayMode) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -70,7 +70,7 @@ fun MangaLibraryPager(
|
||||||
|
|
||||||
remember(isLandscape) { getColumnsForOrientation(isLandscape) }
|
remember(isLandscape) { getColumnsForOrientation(isLandscape) }
|
||||||
} else {
|
} else {
|
||||||
remember { mutableStateOf(0) }
|
remember { mutableIntStateOf(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
when (displayMode) {
|
when (displayMode) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
@ -174,7 +175,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
||||||
|
|
||||||
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
||||||
val episodeCache = remember { Injekt.get<EpisodeCache>() }
|
val episodeCache = remember { Injekt.get<EpisodeCache>() }
|
||||||
var readableSizeSema by remember { mutableStateOf(0) }
|
var readableSizeSema by remember { mutableIntStateOf(0) }
|
||||||
val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
|
val readableSize = remember(readableSizeSema) { chapterCache.readableSize }
|
||||||
val readableAnimeSize = remember(readableSizeSema) { episodeCache.readableSize }
|
val readableAnimeSize = remember(readableSizeSema) { episodeCache.readableSize }
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
@ -93,7 +94,7 @@ object SettingsBackupScreen : SearchableSettings {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
var flag by rememberSaveable { mutableStateOf(0) }
|
var flag by rememberSaveable { mutableIntStateOf(0) }
|
||||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.CreateDocument("application/*"),
|
contract = ActivityResultContracts.CreateDocument("application/*"),
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package eu.kanade.presentation.more.settings.screen.debug
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.ContentCopy
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import eu.kanade.presentation.components.AppBar
|
||||||
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
|
import eu.kanade.presentation.util.Screen
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
|
import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator
|
||||||
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
||||||
|
object BackupSchemaScreen : Screen() {
|
||||||
|
|
||||||
|
const val title = "Backup file schema"
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
|
val schema = remember { ProtoBufSchemaGenerator.generateSchemaText(Backup.serializer().descriptor) }
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(text = title) },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = navigator::pop) {
|
||||||
|
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
AppBarActions(
|
||||||
|
listOf(
|
||||||
|
AppBar.Action(
|
||||||
|
title = stringResource(R.string.action_copy_to_clipboard),
|
||||||
|
icon = Icons.Default.ContentCopy,
|
||||||
|
onClick = {
|
||||||
|
context.copyToClipboard(title, schema)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
scrollBehavior = it,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { contentPadding ->
|
||||||
|
Text(
|
||||||
|
text = schema,
|
||||||
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(contentPadding)
|
||||||
|
.padding(16.dp),
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,10 @@ object DebugInfoScreen : Screen() {
|
||||||
title = WorkerInfoScreen.title,
|
title = WorkerInfoScreen.title,
|
||||||
onClick = { navigator.push(WorkerInfoScreen) },
|
onClick = { navigator.push(WorkerInfoScreen) },
|
||||||
),
|
),
|
||||||
|
Preference.PreferenceItem.TextPreference(
|
||||||
|
title = BackupSchemaScreen.title,
|
||||||
|
onClick = { navigator.push(BackupSchemaScreen) },
|
||||||
|
),
|
||||||
getAppInfoGroup(),
|
getAppInfoGroup(),
|
||||||
getDeviceInfoGroup(),
|
getDeviceInfoGroup(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -203,7 +203,7 @@ fun AnimeUpdatesUiItem(
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
if (!update.seen) {
|
if (!update.seen) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Circle,
|
imageVector = Icons.Filled.Circle,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -200,7 +200,7 @@ fun MangaUpdatesUiItem(
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
if (!update.read) {
|
if (!update.read) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Circle,
|
imageVector = Icons.Filled.Circle,
|
||||||
|
|
|
@ -81,15 +81,15 @@ fun WebViewScreenContent(
|
||||||
),
|
),
|
||||||
AppBar.OverflowAction(
|
AppBar.OverflowAction(
|
||||||
title = stringResource(R.string.action_share),
|
title = stringResource(R.string.action_share),
|
||||||
onClick = { onShare(state.lastLoadedUrl!!) },
|
onClick = { onShare(state.lastLoadedUrl ?: url) },
|
||||||
),
|
),
|
||||||
AppBar.OverflowAction(
|
AppBar.OverflowAction(
|
||||||
title = stringResource(R.string.action_open_in_browser),
|
title = stringResource(R.string.action_open_in_browser),
|
||||||
onClick = { onOpenInBrowser(state.lastLoadedUrl!!) },
|
onClick = { onOpenInBrowser(state.lastLoadedUrl ?: url) },
|
||||||
),
|
),
|
||||||
AppBar.OverflowAction(
|
AppBar.OverflowAction(
|
||||||
title = stringResource(R.string.pref_clear_cookies),
|
title = stringResource(R.string.pref_clear_cookies),
|
||||||
onClick = { onClearCookies(state.lastLoadedUrl!!) },
|
onClick = { onClearCookies(state.lastLoadedUrl ?: url) },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -216,19 +216,21 @@ class AnimeDownloadManager(
|
||||||
* @param source the source of the episodes.
|
* @param source the source of the episodes.
|
||||||
*/
|
*/
|
||||||
fun deleteEpisodes(episodes: List<Episode>, anime: Anime, source: AnimeSource) {
|
fun deleteEpisodes(episodes: List<Episode>, anime: Anime, source: AnimeSource) {
|
||||||
val filteredEpisodes = getEpisodesToDelete(episodes, anime)
|
launchIO {
|
||||||
if (filteredEpisodes.isNotEmpty()) {
|
val filteredEpisodes = getEpisodesToDelete(episodes, anime)
|
||||||
launchIO {
|
if (filteredEpisodes.isEmpty()) {
|
||||||
removeFromDownloadQueue(filteredEpisodes)
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
val (animeDir, episodeDirs) = provider.findEpisodeDirs(filteredEpisodes, anime, source)
|
removeFromDownloadQueue(filteredEpisodes)
|
||||||
episodeDirs.forEach { it.delete() }
|
|
||||||
cache.removeEpisodes(filteredEpisodes, anime)
|
|
||||||
|
|
||||||
// Delete anime directory if empty
|
val (animeDir, episodeDirs) = provider.findEpisodeDirs(filteredEpisodes, anime, source)
|
||||||
if (animeDir?.listFiles()?.isEmpty() == true) {
|
episodeDirs.forEach { it.delete() }
|
||||||
deleteAnime(anime, source, removeQueued = false)
|
cache.removeEpisodes(filteredEpisodes, anime)
|
||||||
}
|
|
||||||
|
// Delete anime directory if empty
|
||||||
|
if (animeDir?.listFiles()?.isEmpty() == true) {
|
||||||
|
deleteAnime(anime, source, removeQueued = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +281,7 @@ class AnimeDownloadManager(
|
||||||
* @param episodes the list of episodes to delete.
|
* @param episodes the list of episodes to delete.
|
||||||
* @param anime the anime of the episodes.
|
* @param anime the anime of the episodes.
|
||||||
*/
|
*/
|
||||||
fun enqueueEpisodesToDelete(episodes: List<Episode>, anime: Anime) {
|
suspend fun enqueueEpisodesToDelete(episodes: List<Episode>, anime: Anime) {
|
||||||
pendingDeleter.addEpisodes(getEpisodesToDelete(episodes, anime), anime)
|
pendingDeleter.addEpisodes(getEpisodesToDelete(episodes, anime), anime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,22 +351,24 @@ class AnimeDownloadManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getEpisodesToDelete(episodes: List<Episode>, anime: Anime): List<Episode> {
|
private suspend fun getEpisodesToDelete(episodes: List<Episode>, anime: Anime): List<Episode> {
|
||||||
// Retrieve the categories that are set to exclude from being deleted on read
|
// Retrieve the categories that are set to exclude from being deleted on read
|
||||||
val categoriesToExclude = downloadPreferences.removeExcludeAnimeCategories().get().map(String::toLong)
|
val categoriesToExclude = downloadPreferences.removeExcludeAnimeCategories().get().map(String::toLong)
|
||||||
|
|
||||||
val categoriesForAnime = runBlocking { getCategories.await(anime.id) }
|
val categoriesForAnime = getCategories.await(anime.id)
|
||||||
.map { it.id }
|
.map { it.id }
|
||||||
.takeUnless { it.isEmpty() }
|
.ifEmpty { listOf(0) }
|
||||||
?: listOf(0)
|
val filteredCategoryAnime = if (categoriesForAnime.intersect(categoriesToExclude).isNotEmpty()) {
|
||||||
|
|
||||||
return if (categoriesForAnime.intersect(categoriesToExclude).isNotEmpty()) {
|
|
||||||
episodes.filterNot { it.seen }
|
episodes.filterNot { it.seen }
|
||||||
} else if (!downloadPreferences.removeBookmarkedChapters().get()) {
|
|
||||||
episodes.filterNot { it.bookmark }
|
|
||||||
} else {
|
} else {
|
||||||
episodes
|
episodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (!downloadPreferences.removeBookmarkedChapters().get()) {
|
||||||
|
filteredCategoryAnime.filterNot { it.bookmark }
|
||||||
|
} else {
|
||||||
|
filteredCategoryAnime
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun statusFlow(): Flow<AnimeDownload> = queueState
|
fun statusFlow(): Flow<AnimeDownload> = queueState
|
||||||
|
|
|
@ -213,19 +213,21 @@ class MangaDownloadManager(
|
||||||
* @param source the source of the chapters.
|
* @param source the source of the chapters.
|
||||||
*/
|
*/
|
||||||
fun deleteChapters(chapters: List<Chapter>, manga: Manga, source: MangaSource) {
|
fun deleteChapters(chapters: List<Chapter>, manga: Manga, source: MangaSource) {
|
||||||
val filteredChapters = getChaptersToDelete(chapters, manga)
|
launchIO {
|
||||||
if (filteredChapters.isNotEmpty()) {
|
val filteredChapters = getChaptersToDelete(chapters, manga)
|
||||||
launchIO {
|
if (filteredChapters.isEmpty()) {
|
||||||
removeFromDownloadQueue(filteredChapters)
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
val (mangaDir, chapterDirs) = provider.findChapterDirs(filteredChapters, manga, source)
|
removeFromDownloadQueue(filteredChapters)
|
||||||
chapterDirs.forEach { it.delete() }
|
|
||||||
cache.removeChapters(filteredChapters, manga)
|
|
||||||
|
|
||||||
// Delete manga directory if empty
|
val (mangaDir, chapterDirs) = provider.findChapterDirs(filteredChapters, manga, source)
|
||||||
if (mangaDir?.listFiles()?.isEmpty() == true) {
|
chapterDirs.forEach { it.delete() }
|
||||||
deleteManga(manga, source, removeQueued = false)
|
cache.removeChapters(filteredChapters, manga)
|
||||||
}
|
|
||||||
|
// Delete manga directory if empty
|
||||||
|
if (mangaDir?.listFiles()?.isEmpty() == true) {
|
||||||
|
deleteManga(manga, source, removeQueued = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +279,7 @@ class MangaDownloadManager(
|
||||||
* @param chapters the list of chapters to delete.
|
* @param chapters the list of chapters to delete.
|
||||||
* @param manga the manga of the chapters.
|
* @param manga the manga of the chapters.
|
||||||
*/
|
*/
|
||||||
fun enqueueChaptersToDelete(chapters: List<Chapter>, manga: Manga) {
|
suspend fun enqueueChaptersToDelete(chapters: List<Chapter>, manga: Manga) {
|
||||||
pendingDeleter.addChapters(getChaptersToDelete(chapters, manga), manga)
|
pendingDeleter.addChapters(getChaptersToDelete(chapters, manga), manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,22 +352,24 @@ class MangaDownloadManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getChaptersToDelete(chapters: List<Chapter>, manga: Manga): List<Chapter> {
|
private suspend fun getChaptersToDelete(chapters: List<Chapter>, manga: Manga): List<Chapter> {
|
||||||
// Retrieve the categories that are set to exclude from being deleted on read
|
// Retrieve the categories that are set to exclude from being deleted on read
|
||||||
val categoriesToExclude = downloadPreferences.removeExcludeCategories().get().map(String::toLong)
|
val categoriesToExclude = downloadPreferences.removeExcludeCategories().get().map(String::toLong)
|
||||||
|
|
||||||
val categoriesForManga = runBlocking { getCategories.await(manga.id) }
|
val categoriesForManga = getCategories.await(manga.id)
|
||||||
.map { it.id }
|
.map { it.id }
|
||||||
.takeUnless { it.isEmpty() }
|
.ifEmpty { listOf(0) }
|
||||||
?: listOf(0)
|
val filteredCategoryManga = if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) {
|
||||||
|
|
||||||
return if (categoriesForManga.intersect(categoriesToExclude).isNotEmpty()) {
|
|
||||||
chapters.filterNot { it.read }
|
chapters.filterNot { it.read }
|
||||||
} else if (!downloadPreferences.removeBookmarkedChapters().get()) {
|
|
||||||
chapters.filterNot { it.bookmark }
|
|
||||||
} else {
|
} else {
|
||||||
chapters
|
chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (!downloadPreferences.removeBookmarkedChapters().get()) {
|
||||||
|
filteredCategoryManga.filterNot { it.bookmark }
|
||||||
|
} else {
|
||||||
|
filteredCategoryManga
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun statusFlow(): Flow<MangaDownload> = queueState
|
fun statusFlow(): Flow<MangaDownload> = queueState
|
||||||
|
|
|
@ -15,6 +15,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
@ -93,7 +94,7 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen() {
|
||||||
commit: FragmentTransaction.(containerId: Int) -> Unit,
|
commit: FragmentTransaction.(containerId: Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
val containerId by rememberSaveable {
|
val containerId by rememberSaveable {
|
||||||
mutableStateOf(View.generateViewId())
|
mutableIntStateOf(View.generateViewId())
|
||||||
}
|
}
|
||||||
var initialized by rememberSaveable { mutableStateOf(false) }
|
var initialized by rememberSaveable { mutableStateOf(false) }
|
||||||
AndroidView(
|
AndroidView(
|
||||||
|
|
|
@ -15,6 +15,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
@ -93,7 +94,7 @@ class MangaSourcePreferencesScreen(val sourceId: Long) : Screen() {
|
||||||
commit: FragmentTransaction.(containerId: Int) -> Unit,
|
commit: FragmentTransaction.(containerId: Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
val containerId by rememberSaveable {
|
val containerId by rememberSaveable {
|
||||||
mutableStateOf(View.generateViewId())
|
mutableIntStateOf(View.generateViewId())
|
||||||
}
|
}
|
||||||
var initialized by rememberSaveable { mutableStateOf(false) }
|
var initialized by rememberSaveable { mutableStateOf(false) }
|
||||||
AndroidView(
|
AndroidView(
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.graphics.Paint
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
|
@ -38,6 +39,7 @@ import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
|
import com.google.android.material.internal.ToolbarUtils
|
||||||
import com.google.android.material.shape.MaterialShapeDrawable
|
import com.google.android.material.shape.MaterialShapeDrawable
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransform
|
import com.google.android.material.transition.platform.MaterialContainerTransform
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
|
@ -697,10 +699,16 @@ class ReaderActivity : BaseActivity() {
|
||||||
* method to the current viewer, but also set the subtitle on the toolbar, and
|
* method to the current viewer, but also set the subtitle on the toolbar, and
|
||||||
* hides or disables the reader prev/next buttons if there's a prev or next chapter
|
* hides or disables the reader prev/next buttons if there's a prev or next chapter
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
private fun setChapters(viewerChapters: ViewerChapters) {
|
private fun setChapters(viewerChapters: ViewerChapters) {
|
||||||
binding.readerContainer.removeView(loadingIndicator)
|
binding.readerContainer.removeView(loadingIndicator)
|
||||||
viewModel.state.value.viewer?.setChapters(viewerChapters)
|
viewModel.state.value.viewer?.setChapters(viewerChapters)
|
||||||
|
|
||||||
binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name
|
binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name
|
||||||
|
ToolbarUtils.getSubtitleTextView(binding.toolbar)?.let {
|
||||||
|
it.ellipsize = TextUtils.TruncateAt.MARQUEE
|
||||||
|
it.isSelected = true
|
||||||
|
}
|
||||||
|
|
||||||
// Invalidate menu to show proper chapter bookmark state
|
// Invalidate menu to show proper chapter bookmark state
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
|
|
@ -25,10 +25,12 @@ import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.lang.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.ImageUtil
|
import tachiyomi.core.util.system.ImageUtil
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
|
@ -234,19 +236,24 @@ class WebtoonPageHolder(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onStripSplit(imageStream: BufferedInputStream): InputStream {
|
private fun onStripSplit(imageStream: BufferedInputStream): InputStream {
|
||||||
// If we have reached this point [page] and its stream shouldn't be null
|
try {
|
||||||
val page = page!!
|
// If we have reached this point [page] and its stream shouldn't be null
|
||||||
val stream = page.stream!!
|
val page = page!!
|
||||||
val splitData = ImageUtil.getSplitDataForStream(imageStream).toMutableList()
|
val stream = page.stream!!
|
||||||
val currentSplitData = splitData.removeFirst()
|
val splitData = ImageUtil.getSplitDataForStream(imageStream).toMutableList()
|
||||||
val newPages = splitData.map {
|
val currentSplitData = splitData.removeFirst()
|
||||||
StencilPage(page) { ImageUtil.splitStrip(it, stream) }
|
val newPages = splitData.map {
|
||||||
}
|
StencilPage(page) { ImageUtil.splitStrip(it, stream) }
|
||||||
return ImageUtil.splitStrip(currentSplitData) { imageStream }
|
|
||||||
.also {
|
|
||||||
// Running [onLongStripSplit] first results in issues with splitting
|
|
||||||
viewer.onLongStripSplit(page, newPages)
|
|
||||||
}
|
}
|
||||||
|
return ImageUtil.splitStrip(currentSplitData) { imageStream }
|
||||||
|
.also {
|
||||||
|
// Running [onLongStripSplit] first results in issues with splitting
|
||||||
|
viewer.onLongStripSplit(page, newPages)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e) { "Failed to split image" }
|
||||||
|
return imageStream
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -298,9 +298,8 @@ object ImageUtil {
|
||||||
"splitHeight=${splitData.splitHeight} bottomOffset=${splitData.bottomOffset}"
|
"splitHeight=${splitData.splitHeight} bottomOffset=${splitData.bottomOffset}"
|
||||||
}
|
}
|
||||||
|
|
||||||
val region = Rect(0, splitData.topOffset, splitData.splitWidth, splitData.bottomOffset)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
val region = Rect(0, splitData.topOffset, splitData.splitWidth, splitData.bottomOffset)
|
||||||
val splitBitmap = bitmapRegionDecoder.decodeRegion(region, null)
|
val splitBitmap = bitmapRegionDecoder.decodeRegion(region, null)
|
||||||
val outputStream = ByteArrayOutputStream()
|
val outputStream = ByteArrayOutputStream()
|
||||||
splitBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
|
splitBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[versions]
|
[versions]
|
||||||
compiler = "1.4.7"
|
compiler = "1.4.7"
|
||||||
compose-bom = "2023.04.00-alpha04"
|
compose-bom = "2023.04.00-beta01.1"
|
||||||
accompanist = "0.31.2-alpha"
|
accompanist = "0.31.2-alpha"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|
|
@ -26,7 +26,7 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
@ -61,7 +61,7 @@ fun AdaptiveSheet(
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
if (isTabletUi) {
|
if (isTabletUi) {
|
||||||
var targetAlpha by remember { mutableStateOf(0f) }
|
var targetAlpha by remember { mutableFloatStateOf(0f) }
|
||||||
val alpha by animateFloatAsState(
|
val alpha by animateFloatAsState(
|
||||||
targetValue = targetAlpha,
|
targetValue = targetAlpha,
|
||||||
animationSpec = SheetAnimationSpec,
|
animationSpec = SheetAnimationSpec,
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package tachiyomi.presentation.core.components
|
package tachiyomi.presentation.core.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.IntrinsicSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.requiredWidth
|
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -24,7 +23,7 @@ fun Pill(
|
||||||
elevation: Dp = 1.dp,
|
elevation: Dp = 1.dp,
|
||||||
fontSize: TextUnit = LocalTextStyle.current.fontSize,
|
fontSize: TextUnit = LocalTextStyle.current.fontSize,
|
||||||
) {
|
) {
|
||||||
androidx.compose.material3.Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(start = 4.dp),
|
.padding(start = 4.dp),
|
||||||
shape = MaterialTheme.shapes.extraLarge,
|
shape = MaterialTheme.shapes.extraLarge,
|
||||||
|
@ -34,7 +33,6 @@ fun Pill(
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.requiredWidth(IntrinsicSize.Max)
|
|
||||||
.padding(6.dp, 1.dp),
|
.padding(6.dp, 1.dp),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -85,7 +85,7 @@ fun VerticalFastScroller(
|
||||||
if (!showScroller) return@subcompose
|
if (!showScroller) return@subcompose
|
||||||
|
|
||||||
val thumbTopPadding = with(LocalDensity.current) { topContentPadding.toPx() }
|
val thumbTopPadding = with(LocalDensity.current) { topContentPadding.toPx() }
|
||||||
var thumbOffsetY by remember(thumbTopPadding) { mutableStateOf(thumbTopPadding) }
|
var thumbOffsetY by remember(thumbTopPadding) { mutableFloatStateOf(thumbTopPadding) }
|
||||||
|
|
||||||
val dragInteractionSource = remember { MutableInteractionSource() }
|
val dragInteractionSource = remember { MutableInteractionSource() }
|
||||||
val isThumbDragged by dragInteractionSource.collectIsDraggedAsState()
|
val isThumbDragged by dragInteractionSource.collectIsDraggedAsState()
|
||||||
|
@ -251,7 +251,7 @@ fun VerticalGridFastScroller(
|
||||||
val showScroller = layoutInfo.visibleItemsInfo.size < layoutInfo.totalItemsCount
|
val showScroller = layoutInfo.visibleItemsInfo.size < layoutInfo.totalItemsCount
|
||||||
if (!showScroller) return@subcompose
|
if (!showScroller) return@subcompose
|
||||||
val thumbTopPadding = with(LocalDensity.current) { topContentPadding.toPx() }
|
val thumbTopPadding = with(LocalDensity.current) { topContentPadding.toPx() }
|
||||||
var thumbOffsetY by remember(thumbTopPadding) { mutableStateOf(thumbTopPadding) }
|
var thumbOffsetY by remember(thumbTopPadding) { mutableFloatStateOf(thumbTopPadding) }
|
||||||
|
|
||||||
val dragInteractionSource = remember { MutableInteractionSource() }
|
val dragInteractionSource = remember { MutableInteractionSource() }
|
||||||
val isThumbDragged by dragInteractionSource.collectIsDraggedAsState()
|
val isThumbDragged by dragInteractionSource.collectIsDraggedAsState()
|
||||||
|
|
|
@ -20,6 +20,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
@ -113,7 +114,7 @@ private fun <T> WheelPicker(
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val lazyListState = rememberLazyListState(startIndex)
|
val lazyListState = rememberLazyListState(startIndex)
|
||||||
|
|
||||||
var internalIndex by remember { mutableStateOf(startIndex) }
|
var internalIndex by remember { mutableIntStateOf(startIndex) }
|
||||||
val internalOnSelectionChanged: (Int) -> Unit = {
|
val internalOnSelectionChanged: (Int) -> Unit = {
|
||||||
internalIndex = it
|
internalIndex = it
|
||||||
onSelectionChanged(it)
|
onSelectionChanged(it)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ fun LazyListState.isScrolledToEnd(): Boolean {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyListState.isScrollingUp(): Boolean {
|
fun LazyListState.isScrollingUp(): Boolean {
|
||||||
var previousIndex by remember { mutableStateOf(firstVisibleItemIndex) }
|
var previousIndex by remember { mutableIntStateOf(firstVisibleItemIndex) }
|
||||||
var previousScrollOffset by remember { mutableStateOf(firstVisibleItemScrollOffset) }
|
var previousScrollOffset by remember { mutableIntStateOf(firstVisibleItemScrollOffset) }
|
||||||
return remember {
|
return remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (previousIndex != firstVisibleItemIndex) {
|
if (previousIndex != firstVisibleItemIndex) {
|
||||||
|
@ -48,8 +48,8 @@ fun LazyListState.isScrollingUp(): Boolean {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyListState.isScrollingDown(): Boolean {
|
fun LazyListState.isScrollingDown(): Boolean {
|
||||||
var previousIndex by remember { mutableStateOf(firstVisibleItemIndex) }
|
var previousIndex by remember { mutableIntStateOf(firstVisibleItemIndex) }
|
||||||
var previousScrollOffset by remember { mutableStateOf(firstVisibleItemScrollOffset) }
|
var previousScrollOffset by remember { mutableIntStateOf(firstVisibleItemScrollOffset) }
|
||||||
return remember {
|
return remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (previousIndex != firstVisibleItemIndex) {
|
if (previousIndex != firstVisibleItemIndex) {
|
||||||
|
|
Loading…
Reference in a new issue