diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c89c917..3ff13d9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -62,4 +62,5 @@ dependencies { implementation(libs.androidpdfviewer) implementation(libs.pdfbox.android) implementation(libs.jp2forandroid) + implementation(libs.flexbox) } \ No newline at end of file diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/SearchActivity.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/SearchActivity.kt index 3edf93c..dda8d32 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/act/SearchActivity.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/act/SearchActivity.kt @@ -2,77 +2,93 @@ package com.all.pdfreader.pro.app.ui.act import android.content.Context import android.content.Intent +import android.content.SharedPreferences import android.os.Bundle import android.text.Editable import android.text.TextWatcher +import android.view.LayoutInflater import android.view.View -import androidx.lifecycle.Lifecycle +import android.widget.TextView +import androidx.core.content.edit import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager import com.all.pdfreader.pro.app.R -import com.all.pdfreader.pro.app.databinding.ActivitySearchPddBinding -import com.all.pdfreader.pro.app.ui.adapter.PdfAdapter +import com.all.pdfreader.pro.app.databinding.ActivitySearchPdfBinding import com.all.pdfreader.pro.app.ui.adapter.SearchPdfAdapter import com.all.pdfreader.pro.app.ui.dialog.ListMoreDialogFragment +import com.all.pdfreader.pro.app.ui.dialog.PermissionDialogFragment +import com.all.pdfreader.pro.app.ui.dialog.PromptDialogFragment import com.all.pdfreader.pro.app.util.AppUtils.showKeyboard import com.gyf.immersionbar.ImmersionBar import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import org.json.JSONArray class SearchActivity : BaseActivity() { override val TAG: String = "SearchActivity" companion object { const val FRAG_TAG = "SearchActivity" + private const val PREF_SEARCH_HISTORY = "pref_search_history" + private const val KEY_HISTORY_LIST = "key_history_list_json" + fun createIntent(context: Context): Intent { return Intent(context, SearchActivity::class.java) } } - private lateinit var binding: ActivitySearchPddBinding + private lateinit var binding: ActivitySearchPdfBinding private lateinit var adapter: SearchPdfAdapter private val pdfRepository = getRepository() private var searchJob: Job? = null + private val searchHistory: MutableList = mutableListOf() + private lateinit var sp: SharedPreferences + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivitySearchPddBinding.inflate(layoutInflater) + binding = ActivitySearchPdfBinding.inflate(layoutInflater) setContentView(binding.root) ImmersionBar.with(this).statusBarView(binding.view).statusBarDarkFont(true) .navigationBarColor(R.color.bg_color).init() + + sp = getSharedPreferences(PREF_SEARCH_HISTORY, MODE_PRIVATE) + loadHistory() + initView() setupClick() + showHistory() } private fun setupClick() { - binding.backBtn.setOnClickListener { - finish() - } + binding.backBtn.setOnClickListener { finish() } + binding.searchEdit.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { val query = s?.toString().orEmpty() - binding.deleteIv.visibility = - if (query.isEmpty()) View.GONE else View.VISIBLE - binding.searchIv.visibility = - if (query.isEmpty()) View.VISIBLE else View.GONE - // 取消之前的任务,防止重复 collect + binding.deleteIv.visibility = if (query.isEmpty()) View.GONE else View.VISIBLE + binding.searchIv.visibility = if (query.isEmpty()) View.VISIBLE else View.GONE + + if (query.isEmpty()) { + showHistory() + adapter.updateData(emptyList()) + binding.noFilesLayout.visibility = View.GONE + return + } else { + binding.historyLayout.visibility = View.GONE + } + searchJob?.cancel() searchJob = lifecycleScope.launch { - delay(150)//防止用户飞快打字 - if (query.isEmpty()) { - adapter.updateData(emptyList()) - binding.noFilesLayout.visibility = View.VISIBLE - return@launch - } + delay(150) pdfRepository.searchDocuments(query).collectLatest { list -> if (list.isNotEmpty()) { adapter.updateData(list) - adapter.highlightItems(query.trim()) // payload 高亮 + adapter.highlightItems(query.trim()) binding.noFilesLayout.visibility = View.GONE } else { adapter.updateData(emptyList()) @@ -82,6 +98,7 @@ class SearchActivity : BaseActivity() { } } }) + binding.deleteIv.setOnClickListener { binding.searchEdit.apply { setText("") @@ -89,6 +106,18 @@ class SearchActivity : BaseActivity() { setSelection(0) } } + + binding.clearHistory.setOnClickListener { + PromptDialogFragment( + getString(R.string.tip), + getString(R.string.clear_history_desc), + getString(R.string.clear), + onOkClick = { + searchHistory.clear() + saveHistoryList() // 保存空列表 + showHistory() + }).show(supportFragmentManager, "clearHistory") + } } private fun initView() { @@ -96,6 +125,8 @@ class SearchActivity : BaseActivity() { adapter = SearchPdfAdapter(onItemClick = { pdf -> val intent = PdfViewActivity.createIntent(this, pdf.filePath) startActivity(intent) + val query = binding.searchEdit.text.toString() + if (query.isNotEmpty()) saveHistory(query) }, onMoreClick = { pdf -> ListMoreDialogFragment(pdf.filePath).show(supportFragmentManager, FRAG_TAG) }) @@ -103,4 +134,51 @@ class SearchActivity : BaseActivity() { binding.recyclerView.layoutManager = LinearLayoutManager(this) binding.recyclerView.adapter = adapter } -} \ No newline at end of file + + /** 搜索历史逻辑 **/ + private fun loadHistory() { + val json = sp.getString(KEY_HISTORY_LIST, "[]") + val array = JSONArray(json) + searchHistory.clear() + for (i in 0 until array.length()) { + searchHistory.add(array.getString(i)) + } + } + + private fun saveHistory(query: String) { + if (searchHistory.contains(query)) searchHistory.remove(query) + searchHistory.add(0, query) + if (searchHistory.size > 20) searchHistory.removeAt(searchHistory.size - 1) + saveHistoryList() + } + + private fun saveHistoryList() { + val json = JSONArray(searchHistory).toString() + sp.edit { putString(KEY_HISTORY_LIST, json) } + } + + private fun showHistory() { + binding.historyFlexLayout.removeAllViews() + if (searchHistory.isEmpty()) { + binding.historyLayout.visibility = View.GONE + return + } + binding.historyLayout.visibility = View.VISIBLE + val inflater = LayoutInflater.from(this) + + searchHistory.forEach { keyword -> + val tagView = inflater.inflate( + R.layout.item_history_tag, + binding.historyFlexLayout, + false + ) as TextView + tagView.text = keyword + tagView.setOnClickListener { + binding.searchEdit.setText(keyword) + binding.searchEdit.setSelection(keyword.length) + } + + binding.historyFlexLayout.addView(tagView) + } + } +} diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/PdfAdapter.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/PdfAdapter.kt index c62ad0f..7d15d46 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/PdfAdapter.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/PdfAdapter.kt @@ -45,6 +45,11 @@ class PdfAdapter( .transform(CenterCrop(), RoundedCorners(8.dpToPx(holder.binding.root.context))) .into(holder.binding.tvFileImg) } + if (item.isFavorite) { + holder.binding.collectState.visibility = View.VISIBLE + } else { + holder.binding.collectState.visibility = View.GONE + } holder.binding.root.setOnClickListener { onItemClick(item) diff --git a/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/SearchPdfAdapter.kt b/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/SearchPdfAdapter.kt index ca5ea06..4e7afe6 100644 --- a/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/SearchPdfAdapter.kt +++ b/app/src/main/java/com/all/pdfreader/pro/app/ui/adapter/SearchPdfAdapter.kt @@ -71,7 +71,11 @@ class SearchPdfAdapter( .transform(CenterCrop(), RoundedCorners(8.dpToPx(context))) .into(holder.binding.tvFileImg) } - + if (item.isFavorite) { + holder.binding.collectState.visibility = View.VISIBLE + } else { + holder.binding.collectState.visibility = View.GONE + } holder.binding.root.setOnClickListener { onItemClick(item) } holder.binding.moreBtn.setOnClickListener { onMoreClick(item) } } diff --git a/app/src/main/res/drawable/bg_history_item.xml b/app/src/main/res/drawable/bg_history_item.xml new file mode 100644 index 0000000..050603d --- /dev/null +++ b/app/src/main/res/drawable/bg_history_item.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/collected_white.xml b/app/src/main/res/drawable/collected_white.xml new file mode 100644 index 0000000..2fe3c0a --- /dev/null +++ b/app/src/main/res/drawable/collected_white.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/dr_collect_state_bg.xml b/app/src/main/res/drawable/dr_collect_state_bg.xml new file mode 100644 index 0000000..293c2b1 --- /dev/null +++ b/app/src/main/res/drawable/dr_collect_state_bg.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search_pdd.xml b/app/src/main/res/layout/activity_search_pdf.xml similarity index 66% rename from app/src/main/res/layout/activity_search_pdd.xml rename to app/src/main/res/layout/activity_search_pdf.xml index 0e8db6d..16b8fb9 100644 --- a/app/src/main/res/layout/activity_search_pdd.xml +++ b/app/src/main/res/layout/activity_search_pdf.xml @@ -1,7 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 064738a..5cd6e97 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -140,4 +140,8 @@ Quickly navigate to any page in the file. Please enter a number(1-%1$d) Please enter a number between 1 and %1$d + History + Tip + Are you sure you want to clear history? + Clear \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cb27d74..e45212e 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" +flexbox = "3.0.0" fragmentKtx = "1.8.9" glide = "5.0.4" jp2forandroid = "1.0.4" @@ -30,6 +31,7 @@ androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref 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" } +flexbox = { module = "com.google.android.flexbox:flexbox", version.ref = "flexbox" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } jp2forandroid = { module = "com.github.Tgo1014:JP2ForAndroid", version.ref = "jp2forandroid" } junit = { group = "junit", name = "junit", version.ref = "junit" }