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

+ 5 - 1
app/src/main/java/io/legato/kazusa/base/BaseService.kt

@@ -8,6 +8,7 @@ import androidx.lifecycle.LifecycleService
 import androidx.lifecycle.lifecycleScope
 import io.legato.kazusa.R
 import io.legato.kazusa.help.LifecycleHelp
+import io.legato.kazusa.help.config.AppConfig
 import io.legato.kazusa.help.coroutine.Coroutine
 import io.legato.kazusa.lib.permission.Permissions
 import io.legato.kazusa.lib.permission.PermissionsCompat
@@ -37,7 +38,10 @@ abstract class BaseService : LifecycleService() {
     override fun onCreate() {
         super.onCreate()
         LifecycleHelp.onServiceCreate(this)
-        checkPermission()
+        if (!AppConfig.permissionChecked) {
+            AppConfig.permissionChecked = true
+            checkPermission()
+        }
     }
 
     @CallSuper

+ 4 - 0
app/src/main/java/io/legato/kazusa/constant/PreferKey.kt

@@ -205,4 +205,8 @@ object PreferKey {
     const val mangaClickActionBC = "mangaClickActionBottomCenter"
     const val mangaClickActionBR = "mangaClickActionBottomRight"
 
+    const val permissionChecked = "permissionChecked"
+    const val notificationsPost = "notificationsPost"
+    const val ignoreBatteryPermission = "ignoreBatteryPermission"
+
 }

+ 6 - 0
app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt

@@ -181,6 +181,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
             }
         }
 
+    var permissionChecked: Boolean
+        get() = appCtx.getPrefBoolean(PreferKey.permissionChecked, false)
+        set(value) {
+            appCtx.putPrefBoolean(PreferKey.permissionChecked, value)
+        }
+
     val textSelectAble: Boolean
         get() = appCtx.getPrefBoolean(PreferKey.textSelectAble, true)
 

+ 13 - 5
app/src/main/java/io/legato/kazusa/ui/book/toc/ChapterListAdapter.kt

