HapeLee 1 год назад
Родитель
Сommit
a73e3db0fc

+ 8 - 3
app/src/main/java/io/legato/kazusa/data/entities/Book.kt

@@ -265,14 +265,19 @@ data class Book(
 
     // startDate 的 setter 和 getter
     fun setStartDate(startDate: LocalDate?) {
-        config.startDate = startDate
+        config.startDate = startDate?.toString()
     }
 
     fun getStartDate(): LocalDate? {
         if (!config.readSimulating || config.startDate == null) {
             return LocalDate.now()
         }
-        return config.startDate
+        return try {
+            LocalDate.parse(config.startDate)
+        } catch (e: Exception) {
+            println("解析日期失败: ${config.startDate}, 错误: ${e.message}")
+            LocalDate.now()
+        }
     }
 
     // startChapter 的 setter 和 getter
@@ -400,7 +405,7 @@ data class Book(
         var ttsEngine: String? = null,
         var splitLongChapter: Boolean = true,
         var readSimulating: Boolean = false,
-        var startDate: LocalDate? = null,
+        var startDate: String? = null,
         var startChapter: Int? = null,     // 用户设置的起始章节
         var dailyChapters: Int = 3,    // 用户设置的每日更新章节数
 

+ 12 - 2
app/src/main/java/io/legato/kazusa/help/book/BookExtensions.kt

@@ -28,7 +28,7 @@ import io.legato.kazusa.utils.toastOnUi
 import splitties.init.appCtx
 import java.io.File
 import java.time.LocalDate
-import java.time.Period.between
+import java.time.temporal.ChronoUnit
 import java.util.concurrent.ConcurrentHashMap
 import kotlin.math.max
 import kotlin.math.min
@@ -353,7 +353,17 @@ fun Book.getExportFileName(
 fun Book.simulatedTotalChapterNum(): Int {
     return if (readSimulating()) {
         val currentDate = LocalDate.now()
-        val daysPassed = between(config.startDate, currentDate).days + 1
+        val daysPassed = if (config.startDate != null) {
+            try {
+                val startDate = LocalDate.parse(config.startDate)
+                ChronoUnit.DAYS.between(startDate, currentDate).toInt() + 1
+            } catch (e: Exception) {
+                println("解析起始日期失败: ${config.startDate}, 错误: ${e.message}")
+                1 // 解析失败时返回默认值1
+            }
+        } else {
+            1 // 没有设置起始日期时返回默认值1
+        }
         // 计算当前应该解锁到哪一章
         val chaptersToUnlock =
             max(0, (config.startChapter ?: 0) + (daysPassed * config.dailyChapters))

+ 42 - 29
app/src/main/java/io/legato/kazusa/ui/book/read/BaseReadBookActivity.kt

@@ -1,7 +1,6 @@
 package io.legato.kazusa.ui.book.read
 
 import android.annotation.SuppressLint
-import android.app.DatePickerDialog
 import android.content.pm.ActivityInfo
 import android.os.Build
 import android.os.Bundle
@@ -10,10 +9,12 @@ import android.view.View
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.doOnDetach
 import androidx.core.view.isVisible
 import androidx.core.view.updateLayoutParams
+import com.google.android.material.datepicker.MaterialDatePicker
 import io.legato.kazusa.R
 import io.legato.kazusa.base.VMBaseActivity
 import io.legato.kazusa.constant.AppConst.charsets
@@ -27,7 +28,6 @@ import io.legato.kazusa.help.config.LocalConfig
 import io.legato.kazusa.help.config.ReadBookConfig
 import io.legato.kazusa.lib.dialogs.alert
 import io.legato.kazusa.lib.dialogs.selector
-//import io.legado.app.lib.theme.bottomBackground
 import io.legato.kazusa.model.CacheBook
 import io.legato.kazusa.model.ReadBook
 import io.legato.kazusa.ui.book.read.config.BgTextConfigDialog
@@ -47,7 +47,9 @@ import io.legato.kazusa.utils.setOnApplyWindowInsetsListenerCompat
 import io.legato.kazusa.utils.showDialogFragment
 import io.legato.kazusa.utils.themeColor
 import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
+import java.time.Instant
 import java.time.LocalDate
+import java.time.ZoneId
 import java.time.format.DateTimeFormatter
 
 /**
@@ -288,46 +290,57 @@ abstract class BaseReadBookActivity :
     fun showSimulatedReading() {
         val book = ReadBook.book ?: return
         val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
+
         val alertBinding = DialogSimulatedReadingBinding.inflate(layoutInflater).apply {
             srEnabled.isChecked = book.getReadSimulating()
             editStart.setText(book.getStartChapter().toString())
             editNum.setText(book.getDailyChapters().toString())
-            startDate.setText(book.getStartDate()?.format(dateFormatter))
-            startDate.isFocusable = false // 设置为false,不允许获得焦点
-            startDate.isCursorVisible = false // 不显示光标
+
+            // 安全地设置初始日期
+            val safeDate = book.getStartDate() ?: LocalDate.now()
+            startDate.setText(safeDate.format(dateFormatter))
+
+            // 让 EditText 不可直接编辑,只能通过选择器
+            startDate.isFocusable = false
+            startDate.isCursorVisible = false
+
             startDate.setOnClickListener {
-                // 获取当前日期
-                val localStartDate = LocalDate.parse(startDate.text)
-                // 创建 DatePickerDialog
-                val datePickerDialog = DatePickerDialog(
-                    root.context,
-                    { _, yy, mm, dayOfMonth ->
-                        // 使用Java 8的日期和时间API来格式化日期
-                        val date = LocalDate.of(yy, mm + 1, dayOfMonth) // Java 8的LocalDate,月份从1开始
-                        val formattedDate = date.format(dateFormatter)
-                        startDate.setText(formattedDate)
-                    }, localStartDate.year,
-                    localStartDate.monthValue - 1,
-                    localStartDate.dayOfMonth
-                )
-                datePickerDialog.show()
+                val currentDate = try {
+                    LocalDate.parse(startDate.text.toString(), dateFormatter)
+                } catch (e: Exception) {
+                    LocalDate.now()
+                }
+                val initialSelection = currentDate
+                    .atStartOfDay(ZoneId.systemDefault())
+                    .toInstant()
+                    .toEpochMilli()
+                val picker = MaterialDatePicker.Builder.datePicker()
+                    .setTitleText("选择开始日期")
+                    .setSelection(initialSelection)
+                    .build()
+                picker.addOnPositiveButtonClickListener { selection ->
+                    val date = Instant.ofEpochMilli(selection)
+                        .atZone(ZoneId.systemDefault())
+                        .toLocalDate()
+                    startDate.setText(date.format(dateFormatter))
+                }
+                picker.show((root.context as AppCompatActivity).supportFragmentManager, "md3_date_picker")
             }
         }
         alert(titleResource = R.string.simulated_reading) {
             customView { alertBinding.root }
             okButton {
                 alertBinding.run {
-                    val start = editStart.text!!.toString().let {
-                        if (it.isEmpty()) 0 else it.toInt()
-                    }
-                    val num = editNum.text!!.toString().let {
-                        if (it.isEmpty()) book.totalChapterNum else it.toInt()
-                    }
+                    val start = editStart.text.toString().toIntOrNull() ?: 0
+                    val num = editNum.text.toString().toIntOrNull() ?: book.totalChapterNum
                     val enabled = srEnabled.isChecked
-                    val date = startDate.text!!.toString().let {
-                        if (it.isEmpty()) LocalDate.now()
-                        else LocalDate.parse(it, dateFormatter)
+
+                    val date = try {
+                        LocalDate.parse(startDate.text.toString(), dateFormatter)
+                    } catch (e: Exception) {
+                        LocalDate.now()
                     }
+
                     book.setStartDate(date)
                     book.setDailyChapters(num)
                     book.setStartChapter(start)

+ 49 - 122
app/src/main/res/layout/dialog_simulated_reading.xml

@@ -1,159 +1,86 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/ll_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:gravity="center"
-    android:padding="16dp"
+    android:padding="24dp"
     android:orientation="vertical">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="start"
+        android:layout_gravity="center_vertical"
         android:orientation="horizontal">
 
-        <TextView
-            android:layout_width="wrap_content"
+        <com.google.android.material.textfield.TextInputLayout
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_marginEnd="16dp"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:layout_marginRight="2dp"
-            android:text="@string/switch_on"
-            android:textSize="16sp"
-            tools:ignore="RtlHardcoded"
-            android:minWidth="88dp" />
+            style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense">
+            <com.google.android.material.textfield.TextInputEditText
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:inputType="date"
+                android:ems="10"
+                android:id="@+id/start_date"
+                android:hint="@string/start_from"
+                android:layout_weight="1"
+                android:clickable="true"
+                android:textSize="16sp" />
+        </com.google.android.material.textfield.TextInputLayout>
 
         <com.google.android.material.materialswitch.MaterialSwitch
-            android:layout_height="wrap_content"
-            android:id="@+id/sr_enabled"
-            android:gravity="start|center_vertical"
-            android:layout_width="wrap_content" />
-
-
-        <View
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="65dp"
-        android:orientation="horizontal"
-        android:gravity="start|center_vertical">
-
-        <TextView
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:text="@string/start_from"
-            android:textSize="16sp"
-            android:gravity="center_vertical"
-            android:minWidth="100dp" />
-
-        <View
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-        <EditText
-            android:layout_width="match_parent"
-            android:layout_height="49dp"
-            android:inputType="none"
-            android:ems="10"
-            android:id="@+id/start_date"
-            android:hint="Select date"
-            android:layout_weight="1"
-            android:clickable="true"
-            android:textSize="16sp"
-            android:layout_marginRight="68dp" />
-
-        <View
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
+            android:layout_height="match_parent"
+            android:id="@+id/sr_enabled" />
 
     </LinearLayout>
 
     <LinearLayout
+        android:baselineAligned="false"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginTop="24dp"
         android:gravity="start">
 
-        <LinearLayout
-            android:orientation="horizontal"
-            android:layout_width="100dp"
-            android:layout_height="match_parent"
-            android:minWidth="100dp">
-
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginRight="2dp"
-                android:text="@string/start_chapter"
-                android:textSize="16sp"
-                tools:ignore="RtlHardcoded" />
-
-        </LinearLayout>
-
-        <EditText
-            android:id="@+id/edit_start"
-            android:layout_width="47dp"
+        <com.google.android.material.textfield.TextInputLayout
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:background="@drawable/bg_edit"
-            android:hint="@string/start"
-            android:importantForAutofill="no"
-            android:inputType="number"
-            android:lines="1"
-            android:maxLength="5"
-            android:minWidth="60dp"
-            android:paddingLeft="5dp"
-            android:paddingTop="4dp"
-            android:paddingRight="5dp"
-            android:paddingBottom="4dp"
-            android:textSize="14sp"
-            tools:ignore="TouchTargetSizeCheck,TextContrastCheck" />
-
-        <LinearLayout
-            android:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="end">
-
-            <TextView
-                android:layout_width="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginEnd="32dp"
+            style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense">
+            <com.google.android.material.textfield.TextInputEditText
+                android:id="@+id/edit_start"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:layout_marginLeft="16dp"
-                android:layout_marginRight="5dp"
-                android:text="@string/daily_chapters"
-                android:textSize="16sp" />
+                android:hint="@string/start_chapter"
+                android:importantForAutofill="no"
+                android:inputType="number"
+                android:lines="1"
+                android:maxLength="5" />
+        </com.google.android.material.textfield.TextInputLayout>
 
-            <EditText
+        <com.google.android.material.textfield.TextInputLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense">
+            <com.google.android.material.textfield.TextInputEditText
                 android:id="@+id/edit_num"
-                android:layout_width="42dp"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:background="@drawable/bg_edit"
-                android:hint="3"
+                android:hint="@string/daily_chapters"
                 android:importantForAutofill="no"
                 android:inputType="number"
                 android:lines="1"
-                android:maxLength="5"
-                android:minWidth="60dp"
-                android:paddingLeft="5dp"
-                android:paddingTop="4dp"
-                android:paddingRight="5dp"
-                android:paddingBottom="4dp"
-                android:textSize="14sp"
-                tools:ignore="TouchTargetSizeCheck,SpeakableTextPresentCheck,TextContrastCheck"
-                android:textAlignment="center" />
-        </LinearLayout>
+                android:maxLength="5" />
+        </com.google.android.material.textfield.TextInputLayout>
+
+
+
 
     </LinearLayout>