Skip to content

Commit

Permalink
Rework new posts button logic
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandarIlic committed Jun 18, 2024
1 parent bdfcf9b commit 4da9842
Show file tree
Hide file tree
Showing 11 changed files with 1,710 additions and 206 deletions.
1,355 changes: 1,355 additions & 0 deletions app/schemas/net.primal.android.db.PrimalDatabase/29.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package net.primal.android.core.compose.feed.model
import net.primal.android.attachments.domain.CdnImage

data class FeedPostsSyncStats(
val postsCount: Int = 0,
val postIds: List<String> = emptyList(),
val avatarCdnImages: List<CdnImage> = emptyList(),
val latestNoteIds: List<String> = emptyList(),
val latestAvatarCdnImages: List<CdnImage> = emptyList(),
)
7 changes: 1 addition & 6 deletions app/src/main/kotlin/net/primal/android/db/PrimalDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import net.primal.android.feed.db.FeedPostDataCrossRef
import net.primal.android.feed.db.FeedPostDataCrossRefDao
import net.primal.android.feed.db.FeedPostRemoteKey
import net.primal.android.feed.db.FeedPostRemoteKeyDao
import net.primal.android.feed.db.FeedPostSync
import net.primal.android.feed.db.FeedPostSyncDao
import net.primal.android.feed.db.PostDao
import net.primal.android.feed.db.PostData
import net.primal.android.feed.db.RepostDao
Expand Down Expand Up @@ -67,7 +65,6 @@ import net.primal.android.wallet.db.WalletTransactionData
Feed::class,
FeedPostDataCrossRef::class,
FeedPostRemoteKey::class,
FeedPostSync::class,
ThreadConversationCrossRef::class,
NoteUserStats::class,
ProfileStats::class,
Expand All @@ -81,7 +78,7 @@ import net.primal.android.wallet.db.WalletTransactionData
EventHints::class,
ProfileInteraction::class,
],
version = 28,
version = 29,
exportSchema = true,
)
@TypeConverters(
Expand All @@ -108,8 +105,6 @@ abstract class PrimalDatabase : RoomDatabase() {

abstract fun feedPostsRemoteKeys(): FeedPostRemoteKeyDao

abstract fun feedPostsSync(): FeedPostSyncDao

abstract fun conversationConnections(): ThreadConversationCrossRefDao

abstract fun threadConversations(): ThreadConversationDao
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface FeedContract {
val syncStats: FeedPostsSyncStats = FeedPostsSyncStats(),
val badges: Badges = Badges(),
val confirmBookmarkingNoteId: String? = null,
val topVisibleNote: Pair<String, String?>? = null,
val error: FeedError? = null,
) {
sealed class FeedError {
Expand All @@ -36,6 +37,10 @@ interface FeedContract {
sealed class UiEvent {
data object FeedScrolledToTop : UiEvent()
data object RequestUserDataUpdate : UiEvent()
data object StartPolling : UiEvent()
data object StopPolling : UiEvent()
data object ShowLatestNotes : UiEvent()
data class UpdateCurrentTopVisibleNote(val noteId: String, val repostId: String? = null) : UiEvent()
data class PostLikeAction(val postId: String, val postAuthorId: String) : UiEvent()
data class RepostAction(
val postId: String,
Expand Down
75 changes: 55 additions & 20 deletions app/src/main/kotlin/net/primal/android/discuss/feed/FeedScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -39,8 +41,14 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.paging.compose.collectAsLazyPagingItems
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.primal.android.LocalContentDisplaySettings
import net.primal.android.R
import net.primal.android.core.compose.AppBarIcon
Expand Down Expand Up @@ -85,8 +93,17 @@ fun FeedScreen(
val uiState = viewModel.state.collectAsState()

DisposableLifecycleObserverEffect(viewModel) {
if (it == Lifecycle.Event.ON_START) {
viewModel.setEvent(FeedContract.UiEvent.RequestUserDataUpdate)
when (it) {
Lifecycle.Event.ON_START -> {
viewModel.setEvent(FeedContract.UiEvent.RequestUserDataUpdate)
viewModel.setEvent(FeedContract.UiEvent.StartPolling)
}

Lifecycle.Event.ON_STOP -> {
viewModel.setEvent(FeedContract.UiEvent.StopPolling)
}

else -> Unit
}
}

Expand Down Expand Up @@ -129,14 +146,27 @@ fun FeedScreen(
val uiScope = rememberCoroutineScope()
val drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed)

val feedPagingItems = state.posts.collectAsLazyPagingItems()
val feedListState = feedPagingItems.rememberLazyListStatePagingWorkaround()
val pagingItems = state.posts.collectAsLazyPagingItems()
val feedListState = pagingItems.rememberLazyListStatePagingWorkaround()

val snackbarHostState = remember { SnackbarHostState() }

val canScrollUp by remember(feedListState) {
derivedStateOf {
feedListState.firstVisibleItemIndex > 0
LaunchedEffect(feedListState, pagingItems) {
withContext(Dispatchers.IO) {
snapshotFlow { feedListState.firstVisibleItemIndex to pagingItems.itemCount }
.distinctUntilChanged()
.filter { (_, size) -> size > 0 }
.collect { (index, _) ->
val firstVisibleNote = pagingItems.peek(index)
if (firstVisibleNote != null) {
eventPublisher(
FeedContract.UiEvent.UpdateCurrentTopVisibleNote(
noteId = firstVisibleNote.postId,
repostId = firstVisibleNote.repostId,
),
)
}
}
}
}

Expand Down Expand Up @@ -169,7 +199,7 @@ fun FeedScreen(
onDrawerDestinationClick = onDrawerDestinationClick,
onDrawerQrCodeClick = onDrawerQrCodeClick,
badges = state.badges,
focusModeEnabled = LocalContentDisplaySettings.current.focusModeEnabled && feedPagingItems.isNotEmpty(),
focusModeEnabled = LocalContentDisplaySettings.current.focusModeEnabled && pagingItems.isNotEmpty(),
topBar = {
PrimalTopAppBar(
title = state.feedTitle,
Expand All @@ -190,7 +220,7 @@ fun FeedScreen(
},
content = { paddingValues ->
FeedNoteList(
pagingItems = feedPagingItems,
pagingItems = pagingItems,
feedListState = feedListState,
zappingState = state.zappingState,
onPostClick = onPostClick,
Expand Down Expand Up @@ -244,15 +274,20 @@ fun FeedScreen(
)
},
floatingNewDataHost = {
if (canScrollUp && state.syncStats.postsCount > 0) {
NewPostsButton(
syncStats = state.syncStats,
onClick = {
uiScope.launch {
feedListState.animateScrollToItem(0)
}
},
)
if (state.syncStats.latestNoteIds.isNotEmpty() && pagingItems.isNotEmpty()) {
var doneDelaying by remember { mutableStateOf(false) }
LaunchedEffect(true) {
delay(0.21.seconds)
doneDelaying = true
}
if (doneDelaying) {
NewPostsButton(
syncStats = state.syncStats,
onClick = {
eventPublisher(FeedContract.UiEvent.ShowLatestNotes)
},
)
}
}
},
floatingActionButton = {
Expand Down Expand Up @@ -294,7 +329,7 @@ private fun NewPostsButton(syncStats: FeedPostsSyncStats, onClick: () -> Unit) {
) {
AvatarThumbnailsRow(
modifier = Modifier.padding(start = 6.dp),
avatarCdnImages = syncStats.avatarCdnImages,
avatarCdnImages = syncStats.latestAvatarCdnImages,
onClick = { onClick() },
)

Expand Down
Loading

0 comments on commit 4da9842

Please sign in to comment.