|
|
|
@ -48,6 +48,7 @@ import org.xtimms.tokusho.core.components.effects.updateAnimatedItemsState
|
|
|
|
import org.xtimms.tokusho.core.prefs.AppSettings
|
|
|
|
import org.xtimms.tokusho.core.prefs.AppSettings
|
|
|
|
import org.xtimms.tokusho.core.prefs.SWIPE_TUTORIAL
|
|
|
|
import org.xtimms.tokusho.core.prefs.SWIPE_TUTORIAL
|
|
|
|
import org.xtimms.tokusho.core.screens.EmptyScreen
|
|
|
|
import org.xtimms.tokusho.core.screens.EmptyScreen
|
|
|
|
|
|
|
|
import org.xtimms.tokusho.core.screens.LoadingScreen
|
|
|
|
import org.xtimms.tokusho.utils.lang.calculateTimeAgo
|
|
|
|
import org.xtimms.tokusho.utils.lang.calculateTimeAgo
|
|
|
|
import org.xtimms.tokusho.utils.lang.isSameDay
|
|
|
|
import org.xtimms.tokusho.utils.lang.isSameDay
|
|
|
|
import java.time.Instant
|
|
|
|
import java.time.Instant
|
|
|
|
@ -70,11 +71,11 @@ fun HistoryView(
|
|
|
|
val scrollState = rememberScrollState()
|
|
|
|
val scrollState = rememberScrollState()
|
|
|
|
var isUserTrySwipe by remember { mutableStateOf(false) }
|
|
|
|
var isUserTrySwipe by remember { mutableStateOf(false) }
|
|
|
|
|
|
|
|
|
|
|
|
val history by viewModel.content.collectAsStateWithLifecycle(emptyList())
|
|
|
|
val history by viewModel.content.collectAsStateWithLifecycle(null)
|
|
|
|
|
|
|
|
|
|
|
|
DisposableEffect(Unit) {
|
|
|
|
DisposableEffect(Unit) {
|
|
|
|
onDispose {
|
|
|
|
onDispose {
|
|
|
|
if (history.isNotEmpty() && isUserTrySwipe) {
|
|
|
|
if (history?.isNotEmpty() == true && isUserTrySwipe) {
|
|
|
|
AppSettings.updateValue(SWIPE_TUTORIAL, isUserTrySwipe)
|
|
|
|
AppSettings.updateValue(SWIPE_TUTORIAL, isUserTrySwipe)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -83,7 +84,7 @@ fun HistoryView(
|
|
|
|
val animatedList = run {
|
|
|
|
val animatedList = run {
|
|
|
|
val list = emptyList<RowEntity>().toMutableList()
|
|
|
|
val list = emptyList<RowEntity>().toMutableList()
|
|
|
|
var readDate: Instant? = null
|
|
|
|
var readDate: Instant? = null
|
|
|
|
history.forEach { item ->
|
|
|
|
history?.forEach { item ->
|
|
|
|
|
|
|
|
|
|
|
|
if (readDate === null || !isSameDay(
|
|
|
|
if (readDate === null || !isSameDay(
|
|
|
|
item.history.updatedAt.toEpochMilli(),
|
|
|
|
item.history.updatedAt.toEpochMilli(),
|
|
|
|
@ -116,114 +117,127 @@ fun HistoryView(
|
|
|
|
Box(
|
|
|
|
Box(
|
|
|
|
Modifier.fillMaxSize()
|
|
|
|
Modifier.fillMaxSize()
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
Column(Modifier.fillMaxSize()) {
|
|
|
|
history.let {
|
|
|
|
LazyColumn(
|
|
|
|
if (it == null) {
|
|
|
|
modifier = Modifier
|
|
|
|
LoadingScreen(Modifier.padding(padding))
|
|
|
|
.collapsable(
|
|
|
|
} else if (it.isEmpty()) {
|
|
|
|
state = scrollState,
|
|
|
|
EmptyScreen(
|
|
|
|
topBarHeightPx = topBarHeightPx,
|
|
|
|
icon = Icons.Outlined.History,
|
|
|
|
topBarOffsetY = topBarOffsetY
|
|
|
|
title = R.string.empty_history_title,
|
|
|
|
)
|
|
|
|
description = R.string.empty_history_description
|
|
|
|
.padding(padding)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
} else {
|
|
|
|
animatedItemsIndexed(
|
|
|
|
Column(Modifier.fillMaxSize()) {
|
|
|
|
state = animatedList.value,
|
|
|
|
LazyColumn(
|
|
|
|
key = { rowItem -> rowItem.key },
|
|
|
|
modifier = Modifier
|
|
|
|
) { index, item ->
|
|
|
|
.collapsable(
|
|
|
|
when (item.type) {
|
|
|
|
state = scrollState,
|
|
|
|
RowEntityType.Header -> ListGroupHeader(
|
|
|
|
topBarHeightPx = topBarHeightPx,
|
|
|
|
calculateTimeAgo(item.day).format(
|
|
|
|
topBarOffsetY = topBarOffsetY
|
|
|
|
LocalContext.current.resources
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.padding(padding)
|
|
|
|
RowEntityType.Item -> SwipeActions(
|
|
|
|
) {
|
|
|
|
startActionsConfig = SwipeActionsConfig(
|
|
|
|
animatedItemsIndexed(
|
|
|
|
threshold = 0.33f,
|
|
|
|
state = animatedList.value,
|
|
|
|
background = MaterialTheme.colorScheme.errorContainer,
|
|
|
|
key = { rowItem -> rowItem.key },
|
|
|
|
backgroundActive = MaterialTheme.colorScheme.error,
|
|
|
|
) { index, item ->
|
|
|
|
iconTint = MaterialTheme.colorScheme.onError,
|
|
|
|
when (item.type) {
|
|
|
|
icon = Icons.Outlined.DeleteForever,
|
|
|
|
RowEntityType.Header -> ListGroupHeader(
|
|
|
|
stayDismissed = true,
|
|
|
|
calculateTimeAgo(item.day).format(
|
|
|
|
onDismiss = {
|
|
|
|
LocalContext.current.resources
|
|
|
|
viewModel.removeFromHistory(item.historyItemModel!!)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
),
|
|
|
|
|
|
|
|
endActionsConfig = SwipeActionsConfig(
|
|
|
|
|
|
|
|
threshold = 0.33f,
|
|
|
|
|
|
|
|
background = MaterialTheme.colorScheme.tertiaryContainer,
|
|
|
|
|
|
|
|
backgroundActive = MaterialTheme.colorScheme.tertiary,
|
|
|
|
|
|
|
|
iconTint = MaterialTheme.colorScheme.onTertiary,
|
|
|
|
|
|
|
|
icon = Icons.Outlined.PlayArrow,
|
|
|
|
|
|
|
|
stayDismissed = false,
|
|
|
|
|
|
|
|
onDismiss = {
|
|
|
|
|
|
|
|
navigateToReader()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
onTried = { isUserTrySwipe = true },
|
|
|
|
|
|
|
|
showTutorial = false,
|
|
|
|
|
|
|
|
) { state ->
|
|
|
|
|
|
|
|
val size = with(LocalDensity.current) {
|
|
|
|
|
|
|
|
java.lang.Float.max(
|
|
|
|
|
|
|
|
java.lang.Float.min(
|
|
|
|
|
|
|
|
16.dp.toPx(),
|
|
|
|
|
|
|
|
abs(state.offset.value)
|
|
|
|
|
|
|
|
), 0f
|
|
|
|
|
|
|
|
).toDp()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val animateCorners by remember {
|
|
|
|
RowEntityType.Item -> SwipeActions(
|
|
|
|
derivedStateOf {
|
|
|
|
startActionsConfig = SwipeActionsConfig(
|
|
|
|
state.offset.value.absoluteValue > 30
|
|
|
|
threshold = 0.33f,
|
|
|
|
}
|
|
|
|
background = MaterialTheme.colorScheme.errorContainer,
|
|
|
|
}
|
|
|
|
backgroundActive = MaterialTheme.colorScheme.error,
|
|
|
|
val startCorners by animateDpAsState(
|
|
|
|
iconTint = MaterialTheme.colorScheme.onError,
|
|
|
|
targetValue = when {
|
|
|
|
icon = Icons.Outlined.DeleteForever,
|
|
|
|
state.dismissDirection == DismissDirection.StartToEnd &&
|
|
|
|
stayDismissed = true,
|
|
|
|
animateCorners -> 8.dp
|
|
|
|
onDismiss = {
|
|
|
|
|
|
|
|
viewModel.removeFromHistory(item.historyItemModel!!)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
endActionsConfig = SwipeActionsConfig(
|
|
|
|
|
|
|
|
threshold = 0.33f,
|
|
|
|
|
|
|
|
background = MaterialTheme.colorScheme.tertiaryContainer,
|
|
|
|
|
|
|
|
backgroundActive = MaterialTheme.colorScheme.tertiary,
|
|
|
|
|
|
|
|
iconTint = MaterialTheme.colorScheme.onTertiary,
|
|
|
|
|
|
|
|
icon = Icons.Outlined.PlayArrow,
|
|
|
|
|
|
|
|
stayDismissed = false,
|
|
|
|
|
|
|
|
onDismiss = {
|
|
|
|
|
|
|
|
navigateToReader()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
onTried = { isUserTrySwipe = true },
|
|
|
|
|
|
|
|
showTutorial = false,
|
|
|
|
|
|
|
|
) { state ->
|
|
|
|
|
|
|
|
val size = with(LocalDensity.current) {
|
|
|
|
|
|
|
|
java.lang.Float.max(
|
|
|
|
|
|
|
|
java.lang.Float.min(
|
|
|
|
|
|
|
|
16.dp.toPx(),
|
|
|
|
|
|
|
|
abs(state.offset.value)
|
|
|
|
|
|
|
|
), 0f
|
|
|
|
|
|
|
|
).toDp()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
else -> 0.dp
|
|
|
|
val animateCorners by remember {
|
|
|
|
}, label = "startCorners"
|
|
|
|
derivedStateOf {
|
|
|
|
)
|
|
|
|
state.offset.value.absoluteValue > 30
|
|
|
|
val endCorners by animateDpAsState(
|
|
|
|
}
|
|
|
|
targetValue = when {
|
|
|
|
}
|
|
|
|
state.dismissDirection == DismissDirection.EndToStart &&
|
|
|
|
val startCorners by animateDpAsState(
|
|
|
|
animateCorners -> 8.dp
|
|
|
|
targetValue = when {
|
|
|
|
|
|
|
|
state.dismissDirection == DismissDirection.StartToEnd &&
|
|
|
|
|
|
|
|
animateCorners -> 8.dp
|
|
|
|
|
|
|
|
|
|
|
|
else -> 0.dp
|
|
|
|
else -> 0.dp
|
|
|
|
}, label = "endCorners"
|
|
|
|
}, label = "startCorners"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
val endCorners by animateDpAsState(
|
|
|
|
|
|
|
|
targetValue = when {
|
|
|
|
|
|
|
|
state.dismissDirection == DismissDirection.EndToStart &&
|
|
|
|
|
|
|
|
animateCorners -> 8.dp
|
|
|
|
|
|
|
|
|
|
|
|
Box(
|
|
|
|
else -> 0.dp
|
|
|
|
modifier = Modifier.height(IntrinsicSize.Min)
|
|
|
|
}, label = "endCorners"
|
|
|
|
) {
|
|
|
|
|
|
|
|
Surface(
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.fillMaxSize()
|
|
|
|
|
|
|
|
.padding(
|
|
|
|
|
|
|
|
vertical = min(
|
|
|
|
|
|
|
|
size / 4f,
|
|
|
|
|
|
|
|
4.dp
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.clip(RoundedCornerShape(size)),
|
|
|
|
|
|
|
|
color = MaterialTheme.colorScheme.surface,
|
|
|
|
|
|
|
|
shape = RoundedCornerShape(
|
|
|
|
|
|
|
|
topStart = startCorners,
|
|
|
|
|
|
|
|
bottomStart = startCorners,
|
|
|
|
|
|
|
|
topEnd = endCorners,
|
|
|
|
|
|
|
|
bottomEnd = endCorners,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// nothing
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Box(
|
|
|
|
|
|
|
|
modifier = Modifier.padding(vertical = 4.dp)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
HistoryItem(
|
|
|
|
|
|
|
|
coil = coil,
|
|
|
|
|
|
|
|
history = item.historyItemModel!!,
|
|
|
|
|
|
|
|
onClick = { navigateToDetails(item.historyItemModel!!.manga.id) },
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Box(
|
|
|
|
|
|
|
|
modifier = Modifier.height(IntrinsicSize.Min)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
Surface(
|
|
|
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
|
|
|
.fillMaxSize()
|
|
|
|
|
|
|
|
.padding(
|
|
|
|
|
|
|
|
vertical = min(
|
|
|
|
|
|
|
|
size / 4f,
|
|
|
|
|
|
|
|
4.dp
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.clip(RoundedCornerShape(size)),
|
|
|
|
|
|
|
|
color = MaterialTheme.colorScheme.surface,
|
|
|
|
|
|
|
|
shape = RoundedCornerShape(
|
|
|
|
|
|
|
|
topStart = startCorners,
|
|
|
|
|
|
|
|
bottomStart = startCorners,
|
|
|
|
|
|
|
|
topEnd = endCorners,
|
|
|
|
|
|
|
|
bottomEnd = endCorners,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// nothing
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Box(
|
|
|
|
|
|
|
|
modifier = Modifier.padding(vertical = 4.dp)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
HistoryItem(
|
|
|
|
|
|
|
|
coil = coil,
|
|
|
|
|
|
|
|
history = item.historyItemModel!!,
|
|
|
|
|
|
|
|
onClick = { navigateToDetails(item.historyItemModel!!.manga.id) },
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -231,12 +245,5 @@ fun HistoryView(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (history.isEmpty()) {
|
|
|
|
|
|
|
|
EmptyScreen(
|
|
|
|
|
|
|
|
icon = Icons.Outlined.History,
|
|
|
|
|
|
|
|
title = R.string.empty_history_title,
|
|
|
|
|
|
|
|
description = R.string.empty_history_description
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|