mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-19 21:31:17 +02:00
Saves the position of the Notification feed
This commit is contained in:
@@ -53,13 +53,9 @@ fun AppNavigation(
|
||||
GlobalFeedFilter.account = account
|
||||
val searchFeedViewModel: NostrGlobalFeedViewModel = viewModel()
|
||||
|
||||
val restartNotificationList = NotificationFeedFilter.isDifferentAccount(account)
|
||||
|
||||
NotificationFeedFilter.account = account
|
||||
val notifFeedViewModel: NotificationViewModel = viewModel()
|
||||
|
||||
if (restartNotificationList) notifFeedViewModel.clear()
|
||||
|
||||
NavHost(navController, startDestination = Route.Home.route) {
|
||||
Route.Search.let { route ->
|
||||
composable(route.route, route.arguments, content = {
|
||||
@@ -99,8 +95,25 @@ fun AppNavigation(
|
||||
})
|
||||
}
|
||||
|
||||
Route.Notification.let { route ->
|
||||
composable(route.route, route.arguments, content = {
|
||||
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
|
||||
|
||||
NotificationScreen(
|
||||
notifFeedViewModel = notifFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
|
||||
// Avoids running scroll to top when back button is pressed
|
||||
if (scrollToTop) {
|
||||
it.arguments?.remove("scrollToTop")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
composable(Route.Message.route, content = { ChatroomListScreen(accountViewModel, navController) })
|
||||
composable(Route.Notification.route, content = { NotificationScreen(notifFeedViewModel, accountViewModel, navController) })
|
||||
composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, navController) })
|
||||
composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, navController) })
|
||||
|
||||
|
@@ -37,8 +37,9 @@ sealed class Route(
|
||||
)
|
||||
|
||||
object Notification : Route(
|
||||
route = "Notification",
|
||||
route = "Notification?scrollToTop={scrollToTop}",
|
||||
icon = R.drawable.ic_notifications,
|
||||
arguments = listOf(navArgument("scrollToTop") { type = NavType.BoolType; defaultValue = false }),
|
||||
hasNewItems = { accountViewModel, cache -> notificationHasNewItems(accountViewModel, cache) }
|
||||
)
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -33,7 +34,14 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun CardFeedView(viewModel: CardFeedViewModel, accountViewModel: AccountViewModel, navController: NavController, routeForLastRead: String) {
|
||||
fun CardFeedView(
|
||||
viewModel: CardFeedViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
routeForLastRead: String,
|
||||
scrollStateKey: String? = null,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val feedState by viewModel.feedContent.collectAsState()
|
||||
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
@@ -57,10 +65,12 @@ fun CardFeedView(viewModel: CardFeedViewModel, accountViewModel: AccountViewMode
|
||||
is CardFeedState.Loaded -> {
|
||||
refreshing = false
|
||||
FeedLoaded(
|
||||
state,
|
||||
accountViewModel,
|
||||
navController,
|
||||
routeForLastRead
|
||||
state = state,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = routeForLastRead,
|
||||
scrollStateKey = scrollStateKey,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
}
|
||||
CardFeedState.Loading -> {
|
||||
@@ -79,9 +89,21 @@ private fun FeedLoaded(
|
||||
state: CardFeedState.Loaded,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
routeForLastRead: String
|
||||
routeForLastRead: String,
|
||||
scrollStateKey: String?,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val listState = if (scrollStateKey != null) {
|
||||
rememberForeverLazyListState(scrollStateKey)
|
||||
} else {
|
||||
rememberLazyListState()
|
||||
}
|
||||
|
||||
if (scrollToTop) {
|
||||
LaunchedEffect(Unit) {
|
||||
listState.scrollToItem(index = 0)
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(
|
||||
|
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.screen
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.LocalCacheState
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
@@ -32,6 +33,7 @@ open class CardFeedViewModel(val dataSource: FeedFilter<Note>) : ViewModel() {
|
||||
private val _feedContent = MutableStateFlow<CardFeedState>(CardFeedState.Loading)
|
||||
val feedContent = _feedContent.asStateFlow()
|
||||
|
||||
private var lastAccount: Account? = null
|
||||
private var lastNotes: List<Note>? = null
|
||||
|
||||
private fun refresh() {
|
||||
@@ -45,18 +47,21 @@ open class CardFeedViewModel(val dataSource: FeedFilter<Note>) : ViewModel() {
|
||||
private fun refreshSuspended() {
|
||||
val notes = dataSource.loadTop()
|
||||
|
||||
val lastNotesCopy = lastNotes
|
||||
val thisAccount = (dataSource as? NotificationFeedFilter)?.account
|
||||
val lastNotesCopy = if (thisAccount == lastAccount) lastNotes else null
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
|
||||
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
||||
if (newCards.isNotEmpty()) {
|
||||
lastNotes = notes
|
||||
lastAccount = (dataSource as? NotificationFeedFilter)?.account
|
||||
updateFeed((oldNotesState.feed.value + newCards).distinctBy { it.id() }.sortedBy { it.createdAt() }.reversed())
|
||||
}
|
||||
} else {
|
||||
val cards = convertToCard(notes)
|
||||
lastNotes = notes
|
||||
lastAccount = (dataSource as? NotificationFeedFilter)?.account
|
||||
updateFeed(cards)
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ private data class ScrollState(val index: Int, val scrollOffset: Int)
|
||||
|
||||
object ScrollStateKeys {
|
||||
const val GLOBAL_SCREEN = "Global"
|
||||
const val NOTIFICATION_SCREEN = "Notifications"
|
||||
val HOME_FOLLOWS = Route.Home.base + "Follows"
|
||||
val HOME_REPLIES = Route.Home.base + "FollowsReplies"
|
||||
}
|
||||
|
@@ -18,9 +18,15 @@ import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.screen.CardFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
|
||||
|
||||
@Composable
|
||||
fun NotificationScreen(notifFeedViewModel: NotificationViewModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
fun NotificationScreen(
|
||||
notifFeedViewModel: NotificationViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
scrollToTop: Boolean = false
|
||||
) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
@@ -48,7 +54,14 @@ fun NotificationScreen(notifFeedViewModel: NotificationViewModel, accountViewMod
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
CardFeedView(notifFeedViewModel, accountViewModel = accountViewModel, navController, Route.Notification.route)
|
||||
CardFeedView(
|
||||
viewModel = notifFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
routeForLastRead = Route.Notification.base,
|
||||
scrollStateKey = ScrollStateKeys.NOTIFICATION_SCREEN,
|
||||
scrollToTop = scrollToTop
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
app/src/main/res/drawable/alby.xml
Normal file
39
app/src/main/res/drawable/alby.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="250dp"
|
||||
android:height="250dp"
|
||||
android:viewportWidth="250"
|
||||
android:viewportHeight="250">
|
||||
<path
|
||||
android:pathData="M48.12,70.63m18.75,0a18.75,18.75 0,1 0,-37.5 0a18.75,18.75 0,1 0,37.5 0"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M45,67.82L80,102.82"
|
||||
android:strokeWidth="9.37484"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M201.25,70.63m-18.75,0a18.75,18.75 0,1 1,37.5 0a18.75,18.75 0,1 1,-37.5 0"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M204.68,67.82L169.68,102.82"
|
||||
android:strokeWidth="9.37484"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M53.45,182.51C43.34,177.7 37.46,166.9 39.43,155.88C47.89,108.59 83.12,73.13 125.31,73.13C167.6,73.13 202.91,108.77 211.25,156.23C213.19,167.26 207.26,178.06 197.12,182.83C175.43,193.04 151.19,198.75 125.62,198.75C99.79,198.75 75.32,192.92 53.45,182.51Z"
|
||||
android:fillColor="#FFDF6F"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M211.25,156.23L206.64,157.04L211.25,156.23ZM53.45,182.51L51.43,186.74L53.45,182.51ZM44.04,156.71C52.21,111.01 85.99,77.82 125.31,77.82V68.44C80.26,68.44 43.56,106.17 34.82,155.06L44.04,156.71ZM125.31,77.82C164.73,77.82 198.57,111.18 206.64,157.04L215.87,155.41C207.24,106.36 170.47,68.44 125.31,68.44V77.82ZM195.13,178.59C174.04,188.51 150.49,194.06 125.62,194.06V203.44C151.9,203.44 176.81,197.57 199.12,187.07L195.13,178.59ZM125.62,194.06C100.5,194.06 76.71,188.4 55.46,178.28L51.43,186.74C73.92,197.45 99.08,203.44 125.62,203.44V194.06ZM206.64,157.04C208.19,165.89 203.45,174.67 195.13,178.59L199.12,187.07C211.07,181.45 218.2,168.64 215.87,155.41L206.64,157.04ZM34.82,155.06C32.45,168.26 39.52,181.07 51.43,186.74L55.46,178.28C47.16,174.33 42.46,165.54 44.04,156.71L34.82,155.06Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M71.48,170.76C63.34,167.44 58.52,158.79 61.34,150.47C70.03,124.82 95.38,106.25 125.31,106.25C155.24,106.25 180.59,124.82 189.29,150.47C192.1,158.79 187.28,167.44 179.14,170.76C162.53,177.52 144.36,181.25 125.31,181.25C106.26,181.25 88.09,177.52 71.48,170.76Z"
|
||||
android:fillColor="#000000"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M131.25,146.25a15.62,12.5 0,1 0,31.25 0a15.62,12.5 0,1 0,-31.25 0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M86.52,146.26a15.62,12.5 0,1 0,31.25 0a15.62,12.5 0,1 0,-31.25 0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
Reference in New Issue
Block a user