@@ -133,6 +133,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
                     tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurfaceContainer))
                 } else {
                     tvChapterName.setTextColor(context.themeColor(com.google.android.material.R.attr.colorOnSurface))
+                    tvChapterItem.setBackgroundColor(context.themeColor(com.google.android.material.R.attr.colorSurface))
                 }
                 tvChapterName.text = getDisplayTitle(item)
                 if (item.isVolume) {
@@ -188,14 +189,21 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
 
     private fun upHasCache(binding: ItemChapterListBinding, isDur: Boolean, cached: Boolean) =
         binding.apply {
-            ivChecked.setImageResource(R.drawable.ic_outline_cloud_24)
-            ivChecked.visible(!cached)
-            if (isDur) {
-                ivChecked.setImageResource(R.drawable.ic_check)
-                ivChecked.visible()
+            when {
+                isDur -> ivChecked.gone()
+                cached -> {
+                    ivChecked.setImageResource(R.drawable.ic_check)
+                    ivChecked.visible()
+                }
+
+                else -> {
+                    ivChecked.setImageResource(R.drawable.ic_outline_cloud_24)
+                    ivChecked.visible()
+                }
             }
         }
 
+
     interface Callback {
         val scope: CoroutineScope
         val book: Book?

+ 102 - 10
app/src/main/java/io/legato/kazusa/ui/book/toc/ChapterListFragment.kt

@@ -1,12 +1,20 @@
 package io.legato.kazusa.ui.book.toc
 
+//import io.legado.app.lib.theme.bottomBackground
+//import io.legado.app.lib.theme.getPrimaryTextColor
 import android.annotation.SuppressLint
 import android.app.Activity.RESULT_OK
 import android.content.Intent
+import android.graphics.Canvas
 import android.os.Bundle
 import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.toDrawable
 import androidx.fragment.app.activityViewModels
+import androidx.interpolator.view.animation.FastOutSlowInInterpolator
 import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.RecyclerView
 import io.legato.kazusa.R
 import io.legato.kazusa.base.VMBaseFragment
 import io.legato.kazusa.constant.EventBus
@@ -17,12 +25,15 @@ import io.legato.kazusa.databinding.FragmentChapterListBinding
 import io.legato.kazusa.help.book.BookHelp
 import io.legato.kazusa.help.book.isLocal
 import io.legato.kazusa.help.book.simulatedTotalChapterNum
-//import io.legado.app.lib.theme.bottomBackground
-//import io.legado.app.lib.theme.getPrimaryTextColor
+import io.legato.kazusa.model.CacheBook
 import io.legato.kazusa.ui.widget.recycler.UpLinearLayoutManager
 import io.legato.kazusa.ui.widget.recycler.VerticalDivider
+import io.legato.kazusa.utils.VibrationUtils
 import io.legato.kazusa.utils.applyNavigationBarMargin
+import io.legato.kazusa.utils.dpToPx
 import io.legato.kazusa.utils.observeEvent
+import io.legato.kazusa.utils.themeColor
+import io.legato.kazusa.utils.toastOnUi
 import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.Default
@@ -30,6 +41,7 @@ import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.Main
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import kotlin.math.min
 
 class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapter_list),
     ChapterListAdapter.Callback,
@@ -42,12 +54,6 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
 
     override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) = binding.run {
         viewModel.chapterListCallBack = this@ChapterListFragment
-//        val bbg = bottomBackground
-//        val btc = requireContext().getPrimaryTextColor(ColorUtils.isColorLight(bbg))
-//        llChapterBaseInfo.setBackgroundColor(bbg)
-//        tvCurrentChapterInfo.setTextColor(btc)
-//        ivChapterTop.setColorFilter(btc, PorterDuff.Mode.SRC_IN)
-//        ivChapterBottom.setColorFilter(btc, PorterDuff.Mode.SRC_IN)
         initRecyclerView()
         initView()
         viewModel.bookData.observe(this@ChapterListFragment) {
@@ -56,12 +62,99 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
     }
 
     private fun initRecyclerView() {
+        val swipeCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
+
+            override fun onMove(
+                recyclerView: RecyclerView,
+                viewHolder: RecyclerView.ViewHolder,
+                target: RecyclerView.ViewHolder
+            ): Boolean = false
+
+            override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float = 0.3f
+
+            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+                val position = viewHolder.bindingAdapterPosition
+                val chapter = adapter.getItem(position) ?: return
+                val book = book ?: return
+
+                toastOnUi("开始下载: ${adapter.getItem(position)?.title}")
+                CacheBook.start(requireContext(), book, chapter.index, chapter.index)
+                VibrationUtils.vibrate(context!!, 100)
+                adapter.notifyItemChanged(position)
+            }
+
+            override fun onChildDraw(
+                c: Canvas,
+                recyclerView: RecyclerView,
+                viewHolder: RecyclerView.ViewHolder,
+                dX: Float,
+                dY: Float,
+                actionState: Int,
+                isCurrentlyActive: Boolean
+            ) {
+                if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE && dX > 0) {
+                    val itemView = viewHolder.itemView
+
+                    val interpolator = FastOutSlowInInterpolator()
+                    val dampedDx =
+                        interpolator.getInterpolation(min(1f, dX / itemView.width)) * itemView.width
+
+                    // 背景
+                    val background =
+                        requireContext().themeColor(com.google.android.material.R.attr.colorSecondary)
+                            .toDrawable()
+                    background.setBounds(
+                        itemView.left,
+                        itemView.top,
+                        itemView.left + dampedDx.toInt(),
+                        itemView.bottom
+                    )
+                    background.draw(c)
+
+                    // 图标
+                    val icon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_download)!!
+                    val iconMargin = (itemView.height - icon.intrinsicHeight) / 2
+                    val iconTop = itemView.top + iconMargin
+                    val iconBottom = iconTop + icon.intrinsicHeight
+                    val iconLeft = 12.dpToPx()
+                    val iconRight = iconLeft + icon.intrinsicWidth
+                    icon.setTint(requireContext().themeColor(com.google.android.material.R.attr.colorOnSecondary))
+                    icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
+                    icon.draw(c)
+
+                    super.onChildDraw(
+                        c,
+                        recyclerView,
+                        viewHolder,
+                        dampedDx,
+                        dY,
+                        actionState,
+                        isCurrentlyActive
+                    )
+                } else {
+                    super.onChildDraw(
+                        c,
+                        recyclerView,
+                        viewHolder,
+                        dX,
+                        dY,
+                        actionState,
+                        isCurrentlyActive
+                    )
+                }
+            }
+        }
+
+        val itemTouchHelper = ItemTouchHelper(swipeCallback)
+        itemTouchHelper.attachToRecyclerView(binding.recyclerView)
+
         binding.recyclerView.layoutManager = mLayoutManager
         binding.recyclerView.addItemDecoration(VerticalDivider(requireContext()))
         binding.recyclerView.adapter = adapter
     }
 
     private fun initView() = binding.run {
+        cdBase.applyNavigationBarMargin()
         btnChapterTop.setOnClickListener {
             mLayoutManager.scrollToPositionWithOffset(0, 0)
         }
@@ -70,10 +163,9 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
                 mLayoutManager.scrollToPositionWithOffset(adapter.itemCount - 1, 0)
             }
         }
