更新界面

This commit is contained in:
HapeLee
2025-08-18 14:19:54 +08:00
parent 8159187dc8
commit a0b739a66b
17 changed files with 312 additions and 89 deletions
@@ -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
@@ -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"
}
@@ -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)
@@ -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?
@@ -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")
@@ -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)
}
@@ -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)) {