Increases speed of the bottom navigation by avoiding recreating ViewModels
This commit is contained in:
@@ -2,11 +2,21 @@ package com.vitorpamplona.amethyst.ui.navigation
|
|||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.GlobalFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.NostrGlobalFeedViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.BookmarkListScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.BookmarkListScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelScreen
|
||||||
@@ -30,12 +40,29 @@ fun AppNavigation(
|
|||||||
) {
|
) {
|
||||||
val homePagerState = rememberPagerState()
|
val homePagerState = rememberPagerState()
|
||||||
|
|
||||||
|
// Avoids creating ViewModels for performance reasons (up to 1 second delays)
|
||||||
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
|
val account = accountState?.account ?: return
|
||||||
|
|
||||||
|
HomeNewThreadFeedFilter.account = account
|
||||||
|
HomeConversationsFeedFilter.account = account
|
||||||
|
|
||||||
|
val homeFeedViewModel: NostrHomeFeedViewModel = viewModel()
|
||||||
|
val repliesFeedViewModel: NostrHomeRepliesFeedViewModel = viewModel()
|
||||||
|
|
||||||
|
GlobalFeedFilter.account = account
|
||||||
|
val searchFeedViewModel: NostrGlobalFeedViewModel = viewModel()
|
||||||
|
|
||||||
|
NotificationFeedFilter.account = account
|
||||||
|
val notifFeedViewModel: NotificationViewModel = viewModel()
|
||||||
|
|
||||||
NavHost(navController, startDestination = Route.Home.route) {
|
NavHost(navController, startDestination = Route.Home.route) {
|
||||||
Route.Search.let { route ->
|
Route.Search.let { route ->
|
||||||
composable(route.route, route.arguments, content = {
|
composable(route.route, route.arguments, content = {
|
||||||
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
|
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
|
||||||
|
|
||||||
SearchScreen(
|
SearchScreen(
|
||||||
|
searchFeedViewModel = searchFeedViewModel,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
navController = navController,
|
navController = navController,
|
||||||
scrollToTop = scrollToTop
|
scrollToTop = scrollToTop
|
||||||
@@ -53,6 +80,8 @@ fun AppNavigation(
|
|||||||
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
|
val scrollToTop = it.arguments?.getBoolean("scrollToTop") ?: false
|
||||||
|
|
||||||
HomeScreen(
|
HomeScreen(
|
||||||
|
homeFeedViewModel = homeFeedViewModel,
|
||||||
|
repliesFeedViewModel = repliesFeedViewModel,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
navController = navController,
|
navController = navController,
|
||||||
pagerState = homePagerState,
|
pagerState = homePagerState,
|
||||||
@@ -67,7 +96,7 @@ fun AppNavigation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
composable(Route.Message.route, content = { ChatroomListScreen(accountViewModel, navController) })
|
composable(Route.Message.route, content = { ChatroomListScreen(accountViewModel, navController) })
|
||||||
composable(Route.Notification.route, content = { NotificationScreen(accountViewModel, navController) })
|
composable(Route.Notification.route, content = { NotificationScreen(notifFeedViewModel, accountViewModel, navController) })
|
||||||
composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, navController) })
|
composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, navController) })
|
||||||
composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, navController) })
|
composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, navController) })
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
@@ -77,10 +78,46 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalTime::class)
|
||||||
|
@Composable
|
||||||
|
fun NoteCompose(
|
||||||
|
baseNote: Note,
|
||||||
|
routeForLastRead: String? = null,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
isBoostedNote: Boolean = false,
|
||||||
|
isQuotedNote: Boolean = false,
|
||||||
|
unPackReply: Boolean = true,
|
||||||
|
makeItShort: Boolean = false,
|
||||||
|
addMarginTop: Boolean = true,
|
||||||
|
parentBackgroundColor: Color? = null,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
val (value, elapsed) = measureTimedValue {
|
||||||
|
NoteComposeInner(
|
||||||
|
baseNote,
|
||||||
|
routeForLastRead,
|
||||||
|
modifier,
|
||||||
|
isBoostedNote,
|
||||||
|
isQuotedNote,
|
||||||
|
unPackReply,
|
||||||
|
makeItShort,
|
||||||
|
addMarginTop,
|
||||||
|
parentBackgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d("Time", "Note Compose in $elapsed for ${baseNote.event?.content()?.split("\n")?.get(0)?.take(100)}")
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NoteCompose(
|
fun NoteComposeInner(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
routeForLastRead: String? = null,
|
routeForLastRead: String? = null,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import com.google.accompanist.pager.HorizontalPager
|
import com.google.accompanist.pager.HorizontalPager
|
||||||
@@ -38,6 +37,8 @@ import kotlinx.coroutines.launch
|
|||||||
@OptIn(ExperimentalPagerApi::class)
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
|
homeFeedViewModel: NostrHomeFeedViewModel,
|
||||||
|
repliesFeedViewModel: NostrHomeRepliesFeedViewModel,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
pagerState: PagerState,
|
pagerState: PagerState,
|
||||||
@@ -46,12 +47,6 @@ fun HomeScreen(
|
|||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val account = accountViewModel.accountLiveData.value?.account ?: return
|
val account = accountViewModel.accountLiveData.value?.account ?: return
|
||||||
|
|
||||||
HomeNewThreadFeedFilter.account = account
|
|
||||||
HomeConversationsFeedFilter.account = account
|
|
||||||
|
|
||||||
val homeFeedViewModel: NostrHomeFeedViewModel = viewModel()
|
|
||||||
val repliesFeedViewModel: NostrHomeRepliesFeedViewModel = viewModel()
|
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel) {
|
LaunchedEffect(accountViewModel) {
|
||||||
HomeNewThreadFeedFilter.account = account
|
HomeNewThreadFeedFilter.account = account
|
||||||
HomeConversationsFeedFilter.account = account
|
HomeConversationsFeedFilter.account = account
|
||||||
@@ -64,6 +59,8 @@ fun HomeScreen(
|
|||||||
DisposableEffect(accountViewModel) {
|
DisposableEffect(accountViewModel) {
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
if (event == Lifecycle.Event.ON_RESUME) {
|
if (event == Lifecycle.Event.ON_RESUME) {
|
||||||
|
HomeNewThreadFeedFilter.account = account
|
||||||
|
HomeConversationsFeedFilter.account = account
|
||||||
NostrHomeDataSource.resetFilters()
|
NostrHomeDataSource.resetFilters()
|
||||||
homeFeedViewModel.invalidateData()
|
homeFeedViewModel.invalidateData()
|
||||||
repliesFeedViewModel.invalidateData()
|
repliesFeedViewModel.invalidateData()
|
||||||
|
|||||||
+6
-8
@@ -13,7 +13,6 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
@@ -21,22 +20,21 @@ import com.vitorpamplona.amethyst.ui.screen.CardFeedView
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NotificationScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
fun NotificationScreen(notifFeedViewModel: NotificationViewModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
val account = accountState?.account ?: return
|
val account = accountState?.account ?: return
|
||||||
|
|
||||||
NotificationFeedFilter.account = account
|
|
||||||
val feedViewModel: NotificationViewModel = viewModel()
|
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel) {
|
LaunchedEffect(accountViewModel) {
|
||||||
feedViewModel.invalidateData()
|
NotificationFeedFilter.account = account
|
||||||
|
notifFeedViewModel.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||||
DisposableEffect(accountViewModel) {
|
DisposableEffect(accountViewModel) {
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
if (event == Lifecycle.Event.ON_RESUME) {
|
if (event == Lifecycle.Event.ON_RESUME) {
|
||||||
feedViewModel.invalidateData()
|
NotificationFeedFilter.account = account
|
||||||
|
notifFeedViewModel.invalidateData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +48,7 @@ fun NotificationScreen(accountViewModel: AccountViewModel, navController: NavCon
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(vertical = 0.dp)
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
) {
|
) {
|
||||||
CardFeedView(feedViewModel, accountViewModel = accountViewModel, navController, Route.Notification.route)
|
CardFeedView(notifFeedViewModel, accountViewModel = accountViewModel, navController, Route.Notification.route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
@@ -79,6 +78,7 @@ import kotlinx.coroutines.channels.Channel as CoroutineChannel
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchScreen(
|
fun SearchScreen(
|
||||||
|
searchFeedViewModel: NostrGlobalFeedViewModel,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
scrollToTop: Boolean = false
|
scrollToTop: Boolean = false
|
||||||
@@ -88,21 +88,20 @@ fun SearchScreen(
|
|||||||
|
|
||||||
GlobalFeedFilter.account = account
|
GlobalFeedFilter.account = account
|
||||||
|
|
||||||
val feedViewModel: NostrGlobalFeedViewModel = viewModel()
|
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel) {
|
LaunchedEffect(accountViewModel) {
|
||||||
GlobalFeedFilter.account = account
|
GlobalFeedFilter.account = account
|
||||||
NostrGlobalDataSource.resetFilters()
|
NostrGlobalDataSource.resetFilters()
|
||||||
feedViewModel.invalidateData()
|
searchFeedViewModel.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(accountViewModel) {
|
DisposableEffect(accountViewModel) {
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
if (event == Lifecycle.Event.ON_RESUME) {
|
if (event == Lifecycle.Event.ON_RESUME) {
|
||||||
println("Global Start")
|
println("Global Start")
|
||||||
|
GlobalFeedFilter.account = account
|
||||||
NostrGlobalDataSource.start()
|
NostrGlobalDataSource.start()
|
||||||
NostrSearchEventOrUserDataSource.start()
|
NostrSearchEventOrUserDataSource.start()
|
||||||
feedViewModel.invalidateData()
|
searchFeedViewModel.invalidateData()
|
||||||
}
|
}
|
||||||
if (event == Lifecycle.Event.ON_PAUSE) {
|
if (event == Lifecycle.Event.ON_PAUSE) {
|
||||||
println("Global Stop")
|
println("Global Stop")
|
||||||
@@ -123,7 +122,7 @@ fun SearchScreen(
|
|||||||
modifier = Modifier.padding(vertical = 0.dp)
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
) {
|
) {
|
||||||
SearchBar(accountViewModel, navController)
|
SearchBar(accountViewModel, navController)
|
||||||
FeedView(feedViewModel, accountViewModel, navController, null, ScrollStateKeys.GLOBAL_SCREEN, scrollToTop)
|
FeedView(searchFeedViewModel, accountViewModel, navController, null, ScrollStateKeys.GLOBAL_SCREEN, scrollToTop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user