From 32374b0961142a0593cbb40de119342a2d34025f Mon Sep 17 00:00:00 2001 From: ocean <503259349@qq.com> Date: Wed, 10 Sep 2025 18:58:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BF=AE=E6=94=B9=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=90=8D=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + .../pro/app/model/FileActionEvent.kt | 5 +++ .../pdfreader/pro/app/model/RenameResult.kt | 11 +++++ .../pro/app/room/dao/PdfDocumentDao.kt | 4 ++ .../pro/app/room/repository/PdfRepository.kt | 27 +++++++----- .../pdfreader/pro/app/ui/act/MainActivity.kt | 21 ++++++++++ .../pro/app/ui/act/PdfViewActivity.kt | 23 +++++++++-- .../app/ui/dialog/ListMoreDialogFragment.kt | 3 +- .../pro/app/ui/dialog/RenameDialogFragment.kt | 18 +++----- .../all/pdfreader/pro/app/util/FileUtils.kt | 14 +------ .../pro/app/viewmodel/PdfViewModel.kt | 41 ++++++++++++++++++- gradle/libs.versions.toml | 2 + 12 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 app/src/main/java/com/all/pdfreader/pro/app/model/FileActionEvent.kt create mode 100644 app/src/main/java/com/all/pdfreader/pro/app/model/RenameResult.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 87abfa4..0549fdd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -42,6 +42,7 @@ android { } dependencies { + implementation(libs.androidx.fragment.ktx) implementation(libs.androidx.appcompat) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) diff --git a/app/src/main/java/com/all/pdfreader/pro/app/model/FileActionEvent.kt b/app/src/main/java/com/all/pdfreader/pro/app/model/FileActionEvent.kt new file mode 100644 index 0000000..c20334e --- /dev/null +++ b/app/src/main/java/com/all/pdfreader/pro/app/model/FileActionEvent.kt @@ -0,0 +1,5 @@ +package com.all.pdfreader.pro.app.model + +sealed class FileActionEvent { + data class Rename(val renameResult: RenameResult) : FileActionEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/all/pdfreader/pro/app/model/RenameResult.kt b/app/src/main/java/com/all/pdfreader/pro/app/model/RenameResult.kt new file mode 100644 index 0000000..6e3ebd9 --- /dev/null +++ b/app/src/main/java/com/all/pdfreader/pro/app/model/RenameResult.kt @@ -0,0 +1,11 @@ +package com.all.pdfreader.pro.app.model + +data class RenameResult( + val success: Boolean, + val errorMessage: String? = null +) { + companion object { + fun success() = RenameResult(true) + fun failure(message: String) = RenameResult(false, message) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/all/pdfreader/pro/app/room/dao/PdfDocumentDao.kt b/app/src/main/java/com/all/pdfreader/pro/app/room/dao/PdfDocumentDao.kt index 0a72945..bbb3a3f 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/room/dao/PdfDocumentDao.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/room/dao/PdfDocumentDao.kt @@ -36,4 +36,8 @@ interface PdfDocumentDao { @Query("DELETE FROM pdf_documents WHERE filePath = :filePath") suspend fun deleteByPath(filePath: String) + + @Query("UPDATE pdf_documents SET filePath = :newFilePath, fileName = :newName WHERE filePath = :oldFilePath") + suspend fun updateFilePathAndFileName(oldFilePath: String, newFilePath: String, newName: String) + } \ No newline at end of file diff --git a/app/src/main/java/com/all/pdfreader/pro/app/room/repository/PdfRepository.kt b/app/src/main/java/com/all/pdfreader/pro/app/room/repository/PdfRepository.kt index 461af88..2135e3c 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/room/repository/PdfRepository.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/room/repository/PdfRepository.kt @@ -11,9 +11,7 @@ import java.security.MessageDigest class PdfRepository private constructor(context: Context) { private val database = Room.databaseBuilder( - context, - PdfDatabase::class.java, - PdfDatabase.DATABASE_NAME + context, PdfDatabase::class.java, PdfDatabase.DATABASE_NAME ).build() private val pdfDao = database.pdfDocumentDao() @@ -41,6 +39,17 @@ class PdfRepository private constructor(context: Context) { fun searchDocuments(query: String): Flow> = pdfDao.searchDocuments(query) + suspend fun updateFilePathAndFileName(oldFilePath: String, newFilePath: String, newName: String) { + pdfDao.updateFilePathAndFileName(oldFilePath, newFilePath, newName) + } + +// suspend fun updateFilePathAndFileName(filePath: String, newFilePath: String, newName: String) { +// val document = pdfDao.getByPath(filePath)?.copy( +// filePath = newFilePath, fileName = newName +// ) +// document?.let { pdfDao.update(it) } +// } + suspend fun updateFavoriteStatus(filePath: String, isFavorite: Boolean) { val document = pdfDao.getByPath(filePath)?.copy( isFavorite = isFavorite, @@ -79,7 +88,6 @@ class PdfRepository private constructor(context: Context) { document?.let { pdfDao.update(it) } } - // 最近阅读相关操作 suspend fun addToRecent(filePath: String, page: Int = 0) { val existing = recentDao.getByPdfHash(filePath) @@ -88,8 +96,7 @@ class PdfRepository private constructor(context: Context) { } else { recentDao.insertOrUpdate( RecentReadEntity( - filePath = filePath, - lastOpenedTime = System.currentTimeMillis() + filePath = filePath, lastOpenedTime = System.currentTimeMillis() ) ) } @@ -120,12 +127,10 @@ class PdfRepository private constructor(context: Context) { // 组合查询 suspend fun getPdfWithDetails(pdfHash: String): Flow { - return combine( - pdfDao.getByHash(pdfHash)?.let { kotlinx.coroutines.flow.flowOf(it) } - ?: kotlinx.coroutines.flow.flowOf(null), + return combine(pdfDao.getByHash(pdfHash)?.let { kotlinx.coroutines.flow.flowOf(it) } + ?: kotlinx.coroutines.flow.flowOf(null), bookmarkDao.getBookmarksByPdf(pdfHash), - noteDao.getNotesByPdf(pdfHash) - ) { document, bookmarks, notes -> + noteDao.getNotesByPdf(pdfHash)) { document, bookmarks, notes -> PdfDetails(document, bookmarks, notes) } } diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/MainActivity.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/MainActivity.kt index 1c469ec..34a8ba9 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/MainActivity.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/MainActivity.kt @@ -5,10 +5,12 @@ import android.os.Bundle import android.view.View import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.all.pdfreader.pro.app.PRApp import com.all.pdfreader.pro.app.R import com.all.pdfreader.pro.app.databinding.ActivityMainBinding +import com.all.pdfreader.pro.app.model.FileActionEvent import com.all.pdfreader.pro.app.ui.dialog.PermissionDialogFragment import com.all.pdfreader.pro.app.ui.dialog.SortDialogFragment import com.all.pdfreader.pro.app.ui.fragment.FavoriteFrag @@ -18,6 +20,7 @@ import com.all.pdfreader.pro.app.ui.fragment.ToolsFrag import com.all.pdfreader.pro.app.util.AppUtils.setClickWithAnimation import com.all.pdfreader.pro.app.util.PdfScanner import com.all.pdfreader.pro.app.util.StoragePermissionHelper +import com.all.pdfreader.pro.app.viewmodel.PdfViewModel import com.gyf.immersionbar.ImmersionBar import kotlinx.coroutines.launch @@ -38,10 +41,13 @@ class MainActivity : BaseActivity(), PermissionDialogFragment.PermissionCallback private var activeFragment: Fragment = homeFragment private val fragmentTag = "ACTIVE_FRAGMENT" + private val viewModel by lazy { ViewModelProvider(this)[PdfViewModel::class.java] } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + initObserve() ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true) .navigationBarColor(R.color.black).init() @@ -60,6 +66,21 @@ class MainActivity : BaseActivity(), PermissionDialogFragment.PermissionCallback updateSelectedNav(activeFragment) } + private fun initObserve(){ + //观察其余操作 + viewModel.fileActionEvent.observe(this) { event -> + when (event) { + is FileActionEvent.Rename -> { + if (event.renameResult.success) { + showToast(getString(R.string.rename_successfully)) + } else { + showToast(event.renameResult.errorMessage.toString()) + } + } + } + } + } + private fun setupFragments() { supportFragmentManager.beginTransaction().add(R.id.fragment_fl, toolsFragment, "TOOLS") .hide(toolsFragment).add(R.id.fragment_fl, favoriteFragment, "FAVORITE") diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/PdfViewActivity.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/PdfViewActivity.kt index da46b26..390d446 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/PdfViewActivity.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/PdfViewActivity.kt @@ -7,6 +7,7 @@ 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 @@ -40,10 +41,14 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList super.onCreate(savedInstanceState) binding = ActivityPdfViewBinding.inflate(layoutInflater) setContentView(binding.root) - + initObserve() val filePath = intent.getStringExtra(EXTRA_PDF_HASH) ?: throw IllegalArgumentException("PDF file hash is required") + // 加载PDF数据 + viewModel.getPDFDocument(filePath) + } + private fun initObserve(){ // 观察PDF文档数据 viewModel.pdfDocument.observe(this) { document -> document?.let { @@ -54,9 +59,19 @@ class PdfViewActivity : BaseActivity(), OnLoadCompleteListener, OnPageChangeList finish() } } - - // 加载PDF数据 - viewModel.getPDFDocument(filePath) + //观察其余操作 + viewModel.fileActionEvent.observe(this) { event -> + logDebug("fileActionEvent响应 $event") + when (event) { + is FileActionEvent.Rename -> { + if (event.renameResult.success) { + showToast(getString(R.string.rename_successfully)) + } else { + showToast(event.renameResult.errorMessage.toString()) + } + } + } + } } private fun loadPdf() { diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/ListMoreDialogFragment.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/ListMoreDialogFragment.kt index 740e43a..0c3482f 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/ListMoreDialogFragment.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/ListMoreDialogFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.fragment.app.activityViewModels import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.all.pdfreader.pro.app.R @@ -28,7 +29,7 @@ class ListMoreDialogFragment(val filePath: String) : BottomSheetDialogFragment() private lateinit var binding: DialogListMoreBinding private val pdfRepository = PdfRepository.getInstance() - private val viewModel by lazy { ViewModelProvider(this)[PdfViewModel::class.java] } + private val viewModel: PdfViewModel by activityViewModels() private lateinit var pdfDocument: PdfDocumentEntity private var isFavorite: Boolean = false diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/RenameDialogFragment.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/RenameDialogFragment.kt index eb71356..d44ea75 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/RenameDialogFragment.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/dialog/RenameDialogFragment.kt @@ -3,7 +3,6 @@ package com.all.pdfreader.pro.app.ui.dialog import android.graphics.Color import android.os.Bundle import android.text.Editable -import android.text.InputType import android.text.TextWatcher import android.view.LayoutInflater import android.view.View @@ -11,23 +10,21 @@ import android.view.ViewGroup import android.widget.Toast import androidx.core.graphics.drawable.toDrawable import androidx.fragment.app.DialogFragment -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.activityViewModels import com.all.pdfreader.pro.app.R -import com.all.pdfreader.pro.app.databinding.DialogPdfPasswordProtectionBinding import com.all.pdfreader.pro.app.databinding.DialogRenameFileBinding import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard import com.all.pdfreader.pro.app.util.FileUtils -import com.all.pdfreader.pro.app.util.FileUtils.isPdfPasswordCorrect import com.all.pdfreader.pro.app.viewmodel.PdfViewModel import java.io.File class RenameDialogFragment( - private val filePath: String, + private val filePath: String ) : DialogFragment() { private lateinit var binding: DialogRenameFileBinding - private val viewModel by lazy { ViewModelProvider(this)[PdfViewModel::class.java] } + private val viewModel: PdfViewModel by activityViewModels() private lateinit var pdfDocument: PdfDocumentEntity override fun onCreateView( @@ -81,13 +78,7 @@ class RenameDialogFragment( binding.tvConfirm.setOnClickListener { val text = binding.etName.text.toString() if (validateEnter(text)) { - val renameResult = - FileUtils.renameFile(File(pdfDocument.filePath), text) - if (renameResult.success) { - showToast(getString(R.string.rename_successfully)) - } else { - showToast(renameResult.errorMessage.toString()) - } + viewModel.renamePdf(pdfDocument.filePath, text) dismiss() } } @@ -96,6 +87,7 @@ class RenameDialogFragment( override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { binding.tilName.error = null } + override fun afterTextChanged(s: Editable?) {} }) } diff --git a/app/src/main/java/com/all/pdfreader/pro/app/util/FileUtils.kt b/app/src/main/java/com/all/pdfreader/pro/app/util/FileUtils.kt index f098d6e..ed42f9b 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/util/FileUtils.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/util/FileUtils.kt @@ -20,19 +20,7 @@ import java.security.MessageDigest import java.text.SimpleDateFormat import java.util.Date import java.util.Locale - -/** - * 文件重命名结果封装类 - */ -data class RenameResult( - val success: Boolean, - val errorMessage: String? = null -) { - companion object { - fun success() = RenameResult(true) - fun failure(message: String) = RenameResult(false, message) - } -} +import com.all.pdfreader.pro.app.model.RenameResult object FileUtils { diff --git a/app/src/main/java/com/all/pdfreader/pro/app/viewmodel/PdfViewModel.kt b/app/src/main/java/com/all/pdfreader/pro/app/viewmodel/PdfViewModel.kt index ce5a48b..e45cc52 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/viewmodel/PdfViewModel.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/viewmodel/PdfViewModel.kt @@ -5,16 +5,25 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.all.pdfreader.pro.app.model.FileActionEvent import com.all.pdfreader.pro.app.room.entity.PdfDocumentEntity import com.all.pdfreader.pro.app.room.repository.PdfRepository +import com.all.pdfreader.pro.app.util.FileUtils +import com.all.pdfreader.pro.app.util.LogUtil import kotlinx.coroutines.launch +import java.io.File class PdfViewModel : ViewModel() { private val pdfRepository = PdfRepository.getInstance() - + private val _pdfDocument = MutableLiveData() val pdfDocument: LiveData = _pdfDocument - + + // 用于操作结果或通知UI + private val _fileActionEvent = MutableLiveData() + val fileActionEvent: LiveData = _fileActionEvent + + fun getPDFDocument(filePath: String) { viewModelScope.launch { val document = pdfRepository.getDocumentByPath(filePath) @@ -22,4 +31,32 @@ class PdfViewModel : ViewModel() { _pdfDocument.postValue(document) } } + + //触发修改文件名操作 + fun renamePdf(filePath: String, newName: String) { + viewModelScope.launch { + val oldFile = File(filePath) + val renameResult = FileUtils.renameFile(oldFile, newName) + Log.d("ocean", "renamePdf->oldFile: $oldFile, newName=$newName, renameResult=$renameResult") + if (renameResult.success) {//修改成功更新数据库 + val finalName = if (newName.contains('.')) { + // 用户提供了后缀,使用用户的 + newName + } else { + // 用户没有提供后缀,自动添加原文件后缀 + val originalExtension = File(filePath).extension + if (originalExtension.isNotEmpty()) { + "$newName.$originalExtension" + } else { + newName + } + } + val parentDir = oldFile.parentFile + val newFilePath = File(parentDir, finalName).absolutePath.toString() + Log.d("ocean", "renamePdf->newFilePath: $newFilePath, finalName=$finalName") + pdfRepository.updateFilePathAndFileName(filePath, newFilePath, finalName) + } + _fileActionEvent.postValue(FileActionEvent.Rename(renameResult)) + } + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 99078f5..f45de91 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,7 @@ androidpdfviewer = "3.2.8" appcompat = "1.7.1" agp = "8.10.1" +fragmentKtx = "1.8.9" glide = "5.0.4" kotlin = "2.0.21" ksp = "2.0.21-1.0.27" @@ -23,6 +24,7 @@ material = "1.12.0" androidpdfviewer = { module = "com.github.marain87:AndroidPdfViewer", version.ref = "androidpdfviewer" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" } androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room_version" } androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room_version" } androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room_version" }