更新关于界面
搜索书籍界面切换至SearchBar与SearchView
This commit is contained in:
@@ -1,53 +1,97 @@
|
||||
package io.legato.kazusa.ui.about
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseActivity
|
||||
import io.legato.kazusa.databinding.ActivityAboutBinding
|
||||
//import io.legado.app.lib.theme.accentColor
|
||||
//import io.legado.app.lib.theme.filletBackground
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseActivity
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.databinding.ActivityAboutBinding
|
||||
import io.legato.kazusa.help.CrashHandler
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.help.coroutine.Coroutine
|
||||
import io.legato.kazusa.help.update.AppUpdate
|
||||
import io.legato.kazusa.ui.widget.dialog.TextDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.FileDoc
|
||||
import io.legato.kazusa.utils.compress.ZipUtils
|
||||
import io.legato.kazusa.utils.createFileIfNotExist
|
||||
import io.legato.kazusa.utils.createFolderIfNotExist
|
||||
import io.legato.kazusa.utils.delete
|
||||
import io.legato.kazusa.utils.externalCache
|
||||
import io.legato.kazusa.utils.find
|
||||
import io.legato.kazusa.utils.list
|
||||
import io.legato.kazusa.utils.openInputStream
|
||||
import io.legato.kazusa.utils.openOutputStream
|
||||
import io.legato.kazusa.utils.openUrl
|
||||
import io.legato.kazusa.utils.share
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.delay
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
|
||||
|
||||
class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
|
||||
override val binding by viewBinding(ActivityAboutBinding::inflate)
|
||||
|
||||
private val waitDialog by lazy {
|
||||
WaitDialog(this).setText(R.string.checking_update)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setSupportActionBar(binding.topBar)
|
||||
|
||||
val fTag = "aboutFragment"
|
||||
var aboutFragment = supportFragmentManager.findFragmentByTag(fTag)
|
||||
if (aboutFragment == null) aboutFragment = AboutFragment()
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_fragment, aboutFragment, fTag)
|
||||
.commit()
|
||||
binding.tvAppSummary.post {
|
||||
kotlin.runCatching {
|
||||
val typedValue = TypedValue()
|
||||
val context = binding.root.context
|
||||
context.theme.resolveAttribute(
|
||||
androidx.appcompat.R.attr.colorPrimary,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
val accentColor = typedValue.data
|
||||
val spannableString = SpannableString(binding.tvAppSummary.text)
|
||||
val gzh = getString(R.string.legado_gzh)
|
||||
val start = spannableString.indexOf(gzh)
|
||||
spannableString.setSpan(
|
||||
accentColor, start, start + gzh.length,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
binding.tvAppSummary.text = spannableString
|
||||
}
|
||||
binding.btnUpdate.setOnClickListener {
|
||||
checkUpdate()
|
||||
}
|
||||
|
||||
binding.btnGithub.setOnClickListener {
|
||||
openUrl(R.string.github_url)
|
||||
}
|
||||
|
||||
binding.btnWeb.setOnClickListener {
|
||||
openUrl(R.string.legado_url)
|
||||
}
|
||||
|
||||
binding.llContributors.setOnClickListener {
|
||||
openUrl(R.string.contributors_url)
|
||||
}
|
||||
|
||||
binding.llUpdateLog.setOnClickListener {
|
||||
showMdFile(getString(R.string.update_log), "updateLog.md")
|
||||
}
|
||||
|
||||
binding.llPrivacyPolicy.setOnClickListener {
|
||||
showMdFile(getString(R.string.privacy_policy), "privacyPolicy.md")
|
||||
}
|
||||
|
||||
binding.llLicense.setOnClickListener {
|
||||
showMdFile(getString(R.string.license), "LICENSE.md")
|
||||
}
|
||||
|
||||
binding.llDisclaimer.setOnClickListener {
|
||||
showMdFile(getString(R.string.disclaimer), "disclaimer.md")
|
||||
}
|
||||
|
||||
binding.llCrashLog.setOnClickListener {
|
||||
showDialogFragment<CrashLogsDialog>()
|
||||
}
|
||||
|
||||
binding.llSaveLog.setOnClickListener {
|
||||
saveLog()
|
||||
}
|
||||
|
||||
binding.llCreateHeapDump.setOnClickListener {
|
||||
createHeapDump()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +102,6 @@ class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
|
||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_scoring -> openUrl("market://details?id=$packageName")
|
||||
R.id.menu_share_it -> share(
|
||||
getString(R.string.app_share_description),
|
||||
getString(R.string.app_name)
|
||||
@@ -67,4 +110,118 @@ class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
return super.onCompatOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun showMdFile(title: String, fileName: String) {
|
||||
val mdText = String(this.assets.open(fileName).readBytes())
|
||||
showDialogFragment(TextDialog(title, mdText, TextDialog.Mode.MD))
|
||||
}
|
||||
|
||||
private fun checkUpdate() {
|
||||
waitDialog.show()
|
||||
AppUpdate.gitHubUpdate?.run {
|
||||
check(lifecycleScope)
|
||||
.onSuccess {
|
||||
showDialogFragment(UpdateDialog(it))
|
||||
}.onError {
|
||||
appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
|
||||
}.onFinally {
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun openUrl(@StringRes addressID: Int) {
|
||||
this.openUrl(getString(addressID))
|
||||
}
|
||||
|
||||
private fun saveLog() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordLog) {
|
||||
appCtx.toastOnUi("未开启日志记录,请去其他设置里打开记录日志")
|
||||
delay(3000)
|
||||
}
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
copyLogs(doc)
|
||||
copyHeapDump(doc)
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}.onError {
|
||||
AppLog.put("保存日志出错\n${it.localizedMessage}", it, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHeapDump() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordHeapDump) {
|
||||
appCtx.toastOnUi("未开启堆转储记录,请去其他设置里打开记录堆转储")
|
||||
delay(3000)
|
||||
}
|
||||
appCtx.toastOnUi("开始创建堆转储")
|
||||
System.gc()
|
||||
CrashHandler.doHeapDump(true)
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
if (!copyHeapDump(doc)) {
|
||||
appCtx.toastOnUi("未找到堆转储文件")
|
||||
} else {
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}
|
||||
}.onError {
|
||||
AppLog.put("保存堆转储失败\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLogs(doc: FileDoc) {
|
||||
val cacheDir = appCtx.externalCache
|
||||
val logFiles = File(cacheDir, "logs")
|
||||
val crashFiles = File(cacheDir, "crash")
|
||||
val logcatFile = File(cacheDir, "logcat.txt")
|
||||
|
||||
dumpLogcat(logcatFile)
|
||||
|
||||
val zipFile = File(cacheDir, "logs.zip")
|
||||
ZipUtils.zipFiles(arrayListOf(logFiles, crashFiles, logcatFile), zipFile)
|
||||
|
||||
doc.find("logs.zip")?.delete()
|
||||
|
||||
zipFile.inputStream().use { input ->
|
||||
doc.createFileIfNotExist("logs.zip").openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
zipFile.delete()
|
||||
}
|
||||
|
||||
private fun copyHeapDump(doc: FileDoc): Boolean {
|
||||
val heapFile = FileDoc.fromFile(File(appCtx.externalCache, "heapDump")).list()
|
||||
?.firstOrNull() ?: return false
|
||||
doc.find("heapDump")?.delete()
|
||||
val heapDumpDoc = doc.createFolderIfNotExist("heapDump")
|
||||
heapFile.openInputStream().getOrNull()?.use { input ->
|
||||
heapDumpDoc.createFileIfNotExist(heapFile.name).openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dumpLogcat(file: File) {
|
||||
try {
|
||||
val process = Runtime.getRuntime().exec("logcat -d")
|
||||
file.outputStream().use {
|
||||
process.inputStream.copyTo(it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("保存Logcat失败\n$e", e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
package io.legato.kazusa.ui.about
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.AppConst.appInfo
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.help.CrashHandler
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.help.coroutine.Coroutine
|
||||
import io.legato.kazusa.help.update.AppUpdate
|
||||
import io.legato.kazusa.ui.widget.dialog.TextDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.FileDoc
|
||||
import io.legato.kazusa.utils.compress.ZipUtils
|
||||
import io.legato.kazusa.utils.createFileIfNotExist
|
||||
import io.legato.kazusa.utils.createFolderIfNotExist
|
||||
import io.legato.kazusa.utils.delete
|
||||
import io.legato.kazusa.utils.externalCache
|
||||
import io.legato.kazusa.utils.find
|
||||
import io.legato.kazusa.utils.list
|
||||
import io.legato.kazusa.utils.openInputStream
|
||||
import io.legato.kazusa.utils.openOutputStream
|
||||
import io.legato.kazusa.utils.openUrl
|
||||
import io.legato.kazusa.utils.sendMail
|
||||
import io.legato.kazusa.utils.sendToClip
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import kotlinx.coroutines.delay
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import androidx.core.net.toUri
|
||||
|
||||
class AboutFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val waitDialog by lazy {
|
||||
WaitDialog(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.about)
|
||||
findPreference<Preference>("update_log")?.summary =
|
||||
"${getString(R.string.version)} ${appInfo.versionName}"
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
listView.overScrollMode = View.OVER_SCROLL_NEVER
|
||||
}
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||
when (preference.key) {
|
||||
"contributors" -> openUrl(R.string.contributors_url)
|
||||
"update_log" -> showMdFile(getString(R.string.update_log), "updateLog.md")
|
||||
"check_update" -> checkUpdate()
|
||||
"mail" -> requireContext().sendMail(getString(R.string.email))
|
||||
"license" -> showMdFile(getString(R.string.license), "LICENSE.md")
|
||||
"disclaimer" -> showMdFile(getString(R.string.disclaimer), "disclaimer.md")
|
||||
"privacyPolicy" -> showMdFile(getString(R.string.privacy_policy), "privacyPolicy.md")
|
||||
"gzGzh" -> requireContext().sendToClip(getString(R.string.legado_gzh))
|
||||
"crashLog" -> showDialogFragment<CrashLogsDialog>()
|
||||
"saveLog" -> saveLog()
|
||||
"createHeapDump" -> createHeapDump()
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun openUrl(@StringRes addressID: Int) {
|
||||
requireContext().openUrl(getString(addressID))
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示md文件
|
||||
*/
|
||||
private fun showMdFile(title: String, fileName: String) {
|
||||
val mdText = String(requireContext().assets.open(fileName).readBytes())
|
||||
showDialogFragment(TextDialog(title, mdText, TextDialog.Mode.MD))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测更新
|
||||
*/
|
||||
private fun checkUpdate() {
|
||||
waitDialog.show()
|
||||
AppUpdate.gitHubUpdate?.run {
|
||||
check(lifecycleScope)
|
||||
.onSuccess {
|
||||
showDialogFragment(
|
||||
UpdateDialog(it)
|
||||
)
|
||||
}.onError {
|
||||
appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
|
||||
}.onFinally {
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 加入qq群
|
||||
// */
|
||||
// private fun joinQQGroup(key: String): Boolean {
|
||||
// val intent = Intent()
|
||||
// intent.data =
|
||||
// "mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$key".toUri()
|
||||
// // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面
|
||||
// // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
// kotlin.runCatching {
|
||||
// startActivity(intent)
|
||||
// return true
|
||||
// }.onFailure {
|
||||
// toastOnUi("添加失败,请手动添加")
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
|
||||
private fun saveLog() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordLog) {
|
||||
appCtx.toastOnUi("未开启日志记录,请去其他设置里打开记录日志")
|
||||
delay(3000)
|
||||
}
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
copyLogs(doc)
|
||||
copyHeapDump(doc)
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}.onError {
|
||||
AppLog.put("保存日志出错\n${it.localizedMessage}", it, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHeapDump() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordHeapDump) {
|
||||
appCtx.toastOnUi("未开启堆转储记录,请去其他设置里打开记录堆转储")
|
||||
delay(3000)
|
||||
}
|
||||
appCtx.toastOnUi("开始创建堆转储")
|
||||
System.gc()
|
||||
CrashHandler.doHeapDump(true)
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
if (!copyHeapDump(doc)) {
|
||||
appCtx.toastOnUi("未找到堆转储文件")
|
||||
} else {
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}
|
||||
}.onError {
|
||||
AppLog.put("保存堆转储失败\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLogs(doc: FileDoc) {
|
||||
val cacheDir = appCtx.externalCache
|
||||
val logFiles = File(cacheDir, "logs")
|
||||
val crashFiles = File(cacheDir, "crash")
|
||||
val logcatFile = File(cacheDir, "logcat.txt")
|
||||
|
||||
dumpLogcat(logcatFile)
|
||||
|
||||
val zipFile = File(cacheDir, "logs.zip")
|
||||
ZipUtils.zipFiles(arrayListOf(logFiles, crashFiles, logcatFile), zipFile)
|
||||
|
||||
doc.find("logs.zip")?.delete()
|
||||
|
||||
zipFile.inputStream().use { input ->
|
||||
doc.createFileIfNotExist("logs.zip").openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
zipFile.delete()
|
||||
}
|
||||
|
||||
private fun copyHeapDump(doc: FileDoc): Boolean {
|
||||
val heapFile = FileDoc.fromFile(File(appCtx.externalCache, "heapDump")).list()
|
||||
?.firstOrNull() ?: return false
|
||||
doc.find("heapDump")?.delete()
|
||||
val heapDumpDoc = doc.createFolderIfNotExist("heapDump")
|
||||
heapFile.openInputStream().getOrNull()?.use { input ->
|
||||
heapDumpDoc.createFileIfNotExist(heapFile.name).openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dumpLogcat(file: File) {
|
||||
try {
|
||||
val process = Runtime.getRuntime().exec("logcat -d")
|
||||
file.outputStream().use {
|
||||
process.inputStream.copyTo(it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("保存Logcat失败\n$e", e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import android.view.ViewGroup
|
||||
import io.legato.kazusa.base.adapter.ItemViewHolder
|
||||
import io.legato.kazusa.base.adapter.RecyclerAdapter
|
||||
import io.legato.kazusa.data.entities.Book
|
||||
import io.legato.kazusa.databinding.ItemFilletTextBinding
|
||||
import io.legato.kazusa.databinding.ItemSearchHistoryBinding
|
||||
import io.legato.kazusa.utils.gone
|
||||
|
||||
|
||||
class BookAdapter(context: Context, val callBack: CallBack) :
|
||||
@@ -39,6 +39,7 @@ class BookAdapter(context: Context, val callBack: CallBack) :
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.btnDelete.gone()
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.view.ViewGroup
|
||||
import io.legato.kazusa.base.adapter.ItemViewHolder
|
||||
import io.legato.kazusa.base.adapter.RecyclerAdapter
|
||||
import io.legato.kazusa.data.entities.SearchKeyword
|
||||
import io.legato.kazusa.databinding.ItemFilletTextBinding
|
||||
import io.legato.kazusa.databinding.ItemSearchHistoryBinding
|
||||
import io.legato.kazusa.ui.widget.anima.explosion_field.ExplosionField
|
||||
import splitties.views.onLongClick
|
||||
@@ -47,6 +46,11 @@ class HistoryKeyAdapter(activity: SearchActivity, val callBack: CallBack) :
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.btnDelete.setOnClickListener {
|
||||
getItemByLayoutPosition(holder.layoutPosition)?.let {
|
||||
callBack.deleteHistory(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
|
||||
@@ -5,17 +5,18 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.TextView
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.flexbox.FlexboxLayoutManager
|
||||
import com.google.android.material.search.SearchBar
|
||||
import com.google.android.material.search.SearchView
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.VMBaseActivity
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
@@ -25,15 +26,12 @@ import io.legato.kazusa.data.entities.Book
|
||||
import io.legato.kazusa.data.entities.SearchKeyword
|
||||
import io.legato.kazusa.databinding.ActivityBookSearchBinding
|
||||
import io.legato.kazusa.lib.dialogs.alert
|
||||
//import io.legado.app.lib.theme.accentColor
|
||||
//import io.legado.app.lib.theme.backgroundColor
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
//import io.legado.app.lib.theme.primaryTextColor
|
||||
import io.legato.kazusa.ui.about.AppLogDialog
|
||||
import io.legato.kazusa.ui.book.info.BookInfoActivity
|
||||
import io.legato.kazusa.ui.book.source.manage.BookSourceActivity
|
||||
import io.legato.kazusa.utils.applyNavigationBarMargin
|
||||
import io.legato.kazusa.utils.applyNavigationBarPadding
|
||||
import io.legato.kazusa.utils.applyStatusBarPadding
|
||||
import io.legato.kazusa.utils.getPrefBoolean
|
||||
import io.legato.kazusa.utils.gone
|
||||
import io.legato.kazusa.utils.invisible
|
||||
@@ -73,9 +71,10 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
setHasStableIds(true)
|
||||
}
|
||||
}
|
||||
private val searchView: SearchView by lazy {
|
||||
binding.titleBar.findViewById(R.id.search_view)
|
||||
}
|
||||
|
||||
private val searchBar: SearchBar by lazy { binding.searchBar }
|
||||
private val searchView: SearchView by lazy { binding.searchView }
|
||||
|
||||
private var menu: Menu? = null
|
||||
private var groups: List<String>? = null
|
||||
private var historyFlowJob: Job? = null
|
||||
@@ -85,9 +84,9 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
//binding.llInputHelp.setBackgroundColor(backgroundColor)
|
||||
setSupportActionBar(binding.searchBar)
|
||||
initRecyclerView()
|
||||
initSearchView()
|
||||
initMaterialSearch()
|
||||
initOtherView()
|
||||
initData()
|
||||
receiptIntent(intent)
|
||||
@@ -154,8 +153,8 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
!getPrefBoolean(PreferKey.precisionSearch)
|
||||
)
|
||||
precisionSearchMenuItem?.isChecked = getPrefBoolean(PreferKey.precisionSearch)
|
||||
searchView.query?.toString()?.trim()?.let {
|
||||
searchView.setQuery(it, true)
|
||||
searchView.text.toString().trim().let {
|
||||
searchView.setText(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,44 +173,63 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
return super.onCompatOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun initSearchView() {
|
||||
//searchView.applyTint(primaryTextColor)
|
||||
searchView.isSubmitButtonEnabled = true
|
||||
searchView.queryHint = getString(R.string.search_book_key)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
searchView.clearFocus()
|
||||
query.trim().let { searchKey ->
|
||||
isManualStopSearch = false
|
||||
viewModel.saveSearchKey(searchKey)
|
||||
viewModel.searchKey = ""
|
||||
viewModel.search(searchKey)
|
||||
}
|
||||
visibleInputHelp(false)
|
||||
return true
|
||||
}
|
||||
private fun initMaterialSearch() {
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
viewModel.stop()
|
||||
binding.fbStartStop.invisible()
|
||||
upHistory(newText.trim())
|
||||
return false
|
||||
binding.appBar.applyStatusBarPadding()
|
||||
|
||||
searchBar.setOnMenuItemClickListener { item ->
|
||||
onCompatOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
searchBar.setNavigationOnClickListener {
|
||||
finish()
|
||||
}
|
||||
|
||||
searchView.setupWithSearchBar(searchBar)
|
||||
|
||||
binding.searchView.show()
|
||||
binding.searchView.editText.requestFocus()
|
||||
|
||||
searchView.editText.hint = getString(R.string.search_book_key)
|
||||
searchView.editText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
val key = searchView.text.toString().trim()
|
||||
if (key.isNotEmpty()) {
|
||||
isManualStopSearch = false
|
||||
viewModel.saveSearchKey(key)
|
||||
viewModel.searchKey = ""
|
||||
viewModel.search(key)
|
||||
visibleInputHelp()
|
||||
searchView.hide()
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
}
|
||||
})
|
||||
// searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
||||
// if (binding.refreshProgressBar.isAutoLoading || (!hasFocus && adapter.isNotEmpty() && searchView.query.isNotBlank())) {
|
||||
// visibleInputHelp(false)
|
||||
// } else {
|
||||
// visibleInputHelp(true)
|
||||
// }
|
||||
// }
|
||||
visibleInputHelp(true)
|
||||
false
|
||||
}
|
||||
|
||||
searchView.editText.doAfterTextChanged {
|
||||
viewModel.stop()
|
||||
binding.fbStartStop.invisible()
|
||||
upHistory(it?.toString()?.trim().orEmpty())
|
||||
}
|
||||
|
||||
searchView.addTransitionListener { _, _, newState ->
|
||||
if (newState == SearchView.TransitionState.HIDDEN) {
|
||||
// 当 SearchView 关闭时,将搜索文本设置回 SearchBar
|
||||
searchBar.setText(searchView.text)
|
||||
}
|
||||
}
|
||||
|
||||
searchView.addTransitionListener { _, oldState, newState ->
|
||||
if (oldState == SearchView.TransitionState.HIDDEN && newState == SearchView.TransitionState.SHOWN) {
|
||||
searchView.editText.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
visibleInputHelp()
|
||||
}
|
||||
|
||||
private fun initRecyclerView() {
|
||||
// binding.recyclerView.setEdgeEffectColor(primaryColor)
|
||||
// binding.rvBookshelfSearch.setEdgeEffectColor(primaryColor)
|
||||
// binding.rvHistoryKey.setEdgeEffectColor(primaryColor)
|
||||
binding.rvBookshelfSearch.layoutManager = FlexboxLayoutManager(this)
|
||||
binding.rvBookshelfSearch.adapter = bookAdapter
|
||||
binding.rvBookshelfSearch.applyNavigationBarMargin()
|
||||
@@ -261,16 +279,10 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
}
|
||||
|
||||
private fun initOtherView() {
|
||||
// binding.fbStartStop.backgroundTintList =
|
||||
// Selector.colorBuild()
|
||||
// .setDefaultColor(accentColor)
|
||||
// .setPressedColor(ColorUtils.darkenColor(accentColor))
|
||||
// .create()
|
||||
binding.fbStartStop.setOnClickListener {
|
||||
if (viewModel.isSearchLiveData.value == true) {
|
||||
isManualStopSearch = true
|
||||
viewModel.stop()
|
||||
//binding.refreshProgressBar.visibility = GONE
|
||||
} else {
|
||||
viewModel.search("")
|
||||
}
|
||||
@@ -281,8 +293,8 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
private fun initData() {
|
||||
viewModel.searchScope.stateLiveData.observe(this) {
|
||||
if (!binding.llInputHelp.isVisible) {
|
||||
searchView.query?.toString()?.trim()?.let {
|
||||
searchView.setQuery(it, true)
|
||||
searchView.text.toString().trim().let {
|
||||
searchView.setText(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,6 +307,11 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
}
|
||||
viewModel.searchBookLiveData.observe(this) {
|
||||
adapter.setItems(it)
|
||||
if (it.isNullOrEmpty()) {
|
||||
binding.tvEmptyMsg.visible()
|
||||
} else {
|
||||
binding.tvEmptyMsg.gone()
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
appDb.bookSourceDao.flowEnabledGroups().collect {
|
||||
@@ -313,10 +330,9 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
}
|
||||
val key = intent?.getStringExtra("key")
|
||||
if (key.isNullOrBlank()) {
|
||||
searchView.findViewById<TextView>(androidx.appcompat.R.id.search_src_text)
|
||||
.requestFocus()
|
||||
searchView.editText.requestFocus()
|
||||
} else {
|
||||
searchView.setQuery(key, true)
|
||||
searchView.setText(key)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,13 +354,9 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
/**
|
||||
* 打开关闭输入帮助
|
||||
*/
|
||||
private fun visibleInputHelp(visible: Boolean) {
|
||||
if (visible) {
|
||||
upHistory(searchView.query.toString())
|
||||
binding.llInputHelp.visibility = VISIBLE
|
||||
} else {
|
||||
binding.llInputHelp.visibility = GONE
|
||||
}
|
||||
private fun visibleInputHelp() {
|
||||
upHistory(searchView.text.toString())
|
||||
binding.llInputHelp.visibility = VISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,7 +413,6 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
* 搜索结束
|
||||
*/
|
||||
private fun searchFinally() {
|
||||
//binding.refreshProgressBar.isAutoLoading = false
|
||||
binding.refreshProgressBar.gone()
|
||||
if (!isManualStopSearch && viewModel.hasMore) {
|
||||
binding.fbStartStop.setImageResource(R.drawable.ic_play_24dp)
|
||||
@@ -425,7 +436,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
appCtx.putPrefBoolean(PreferKey.precisionSearch, false)
|
||||
precisionSearchMenuItem?.isChecked = false
|
||||
viewModel.searchKey = ""
|
||||
viewModel.search(searchView.query.toString())
|
||||
viewModel.search(searchView.text.toString())
|
||||
}
|
||||
} else {
|
||||
setMessage("${displayScope}分组搜索结果为空,是否切换到全部分组?")
|
||||
@@ -469,16 +480,16 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
override fun searchHistory(key: String) {
|
||||
lifecycleScope.launch {
|
||||
when {
|
||||
searchView.query.toString() == key -> {
|
||||
searchView.setQuery(key, true)
|
||||
searchView.text.toString() == key -> {
|
||||
searchView.setText(key)
|
||||
}
|
||||
|
||||
withContext(IO) { appDb.bookDao.findByName(key).isEmpty() } -> {
|
||||
searchView.setQuery(key, true)
|
||||
searchView.setText(key)
|
||||
}
|
||||
|
||||
else -> {
|
||||
searchView.setQuery(key, false)
|
||||
searchView.setText(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,23 @@ package io.legato.kazusa.ui.widget.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.databinding.DialogWaitBinding
|
||||
|
||||
class WaitDialog(context: Context) {
|
||||
|
||||
@Suppress("unused")
|
||||
class WaitDialog(context: Context) : Dialog(context) {
|
||||
private val binding: DialogWaitBinding =
|
||||
DialogWaitBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
val binding = DialogWaitBinding.inflate(layoutInflater)
|
||||
private val dialog: Dialog = MaterialAlertDialogBuilder(context)
|
||||
.setView(binding.root)
|
||||
.setCancelable(false)
|
||||
.create()
|
||||
|
||||
init {
|
||||
setCanceledOnTouchOutside(false)
|
||||
setContentView(binding.root)
|
||||
binding.tvMsg.setText(R.string.loading)
|
||||
}
|
||||
|
||||
fun setText(text: String): WaitDialog {
|
||||
@@ -20,9 +26,31 @@ class WaitDialog(context: Context) : Dialog(context) {
|
||||
return this
|
||||
}
|
||||
|
||||
fun setText(res: Int): WaitDialog {
|
||||
binding.tvMsg.setText(res)
|
||||
fun setText(resId: Int): WaitDialog {
|
||||
binding.tvMsg.setText(resId)
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
fun show(): WaitDialog {
|
||||
dialog.show()
|
||||
return this
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
fun isShowing(): Boolean {
|
||||
return dialog.isShowing
|
||||
}
|
||||
|
||||
fun setOnCancelListener(listener: () -> Unit): WaitDialog {
|
||||
dialog.setOnCancelListener { listener() }
|
||||
return this
|
||||
}
|
||||
|
||||
fun setCancelable(cancelable: Boolean): WaitDialog {
|
||||
dialog.setCancelable(cancelable)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user