- Removing unnecessary feed definitions

- Adds favorite relays to the top filter
This commit is contained in:
Vitor Pamplona
2026-03-02 16:16:23 -05:00
parent bb6f052f32
commit 399c9463bf
2 changed files with 62 additions and 50 deletions
@@ -64,13 +64,13 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNo
import com.vitorpamplona.amethyst.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.ui.components.LoadingAnimation
import com.vitorpamplona.amethyst.ui.components.SpinnerSelectionDialog import com.vitorpamplona.amethyst.ui.components.SpinnerSelectionDialog
import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName import com.vitorpamplona.amethyst.ui.note.creators.location.LoadCityName
import com.vitorpamplona.amethyst.ui.screen.AroundMeFeedDefinition
import com.vitorpamplona.amethyst.ui.screen.CommunityName import com.vitorpamplona.amethyst.ui.screen.CommunityName
import com.vitorpamplona.amethyst.ui.screen.FeedDefinition import com.vitorpamplona.amethyst.ui.screen.FeedDefinition
import com.vitorpamplona.amethyst.ui.screen.GeoHashName import com.vitorpamplona.amethyst.ui.screen.GeoHashName
import com.vitorpamplona.amethyst.ui.screen.HashtagName import com.vitorpamplona.amethyst.ui.screen.HashtagName
import com.vitorpamplona.amethyst.ui.screen.Name import com.vitorpamplona.amethyst.ui.screen.Name
import com.vitorpamplona.amethyst.ui.screen.PeopleListName import com.vitorpamplona.amethyst.ui.screen.PeopleListName
import com.vitorpamplona.amethyst.ui.screen.RelayName
import com.vitorpamplona.amethyst.ui.screen.ResourceName import com.vitorpamplona.amethyst.ui.screen.ResourceName
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
@@ -136,7 +136,7 @@ fun FeedFilterSpinner(
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(currentText) Text(currentText)
if (selected is AroundMeFeedDefinition) { if (selected?.code is TopFilter.AroundMe) {
if (!locationPermissionState.status.isGranted) { if (!locationPermissionState.status.isGranted) {
LaunchedEffect(locationPermissionState) { locationPermissionState.launchPermissionRequest() } LaunchedEffect(locationPermissionState) { locationPermissionState.launchPermissionRequest() }
@@ -313,5 +313,17 @@ fun RenderOption(
Text(text = "/n/${((it.note as? AddressableNote)?.dTag() ?: "")}", color = MaterialTheme.colorScheme.onSurface) Text(text = "/n/${((it.note as? AddressableNote)?.dTag() ?: "")}", color = MaterialTheme.colorScheme.onSurface)
} }
} }
is RelayName -> {
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth(),
) {
Text(
text = option.name(),
color = MaterialTheme.colorScheme.onSurface,
)
}
}
} }
} }
@@ -30,6 +30,8 @@ import com.vitorpamplona.amethyst.model.TopFilter
import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent
import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.Log
@@ -45,6 +47,7 @@ import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transform
@Stable @Stable
class TopNavFilterState( class TopNavFilterState(
@@ -52,43 +55,43 @@ class TopNavFilterState(
val scope: CoroutineScope, val scope: CoroutineScope,
) { ) {
val allFollows = val allFollows =
PeopleListOutBoxFeedDefinition( FeedDefinition(
code = TopFilter.AllFollows, code = TopFilter.AllFollows,
name = ResourceName(R.string.follow_list_kind3follows), name = ResourceName(R.string.follow_list_kind3follows),
) )
val userFollows = val userFollows =
PeopleListOutBoxFeedDefinition( FeedDefinition(
code = TopFilter.AllUserFollows, code = TopFilter.AllUserFollows,
name = ResourceName(R.string.follow_list_kind3follows_users_only), name = ResourceName(R.string.follow_list_kind3follows_users_only),
) )
val kind3Follows = val kind3Follows =
PeopleListOutBoxFeedDefinition( FeedDefinition(
code = TopFilter.DefaultFollows, code = TopFilter.DefaultFollows,
name = ResourceName(R.string.follow_list_kind3_follows_users_only), name = ResourceName(R.string.follow_list_kind3_follows_users_only),
) )
val globalFollow = val globalFollow =
GlobalFeedDefinition( FeedDefinition(
code = TopFilter.Global, code = TopFilter.Global,
name = ResourceName(R.string.follow_list_global), name = ResourceName(R.string.follow_list_global),
) )
val aroundMe = val aroundMe =
AroundMeFeedDefinition( FeedDefinition(
code = TopFilter.AroundMe, code = TopFilter.AroundMe,
name = ResourceName(R.string.follow_list_aroundme), name = ResourceName(R.string.follow_list_aroundme),
) )
val muteListFollow = val muteListFollow =
PeopleListOutBoxFeedDefinition( FeedDefinition(
code = TopFilter.MuteList(account.muteList.getMuteListAddress()), code = TopFilter.MuteList(account.muteList.getMuteListAddress()),
name = ResourceName(R.string.follow_list_mute_list), name = ResourceName(R.string.follow_list_mute_list),
) )
val chessFollow = val chessFollow =
GlobalFeedDefinition( FeedDefinition(
code = TopFilter.Chess, code = TopFilter.Chess,
name = ResourceName(R.string.follow_list_chess), name = ResourceName(R.string.follow_list_chess),
) )
@@ -101,7 +104,7 @@ class TopNavFilterState(
): List<FeedDefinition> { ): List<FeedDefinition> {
val peopleListsDefs = val peopleListsDefs =
peopleLists.map { peopleLists.map {
PeopleListOutBoxFeedDefinition( FeedDefinition(
TopFilter.PeopleList(it.address), TopFilter.PeopleList(it.address),
PeopleListName(it), PeopleListName(it),
) )
@@ -109,7 +112,7 @@ class TopNavFilterState(
val followListsDefs = val followListsDefs =
followLists.map { followLists.map {
PeopleListOutBoxFeedDefinition( FeedDefinition(
TopFilter.PeopleList(it.address), TopFilter.PeopleList(it.address),
PeopleListName(it), PeopleListName(it),
) )
@@ -136,10 +139,11 @@ class TopNavFilterState(
hashtagList: Set<String>, hashtagList: Set<String>,
geotagList: Set<String>, geotagList: Set<String>,
communityList: List<AddressableNote>, communityList: List<AddressableNote>,
relayList: Set<NormalizedRelayUrl>,
): List<FeedDefinition> { ): List<FeedDefinition> {
val hashtags = val hashtags =
hashtagList.map { hashtagList.map {
TagFeedDefinition( FeedDefinition(
TopFilter.Hashtag(it), TopFilter.Hashtag(it),
HashtagName(it), HashtagName(it),
route = Route.Hashtag(it), route = Route.Hashtag(it),
@@ -148,7 +152,7 @@ class TopNavFilterState(
val geotags = val geotags =
geotagList.map { geotagList.map {
TagFeedDefinition( FeedDefinition(
TopFilter.Geohash(it), TopFilter.Geohash(it),
GeoHashName(it), GeoHashName(it),
route = Route.Geohash(it), route = Route.Geohash(it),
@@ -157,14 +161,23 @@ class TopNavFilterState(
val communities = val communities =
communityList.map { communityNote -> communityList.map { communityNote ->
TagFeedDefinition( FeedDefinition(
TopFilter.Community(communityNote.address), TopFilter.Community(communityNote.address),
CommunityName(communityNote), CommunityName(communityNote),
route = Route.Community(communityNote.address.kind, communityNote.address.pubKeyHex, communityNote.address.dTag), route = Route.Community(communityNote.address.kind, communityNote.address.pubKeyHex, communityNote.address.dTag),
) )
} }
return (communities + hashtags + geotags).sortedBy { it.name.name() } val relays =
relayList.map { relayUrl ->
FeedDefinition(
TopFilter.Relay(relayUrl.url),
RelayName(relayUrl),
route = Route.RelayFeed(relayUrl.url),
)
}
return (communities + hashtags + geotags + relays).sortedBy { it.name.name() }
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@@ -173,6 +186,7 @@ class TopNavFilterState(
account.hashtagList.flow, account.hashtagList.flow,
account.geohashList.flow, account.geohashList.flow,
account.communityList.flowNotes, account.communityList.flowNotes,
account.favoriteRelayList.flow,
::mergeInterests, ::mergeInterests,
).onStart { ).onStart {
emit( emit(
@@ -180,6 +194,7 @@ class TopNavFilterState(
account.hashtagList.flow.value, account.hashtagList.flow.value,
account.geohashList.flow.value, account.geohashList.flow.value,
account.communityList.flowNotes.value, account.communityList.flowNotes.value,
account.favoriteRelayList.flow.value,
), ),
) )
} }
@@ -188,28 +203,25 @@ class TopNavFilterState(
combineTransform( combineTransform(
livePeopleListsFlow, livePeopleListsFlow,
liveInterestFlows, liveInterestFlows,
) { myLivePeopleListsFlow, myLiveKind3FollowsFlow -> ) { peopleLists, interests ->
checkNotInMainThread() checkNotInMainThread()
emit( emit(
listOf( listOf(
listOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow), listOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow),
myLivePeopleListsFlow, peopleLists,
myLiveKind3FollowsFlow, interests,
listOf(muteListFollow), listOf(muteListFollow),
).flatten().toImmutableList(), ).flatten().toImmutableList(),
) )
} }
private val _kind3GlobalPeople = private val _kind3GlobalPeople =
combineTransform( livePeopleListsFlow.transform { peopleLists ->
livePeopleListsFlow,
liveInterestFlows,
) { myLivePeopleListsFlow, myLiveKind3FollowsFlow ->
checkNotInMainThread() checkNotInMainThread()
emit( emit(
listOf( listOf(
listOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow), listOf(allFollows, userFollows, kind3Follows, aroundMe, globalFollow),
myLivePeopleListsFlow, peopleLists,
listOf(muteListFollow), listOf(muteListFollow),
).flatten().toImmutableList(), ).flatten().toImmutableList(),
) )
@@ -230,24 +242,35 @@ class TopNavFilterState(
} }
} }
@Stable
abstract class Name { abstract class Name {
abstract fun name(): String abstract fun name(): String
open fun name(context: Context) = name() open fun name(context: Context) = name()
} }
@Stable
class GeoHashName( class GeoHashName(
val geoHashTag: String, val geoHashTag: String,
) : Name() { ) : Name() {
override fun name() = "/g/$geoHashTag" override fun name() = "/g/$geoHashTag"
} }
@Stable
class HashtagName( class HashtagName(
val hashTag: String, val hashTag: String,
) : Name() { ) : Name() {
override fun name() = "#$hashTag" override fun name() = "#$hashTag"
} }
@Stable
class RelayName(
val url: NormalizedRelayUrl,
) : Name() {
override fun name() = url.displayUrl()
}
@Stable
class ResourceName( class ResourceName(
val resourceId: Int, val resourceId: Int,
) : Name() { ) : Name() {
@@ -256,6 +279,7 @@ class ResourceName(
override fun name(context: Context) = stringRes(context, resourceId) override fun name(context: Context) = stringRes(context, resourceId)
} }
@Stable
class PeopleListName( class PeopleListName(
val note: AddressableNote, val note: AddressableNote,
) : Name() { ) : Name() {
@@ -271,6 +295,7 @@ class PeopleListName(
} }
} }
@Stable
class CommunityName( class CommunityName(
val note: AddressableNote, val note: AddressableNote,
) : Name() { ) : Name() {
@@ -278,33 +303,8 @@ class CommunityName(
} }
@Immutable @Immutable
abstract class FeedDefinition( class FeedDefinition(
val code: TopFilter, val code: TopFilter,
val name: Name, val name: Name,
val route: Route?, val route: Route? = null,
) )
@Immutable
class GlobalFeedDefinition(
code: TopFilter,
name: Name,
) : FeedDefinition(code, name, null)
@Immutable
class TagFeedDefinition(
code: TopFilter,
name: Name,
route: Route?,
) : FeedDefinition(code, name, route)
@Immutable
class AroundMeFeedDefinition(
code: TopFilter,
name: Name,
) : FeedDefinition(code, name, null)
@Immutable
class PeopleListOutBoxFeedDefinition(
code: TopFilter,
name: Name,
) : FeedDefinition(code, name, null)