-        tvCurrentChapterInfo.setOnClickListener {
+        btnLocate.setOnClickListener {
             mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
         }
-        binding.llChapterBaseInfo.applyNavigationBarMargin()
     }
 
     @SuppressLint("SetTextI18n")

+ 2 - 4
app/src/main/java/io/legato/kazusa/ui/book/toc/TocActivity.kt

@@ -56,12 +56,10 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>(),
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        tabLayout = binding.titleBar.findViewById(R.id.tab_layout)
-        //tabLayout.isTabIndicatorFullWidth = false
-        //tabLayout.setSelectedTabIndicatorColor(accentColor)
+        setSupportActionBar(binding.topBar)
+        tabLayout = binding.tabLayout
         binding.viewPager.adapter = TabFragmentPageAdapter()
         tabLayout.setupWithViewPager(binding.viewPager)
-        tabLayout.tabGravity = TabLayout.GRAVITY_CENTER
         viewModel.bookData.observe(this) {
             menu?.setGroupVisible(R.id.menu_group_text, it.isLocalTxt)
         }

+ 50 - 1
app/src/main/java/io/legato/kazusa/ui/config/OtherConfigFragment.kt

@@ -1,11 +1,16 @@
 package io.legato.kazusa.ui.config
 
+//import io.legado.app.lib.theme.primaryColor
 import android.annotation.SuppressLint
 import android.content.ComponentName
+import android.content.Context
 import android.content.SharedPreferences
 import android.content.pm.PackageManager
+import android.os.Build
 import android.os.Bundle
+import android.os.PowerManager
 import android.view.View
+import androidx.core.content.ContextCompat
 import androidx.core.view.postDelayed
 import androidx.fragment.app.activityViewModels
 import androidx.preference.ListPreference
@@ -19,8 +24,9 @@ import io.legato.kazusa.help.AppFreezeMonitor
 import io.legato.kazusa.help.config.AppConfig
 import io.legato.kazusa.help.config.LocalConfig
 import io.legato.kazusa.lib.dialogs.alert
+import io.legato.kazusa.lib.permission.Permissions
+import io.legato.kazusa.lib.permission.PermissionsCompat
 import io.legato.kazusa.lib.prefs.fragment.PreferenceFragment
-//import io.legado.app.lib.theme.primaryColor
 import io.legato.kazusa.model.CheckSource
 import io.legato.kazusa.model.ImageProvider
 import io.legato.kazusa.receiver.SharedReceiverActivity
@@ -70,6 +76,7 @@ class OtherConfigFragment : PreferenceFragment(),
         upPreferenceSummary(PreferKey.bitmapCacheSize, AppConfig.bitmapCacheSize.toString())
         upPreferenceSummary(PreferKey.imageRetainNum, AppConfig.imageRetainNum.toString())
         upPreferenceSummary(PreferKey.sourceEditMaxLine, AppConfig.sourceEditMaxLine.toString())
