全文搜索界面优化 #262
This commit is contained in:
4 files changed
+90
-54
No files matched your search
@@ -61,13 +61,7 @@ class SearchContentActivity :
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// val bbg = bottomBackground
|
|
||||||
// val btc = getPrimaryTextColor(ColorUtils.isColorLight(bbg))
|
|
||||||
// binding.llSearchBaseInfo.setBackgroundColor(bbg)
|
|
||||||
binding.llSearchBaseInfo.applyNavigationBarPadding()
|
binding.llSearchBaseInfo.applyNavigationBarPadding()
|
||||||
// binding.tvCurrentSearchInfo.setTextColor(btc)
|
|
||||||
// binding.ivSearchContentTop.setColorFilter(btc)
|
|
||||||
// binding.ivSearchContentBottom.setColorFilter(btc)
|
|
||||||
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList")
|
val searchResultList = IntentData.get<List<SearchResult>>("searchResultList")
|
||||||
val position = intent.getIntExtra("searchResultIndex", 0)
|
val position = intent.getIntExtra("searchResultIndex", 0)
|
||||||
val noSearchResult = searchResultList == null
|
val noSearchResult = searchResultList == null
|
||||||
@@ -143,7 +137,6 @@ class SearchContentActivity :
|
|||||||
|
|
||||||
private fun initRecyclerView() {
|
private fun initRecyclerView() {
|
||||||
binding.recyclerView.layoutManager = mLayoutManager
|
binding.recyclerView.layoutManager = mLayoutManager
|
||||||
binding.recyclerView.addItemDecoration(VerticalDivider(this))
|
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
package io.legado.app.ui.book.searchContent
|
package io.legado.app.ui.book.searchContent
|
||||||
|
|
||||||
//import io.legado.app.lib.theme.accentColor
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import io.legado.app.base.adapter.ItemViewHolder
|
import io.legado.app.base.adapter.ItemViewHolder
|
||||||
import io.legado.app.base.adapter.RecyclerAdapter
|
import io.legado.app.base.adapter.RecyclerAdapter
|
||||||
import io.legado.app.databinding.ItemSearchListBinding
|
import io.legado.app.databinding.ItemSearchListBinding
|
||||||
import io.legado.app.utils.hexString
|
|
||||||
import io.legado.app.utils.themeColor
|
import io.legado.app.utils.themeColor
|
||||||
|
|
||||||
|
|
||||||
class SearchContentAdapter(context: Context, val callback: Callback) :
|
class SearchContentAdapter(context: Context, val callback: Callback) :
|
||||||
RecyclerAdapter<SearchResult, ItemSearchListBinding>(context) {
|
RecyclerAdapter<SearchResult, ItemSearchListBinding>(context) {
|
||||||
|
|
||||||
val textColor = context.themeColor(com.google.android.material.R.attr.colorOnSurface).hexString.substring(2)
|
private val textColorInt = context.themeColor(com.google.android.material.R.attr.colorOnSurface)
|
||||||
val accentColor =
|
private val accentColorInt = context.themeColor(androidx.appcompat.R.attr.colorPrimary)
|
||||||
context.themeColor(androidx.appcompat.R.attr.colorPrimary).hexString.substring(2)
|
private val bgColorInt = context.themeColor(com.google.android.material.R.attr.colorSecondaryContainer)
|
||||||
|
|
||||||
override fun getViewBinding(parent: ViewGroup): ItemSearchListBinding {
|
override fun getViewBinding(parent: ViewGroup): ItemSearchListBinding {
|
||||||
return ItemSearchListBinding.inflate(inflater, parent, false)
|
return ItemSearchListBinding.inflate(inflater, parent, false)
|
||||||
@@ -30,14 +28,19 @@ class SearchContentAdapter(context: Context, val callback: Callback) :
|
|||||||
binding.run {
|
binding.run {
|
||||||
val isDur = callback.durChapterIndex() == item.chapterIndex
|
val isDur = callback.durChapterIndex() == item.chapterIndex
|
||||||
if (payloads.isEmpty()) {
|
if (payloads.isEmpty()) {
|
||||||
tvSearchResult.text = item.getHtmlCompat(textColor, accentColor)
|
tvTitle.text = item.getTitleSpannable(textColorInt)
|
||||||
tvSearchResult.paint.isFakeBoldText = isDur
|
tvContent.text = item.getContentSpannable(textColorInt, accentColorInt, bgColorInt)
|
||||||
|
|
||||||
|
cdRoot.setCardBackgroundColor(
|
||||||
|
if (isDur) context.themeColor(com.google.android.material.R.attr.colorSurfaceContainer)
|
||||||
|
else context.themeColor(com.google.android.material.R.attr.colorSurface)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerListener(holder: ItemViewHolder, binding: ItemSearchListBinding) {
|
override fun registerListener(holder: ItemViewHolder, binding: ItemSearchListBinding) {
|
||||||
holder.itemView.setOnClickListener {
|
binding.cdRoot.setOnClickListener {
|
||||||
getItem(holder.layoutPosition)?.let {
|
getItem(holder.layoutPosition)?.let {
|
||||||
if (it.query.isNotBlank()) callback.openSearchResult(it, holder.layoutPosition)
|
if (it.query.isNotBlank()) callback.openSearchResult(it, holder.layoutPosition)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package io.legado.app.ui.book.searchContent
|
package io.legado.app.ui.book.searchContent
|
||||||
|
|
||||||
import android.text.Spanned
|
import android.graphics.Typeface
|
||||||
import androidx.core.text.HtmlCompat
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.style.BackgroundColorSpan
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.text.style.StyleSpan
|
||||||
|
import android.text.style.UnderlineSpan
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
|
|
||||||
data class SearchResult(
|
data class SearchResult(
|
||||||
@@ -17,44 +23,48 @@ data class SearchResult(
|
|||||||
val queryIndexInChapter: Int = 0
|
val queryIndexInChapter: Int = 0
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getHtmlCompat(textColor: String, accentColor: String): Spanned {
|
fun getTitleSpannable(accentColor: Int): SpannableString {
|
||||||
return if (query.isNotBlank()) {
|
return if (AppConfig.isEInkMode) {
|
||||||
val queryIndexInSurrounding = resultText.indexOf(query)
|
SpannableString(chapterTitle).apply {
|
||||||
val leftString = resultText.substring(0, queryIndexInSurrounding)
|
setSpan(UnderlineSpan(), 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
val rightString =
|
|
||||||
resultText.substring(queryIndexInSurrounding + query.length, resultText.length)
|
|
||||||
// 检查是否为墨水屏模式
|
|
||||||
val html = if (AppConfig.isEInkMode) {
|
|
||||||
// 墨水屏模式:使用下划线
|
|
||||||
buildString {
|
|
||||||
append("<u>${chapterTitle}</u>")
|
|
||||||
append("<br>")
|
|
||||||
append(leftString)
|
|
||||||
append("<u>${query}</u>")
|
|
||||||
append(rightString)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 普通模式:使用颜色
|
SpannableString(chapterTitle).apply {
|
||||||
buildString {
|
setSpan(ForegroundColorSpan(accentColor), 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
append(chapterTitle.colorTextForHtml(accentColor))
|
|
||||||
append("<br>")
|
|
||||||
append(leftString.colorTextForHtml(textColor))
|
|
||||||
append(query.colorTextForHtml(accentColor))
|
|
||||||
append(rightString.colorTextForHtml(textColor))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
|
||||||
} else {
|
|
||||||
val html = if (AppConfig.isEInkMode) {
|
|
||||||
resultText
|
|
||||||
} else {
|
|
||||||
resultText.colorTextForHtml(textColor)
|
|
||||||
}
|
|
||||||
HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.colorTextForHtml(textColor: String) =
|
fun getContentSpannable(textColor: Int, accentColor: Int, bgColor: Int): SpannableStringBuilder {
|
||||||
"<font color=#${textColor}>$this</font>"
|
val spannable = SpannableStringBuilder(resultText)
|
||||||
|
|
||||||
|
if (query.isNotBlank()) {
|
||||||
|
var searchStart = 0
|
||||||
|
while (true) {
|
||||||
|
val start = resultText.indexOf(query, searchStart, ignoreCase = true)
|
||||||
|
if (start == -1) break
|
||||||
|
val end = start + query.length
|
||||||
|
|
||||||
|
if (AppConfig.isEInkMode) {
|
||||||
|
spannable.setSpan(UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
} else {
|
||||||
|
// 字体加粗
|
||||||
|
spannable.setSpan(StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
// 字体颜色
|
||||||
|
spannable.setSpan(ForegroundColorSpan(accentColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
// 背景色
|
||||||
|
spannable.setSpan(BackgroundColorSpan(bgColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
searchStart = end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置整体字体颜色(正文)
|
||||||
|
if (!AppConfig.isEInkMode) {
|
||||||
|
spannable.setSpan(ForegroundColorSpan(textColor), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
return spannable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,42 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:layout_margin="8dp">
|
||||||
android:padding="16dp">
|
|
||||||
|
<com.google.android.material.listitem.ListItemCardView
|
||||||
|
android:id="@+id/cd_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checkable="true"
|
||||||
|
app:cardCornerRadius="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_search_result"
|
android:id="@+id/tvTitle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="2dp"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="14sp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:lineSpacingExtra="2dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.listitem.ListItemCardView>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Reference in new issue
Block a user