mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-26 17:52:29 +01:00
Adds hidden words filter to search, hashtag and geotag feeds
Applies hidden words even to hashtags that were not included in the content of the event. Pre-process search to avoid showing and hiding posts after hidden words where processed by the UI.
This commit is contained in:
parent
f88985b2bf
commit
518e1c88ce
@ -2043,7 +2043,10 @@ object LocalCache {
|
||||
}
|
||||
}
|
||||
|
||||
fun findUsersStartingWith(username: String): List<User> {
|
||||
fun findUsersStartingWith(
|
||||
username: String,
|
||||
forAccount: Account?,
|
||||
): List<User> {
|
||||
checkNotInMainThread()
|
||||
|
||||
val key = decodePublicKeyAsHexOrNull(username)
|
||||
@ -2056,13 +2059,19 @@ object LocalCache {
|
||||
}
|
||||
|
||||
return users.filter { _, user: User ->
|
||||
(user.anyNameStartsWith(username)) ||
|
||||
user.pubkeyHex.startsWith(username, true) ||
|
||||
user.pubkeyNpub().startsWith(username, true)
|
||||
(
|
||||
(user.anyNameStartsWith(username)) ||
|
||||
user.pubkeyHex.startsWith(username, true) ||
|
||||
user.pubkeyNpub().startsWith(username, true)
|
||||
) &&
|
||||
(forAccount == null || (!forAccount.isHidden(user) && !user.containsAny(forAccount.flowHiddenUsers.value.hiddenWordsCase)))
|
||||
}
|
||||
}
|
||||
|
||||
fun findNotesStartingWith(text: String): List<Note> {
|
||||
fun findNotesStartingWith(
|
||||
text: String,
|
||||
forAccount: Account,
|
||||
): List<Note> {
|
||||
checkNotInMainThread()
|
||||
|
||||
val key = decodeEventIdAsHexOrNull(text)
|
||||
@ -2089,11 +2098,19 @@ object LocalCache {
|
||||
note.idHex.startsWith(text, true) ||
|
||||
note.idNote().startsWith(text, true)
|
||||
) {
|
||||
return@filter true
|
||||
if (!note.isHiddenFor(forAccount.flowHiddenUsers.value)) {
|
||||
return@filter true
|
||||
} else {
|
||||
return@filter false
|
||||
}
|
||||
}
|
||||
|
||||
if (note.event?.isContentEncoded() == false) {
|
||||
return@filter note.event?.content()?.contains(text, true) ?: false
|
||||
if (!note.isHiddenFor(forAccount.flowHiddenUsers.value)) {
|
||||
return@filter note.event?.content()?.contains(text, true) ?: false
|
||||
} else {
|
||||
return@filter false
|
||||
}
|
||||
}
|
||||
|
||||
return@filter false
|
||||
@ -2112,11 +2129,19 @@ object LocalCache {
|
||||
if (addressable.event?.matchTag1With(text) == true ||
|
||||
addressable.idHex.startsWith(text, true)
|
||||
) {
|
||||
return@filter true
|
||||
if (!addressable.isHiddenFor(forAccount.flowHiddenUsers.value)) {
|
||||
return@filter true
|
||||
} else {
|
||||
return@filter false
|
||||
}
|
||||
}
|
||||
|
||||
if (addressable.event?.isContentEncoded() == false) {
|
||||
return@filter addressable.event?.content()?.contains(text, true) ?: false
|
||||
if (!addressable.isHiddenFor(forAccount.flowHiddenUsers.value)) {
|
||||
return@filter addressable.event?.content()?.contains(text, true) ?: false
|
||||
} else {
|
||||
return@filter false
|
||||
}
|
||||
}
|
||||
|
||||
return@filter false
|
||||
|
@ -771,29 +771,11 @@ open class Note(
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.toBestDisplayName()?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
if (thisEvent.anyHashTag { it.containsAny(accountChoices.hiddenWordsCase) }) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.profilePicture()?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.info?.banner?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.info?.about?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.info?.lud06?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (author?.info?.lud16?.containsAny(accountChoices.hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
if (author?.containsAny(accountChoices.hiddenWordsCase) == true) return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -45,6 +45,8 @@ import com.vitorpamplona.quartz.events.MetadataEvent
|
||||
import com.vitorpamplona.quartz.events.ReportEvent
|
||||
import com.vitorpamplona.quartz.events.UserMetadata
|
||||
import com.vitorpamplona.quartz.events.toImmutableListOfLists
|
||||
import com.vitorpamplona.quartz.utils.DualCase
|
||||
import com.vitorpamplona.quartz.utils.containsAny
|
||||
import kotlinx.collections.immutable.persistentSetOf
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@ -370,6 +372,36 @@ class User(
|
||||
(it.event as ReportEvent).reportedAuthor().any { it.reportType == type }
|
||||
} != null
|
||||
|
||||
fun containsAny(hiddenWordsCase: List<DualCase>): Boolean {
|
||||
if (hiddenWordsCase.isEmpty()) return false
|
||||
|
||||
if (toBestDisplayName().containsAny(hiddenWordsCase)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (profilePicture()?.containsAny(hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (info?.banner?.containsAny(hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (info?.about?.containsAny(hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (info?.lud06?.containsAny(hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (info?.lud16?.containsAny(hiddenWordsCase) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun anyNameStartsWith(username: String): Boolean = info?.anyNameStartsWith(username) ?: false
|
||||
|
||||
var liveSet: UserLiveSet? = null
|
||||
|
@ -274,7 +274,7 @@ open class EditPostViewModel : ViewModel() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
userSuggestions =
|
||||
LocalCache
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"))
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"), account)
|
||||
.sortedWith(compareBy({ account?.isFollowing(it) }, { it.toBestDisplayName() }, { it.pubkeyHex }))
|
||||
.reversed()
|
||||
}
|
||||
|
@ -1002,7 +1002,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
userSuggestions =
|
||||
LocalCache
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"))
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"), account)
|
||||
.sortedWith(compareBy({ account?.isFollowing(it) }, { it.toBestDisplayName() }, { it.pubkeyHex }))
|
||||
.reversed()
|
||||
}
|
||||
@ -1031,7 +1031,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
userSuggestions =
|
||||
LocalCache
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"))
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"), account)
|
||||
.sortedWith(compareBy({ account?.isFollowing(it) }, { it.toBestDisplayName() }, { it.pubkeyHex }))
|
||||
.reversed()
|
||||
}
|
||||
@ -1059,7 +1059,7 @@ open class NewPostViewModel : ViewModel() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
userSuggestions =
|
||||
LocalCache
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"))
|
||||
.findUsersStartingWith(lastWord.removePrefix("@"), account)
|
||||
.sortedWith(
|
||||
compareBy(
|
||||
{ account?.isFollowing(it) },
|
||||
|
@ -64,6 +64,7 @@ class GeoHashFeedFilter(
|
||||
it.event is AudioHeaderEvent
|
||||
) &&
|
||||
it.event?.isTaggedGeoHash(geoTag) == true &&
|
||||
!it.isHiddenFor(account.flowHiddenUsers.value) &&
|
||||
account.isAcceptable(it)
|
||||
|
||||
override fun sort(collection: Set<Note>): List<Note> = collection.sortedWith(DefaultFeedOrder)
|
||||
|
@ -68,6 +68,7 @@ class HashtagFeedFilter(
|
||||
it.event is AudioHeaderEvent
|
||||
) &&
|
||||
it.event?.isTaggedHash(hashTag) == true &&
|
||||
!it.isHiddenFor(account.flowHiddenUsers.value) &&
|
||||
account.isAcceptable(it)
|
||||
|
||||
override fun sort(collection: Set<Note>): List<Note> = collection.sortedWith(DefaultFeedOrder)
|
||||
|
@ -75,7 +75,7 @@ class SearchBarViewModel(
|
||||
_hashtagResults.emit(findHashtags(searchValue))
|
||||
_searchResultsUsers.emit(
|
||||
LocalCache
|
||||
.findUsersStartingWith(searchValue)
|
||||
.findUsersStartingWith(searchValue, account)
|
||||
.sortedWith(
|
||||
compareBy(
|
||||
{ it.toBestDisplayName().startsWith(searchValue, true) },
|
||||
@ -86,7 +86,7 @@ class SearchBarViewModel(
|
||||
)
|
||||
_searchResultsNotes.emit(
|
||||
LocalCache
|
||||
.findNotesStartingWith(searchValue)
|
||||
.findNotesStartingWith(searchValue, account)
|
||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
||||
.reversed(),
|
||||
)
|
||||
|
@ -36,7 +36,6 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -178,7 +177,7 @@ fun WatchAccountForSearchScreen(accountViewModel: AccountViewModel) {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class, ExperimentalMaterial3Api::class)
|
||||
@OptIn(FlowPreview::class)
|
||||
@Composable
|
||||
private fun SearchBar(
|
||||
searchBarViewModel: SearchBarViewModel,
|
||||
|
@ -107,6 +107,19 @@ open class Event(
|
||||
}
|
||||
}
|
||||
|
||||
override fun anyHashTag(onEach: (str: String) -> Boolean) = anyTagged("t", onEach)
|
||||
|
||||
private fun anyTagged(
|
||||
tagName: String,
|
||||
onEach: (str: String) -> Boolean,
|
||||
) = tags.any {
|
||||
if (it.size > 1 && it[0] == tagName) {
|
||||
onEach(it[1])
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun <R> mapTaggedEvent(map: (eventId: HexKey) -> R) = mapTagged("e", map)
|
||||
|
||||
override fun <R> mapTaggedAddress(map: (address: String) -> R) = mapTagged("a", map)
|
||||
|
@ -121,6 +121,8 @@ interface EventInterface {
|
||||
|
||||
fun forEachHashTag(onEach: (eventId: HexKey) -> Unit)
|
||||
|
||||
fun anyHashTag(onEach: (str: String) -> Boolean): Boolean
|
||||
|
||||
fun <R> mapTaggedEvent(map: (eventId: HexKey) -> R): List<R>
|
||||
|
||||
fun <R> mapTaggedAddress(map: (address: String) -> R): List<R>
|
||||
|
Loading…
x
Reference in New Issue
Block a user