Moves navController back into Compose

Adds a listener for newIntents
Fixes the App losing the back stack of screens
This commit is contained in:
Vitor Pamplona
2023-08-01 10:39:10 -04:00
parent bd7156082b
commit a50b0b7902
4 changed files with 75 additions and 59 deletions
@@ -17,16 +17,11 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.BuildConfig
import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ServiceManager
@@ -44,7 +39,6 @@ import com.vitorpamplona.amethyst.ui.components.DefaultMutedSetting
import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
import com.vitorpamplona.amethyst.ui.navigation.debugState import com.vitorpamplona.amethyst.ui.navigation.debugState
import com.vitorpamplona.amethyst.ui.navigation.getRouteWithArguments
import com.vitorpamplona.amethyst.ui.note.Nip47 import com.vitorpamplona.amethyst.ui.note.Nip47
import com.vitorpamplona.amethyst.ui.screen.AccountScreen import com.vitorpamplona.amethyst.ui.screen.AccountScreen
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
@@ -58,8 +52,6 @@ import java.net.URLEncoder
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
lateinit var navController: NavHostController
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -75,7 +67,6 @@ class MainActivity : AppCompatActivity() {
} }
setContent { setContent {
navController = rememberNavController()
val themeViewModel: ThemeViewModel = viewModel() val themeViewModel: ThemeViewModel = viewModel()
themeViewModel.onChange(LocalPreferences.getTheme()) themeViewModel.onChange(LocalPreferences.getTheme())
@@ -86,20 +77,9 @@ class MainActivity : AppCompatActivity() {
AccountStateViewModel(this@MainActivity) AccountStateViewModel(this@MainActivity)
} }
AccountScreen(accountStateViewModel, themeViewModel, navController) AccountScreen(accountStateViewModel, themeViewModel)
} }
} }
var actionableNextPage by remember { mutableStateOf(startingPage) }
actionableNextPage?.let {
LaunchedEffect(it) {
navController.navigate(it) {
popUpTo(Route.Home.route)
launchSingleTop = true
}
}
actionableNextPage = null
}
} }
val networkRequest = NetworkRequest.Builder() val networkRequest = NetworkRequest.Builder()
@@ -161,36 +141,7 @@ class MainActivity : AppCompatActivity() {
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent) super.onNewIntent(intent)
if (this::navController.isInitialized) { println("AAA -OnNew Intent")
val uri = intent?.data?.toString()
val startingPage = uriToRoute(uri)
startingPage?.let { route ->
val currentRoute = getRouteWithArguments(navController)
if (!isSameRoute(currentRoute, route)) {
navController.navigate(route) {
popUpTo(Route.Home.route)
launchSingleTop = true
}
}
}
}
}
private fun isSameRoute(currentRoute: String?, newRoute: String): Boolean {
if (currentRoute == null) return false
if (currentRoute == newRoute) {
return true
}
if (newRoute.startsWith("Event/") && currentRoute.contains("/")) {
if (newRoute.split("/")[1] == currentRoute.split("/")[1]) {
return true
}
}
return false
} }
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
@@ -1,12 +1,22 @@
package com.vitorpamplona.amethyst.ui.navigation package com.vitorpamplona.amethyst.ui.navigation
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.util.Consumer
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.vitorpamplona.amethyst.ui.MainActivity
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
@@ -36,6 +46,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ThreadScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ThreadScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.VideoScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.VideoScreen
import com.vitorpamplona.amethyst.ui.uriToRoute
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -54,6 +65,7 @@ fun AppNavigation(
navController: NavHostController, navController: NavHostController,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
startingPage: String? = null,
themeViewModel: ThemeViewModel themeViewModel: ThemeViewModel
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -237,4 +249,58 @@ fun AppNavigation(
}) })
} }
} }
var actionableNextPage by remember { mutableStateOf(startingPage) }
actionableNextPage?.let {
LaunchedEffect(it) {
navController.navigate(it) {
popUpTo(Route.Home.route)
launchSingleTop = true
}
}
actionableNextPage = null
}
val activity = LocalContext.current.getActivity()
DisposableEffect(navController) {
val consumer = Consumer<Intent> { intent ->
val uri = intent?.data?.toString()
val newPage = uriToRoute(uri)
newPage?.let { route ->
val currentRoute = getRouteWithArguments(navController)
if (!isSameRoute(currentRoute, route)) {
navController.navigate(route) {
popUpTo(Route.Home.route)
launchSingleTop = true
}
}
}
}
activity.addOnNewIntentListener(consumer)
onDispose {
activity.removeOnNewIntentListener(consumer)
}
}
}
fun Context.getActivity(): MainActivity {
if (this is MainActivity) return this
return if (this is ContextWrapper) baseContext.getActivity() else getActivity()
}
private fun isSameRoute(currentRoute: String?, newRoute: String): Boolean {
if (currentRoute == null) return false
if (currentRoute == newRoute) {
return true
}
if (newRoute.startsWith("Event/") && currentRoute.contains("/")) {
if (newRoute.split("/")[1] == currentRoute.split("/")[1]) {
return true
}
}
return false
} }
@@ -7,7 +7,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.MainScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.MainScreen
import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginPage import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginPage
@@ -15,8 +14,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginPage
@Composable @Composable
fun AccountScreen( fun AccountScreen(
accountStateViewModel: AccountStateViewModel, accountStateViewModel: AccountStateViewModel,
themeViewModel: ThemeViewModel, themeViewModel: ThemeViewModel
navController: NavHostController
) { ) {
val accountState by accountStateViewModel.accountContent.collectAsState() val accountState by accountStateViewModel.accountContent.collectAsState()
@@ -32,7 +30,7 @@ fun AccountScreen(
factory = AccountViewModel.Factory(state.account) factory = AccountViewModel.Factory(state.account)
) )
MainScreen(accountViewModel, accountStateViewModel, themeViewModel, navController) MainScreen(accountViewModel, accountStateViewModel, themeViewModel)
} }
is AccountState.LoggedInViewOnly -> { is AccountState.LoggedInViewOnly -> {
val accountViewModel: AccountViewModel = viewModel( val accountViewModel: AccountViewModel = viewModel(
@@ -40,7 +38,7 @@ fun AccountScreen(
factory = AccountViewModel.Factory(state.account) factory = AccountViewModel.Factory(state.account)
) )
MainScreen(accountViewModel, accountStateViewModel, themeViewModel, navController) MainScreen(accountViewModel, accountStateViewModel, themeViewModel)
} }
} }
} }
@@ -24,11 +24,12 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.vitorpamplona.amethyst.ui.buttons.ChannelFabColumn import com.vitorpamplona.amethyst.ui.buttons.ChannelFabColumn
import com.vitorpamplona.amethyst.ui.buttons.NewCommunityNoteButton import com.vitorpamplona.amethyst.ui.buttons.NewCommunityNoteButton
import com.vitorpamplona.amethyst.ui.buttons.NewImageButton import com.vitorpamplona.amethyst.ui.buttons.NewImageButton
@@ -60,8 +61,7 @@ import kotlinx.coroutines.launch
fun MainScreen( fun MainScreen(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
accountStateViewModel: AccountStateViewModel, accountStateViewModel: AccountStateViewModel,
themeViewModel: ThemeViewModel, themeViewModel: ThemeViewModel
navController: NavHostController
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed)) val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed))
@@ -71,6 +71,7 @@ fun MainScreen(
skipHalfExpanded = true skipHalfExpanded = true
) )
val navController = rememberNavController()
val navState = navController.currentBackStackEntryAsState() val navState = navController.currentBackStackEntryAsState()
val nav = remember(navController) { val nav = remember(navController) {