Skip to content

Commit

Permalink
Improve search
Browse files Browse the repository at this point in the history
  • Loading branch information
Bartuzen committed Feb 3, 2025
1 parent b6071ca commit 3de2450
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@ class RssArticlesViewModel @Inject constructor(
}.filterNotNull().map { (articles, searchQuery) ->
if (searchQuery.isNotEmpty()) {
articles.filter { article ->
article.title.contains(searchQuery, ignoreCase = true)
val matchesSearchQuery = searchQuery
.split(" ")
.filter { it.isNotEmpty() && it != "-" }
.all { term ->
val isExclusion = term.startsWith("-")
val cleanTerm = term.removePrefix("-")
val containsTerm = article.title.contains(cleanTerm, ignoreCase = true)

if (isExclusion) !containsTerm else containsTerm
}

return@filter matchesSearchQuery
}
} else {
articles
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,20 @@ class SearchResultViewModel @Inject constructor(
Triple(searchResults, searchQuery, filter)
}.filterNotNull().map { (searchResults, searchQuery, filter) ->
searchResults.filter { result ->
if (searchQuery.isNotEmpty() && !result.fileName.contains(searchQuery, ignoreCase = true)) {
return@filter false
if (searchQuery.isNotEmpty()) {
val matchesSearchQuery = searchQuery
.split(" ")
.filter { it.isNotEmpty() && it != "-" }
.all { term ->
val isExclusion = term.startsWith("-")
val cleanTerm = term.removePrefix("-")
val containsTerm = result.fileName.contains(cleanTerm, ignoreCase = true)

if (isExclusion) !containsTerm else containsTerm
}
if (!matchesSearchQuery) {
return@filter false
}
}

if (filter.seedsMin != null && (result.seeders ?: -1) < filter.seedsMin) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ import dev.bartuzen.qbitcontroller.utils.getErrorMessage
import dev.bartuzen.qbitcontroller.utils.getTorrentStateColor
import dev.bartuzen.qbitcontroller.utils.harmonizeWithPrimary
import dev.bartuzen.qbitcontroller.utils.measureTextWidth
import dev.bartuzen.qbitcontroller.utils.rememberApplyStyle
import dev.bartuzen.qbitcontroller.utils.rememberReplaceAndApplyStyle
import dev.bartuzen.qbitcontroller.utils.rememberSearchStyle
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -1289,9 +1289,9 @@ private fun TorrentItem(
.padding(horizontal = 12.dp, vertical = 8.dp),
) {
val name = if (searchQuery != null) {
rememberApplyStyle(
rememberSearchStyle(
text = torrent.name,
textToStyle = searchQuery,
searchQuery = searchQuery,
style = SpanStyle(
color = MaterialTheme.colorScheme.onPrimary,
background = MaterialTheme.colorScheme.primary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,17 @@ class TorrentListViewModel @Inject constructor(
withContext(Dispatchers.Default) {
torrentList.filter { torrent ->
if (searchQuery.isNotEmpty()) {
if (!torrent.name.contains(searchQuery, ignoreCase = true)) {
val matchesSearchQuery = searchQuery
.split(" ")
.filter { it.isNotEmpty() && it != "-" }
.all { term ->
val isExclusion = term.startsWith("-")
val cleanTerm = term.removePrefix("-")
val containsTerm = torrent.name.contains(cleanTerm, ignoreCase = true)

if (isExclusion) !containsTerm else containsTerm
}
if (!matchesSearchQuery) {
return@filter false
}
}
Expand Down
36 changes: 28 additions & 8 deletions app/src/main/java/dev/bartuzen/qbitcontroller/utils/Compose.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,22 +78,42 @@ fun measureTextWidth(text: String, style: TextStyle = LocalTextStyle.current): D
}

@Composable
fun rememberApplyStyle(text: String, textToStyle: String, style: SpanStyle) = remember(text, textToStyle, style) {
fun rememberSearchStyle(text: String, searchQuery: String, style: SpanStyle) = remember(text, searchQuery, style) {
buildAnnotatedString {
var currentIndex = 0
val searchText = textToStyle.lowercase()
val terms = searchQuery
.split(" ")
.filter { it.isNotEmpty() && it != "-" }
val separators = setOf(' ', '-', '_', '.')

var currentIndex = 0
while (currentIndex < text.length) {
val index = text.indexOf(searchText, currentIndex, ignoreCase = true)
if (index == -1) {
val firstMatch = terms.mapNotNull { token ->
text.indexOf(token, currentIndex, ignoreCase = true).takeIf { it != -1 }?.let { it to token }
}.minByOrNull { it.first }
if (firstMatch == null) {
append(text.substring(currentIndex))
break
}
append(text.substring(currentIndex, index))
val (matchIndex, token) = firstMatch
append(text.substring(currentIndex, matchIndex))
var highlightStart = matchIndex
var highlightEnd = matchIndex + token.length
while (true) {
val nextMatch = terms.mapNotNull { token ->
text.indexOf(token, highlightEnd, ignoreCase = true).takeIf { it != -1 }?.let { it to token }
}.minByOrNull { it.first } ?: break
val (nextMatchIndex, nextToken) = nextMatch
val gap = text.substring(highlightEnd, nextMatchIndex)
if (gap.isNotEmpty() && gap.all { it in separators }) {
highlightEnd = nextMatchIndex + nextToken.length
} else {
break
}
}
withStyle(style) {
append(text.substring(index, index + textToStyle.length))
append(text.substring(highlightStart, highlightEnd))
}
currentIndex = index + textToStyle.length
currentIndex = highlightEnd
}
}
}
Expand Down

0 comments on commit 3de2450

Please sign in to comment.