优化阅读记录总览(在阅读记录的成就卡片进入,稳定后会加入主页面)
This commit is contained in:
+12
@@ -69,6 +69,18 @@ class GetReadRecordOverviewUseCase {
|
||||
|
||||
val dailyTimeData = if (period == ReadPeriod.ALL) {
|
||||
emptyList()
|
||||
} else if (period == ReadPeriod.YEAR) {
|
||||
val dateToTime = filteredDetails.groupBy {
|
||||
LocalDate.parse(it.date, DateTimeFormatter.ISO_LOCAL_DATE).with(TemporalAdjusters.firstDayOfMonth())
|
||||
}.mapValues { it.value.sumOf { d -> d.readTime } }
|
||||
|
||||
val monthList = mutableListOf<Pair<LocalDate, Long>>()
|
||||
var curr = startDate.with(TemporalAdjusters.firstDayOfMonth())
|
||||
while (!curr.isAfter(endDate)) {
|
||||
monthList.add(curr to (dateToTime[curr] ?: 0L))
|
||||
curr = curr.plusMonths(1)
|
||||
}
|
||||
monthList
|
||||
} else {
|
||||
val dateToTime = filteredDetails.groupBy { it.date }
|
||||
.mapValues { it.value.sumOf { d -> d.readTime } }
|
||||
|
||||
@@ -29,7 +29,7 @@ import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.components.AppScaffold
|
||||
import io.legado.app.ui.widget.components.button.MediumIconButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.Cover
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapMode
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||
@@ -223,8 +223,12 @@ fun TopReadingListCard(
|
||||
.fillMaxWidth()
|
||||
.adaptiveHorizontalPadding(vertical = 8.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
AppText("阅读时长榜", style = LegadoTheme.typography.titleMedium)
|
||||
Column(modifier = Modifier.padding(vertical = 16.dp)) {
|
||||
AppText(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
text = "阅读时长榜",
|
||||
style = LegadoTheme.typography.titleMedium
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
topBooks.forEachIndexed { index, book ->
|
||||
@@ -237,7 +241,7 @@ fun TopReadingListCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onBookClick(book.bookName, book.bookAuthor) }
|
||||
.padding(vertical = 8.dp),
|
||||
.padding(vertical = 8.dp, horizontal = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
AppText(
|
||||
@@ -247,7 +251,12 @@ fun TopReadingListCard(
|
||||
textAlign = TextAlign.Center,
|
||||
color = if (index < 3) LegadoTheme.colorScheme.primary else LegadoTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Cover(path = coverPath, modifier = Modifier.size(40.dp, 56.dp))
|
||||
CoilBookCover(
|
||||
name = book.bookName,
|
||||
author = book.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.width(40.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
AppText(
|
||||
@@ -264,6 +273,7 @@ fun TopReadingListCard(
|
||||
)
|
||||
}
|
||||
AppText(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
text = ReadRecordFormatter.formatDuration(book.readTime),
|
||||
style = LegadoTheme.typography.bodySmall,
|
||||
color = LegadoTheme.colorScheme.primary
|
||||
@@ -355,10 +365,14 @@ fun CalendarDayCell(
|
||||
.background(LegadoTheme.colorScheme.surfaceVariant),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (coverPath != null) {
|
||||
Cover(
|
||||
if (topBook != null) {
|
||||
CoilBookCover(
|
||||
name = topBook.first,
|
||||
author = topBook.second,
|
||||
path = coverPath,
|
||||
modifier = Modifier.fillMaxSize().alpha(0.4f)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.alpha(0.4f)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.checkBox.CheckboxItem
|
||||
import io.legado.app.ui.widget.components.cover.Cover
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.heatmap.HEATMAP_CALENDAR_TITLE
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarEndAction
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarStartAction
|
||||
@@ -728,7 +728,12 @@ fun LatestReadItem(
|
||||
.adaptiveHorizontalPadding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(coverPath)
|
||||
CoilBookCover(
|
||||
name = record.bookName,
|
||||
author = record.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.width(44.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
@@ -839,7 +844,12 @@ fun TimelineSessionItem(
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(coverPath)
|
||||
CoilBookCover(
|
||||
name = session.bookName,
|
||||
author = session.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.width(44.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Column {
|
||||
AppText(
|
||||
@@ -889,7 +899,12 @@ fun ReadRecordItem(
|
||||
.adaptiveHorizontalPadding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(coverPath)
|
||||
CoilBookCover(
|
||||
name = detail.bookName,
|
||||
author = detail.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.width(44.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
|
||||
@@ -1017,24 +1032,25 @@ fun ReadingSummaryCard(
|
||||
}
|
||||
|
||||
if (bookNamesForCover.isNotEmpty()) {
|
||||
BookStackView(coverPaths = coverPaths)
|
||||
val combined = bookNamesForCover.zip(coverPaths)
|
||||
BookStackView(books = combined)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BookStackView(coverPaths: List<String?>) {
|
||||
fun BookStackView(books: List<Pair<Pair<String, String>, String?>>) {
|
||||
val xOffsetStep = 12.dp
|
||||
val stackWidth = 48.dp + (xOffsetStep * (coverPaths.size - 1).coerceAtLeast(0))
|
||||
val stackWidth = 44.dp + (xOffsetStep * (books.size - 1).coerceAtLeast(0))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(stackWidth)
|
||||
.height(72.dp),
|
||||
.height(64.dp),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
coverPaths.forEachIndexed { index, path ->
|
||||
books.forEachIndexed { index, (info, path) ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = xOffsetStep * index)
|
||||
@@ -1046,7 +1062,12 @@ fun BookStackView(coverPaths: List<String?>) {
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
color = Color.Transparent
|
||||
) {
|
||||
Cover(path = path)
|
||||
CoilBookCover(
|
||||
name = info.first,
|
||||
author = info.second,
|
||||
path = path,
|
||||
modifier = Modifier.width(44.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.formatReadDuration
|
||||
import java.time.LocalDate
|
||||
|
||||
@Composable
|
||||
@@ -48,7 +47,7 @@ fun ReadingTimeBarChartCard(
|
||||
horizontalAlignment = Alignment.End
|
||||
) {
|
||||
AppText(
|
||||
text = formatReadDuration(maxTime),
|
||||
text = formatChartDuration(maxTime),
|
||||
style = LegadoTheme.typography.labelSmall,
|
||||
fontSize = 8.sp,
|
||||
color = LegadoTheme.colorScheme.onSurfaceVariant
|
||||
@@ -76,16 +75,16 @@ fun ReadingTimeBarChartCard(
|
||||
|
||||
val showLabel = when (period) {
|
||||
ReadPeriod.DAY -> true
|
||||
ReadPeriod.WEEK -> date.dayOfWeek.value in listOf(2, 4, 6)
|
||||
ReadPeriod.MONTH -> date.dayOfMonth == 1 || date.dayOfMonth % 7 == 0 || index == data.lastIndex
|
||||
ReadPeriod.YEAR -> date.dayOfMonth == 1
|
||||
ReadPeriod.WEEK -> true
|
||||
ReadPeriod.MONTH -> date.dayOfMonth == 1 || date.dayOfMonth == 15 || index == data.lastIndex
|
||||
ReadPeriod.YEAR -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
val labelText = when (period) {
|
||||
ReadPeriod.YEAR -> "${date.monthValue}月"
|
||||
ReadPeriod.WEEK -> when (date.dayOfWeek.value) {
|
||||
2 -> "二"; 4 -> "四"; 6 -> "六"; else -> ""
|
||||
1 -> "一"; 2 -> "二"; 3 -> "三"; 4 -> "四"; 5 -> "五"; 6 -> "六"; 7 -> "日"; else -> ""
|
||||
}
|
||||
else -> date.dayOfMonth.toString()
|
||||
}
|
||||
@@ -94,20 +93,26 @@ fun ReadingTimeBarChartCard(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.Bottom,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(0.6f)
|
||||
.fillMaxHeight(heightFactor.coerceAtLeast(0.01f))
|
||||
.padding(bottom = 4.dp)
|
||||
.clip(RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp))
|
||||
.background(
|
||||
if (time > 0) LegadoTheme.colorScheme.primary
|
||||
else LegadoTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
|
||||
)
|
||||
)
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(if (period == ReadPeriod.MONTH) 0.8f else 0.6f)
|
||||
.fillMaxHeight(heightFactor.coerceAtLeast(0.01f))
|
||||
.padding(horizontal = 1.dp)
|
||||
.clip(RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp))
|
||||
.background(
|
||||
if (time > 0) LegadoTheme.colorScheme.primary
|
||||
else LegadoTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.height(20.dp), contentAlignment = Alignment.TopCenter) {
|
||||
if (showLabel) {
|
||||
@@ -126,3 +131,10 @@ fun ReadingTimeBarChartCard(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatChartDuration(millis: Long): String {
|
||||
val totalMinutes = millis / (1000 * 60)
|
||||
val hours = totalMinutes / 60
|
||||
val minutes = totalMinutes % 60
|
||||
return if (hours > 0) "${hours}h${if (minutes > 0) "${minutes}m" else ""}" else "${minutes}m"
|
||||
}
|
||||
|
||||
+19
-4
@@ -16,7 +16,7 @@ import io.legado.app.ui.book.readRecord.ReadRecordFormatter
|
||||
import io.legado.app.ui.book.readRecord.ReadRecordViewModel
|
||||
import io.legado.app.ui.book.readRecord.TimelineItem
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.cover.Cover
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import io.legado.app.utils.StringUtils.formatFriendlyDate
|
||||
|
||||
@@ -39,7 +39,12 @@ fun LatestReadItem(
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(path = coverPath, modifier = Modifier.size(48.dp, 64.dp))
|
||||
CoilBookCover(
|
||||
name = record.bookName,
|
||||
author = record.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.size(48.dp, 64.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
AppText(
|
||||
@@ -89,7 +94,12 @@ fun TimelineSessionItem(
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(path = coverPath, modifier = Modifier.size(40.dp, 56.dp))
|
||||
CoilBookCover(
|
||||
name = session.bookName,
|
||||
author = session.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.size(40.dp, 56.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
AppText(
|
||||
@@ -131,7 +141,12 @@ fun ReadRecordItem(
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Cover(path = coverPath, modifier = Modifier.size(40.dp, 56.dp))
|
||||
CoilBookCover(
|
||||
name = detail.bookName,
|
||||
author = detail.bookAuthor,
|
||||
path = coverPath,
|
||||
modifier = Modifier.size(40.dp, 56.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
AppText(
|
||||
|
||||
@@ -12,7 +12,7 @@ import io.legado.app.ui.book.readRecord.ReadRecordViewModel
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.theme.adaptiveHorizontalPadding
|
||||
import io.legado.app.ui.widget.components.card.GlassCard
|
||||
import io.legado.app.ui.widget.components.cover.Cover
|
||||
import io.legado.app.ui.widget.components.cover.CoilBookCover
|
||||
import io.legado.app.ui.widget.components.text.AppText
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@@ -107,11 +107,13 @@ fun BookStackView(
|
||||
coverPath = viewModel.getBookCover(name, author)
|
||||
}
|
||||
|
||||
Cover(
|
||||
CoilBookCover(
|
||||
name = name,
|
||||
author = author,
|
||||
path = coverPath,
|
||||
modifier = Modifier
|
||||
.padding(end = (index * 12).dp)
|
||||
.size(32.dp, 44.dp)
|
||||
.width(32.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
@@ -78,6 +79,7 @@ fun CoilBookCover(
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.aspectRatio(5f / 7f)
|
||||
.then(
|
||||
if (CoverConfig.coverShowShadow) {
|
||||
Modifier.shadow(4.dp, RoundedCornerShape(4.dp))
|
||||
|
||||
Reference in New Issue
Block a user