+        updatePermissionSummary()
     }
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -156,6 +163,9 @@ class OtherConfigFragment : PreferenceFragment(),
             PreferKey.clearWebViewData -> clearWebViewData()
             "localPassword" -> alertLocalPassword()
             PreferKey.shrinkDatabase -> shrinkDatabase()
+
+            PreferKey.notificationsPost -> checkPermission(1)
+            PreferKey.ignoreBatteryPermission -> checkPermission(2)
         }
         return super.onPreferenceTreeClick(preference)
     }
@@ -228,6 +238,30 @@ class OtherConfigFragment : PreferenceFragment(),
 
         }
     }
+    private fun updatePermissionSummary() {
+        val notificationsGranted: Boolean =
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                ContextCompat.checkSelfPermission(
+                    requireContext(), android.Manifest.permission.POST_NOTIFICATIONS
+                ) == PackageManager.PERMISSION_GRANTED
+            } else {
+                true
+            }
+        upPreferenceSummary(
+            PreferKey.notificationsPost,
+            if (notificationsGranted) "已获取" else "未获取"
+        )
+
+        val pm = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
+        val batteryGranted: Boolean =
+            pm.isIgnoringBatteryOptimizations(requireContext().packageName)
+
+        upPreferenceSummary(
+            PreferKey.ignoreBatteryPermission,
+            if (batteryGranted) "已获取" else "未获取"
+        )
+    }
+
 
     private fun upPreferenceSummary(preferenceKey: String, value: String?) {
         val preference = findPreference<Preference>(preferenceKey) ?: return
@@ -255,6 +289,21 @@ class OtherConfigFragment : PreferenceFragment(),
         }
     }
 
