Shakil Karim
07/23/2021, 12:12 PM@Stable
?, I'm using MemoryCache.Key from Coil as a parameter to Composable Function, but not sure if by default it's considered Stable.Gleno
07/23/2021, 12:44 PM@Preview
annotated functions stripped from final binary?Gleno
07/23/2021, 12:45 PM@Preview
annotated function to a pdf or png?Adib Faramarzi
07/23/2021, 1:18 PMAdib Faramarzi
07/23/2021, 1:18 PMjulioromano
07/23/2021, 1:57 PMColton Idle
07/23/2021, 2:02 PMviewModel()
to compile. I've added the lifecycle compose vm dependencyRob
07/23/2021, 5:48 PMjava.lang.ClassCastException: java.lang.String cannot be cast to com.example.myapplication.MyId
when unwrapping boxed value classes in compose collectAsState
. I'm not sure if this a Compose bug or a Kotlin bug. Where should I report this?Colton Idle
07/23/2021, 6:35 PMColton Idle
07/23/2021, 8:05 PM2021-07-23 16:00:13.146 4110-4110/com.rollertoaster.app E/mylog: logged in
2021-07-23 16:00:13.218 4110-4110/com.rollertoaster.app E/mylog: logged in
Chris Fillmore
07/23/2021, 8:51 PMonNewIntent()
when using Compose Navigation? My use case is similar to e.g. OAuth authorization flow. I am redirecting back to an Activity via <intent-filter>, and starting the Activity with SINGLE_TOP. There will be a route in the new Intent, which I want to navigate to. Has anyone handled something like this?
Here’s some dummy code example of what I mean:
class MyActivity {
fun onCreate() {
setContent { MyApp() }
}
fun onNewIntent(intent: Intent) {
val route = intent.getStringExtra("redirect_route")
?? What to do with 'route'
}
}
@Composable
fun MyApp() {
val navController = rememberNavController()
MyNavHost(navController)
}
@Composable
fun MyNavHost(controller: NavController) {
NavHost(...) {
... define routes ...
}
}
Tash
07/23/2021, 10:51 PMButton
, apart from creating physical padding around it by enclosing it in a Box
etc ?Anton Dmytryshyn
07/24/2021, 7:46 AMms
07/24/2021, 9:00 AMAndroid Gradle Plugin Upgrade Assistant
dialog
Dialog says This project is using version 7.1.0-alpha03 of the Android Gradle plugin, which is incompatible with this version of Android Studio.
Using AS Canary 4Mohan
07/24/2021, 11:26 AMNacho Ruiz Martin
07/24/2021, 5:43 PMRE
07/24/2021, 5:54 PMkevindmoore
07/24/2021, 7:13 PMColton Idle
07/25/2021, 1:30 AMAdib Faramarzi
07/25/2021, 5:24 AMLocalBackDispatcher
which does not seem to be there anymore.Abhishek Dewan
07/25/2021, 7:50 AMBox(
modifier = Modifier
.width(1.dp)
.fillMaxHeight()
.background(ScoutTheme.colors.dividerColor.copy(alpha = 0.12f))
)
but I am seeing that when it's used inside a Row who's height is dynamic, nothing ever renders. If I replace the fillMaxHeight with a specific height I see it render but then I have the potential to get empty spaces since the height is specific rather than being dynamicNacho Ruiz Martin
07/25/2021, 10:49 AMursus
07/25/2021, 2:21 PMmario
07/25/2021, 3:09 PMkevindmoore
07/25/2021, 3:18 PMms
07/25/2021, 4:17 PMModalBottomSheetLayout
, is there any way to disable isHalfExpandedEnabled
'cause I want my bottom sheet to expand to it's content heightMehdi Haghgoo
07/25/2021, 5:11 PMJoey
07/25/2021, 6:28 PMJohn Ugwuadi
07/25/2021, 7:00 PMColton Idle
07/26/2021, 1:28 AMScreen1
with Screen2
and Screen3
to get an idea for my duplicated code
@Composable
fun Screen1Screen(navController: NavController, viewModel: Screen1ViewModel = hiltViewModel()) {
if (viewModel.userManagerService.loggedIn) {
ActualScreen1()
} else {
navController.navigate(Screen.SignInScreen.route)
}
}
Making sure that most screens follow the above pattern seems super error prone.Colton Idle
07/26/2021, 1:28 AMScreen1
with Screen2
and Screen3
to get an idea for my duplicated code
@Composable
fun Screen1Screen(navController: NavController, viewModel: Screen1ViewModel = hiltViewModel()) {
if (viewModel.userManagerService.loggedIn) {
ActualScreen1()
} else {
navController.navigate(Screen.SignInScreen.route)
}
}
Making sure that most screens follow the above pattern seems super error prone.Adam Powell
07/26/2021, 1:38 AMnavigate
in composables. Navigate is not idempotent. In general be suspicious of any verbs invoked on any objects that outlive the current recomposition unless those methods are specifically designed to be composition-safe. (e.g. they only mutate snapshot state.) Use the *Effect
APIs to create actors in the composition that can take action if present after composition is successful.
2. You can declare your own extensions on NavGraphBuilder
that wrap the content of a destination in some navigation preamble if you like, or simply create something like a SignedInContent
composable that accepts a content: @Composable () -> Unit
Colton Idle
07/26/2021, 1:49 AMavoid calling😭. Jeez I suck at this navigation thing. lol. If only it wasn't mission critical toin composablesnavigate
or simply create something like aOhh. That makes sense to me at least. Let me try that. That should also prevent the fact that someone could add a screen to the NavHost without thinking about whether it should behave like 99% of screens which require being SignedIn.composable that accepts aSignedInContent
content: @Composable () -> Unit
Adam Powell
07/26/2021, 1:56 AMSignedInContent
you can do something like declare a
fun NavGraphBuilder.signedInComposable(..., content: ...) {
composable(...) {
SignedInContent(..., content)
}
}
which then means when someone goes to add a screen they'll wonder why they're typing composable(...
instead of signedInComposable
like all of the other destinations in the blockif (!signedIn) {
Column {
Text("You are logged out")
Button(onClick = { navigator.navigate("signin") }) {
Text("Sign in")
}
}
}
the sign in action is taken by the user, which mutates state, which triggers recomposition. Nothing too weird.Button(onClick = onSignIn) {
Colton Idle
07/26/2021, 2:02 AMif (!signedIn) {
Column {
Text("You are logged out")
Button(onClick = { navigator.navigate("signin") }) {
Text("Sign in")
}
}
}
Breaking that apart
1. signedIn
is a mutableStateOf() right?
2. Shouldn't the onClick mutate signedIn
to false?Adam Powell
07/26/2021, 2:03 AMvar clicks by remember { mutableStateOf(0) }
Text("Clicked $clicks times")
Button(onClick = { clicks++ }) {
Text("Click me")
}
var clicks by remember { mutableStateOf(0) }
Text("Clicked $clicks times")
// A clicker robot!
LaunchedEffect(Unit) {
while (true) {
delay(1_000)
clicks++
}
}
Colton Idle
07/26/2021, 2:09 AMAdam Powell
07/26/2021, 2:11 AMButton
- it's just a button that knows how to click itself rather than waiting for a user to do it. And it doesn't have to take up space in layout or draw anything either.Colton Idle
07/26/2021, 2:15 AM@Composable
fun Profile(navController: NavController) {
/*...*/
Button(onClick = { navController.navigate("friends") }) {
Text(text = "Navigate next")
}
/*...*/
}
https://developer.android.com/jetpack/compose/navigation#nav-to-composable
So I thought... maybe it's okay to just do this on my "top most" screens?Adam Powell
07/26/2021, 2:18 AMonClick
doesn't happen during compositionColton Idle
07/26/2021, 2:21 AMsignedIn
variable which is a mutableStateOf() also falls into the category of "doesn't happen during recomposition", because I figured it wouldn't be called multiple times.Adam Powell
07/26/2021, 2:22 AMLaunchedEffect
as a kind of actor that can be present in the compositionsignedIn
variableColton Idle
07/26/2021, 2:27 AMthe key there is thatI think I already "knew" that. Basically in my head. I don't want to do anything really in a composable, because I just like to pretend that it can be called 100000 times without me even realizing. I like to operate under that assumption. SOOO I thought if I had adoesn't happen during compositiononClick
signedIn
mutableStateOf() then I thought even if my composable is called 10000000 times, then it would only actually execute once because signedIn
never actually changes.Adam Powell
07/26/2021, 2:28 AMColton Idle
07/26/2021, 2:30 AMAdam Powell
07/26/2021, 2:30 AMColton Idle
07/26/2021, 2:31 AMAdam Powell
07/26/2021, 2:33 AMNavHost
composable call to handle login states without a trampoline, but we'd have to work through all of the potentially complicated cases.Colton Idle
07/26/2021, 2:35 AMuserIsLoggedIn
as state, and was originally thinking that this means that I could probably just handle this on the activity level. i.e. Observe if userIsLoggedIn and then navigate based on that.Adam Powell
07/26/2021, 2:37 AMColton Idle
07/26/2021, 2:38 AMAdam Powell
07/26/2021, 2:43 AMdimsuz
07/26/2021, 5:25 PMAdam Powell
07/26/2021, 8:50 PMdimsuz
07/26/2021, 11:27 PMAdam Powell
07/27/2021, 12:29 AMNick
01/06/2022, 6:00 PM@Composable
fun NavGraph() {
val navController = rememberNavController()
val authenticationState =
viewModel<SignInViewModel>().authenticationState.collectAsState(initial = Unknown).value
when (authenticationState) {
is Authenticated -> {
NavHost(navController = navController, startDestination = NavRoots.ProjectRoot.route) {
projectNavigation(navController)
}
}
is Unauthenticated -> {
NavHost(navController = navController, startDestination = NavRoots.AuthRoot.route) {
authenticationNavigation(navController)
}
}
is Unknown -> Text(text = "Loading")
else -> Text(text = "else $authenticationState")
}
}
fun NavGraphBuilder.projectNavigation(navController: NavHostController) {
navigation(
startDestination = ProjectRoutes.ProjectList.route,
route = NavRoots.ProjectRoot.route
) {
composable(ProjectRoutes.ProjectList.route) {
ProjectsScreen(navController)
}
}
When I switch the navHost
via the result from the viewmodel, it’ll call navigate
under the hood, correct? So this would violate the first point that Adam made in his first message right?Adam Powell
01/06/2022, 6:25 PMNick
01/06/2022, 6:55 PMColton Idle
01/06/2022, 7:40 PMAdam Powell
01/06/2022, 9:05 PMloggedInComposable
in your NavHost
block and it's really no more cumbersomedimsuz
01/07/2022, 5:13 PM