فهرست منبع

优化阅读记录总览(在阅读记录的成就卡片进入,稳定后会加入主页面)

HapeLee 6 ماه پیش
والد
کامیت
c1f7faf050

+ 12 - 0
app/src/main/java/io/legado/app/domain/usecase/readRecord/GetReadRecordOverviewUseCase.kt

@@ -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 } }

+ 22 - 8
app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordOverviewScreen.kt

@@ -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)
             )
         }
         

+ 31 - 10
app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt

@@ -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)
+                    )
                 }
             }
         }

+ 28 - 16
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordCharts.kt

@@ -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
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordListItems.kt

@@ -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(

+ 5 - 3
app/src/main/java/io/legado/app/ui/book/readRecord/component/ReadRecordSummary.kt

@@ -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)
             )
         }
     }

+ 2 - 0
app/src/main/java/io/legado/app/ui/widget/components/cover/CoilBookCover.kt

@@ -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))