添加护眼模式

优化全屏阅读文档展示
This commit is contained in:
ocean 2025-09-12 17:59:07 +08:00
parent 56ce37d303
commit 5f1990f830
10 changed files with 220 additions and 75 deletions

View File

@ -20,9 +20,14 @@ class AppStore(context: Context) {
key = DOCUMENT_SORT_TYPE, defaultValue = SortConfig.default().toPreferenceString()
)
var isEyeCareMode: Boolean by store.boolean(
key = IS_EYE_CARE_MODE, defaultValue = false
)
companion object {
private const val FILE_NAME = "prp_sp_name"
private const val PERMISSIONS_DIALOG_PROMPT = "permissions_dialog_prompt"
private const val DOCUMENT_SORT_TYPE = "document_sort_type"
private const val IS_EYE_CARE_MODE = "is_eye_care_mode"
}
}

View File

@ -52,7 +52,7 @@ class MainActivity : BaseActivity(), PermissionDialogFragment.PermissionCallback
setContentView(binding.root)
initObserve()
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
.navigationBarColor(R.color.black).init()
.navigationBarColor(R.color.white).init()
setupFragments()
setupNavigation()

View File

@ -3,11 +3,12 @@ package com.all.pdfreader.pro.app.ui.act
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.all.pdfreader.pro.app.R
import com.all.pdfreader.pro.app.databinding.ActivityPdfViewBinding
import com.all.pdfreader.pro.app.model.FileActionEvent
import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity
import com.all.pdfreader.pro.app.ui.dialog.PdfPasswordProtectionDialogFragment
import com.all.pdfreader.pro.app.ui.view.CustomScrollHandle
@ -15,11 +16,14 @@ import com.all.pdfreader.pro.app.viewmodel.PdfViewModel
import com.github.barteksc.pdfviewer.listener.OnErrorListener
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener
import com.github.barteksc.pdfviewer.listener.OnTapListener
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import kotlinx.coroutines.launch
import java.io.File
class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeListener,
OnErrorListener {
OnErrorListener, OnTapListener {
override val TAG: String = "PdfViewActivity"
companion object {
@ -37,10 +41,14 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
private lateinit var pdfDocument: PdfDocumentEntity
private val viewModel by lazy { ViewModelProvider(this)[PdfViewModel::class.java] }
private val repository = getRepository()
private var isFullScreen = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPdfViewBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
.navigationBarColor(R.color.white).init()
initObserve()
val filePath = intent.getStringExtra(EXTRA_PDF_HASH)
?: throw IllegalArgumentException("PDF file hash is required")
@ -48,12 +56,14 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
viewModel.getPDFDocument(filePath)
}
private fun initObserve(){
private fun initObserve() {
// 观察PDF文档数据
viewModel.pdfDocument.observe(this) { document ->
document?.let {
pdfDocument = it
loadPdf()
setupOnClick()
toggleEyeCareMode(appStore.isEyeCareMode)
} ?: run {
showToast(getString(R.string.file_not))
finish()
@ -61,6 +71,16 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
}
}
private fun setupOnClick() {
binding.backBtn.setOnClickListener {
finish()
}
binding.eyeCareOverlayBtn.setOnClickListener {
appStore.isEyeCareMode = !appStore.isEyeCareMode
toggleEyeCareMode(appStore.isEyeCareMode)
}
}
private fun loadPdf() {
logDebug("loadPdf ->${pdfDocument.lastReadPage} ${pdfDocument.readingProgress}")
// 使用传递的文件路径加载PDF
@ -72,14 +92,14 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
return
}
// 无密码PDF正常加载
binding.pdfview.fromFile(file)
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
binding.pdfview.fromFile(file).defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
.enableDoubletap(true)// 是否允许双击缩放
.onLoad(this)
.onLoad(this)//加载
.enableAnnotationRendering(true) // 是否渲染注释(如评论、颜色、表单等)
.onError(this)
.onPageChange(this)
.scrollHandle(CustomScrollHandle(this))
.onError(this)//错误
.onTap(this)//点击
.onPageChange(this)//页面改变
.scrollHandle(CustomScrollHandle(this))//自定义的页数展示,并且可快速拖动
.load()
} else {
showToast(getString(R.string.file_not) + ": ${pdfDocument.fileName}")
@ -109,6 +129,11 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
}
}
override fun onTap(e: MotionEvent?): Boolean {
toggleFullScreen()
return true// 表示我们自己处理了单击事件
}
//页面切换时回调
override fun onPageChanged(page: Int, pageCount: Int) {
// 保存阅读进度到内存
@ -139,15 +164,55 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList
}
private fun tryLoadPdfWithPassword(file: File, password: String) {
binding.pdfview.fromFile(file)
.password(password) // 使用输入的密码
binding.pdfview.fromFile(file).password(password) // 使用输入的密码
.defaultPage(pdfDocument.lastReadPage) // 从上次阅读页码开始
.enableDoubletap(true)// 是否允许双击缩放
.onLoad(this)
.onLoad(this)//加载
.onTap(this)//单击
.enableAnnotationRendering(true) // 是否渲染注释(如评论、颜色、表单等)
.onError(this)
.onPageChange(this)
.scrollHandle(CustomScrollHandle(this))
.onError(this)//错误
.onPageChange(this)//页面改变
.scrollHandle(CustomScrollHandle(this))//自定义的页数展示,并且可快速拖动
.load()
}
private fun toggleFullScreen() {
isFullScreen = !isFullScreen
updateStatusAndNavigationLayout(isFullScreen)
if (isFullScreen) {
ImmersionBar.with(this).hideBar(BarHide.FLAG_HIDE_BAR).init()
} else {
val navColor =
if (appStore.isEyeCareMode) R.color.eye_protection_color else R.color.white
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
.navigationBarColor(navColor).hideBar(BarHide.FLAG_SHOW_BAR).init()
}
}
private fun updateStatusAndNavigationLayout(b: Boolean) {
if (b) {
// 隐藏顶部和底部
binding.statusLayout.visibility = View.GONE
binding.navigationLayout.visibility = View.GONE
binding.view.visibility = View.GONE
} else {
// 显示顶部和底部
binding.statusLayout.visibility = View.VISIBLE
binding.navigationLayout.visibility = View.VISIBLE
binding.view.visibility = View.VISIBLE
}
}
private fun toggleEyeCareMode(b: Boolean) {
val navColor = if (b) R.color.eye_protection_color else R.color.white
if (b) {
binding.eyeCareOverlay.visibility = View.VISIBLE
binding.eyeProtectIv.setImageResource(R.drawable.eye_protect_active)
} else {
binding.eyeCareOverlay.visibility = View.GONE
binding.eyeProtectIv.setImageResource(R.drawable.eye_protect)
}
ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true)
.navigationBarColor(navColor).init()
}
}

