Add list following logic
This commit is contained in:
1 parent
1f193af805
commit
c7a8f17dd4
6 files changed
+269
-15
No files matched your search
+3
-7
@@ -1,15 +1,13 @@
|
|||||||
package ac.cord.auxiliary.compose.database.dao
|
package ac.cord.auxiliary.compose.database.dao
|
||||||
|
|
||||||
import ac.cord.auxiliary.compose.database.model.Connection
|
import ac.cord.auxiliary.compose.database.model.Connection
|
||||||
import ac.cord.auxiliary.compose.database.model.Profile
|
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowers
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowers
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowing
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowing
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Upsert
|
import androidx.room.Upsert
|
||||||
import fr.acinq.bitcoin.PublicKey
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface ConnectionDao {
|
interface ConnectionDao {
|
||||||
@@ -17,13 +15,11 @@ interface ConnectionDao {
|
|||||||
fun getAllConnections(limit: Int = 21): List<Connection>
|
fun getAllConnections(limit: Int = 21): List<Connection>
|
||||||
|
|
||||||
@Query("SELECT * FROM Connection WHERE sourcePublicKey = :sourcePublicKey")
|
@Query("SELECT * FROM Connection WHERE sourcePublicKey = :sourcePublicKey")
|
||||||
fun getPublicKeyFollowing(sourcePublicKey: String): LocalFollowing?
|
fun observePublicKeyFollowing(sourcePublicKey: String): Flow<LocalFollowing?>
|
||||||
|
|
||||||
@Query("SELECT * FROM Connection WHERE destinationPublicKey = :destinationPublicKey")
|
@Query("SELECT * FROM Connection WHERE destinationPublicKey = :destinationPublicKey")
|
||||||
fun getPublicKeyFollowers(destinationPublicKey: String): LocalFollowers?
|
fun observePublicKeyFollowers(destinationPublicKey: String): Flow<LocalFollowers?>
|
||||||
|
|
||||||
@Query("SELECT * FROM Connection WHERE destinationPublicKey = :destinationPublicKey")
|
|
||||||
fun observe(destinationPublicKey: String): LocalFollowers?
|
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertPlaceholderProfile(connection: Connection)
|
suspend fun insertPlaceholderProfile(connection: Connection)
|
||||||
|
|||||||
+9
@@ -13,6 +13,8 @@ import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent
|
|||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalBroadcastNostrEventRequest
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalBroadcastNostrEventRequest
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalAccount
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalAccount
|
||||||
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowers
|
||||||
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowing
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
|
||||||
import ac.cord.auxiliary.compose.database.model.typealiases.SynchronizationFilterArray
|
import ac.cord.auxiliary.compose.database.model.typealiases.SynchronizationFilterArray
|
||||||
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||||
@@ -372,6 +374,13 @@ class DatabaseNostrRepository(
|
|||||||
return database.profileDao().filterProfiles(searchTerm = searchTerm)
|
return database.profileDao().filterProfiles(searchTerm = searchTerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun observeProfileFollowers(publicKey: String): Flow<LocalFollowers?> {
|
||||||
|
return database.connectionDao().observePublicKeyFollowers(publicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun observeProfileFollowing(publicKey: String): Flow<LocalFollowing?> {
|
||||||
|
return database.connectionDao().observePublicKeyFollowing(publicKey)
|
||||||
|
}
|
||||||
override suspend fun getRecentSearches(): List<RecentSearch> {
|
override suspend fun getRecentSearches(): List<RecentSearch> {
|
||||||
return database.recentSearchDao().getAllRecentSearches()
|
return database.recentSearchDao().getAllRecentSearches()
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -10,6 +10,8 @@ import ac.cord.auxiliary.compose.database.model.UnsignedNostrEvent
|
|||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalBroadcastNostrEventRequest
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalBroadcastNostrEventRequest
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalAccount
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalAccount
|
||||||
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowers
|
||||||
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalFollowing
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalProfile
|
||||||
import ac.cord.auxiliary.compose.database.model.typealiases.SynchronizationFilterArray
|
import ac.cord.auxiliary.compose.database.model.typealiases.SynchronizationFilterArray
|
||||||
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||||
@@ -81,6 +83,10 @@ interface NostrRepository {
|
|||||||
|
|
||||||
suspend fun filterProfiles(searchTerm: String): List<LocalProfile>
|
suspend fun filterProfiles(searchTerm: String): List<LocalProfile>
|
||||||
|
|
||||||
|
suspend fun observeProfileFollowing(publicKey: String): Flow<LocalFollowing?>
|
||||||
|
|
||||||
|
suspend fun observeProfileFollowers(publicKey: String): Flow<LocalFollowers?>
|
||||||
|
|
||||||
suspend fun getRecentSearches(): List<RecentSearch>
|
suspend fun getRecentSearches(): List<RecentSearch>
|
||||||
|
|
||||||
suspend fun removeRecentSearch(recentSearch: RecentSearch)
|
suspend fun removeRecentSearch(recentSearch: RecentSearch)
|
||||||
@@ -190,6 +196,14 @@ interface NostrRepository {
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun observeProfileFollowing(publicKey: String): Flow<LocalFollowing?> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun observeProfileFollowers(publicKey: String): Flow<LocalFollowers?> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getRecentSearches(): List<RecentSearch> {
|
override suspend fun getRecentSearches(): List<RecentSearch> {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-8
@@ -4,26 +4,23 @@ import ac.cord.auxiliary.compose.database.model.NostrEvent
|
|||||||
import ac.cord.auxiliary.compose.database.model.Profile
|
import ac.cord.auxiliary.compose.database.model.Profile
|
||||||
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent
|
||||||
import ac.cord.auxiliary.compose.repository.NostrRepository
|
import ac.cord.auxiliary.compose.repository.NostrRepository
|
||||||
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.NostrEventDetailRoute
|
|
||||||
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route
|
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route
|
||||||
import ac.cord.auxiliary.compose.ui.composable.widgets.feed.ListView
|
|
||||||
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
|
import ac.cord.auxiliary.compose.ui.theme.AuxTheme
|
||||||
import ac.cord.auxiliary.compose.ui.view.model.FeedListViewModel
|
import ac.cord.auxiliary.compose.ui.view.model.FeedListViewModel
|
||||||
|
import ac.cord.auxiliary.compose.ui.view.model.FollowingListViewModel
|
||||||
import ac.cord.auxiliary.compose.ui.view.model.MetadataEventDetailType
|
import ac.cord.auxiliary.compose.ui.view.model.MetadataEventDetailType
|
||||||
import ac.cord.auxiliary.compose.ui.view.model.MetadataEventDetailViewModel
|
import ac.cord.auxiliary.compose.ui.view.model.MetadataEventDetailViewModel
|
||||||
import ac.cord.auxiliary.compose.ui.view.model.SearchResultType
|
|
||||||
import ac.cord.auxiliary.compose.ui.view.state.FeedListUIState
|
import ac.cord.auxiliary.compose.ui.view.state.FeedListUIState
|
||||||
|
import ac.cord.auxiliary.compose.ui.view.state.FollowingListUIState
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -36,7 +33,6 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LargeTopAppBar
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.LoadingIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.PrimaryScrollableTabRow
|
import androidx.compose.material3.PrimaryScrollableTabRow
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
@@ -46,7 +42,6 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.key
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -238,8 +233,22 @@ fun MetadataEventDetail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
MetadataEventDetailType.Following -> {
|
MetadataEventDetailType.Following -> {
|
||||||
|
val followingListViewModel: FollowingListViewModel = viewModel(
|
||||||
|
key = metadataEventDetailType.name,
|
||||||
|
factory = FollowingListViewModel.factory(
|
||||||
|
initialFeedListUIState = FollowingListUIState.Loading,
|
||||||
|
publicKey = localNostrEvent.nostrEvent.pubKey,
|
||||||
|
synchronizationFilter = metadataEventDetailViewModel.getSynchronizationFilter(metadataEventDetailType),
|
||||||
|
nostrRepository = nostrRepository
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
Text("Implementing logic to see following")
|
|
||||||
|
key(followingListViewModel.followingListUIState) {
|
||||||
|
followingListViewModel.RenderFeed(
|
||||||
|
onNavigateToEvent = onNavigateToEvent
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MetadataEventDetailType.Followers -> {
|
MetadataEventDetailType.Followers -> {
|
||||||
|
|
||||||
|
|||||||
Executable
+213
@@ -0,0 +1,213 @@
|
|||||||
|
package ac.cord.auxiliary.compose.ui.view.model
|
||||||
|
|
||||||
|
import ac.cord.auxiliary.compose.database.model.SynchronizeNostrEventRequest
|
||||||
|
import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter
|
||||||
|
import ac.cord.auxiliary.compose.nostr.Relays
|
||||||
|
import ac.cord.auxiliary.compose.repository.NostrRepository
|
||||||
|
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.NostrEventDetailRoute
|
||||||
|
import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route
|
||||||
|
import ac.cord.auxiliary.compose.ui.composable.widgets.feed.ListView
|
||||||
|
import ac.cord.auxiliary.compose.ui.view.state.FollowingListUIState
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.LoadingIndicator
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
|
import co.touchlab.kermit.Logger
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.IO
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class FollowingListViewModel(
|
||||||
|
initialFollowingListUIState: FollowingListUIState,
|
||||||
|
val publicKey: String,
|
||||||
|
val synchronizationFilter: SynchronizationFilter,
|
||||||
|
val nostrRepository: NostrRepository
|
||||||
|
): ViewModel() {
|
||||||
|
val logger = Logger.withTag(TAG)
|
||||||
|
var followingListUIState: FollowingListUIState by mutableStateOf(initialFollowingListUIState)
|
||||||
|
private set
|
||||||
|
|
||||||
|
val isSynchronizationPending: MutableState<Boolean> = mutableStateOf(false)
|
||||||
|
|
||||||
|
init {
|
||||||
|
logger.d("init")
|
||||||
|
scheduleSynchronization()
|
||||||
|
observeLocalNostrFeed()
|
||||||
|
observeSynchronizeNostrEventRequestByPurposeAndStatusCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun observeLocalNostrFeed() {
|
||||||
|
logger.d("observeLocalNostrFeed")
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
nostrRepository.observeProfileFollowing(
|
||||||
|
publicKey
|
||||||
|
).collect { localFollowing ->
|
||||||
|
followingListUIState = FollowingListUIState.Loaded(
|
||||||
|
profilesBeingFollowed = localFollowing?.following ?: emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scheduleSynchronization() {
|
||||||
|
logger.d("scheduleSynchronization")
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
// Sync Notifications... might want to also run this in the background
|
||||||
|
nostrRepository.queueSynchronizeNostrEvent(
|
||||||
|
Relays.eventPublishRelaySet.take(1).map { normalizedRelay -> // TODO: Sync from all the publish relays...
|
||||||
|
SynchronizeNostrEventRequest(
|
||||||
|
purpose = "feed",
|
||||||
|
synchronizationFilters = arrayOf(
|
||||||
|
synchronizationFilter
|
||||||
|
),
|
||||||
|
relayURL = normalizedRelay.url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun observeSynchronizeNostrEventRequestByPurposeAndStatusCount() {
|
||||||
|
logger.d("observeSynchronizeNostrEventRequestByPurposeAndStatusCount")
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
nostrRepository.observeSynchronizeNostrEventRequestByPurposeAndStatusCount("feed").collect { count ->
|
||||||
|
logger.d("Pending/Processing Synchronization Request: $count")
|
||||||
|
isSynchronizationPending.value = count > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
|
@Composable
|
||||||
|
fun RenderFeed(
|
||||||
|
onNavigateToEvent: (Route) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
when (val feedListUIState = followingListUIState) {
|
||||||
|
FollowingListUIState.Error -> {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier.height(50.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Something went wrong",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is FollowingListUIState.Loaded -> {
|
||||||
|
if (feedListUIState.profilesBeingFollowed.isEmpty()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier.height(50.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "No events were found",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = feedListUIState.profilesBeingFollowed,
|
||||||
|
key = { profile -> profile.publicKey }
|
||||||
|
) { profile ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onNavigateToEvent.invoke(
|
||||||
|
NostrEventDetailRoute(
|
||||||
|
profile.nostrEventId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = profile.displayName ?: profile.userName ?: profile.userName ?: profile.publicKey
|
||||||
|
)
|
||||||
|
|
||||||
|
profile.nip05?.let {
|
||||||
|
Text(
|
||||||
|
text = profile.nip05
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
FollowingListUIState.Loading -> {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier.height(50.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Loading",
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier.height(50.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
LoadingIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "FeedListViewModel"
|
||||||
|
|
||||||
|
fun factory(
|
||||||
|
initialFeedListUIState: FollowingListUIState = FollowingListUIState.Loading,
|
||||||
|
publicKey: String,
|
||||||
|
synchronizationFilter: SynchronizationFilter,
|
||||||
|
nostrRepository: NostrRepository,
|
||||||
|
): ViewModelProvider.Factory = viewModelFactory {
|
||||||
|
initializer {
|
||||||
|
FollowingListViewModel(
|
||||||
|
initialFollowingListUIState = initialFeedListUIState,
|
||||||
|
publicKey = publicKey,
|
||||||
|
synchronizationFilter = synchronizationFilter,
|
||||||
|
nostrRepository = nostrRepository
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package ac.cord.auxiliary.compose.ui.view.state
|
||||||
|
|
||||||
|
import ac.cord.auxiliary.compose.database.model.Profile
|
||||||
|
|
||||||
|
sealed interface FollowingListUIState {
|
||||||
|
data class Loaded(
|
||||||
|
val profilesBeingFollowed: List<Profile>
|
||||||
|
): FollowingListUIState
|
||||||
|
|
||||||
|
data object Error: FollowingListUIState
|
||||||
|
data object Loading: FollowingListUIState
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user