mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-06-29 09:09:21 +02:00
No more blinking in Feeds
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
|
||||||
abstract class Card() {
|
abstract class Card() {
|
||||||
@ -37,7 +38,7 @@ class BoostSetCard(val note: Note, val boostEvents: List<Note>): Card() {
|
|||||||
|
|
||||||
sealed class CardFeedState {
|
sealed class CardFeedState {
|
||||||
object Loading: CardFeedState()
|
object Loading: CardFeedState()
|
||||||
class Loaded(val feed: List<Card>): CardFeedState()
|
class Loaded(val feed: MutableState<List<Card>>): CardFeedState()
|
||||||
object Empty: CardFeedState()
|
object Empty: CardFeedState()
|
||||||
class FeedError(val errorMessage: String): CardFeedState()
|
class FeedError(val errorMessage: String): CardFeedState()
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import androidx.compose.animation.Crossfade
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -30,8 +31,6 @@ fun CardFeedView(viewModel: CardFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
|
||||||
|
|
||||||
LaunchedEffect(isRefreshing) {
|
LaunchedEffect(isRefreshing) {
|
||||||
if (isRefreshing) {
|
if (isRefreshing) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
@ -59,21 +58,12 @@ fun CardFeedView(viewModel: CardFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CardFeedState.Loaded -> {
|
is CardFeedState.Loaded -> {
|
||||||
LazyColumn(
|
FeedLoaded(
|
||||||
contentPadding = PaddingValues(
|
state,
|
||||||
top = 10.dp,
|
accountViewModel,
|
||||||
bottom = 10.dp
|
navController,
|
||||||
),
|
routeForLastRead
|
||||||
state = listState
|
)
|
||||||
) {
|
|
||||||
itemsIndexed(state.feed, key = { _, item -> item.id() }) { index, item ->
|
|
||||||
when (item) {
|
|
||||||
is NoteCard -> NoteCompose(item.note, isInnerNote = false, accountViewModel = accountViewModel, navController = navController, routeForLastRead = routeForLastRead)
|
|
||||||
is LikeSetCard -> LikeSetCompose(item, isInnerNote = false, accountViewModel = accountViewModel, navController = navController, routeForLastRead = routeForLastRead)
|
|
||||||
is BoostSetCard -> BoostSetCompose(item, isInnerNote = false, accountViewModel = accountViewModel, navController = navController, routeForLastRead = routeForLastRead)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CardFeedState.Loading -> {
|
CardFeedState.Loading -> {
|
||||||
LoadingFeed()
|
LoadingFeed()
|
||||||
@ -83,3 +73,47 @@ fun CardFeedView(viewModel: CardFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun FeedLoaded(
|
||||||
|
state: CardFeedState.Loaded,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController,
|
||||||
|
routeForLastRead: String
|
||||||
|
) {
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
),
|
||||||
|
state = listState
|
||||||
|
) {
|
||||||
|
itemsIndexed(state.feed.value, key = { _, item -> item.id() }) { index, item ->
|
||||||
|
when (item) {
|
||||||
|
is NoteCard -> NoteCompose(
|
||||||
|
item.note,
|
||||||
|
isInnerNote = false,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
navController = navController,
|
||||||
|
routeForLastRead = routeForLastRead
|
||||||
|
)
|
||||||
|
is LikeSetCard -> LikeSetCompose(
|
||||||
|
item,
|
||||||
|
isInnerNote = false,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
navController = navController,
|
||||||
|
routeForLastRead = routeForLastRead
|
||||||
|
)
|
||||||
|
is BoostSetCard -> BoostSetCompose(
|
||||||
|
item,
|
||||||
|
isInnerNote = false,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
navController = navController,
|
||||||
|
routeForLastRead = routeForLastRead
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.screen
|
|||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
@ -43,7 +44,7 @@ class CardFeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
|||||||
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
||||||
if (newCards.isNotEmpty()) {
|
if (newCards.isNotEmpty()) {
|
||||||
lastNotes = notes
|
lastNotes = notes
|
||||||
updateFeed((oldNotesState.feed + newCards).sortedBy { it.createdAt() }.reversed())
|
updateFeed((oldNotesState.feed.value + newCards).sortedBy { it.createdAt() }.reversed())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val cards = convertToCard(notes)
|
val cards = convertToCard(notes)
|
||||||
@ -83,14 +84,20 @@ class CardFeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
|||||||
fun updateFeed(notes: List<Card>) {
|
fun updateFeed(notes: List<Card>) {
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
val currentState = feedContent.value
|
||||||
|
|
||||||
if (notes.isEmpty()) {
|
if (notes.isEmpty()) {
|
||||||
_feedContent.update { CardFeedState.Empty }
|
_feedContent.update { CardFeedState.Empty }
|
||||||
|
} else if (currentState is CardFeedState.Loaded) {
|
||||||
|
// updates the current list
|
||||||
|
currentState.feed.value = notes
|
||||||
} else {
|
} else {
|
||||||
_feedContent.update { CardFeedState.Loaded(notes) }
|
_feedContent.update { CardFeedState.Loaded(mutableStateOf(notes)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var handlerWaiting = false
|
var handlerWaiting = false
|
||||||
fun invalidateData() {
|
fun invalidateData() {
|
||||||
synchronized(handlerWaiting) {
|
synchronized(handlerWaiting) {
|
||||||
|
@ -25,7 +25,6 @@ fun ChatroomFeedView(viewModel: FeedViewModel, accountViewModel: AccountViewMode
|
|||||||
val feedState by viewModel.feedContent.collectAsState()
|
val feedState by viewModel.feedContent.collectAsState()
|
||||||
|
|
||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
@ -36,43 +35,36 @@ fun ChatroomFeedView(viewModel: FeedViewModel, accountViewModel: AccountViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SwipeRefresh(
|
Column() {
|
||||||
state = swipeRefreshState,
|
Crossfade(targetState = feedState) { state ->
|
||||||
onRefresh = {
|
when (state) {
|
||||||
isRefreshing = true
|
is FeedState.Empty -> {
|
||||||
},
|
FeedEmpty {
|
||||||
) {
|
isRefreshing = true
|
||||||
Column() {
|
}
|
||||||
Crossfade(targetState = feedState) { state ->
|
}
|
||||||
when (state) {
|
is FeedState.FeedError -> {
|
||||||
is FeedState.Empty -> {
|
FeedError(state.errorMessage) {
|
||||||
FeedEmpty {
|
isRefreshing = true
|
||||||
isRefreshing = true
|
}
|
||||||
|
}
|
||||||
|
is FeedState.Loaded -> {
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
),
|
||||||
|
reverseLayout = true,
|
||||||
|
state = listState
|
||||||
|
) {
|
||||||
|
var previousDate: String = ""
|
||||||
|
itemsIndexed(state.feed.value, key = { index, item -> if (index == 0) index else item.idHex }) { index, item ->
|
||||||
|
ChatroomMessageCompose(item, routeForLastRead, accountViewModel = accountViewModel, navController = navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FeedState.FeedError -> {
|
}
|
||||||
FeedError(state.errorMessage) {
|
FeedState.Loading -> {
|
||||||
isRefreshing = true
|
LoadingFeed()
|
||||||
}
|
|
||||||
}
|
|
||||||
is FeedState.Loaded -> {
|
|
||||||
LazyColumn(
|
|
||||||
contentPadding = PaddingValues(
|
|
||||||
top = 10.dp,
|
|
||||||
bottom = 10.dp
|
|
||||||
),
|
|
||||||
reverseLayout = true,
|
|
||||||
state = listState
|
|
||||||
) {
|
|
||||||
var previousDate: String = ""
|
|
||||||
itemsIndexed(state.feed, key = { index, item -> if (index == 0) index else item.idHex }) { index, item ->
|
|
||||||
ChatroomMessageCompose(item, routeForLastRead, accountViewModel = accountViewModel, navController = navController)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FeedState.Loading -> {
|
|
||||||
LoadingFeed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ fun ChatroomListFeedView(viewModel: FeedViewModel, accountViewModel: AccountView
|
|||||||
),
|
),
|
||||||
state = listState
|
state = listState
|
||||||
) {
|
) {
|
||||||
itemsIndexed(state.feed, key = { index, item -> item.idHex }) { index, item ->
|
itemsIndexed(state.feed.value, key = { index, item -> item.idHex }) { index, item ->
|
||||||
ChatroomCompose(item, accountViewModel = accountViewModel, navController = navController)
|
ChatroomCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
|
||||||
|
|
||||||
sealed class FeedState {
|
sealed class FeedState {
|
||||||
object Loading : FeedState()
|
object Loading : FeedState()
|
||||||
class Loaded(val feed: List<Note>) : FeedState()
|
class Loaded(val feed: MutableState<List<Note>>) : FeedState()
|
||||||
object Empty : FeedState()
|
object Empty : FeedState()
|
||||||
class FeedError(val errorMessage: String) : FeedState()
|
class FeedError(val errorMessage: String) : FeedState()
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.Button
|
||||||
@ -40,8 +41,6 @@ fun FeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, navCo
|
|||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
|
||||||
|
|
||||||
LaunchedEffect(isRefreshing) {
|
LaunchedEffect(isRefreshing) {
|
||||||
if (isRefreshing) {
|
if (isRefreshing) {
|
||||||
viewModel.hardRefresh()
|
viewModel.hardRefresh()
|
||||||
@ -49,12 +48,15 @@ fun FeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, navCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("FeedView Refresh ${feedState}")
|
||||||
|
|
||||||
SwipeRefresh(
|
SwipeRefresh(
|
||||||
state = swipeRefreshState,
|
state = swipeRefreshState,
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
isRefreshing = true
|
isRefreshing = true
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Column() {
|
Column() {
|
||||||
Crossfade(targetState = feedState) { state ->
|
Crossfade(targetState = feedState) { state ->
|
||||||
when (state) {
|
when (state) {
|
||||||
@ -69,22 +71,12 @@ fun FeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, navCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FeedState.Loaded -> {
|
is FeedState.Loaded -> {
|
||||||
LazyColumn(
|
FeedLoaded(
|
||||||
contentPadding = PaddingValues(
|
state,
|
||||||
top = 10.dp,
|
routeForLastRead,
|
||||||
bottom = 10.dp
|
accountViewModel,
|
||||||
),
|
navController
|
||||||
state = listState
|
)
|
||||||
) {
|
|
||||||
itemsIndexed(state.feed, key = { _, item -> item.idHex }) { index, item ->
|
|
||||||
NoteCompose(item,
|
|
||||||
isInnerNote = false,
|
|
||||||
routeForLastRead = routeForLastRead,
|
|
||||||
accountViewModel = accountViewModel,
|
|
||||||
navController = navController
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
FeedState.Loading -> {
|
FeedState.Loading -> {
|
||||||
LoadingFeed()
|
LoadingFeed()
|
||||||
@ -95,6 +87,34 @@ fun FeedView(viewModel: FeedViewModel, accountViewModel: AccountViewModel, navCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun FeedLoaded(
|
||||||
|
state: FeedState.Loaded,
|
||||||
|
routeForLastRead: String?,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
),
|
||||||
|
state = listState
|
||||||
|
) {
|
||||||
|
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { index, item ->
|
||||||
|
NoteCompose(
|
||||||
|
item,
|
||||||
|
isInnerNote = false,
|
||||||
|
routeForLastRead = routeForLastRead,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LoadingFeed() {
|
fun LoadingFeed() {
|
||||||
Column(
|
Column(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
@ -97,10 +98,15 @@ abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateFeed(notes: List<Note>) {
|
fun updateFeed(notes: List<Note>) {
|
||||||
|
val currentState = feedContent.value
|
||||||
|
|
||||||
if (notes.isEmpty()) {
|
if (notes.isEmpty()) {
|
||||||
_feedContent.update { FeedState.Empty }
|
_feedContent.update { FeedState.Empty }
|
||||||
|
} else if (currentState is FeedState.Loaded) {
|
||||||
|
// updates the current list
|
||||||
|
currentState.feed.value = notes
|
||||||
} else {
|
} else {
|
||||||
_feedContent.update { FeedState.Loaded(notes) }
|
_feedContent.update { FeedState.Loaded(mutableStateOf(notes)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,9 +88,9 @@ fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: A
|
|||||||
listState.animateScrollToItem(noteIdPositionInThread, 0)
|
listState.animateScrollToItem(noteIdPositionInThread, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val notePosition = state.feed.filter { it.idHex == noteId}.firstOrNull()
|
val notePosition = state.feed.value.filter { it.idHex == noteId}.firstOrNull()
|
||||||
if (notePosition != null) {
|
if (notePosition != null) {
|
||||||
noteIdPositionInThread = state.feed.indexOf(notePosition)
|
noteIdPositionInThread = state.feed.value.indexOf(notePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@ -100,7 +100,7 @@ fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: A
|
|||||||
),
|
),
|
||||||
state = listState
|
state = listState
|
||||||
) {
|
) {
|
||||||
itemsIndexed(state.feed, key = { _, item -> item.idHex }) { index, item ->
|
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { index, item ->
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
NoteMaster(item, accountViewModel = accountViewModel, navController = navController)
|
NoteMaster(item, accountViewModel = accountViewModel, navController = navController)
|
||||||
else {
|
else {
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
|
|
||||||
sealed class UserFeedState {
|
sealed class UserFeedState {
|
||||||
object Loading : UserFeedState()
|
object Loading : UserFeedState()
|
||||||
class Loaded(val feed: List<User>) : UserFeedState()
|
class Loaded(val feed: MutableState<List<User>>) : UserFeedState()
|
||||||
object Empty : UserFeedState()
|
object Empty : UserFeedState()
|
||||||
class FeedError(val errorMessage: String) : UserFeedState()
|
class FeedError(val errorMessage: String) : UserFeedState()
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import androidx.compose.animation.Crossfade
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -28,8 +29,6 @@ fun UserFeedView(viewModel: UserFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
val swipeRefreshState = rememberSwipeRefreshState(isRefreshing)
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
|
||||||
|
|
||||||
LaunchedEffect(isRefreshing) {
|
LaunchedEffect(isRefreshing) {
|
||||||
if (isRefreshing) {
|
if (isRefreshing) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
@ -57,17 +56,7 @@ fun UserFeedView(viewModel: UserFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is UserFeedState.Loaded -> {
|
is UserFeedState.Loaded -> {
|
||||||
LazyColumn(
|
FeedLoaded(state, accountViewModel, navController)
|
||||||
contentPadding = PaddingValues(
|
|
||||||
top = 10.dp,
|
|
||||||
bottom = 10.dp
|
|
||||||
),
|
|
||||||
state = listState
|
|
||||||
) {
|
|
||||||
itemsIndexed(state.feed, key = { _, item -> item.pubkeyHex }) { index, item ->
|
|
||||||
UserCompose(item, accountViewModel = accountViewModel, navController = navController)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UserFeedState.Loading -> {
|
UserFeedState.Loading -> {
|
||||||
LoadingFeed()
|
LoadingFeed()
|
||||||
@ -77,3 +66,24 @@ fun UserFeedView(viewModel: UserFeedViewModel, accountViewModel: AccountViewMode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun FeedLoaded(
|
||||||
|
state: UserFeedState.Loaded,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
top = 10.dp,
|
||||||
|
bottom = 10.dp
|
||||||
|
),
|
||||||
|
state = listState
|
||||||
|
) {
|
||||||
|
itemsIndexed(state.feed.value, key = { _, item -> item.pubkeyHex }) { index, item ->
|
||||||
|
UserCompose(item, accountViewModel = accountViewModel, navController = navController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,10 +2,12 @@ package com.vitorpamplona.amethyst.ui.screen
|
|||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.LocalCacheState
|
import com.vitorpamplona.amethyst.model.LocalCacheState
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.NostrDataSource
|
import com.vitorpamplona.amethyst.service.NostrDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrHiddenAccountsDataSource
|
import com.vitorpamplona.amethyst.service.NostrHiddenAccountsDataSource
|
||||||
@ -60,10 +62,15 @@ open class UserFeedViewModel(val dataSource: NostrDataSource<User>): ViewModel()
|
|||||||
fun updateFeed(notes: List<User>) {
|
fun updateFeed(notes: List<User>) {
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
val currentState = feedContent.value
|
||||||
|
|
||||||
if (notes.isEmpty()) {
|
if (notes.isEmpty()) {
|
||||||
_feedContent.update { UserFeedState.Empty }
|
_feedContent.update { UserFeedState.Empty }
|
||||||
|
} else if (currentState is UserFeedState.Loaded) {
|
||||||
|
// updates the current list
|
||||||
|
currentState.feed.value = notes
|
||||||
} else {
|
} else {
|
||||||
_feedContent.update { UserFeedState.Loaded(notes) }
|
_feedContent.update { UserFeedState.Loaded(mutableStateOf(notes)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
@ -425,7 +426,7 @@ fun FollowButton(onClick: () -> Unit) {
|
|||||||
backgroundColor = MaterialTheme.colors.primary
|
backgroundColor = MaterialTheme.colors.primary
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(text = "Follow", color = Color.White)
|
Text(text = "Follow", color = Color.White, textAlign = TextAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user