+    private fun checkPermission(int: Int) {
+        if (int == 1) {
+            PermissionsCompat.Builder()
+                .addPermissions(Permissions.POST_NOTIFICATIONS)
+                .rationale(R.string.notification_permission_rationale)
+                .request()
+        }
+        if (int == 2 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            PermissionsCompat.Builder()
+                .addPermissions(Permissions.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
+                .rationale(R.string.ignore_battery_permission_rationale)
+                .request()
+        }
+    }
+
     @SuppressLint("InflateParams")
     private fun showUserAgentDialog() {
         alert(getString(R.string.user_agent)) {

+ 11 - 0
app/src/main/res/drawable/ic_locate.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportWidth="960"
+    android:viewportHeight="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M480,480Q513,480 536.5,456.5Q560,433 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,433 423.5,456.5Q447,480 480,480ZM480,774Q602,662 661,570.5Q720,479 720,408Q720,299 650.5,229.5Q581,160 480,160Q379,160 309.5,229.5Q240,299 240,408Q240,479 299,570.5Q358,662 480,774ZM480,880Q319,743 239.5,625.5Q160,508 160,408Q160,258 256.5,169Q353,80 480,80Q607,80 703.5,169Q800,258 800,408Q800,508 720.5,625.5Q641,743 480,880ZM480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Z" />
+</vector>

+ 33 - 11
app/src/main/res/layout/activity_chapter_list.xml

@@ -1,22 +1,44 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:layout_height="match_parent">
 
-    <io.legato.kazusa.ui.widget.TitleBar
-        android:id="@+id/title_bar"
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/app_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        app:contentInsetStartWithNavigation="0dp"
-        app:contentLayout="@layout/view_tab_layout" />
+        android:fitsSystemWindows="true"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
 
+        <com.google.android.material.appbar.MaterialToolbar
+            android:id="@+id/top_bar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            app:layout_collapseMode="pin"
+            app:navigationIcon="@drawable/ic_arrow_back"
+            app:title="@string/chapter_list" />
+
+        <com.google.android.material.tabs.TabLayout
+            android:id="@+id/tab_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="16dp"
+            android:background="?attr/colorSurface"
+            app:tabGravity="fill"
+            app:tabMode="fixed" />
+
+    </com.google.android.material.appbar.AppBarLayout>
+
+    <!-- ViewPager 作为滚动内容 -->
     <androidx.viewpager.widget.ViewPager
         android:id="@+id/view_pager"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        tools:ignore="SpeakableTextPresentCheck" />
+        android:layout_height="0dp"
+        app:layout_behavior="@string/appbar_scrolling_view_behavior"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/app_bar" />
 
-</LinearLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 59 - 37
app/src/main/res/layout/fragment_chapter_list.xml

@@ -11,48 +11,70 @@
         android:layout_height="0dp"
         android:overScrollMode="never"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toTopOf="@+id/ll_chapter_base_info" />
+        app:layout_constraintBottom_toBottomOf="parent" />
 
-    <LinearLayout
-        android:id="@+id/ll_chapter_base_info"
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/cd_base"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingHorizontal="16dp"
-        android:gravity="center_vertical"
-        android:orientation="horizontal"
+        android:layout_marginHorizontal="16dp"
+        app:cardBackgroundColor="?attr/colorSurfaceContainer"
+        app:cardElevation="8dp"
+        app:strokeWidth="0dp"
         app:layout_constraintBottom_toBottomOf="parent">
 
-        <TextView
-            android:id="@+id/tv_current_chapter_info"
-            android:layout_width="0dp"
+        <LinearLayout
+            android:id="@+id/ll_chapter_base_info"
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:background="?attr/selectableItemBackground"
-            android:ellipsize="middle"
-            android:singleLine="true"
-            android:gravity="center_vertical"
-            android:textSize="12sp" />
-
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/btn_chapter_top"
-            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
-            android:layout_width="36dp"
-            android:layout_height="36dp"
-            app:icon="@drawable/ic_arrow_drop_up"
-            android:contentDescription="@string/go_to_top"
-            app:iconGravity="textStart"
-            app:iconPadding="0dp" />
-
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/btn_chapter_bottom"
-            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
-            android:layout_width="36dp"
-            android:layout_height="36dp"
-            app:icon="@drawable/ic_arrow_drop_down"
-            android:contentDescription="@string/go_to_bottom"
-            app:iconGravity="textStart"
-            app:iconPadding="0dp" />
-
-    </LinearLayout>
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:paddingVertical="8dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="10dp">
+
+            <TextView
+                android:id="@+id/tv_current_chapter_info"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center_vertical"
+                android:singleLine="true"
+                android:textSize="12sp"
+                android:textStyle="bold" />
+
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/btn_locate"
+                style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
+                android:layout_width="40dp"
+                android:layout_height="40dp"
+                android:contentDescription="@string/locate_current"
+                app:icon="@drawable/ic_locate"
+                app:iconGravity="textStart"
+                app:iconPadding="0dp"
+                app:iconSize="16dp" />
+
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/btn_chapter_top"
+                style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+                android:layout_width="40dp"
+                android:layout_height="40dp"
+                android:contentDescription="@string/go_to_top"
+                app:icon="@drawable/ic_arrow_drop_up"
+                app:iconGravity="textStart"
+                app:iconPadding="0dp" />
+
+            <com.google.android.material.button.MaterialButton
+                android:id="@+id/btn_chapter_bottom"
+                style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+                android:layout_width="40dp"
+                android:layout_height="40dp"
+                android:contentDescription="@string/go_to_bottom"
+                app:icon="@drawable/ic_arrow_drop_down"
+                app:iconGravity="textStart"
+                app:iconPadding="0dp" />
+
+        </LinearLayout>
+    </com.google.android.material.card.MaterialCardView>
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 0
app/src/main/res/layout/item_bookshelf_grid.xml

@@ -9,6 +9,7 @@
         android:id="@+id/cv_content"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        app:cardBackgroundColor="@android:color/transparent"
         android:layout_marginBottom="4dp"
         android:clickable="true"
         android:focusable="true"

+ 13 - 21
app/src/main/res/layout/item_chapter_list.xml

@@ -18,7 +18,7 @@
         android:src="@drawable/ic_lock_outline"
         android:visibility="gone"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         tools:ignore="RtlSymmetry" />
 
@@ -26,33 +26,25 @@
         android:id="@+id/tv_chapter_name"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:textSize="15sp"
+        android:textSize="14sp"
         android:textStyle="bold"
         android:maxLines="2"
-        app:layout_constraintBottom_toTopOf="@id/barrier"
-        app:layout_constraintLeft_toRightOf="@+id/iv_locked"
-        app:layout_constraintRight_toLeftOf="@+id/iv_checked"
+        app:layout_constraintEnd_toStartOf="@+id/iv_checked"
+        app:layout_constraintStart_toEndOf="@+id/iv_locked"
         app:layout_constraintTop_toTopOf="parent" />
 
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/barrier"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierDirection="top"
-        app:constraint_referenced_ids="tv_word_count,tv_tag" />
-
     <TextView
         android:id="@+id/tv_word_count"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_marginTop="4dp"
         android:paddingEnd="18dp"
         android:singleLine="true"
         android:textSize="12sp"
         android:visibility="gone"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@+id/iv_locked"
-        app:layout_constraintTop_toBottomOf="@+id/barrier"
+        app:layout_constraintEnd_toStartOf="@+id/iv_checked"
+        app:layout_constraintStart_toEndOf="@+id/iv_locked"
+        app:layout_constraintTop_toBottomOf="@id/tv_chapter_name"
         tools:ignore="RtlSymmetry" />
 
     <TextView
@@ -63,21 +55,21 @@
         android:singleLine="true"
         android:textSize="12sp"
         android:visibility="gone"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintLeft_toRightOf="@id/tv_word_count"
-        app:layout_constraintRight_toLeftOf="@+id/iv_checked"
-        app:layout_constraintTop_toBottomOf="@+id/barrier" />
+        app:layout_constraintEnd_toStartOf="@+id/iv_checked"
+        app:layout_constraintStart_toEndOf="@+id/iv_locked"
+        app:layout_constraintTop_toBottomOf="@id/tv_word_count" />
 
     <ImageView
         android:id="@+id/iv_checked"
         android:layout_width="24dp"
         android:layout_height="24dp"
         android:contentDescription="@string/success"
+        app:layout_constraintEnd_toEndOf="parent"
         android:padding="4dp"
         android:src="@drawable/ic_check"
         android:visibility="invisible"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
+        app:tint="?attr/colorSecondary"
         app:layout_constraintTop_toTopOf="parent" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 1 - 0
app/src/main/res/values-zh/strings.xml

@@ -1237,5 +1237,6 @@
     <string name="checking_update">检查更新中...</string>
     <string name="search_empty">没有内容哦</string>
     <string name="firebase_enable_title">匿名统计</string>
+    <string name="locate_current">定位至当前</string>
 
 </resources>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -1241,5 +1241,6 @@
     <string name="search_empty">没有内容哦</string>
     <string name="firebase_enable_title">匿名统计</string>
     <string name="firebase_enable_summary">允许应用使用Google Firebase进行崩溃和性能统计</string>
+    <string name="locate_current">定位至当前</string>
 
 </resources>

+ 12 - 0
app/src/main/res/xml/pref_config_other.xml

@@ -66,6 +66,18 @@
         app:iconSpaceReserved="false"
         app:layout="@layout/view_preference_category">
 
+        <io.legato.kazusa.lib.prefs.Preference
+            android:defaultValue="true"
+            android:key="notificationsPost"
+            android:summary="@string/notification_permission_rationale"
+            android:title="通知权限" />
+
+        <io.legato.kazusa.lib.prefs.Preference
+            android:defaultValue="true"
+            android:key="ignoreBatteryPermission"
+            android:summary="@string/ignore_battery_permission_rationale"
+            android:title="后台权限" />
+
         <io.legato.kazusa.lib.prefs.SwitchPreference
             android:defaultValue="true"
             android:key="firebaseEnable"

+ 1 - 1
gradle/libs.versions.toml

@@ -3,7 +3,7 @@
 datastorePreferences = "1.1.7"
 kotlin = "2.1.21"
 ksp = "2.1.21-2.0.1"
-agp = "8.10.1"
+agp = "8.12.0"
 appcompat = "1.7.1"
 colorpicker = "1.1.0"
 commonsText = "1.13.1"

+ 1 - 1
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
 #Tue Aug 27 18:19:17 CST 2024
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists