Skip to content

Commit

Permalink
Adds hidden words filter to search, hashtag and geotag feeds
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
vitorpamplona committed Oct 24, 2024
1 parent f88985b commit 518e1c8
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down
22 changes: 2 additions & 20 deletions amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
Expand All @@ -86,7 +86,7 @@ class SearchBarViewModel(
)
_searchResultsNotes.emit(
LocalCache
.findNotesStartingWith(searchValue)
.findNotesStartingWith(searchValue, account)
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
.reversed(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -178,7 +177,7 @@ fun WatchAccountForSearchScreen(accountViewModel: AccountViewModel) {
}
}

@OptIn(FlowPreview::class, ExperimentalMaterial3Api::class)
@OptIn(FlowPreview::class)
@Composable
private fun SearchBar(
searchBarViewModel: SearchBarViewModel,
Expand Down
13 changes: 13 additions & 0 deletions quartz/src/main/java/com/vitorpamplona/quartz/events/Event.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 518e1c8

Please sign in to comment.