View File

@ -3,6 +3,7 @@ package com.all.pdfreader.pro.app.ui.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.TypedValue;
@ -17,6 +18,7 @@ import com.github.barteksc.pdfviewer.scroll.ScrollHandle;
import com.github.barteksc.pdfviewer.util.Util;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
public class CustomScrollHandle extends RelativeLayout implements ScrollHandle {
private final static int HANDLE_LONG = 36;
@ -203,6 +205,13 @@ public class CustomScrollHandle extends RelativeLayout implements ScrollHandle {
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
}
/**
* @param tf 自定义font字体
*/
public void setTypeface(Typeface tf){
textView.setTypeface(tf);
}
private boolean isPDFViewReady() {
return pdfView != null && pdfView.getPageCount() > 0 && !pdfView.documentFitsView();
}

View File

@ -3,10 +3,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:color="#6C7A89"
android:color="@color/line_color"
android:width="1dp" />
<corners
android:topLeftRadius="16dp"
android:topRightRadius="16dp" />
<solid android:color="#DADFE1" />
<solid android:color="@color/white" />
</shape>

View File

@ -3,10 +3,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:color="#6C7A89"
android:color="@color/line_color"
android:width="1dp" />
<corners
android:bottomLeftRadius="16dp"
android:topLeftRadius="16dp" />
<solid android:color="#DADFE1" />
<solid android:color="@color/white" />
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="25.0dip" android:width="25.0dip" android:viewportWidth="24.0" android:viewportHeight="25.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#00000000" android:pathData="M3.047,12.953C2.984,12.781 2.984,12.595 3.047,12.423C4.293,8.968 7.831,6.476 12,6.476C16.168,6.476 19.704,8.966 20.953,12.419C21.016,12.591 21.016,12.776 20.953,12.948C19.707,16.404 16.17,18.896 12,18.896C7.832,18.896 4.296,16.406 3.047,12.953Z" android:strokeColor="#ff636366" android:strokeWidth="1.8" android:strokeLineCap="round" android:strokeLineJoin="round" />
<path android:fillColor="#00000000" android:pathData="M14.696,12.686C14.696,13.401 14.412,14.087 13.907,14.592C13.401,15.098 12.715,15.382 12,15.382C11.285,15.382 10.6,15.098 10.094,14.592C9.589,14.087 9.305,13.401 9.305,12.686C9.305,11.971 9.589,11.285 10.094,10.78C10.6,10.274 11.285,9.99 12,9.99C12.715,9.99 13.401,10.274 13.907,10.78C14.412,11.285 14.696,11.971 14.696,12.686Z" android:strokeColor="#ff636366" android:strokeWidth="1.8" android:strokeLineCap="round" android:strokeLineJoin="round" />
</vector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="24.0dip" android:width="24.0dip" android:viewportWidth="24.0" android:viewportHeight="24.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ff1c1c1c" android:pathData="M2.2,11.432C3.584,7.595 7.478,4.89 12,4.89C16.52,4.89 20.412,7.593 21.799,11.427C21.934,11.798 21.933,12.2 21.799,12.569C20.415,16.406 16.521,19.11 12,19.11C7.48,19.11 3.587,16.407 2.2,12.573L2.2,12.572C2.066,12.203 2.066,11.801 2.2,11.432L2.2,11.432ZM9.74,9.74C10.339,9.141 11.152,8.804 12,8.804C12.847,8.804 13.66,9.141 14.259,9.74C14.859,10.34 15.196,11.152 15.196,12C15.196,12.848 14.859,13.66 14.259,14.26C13.66,14.859 12.847,15.196 12,15.196C11.152,15.196 10.339,14.859 9.74,14.26C9.141,13.66 8.804,12.848 8.804,12C8.804,11.152 9.141,10.34 9.74,9.74Z" android:fillType="evenOdd" />
</vector>

View File

@ -1,77 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/statusLayout"
android:id="@+id/bgLayout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal">
android:layout_height="match_parent"
android:background="@color/bg_color"
android:orientation="vertical">
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="0dp" />
<LinearLayout
android:id="@+id/backBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center">
android:id="@+id/statusLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/back_black" />
<LinearLayout
android:id="@+id/backBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/back_black" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/bg_color">
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfview"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/white">
</LinearLayout>
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/navigationLayout"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal">
</LinearLayout>
<LinearLayout
android:id="@+id/lockBtn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:id="@+id/navigationLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical">
<ImageView
android:id="@+id/lockIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/ic_launcher" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/line_color" />
<TextView
android:id="@+id/lockTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_regular"
android:text="@string/home"
android:textColor="@color/black"
android:textSize="14sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/eyeCareOverlayBtn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal|bottom"
android:orientation="vertical">
<ImageView
android:id="@+id/eyeProtectIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/eye_protect" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="@font/poppins_regular"
android:text="@string/eye_protect"
android:textColor="@color/black"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal|bottom"
android:orientation="vertical">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="@font/poppins_regular"
android:text="@string/home"
android:textColor="@color/black"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 护眼模式覆盖层 -->
<View
android:id="@+id/eyeCareOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/eye_protection_color"
android:visibility="gone" />
</FrameLayout>

View File

@ -14,4 +14,5 @@
<color name="line_color">#E0E0E0</color>
<color name="black_img_color">#2c2c2c</color>
<color name="grey_text_color">#666666</color>
<color name="eye_protection_color">#80FFD699</color>
</resources>