Mark
01/31/2024, 8:51 AMJoel Denke
01/31/2024, 9:00 AMMark
01/31/2024, 9:13 AMJoel Denke
01/31/2024, 10:12 AMJoel Denke
01/31/2024, 10:13 AMModalNavigationDrawer(
drawerContent = {
ModalDrawerSheet {
Text("Drawer title", modifier = Modifier.padding(16.dp))
Divider()
NavigationDrawerItem(
label = { Text(text = "Drawer Item") },
selected = false,
onClick = { /*TODO*/ }
)
// ...other drawer items
}
}
) {
// Screen content
}
More samples here https://developer.android.com/jetpack/compose/components/drawerJoel Denke
01/31/2024, 10:15 AMMark
01/31/2024, 10:19 AMModalDrawerSheet is M3 so I can’t use that now. Migration is rather tricky. Like I mentioned, I’ve migrated all Fragments to essentially be shell fragments calling screen composables. So it’s all about the main activity and migrating that now. Current strategy is to migrate the navigation drawer to Compose and programmatically navigate from there, which I guess is what you are recommending too.Joel Denke
01/31/2024, 10:37 AMJoel Denke
01/31/2024, 10:40 AMMark
01/31/2024, 10:42 AMJoel Denke
01/31/2024, 10:47 AMJoel Denke
01/31/2024, 11:20 AMStylianos Gakis
01/31/2024, 5:00 PMMark
02/01/2024, 2:45 AMMark
02/03/2024, 10:57 AMMdcTheme to Material 2 Theme?Stylianos Gakis
02/03/2024, 11:59 AMMark
02/03/2024, 12:21 PMMark
02/03/2024, 1:15 PM<resources>
<item type="color" name="colorPrimary" />
...
</resources>
and each variant (perhaps in the top level app module) would provide it’s own values and those could be picked up in any module.
But how to do the same thing with composables? CompositionLocalProvider?
EDIT: CompositionLocal doesn’t seem to solve the problem when, for example, we have a top-level composable (so needs to set a theme) in a base module. So it looks like the colors need to be provided using DI instead.Stylianos Gakis
02/03/2024, 6:10 PMMark
02/04/2024, 2:48 AMMaterialTheme to do something like:
@Composable
fun JetnewsTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
MaterialTheme(
colors = if (darkTheme) DarkColors else LightColors,
typography = JetnewsTypography,
shapes = JetnewsShapes,
content = content
)
}
I suppose this could be declared in variant-specific source folders of the app module and then would be used at each Activity entry point. And then for other modules, just use MaterialTheme? I suppose this would work so long as there are no entry points outside of the app module.Mark
02/04/2024, 4:11 AMMaterialTheme.
One option might be to have a “flavor” module that declares an AppTheme in each flavor-specific source. This module will be a dependency for the app module as well as any other module (e.g. homescreen widget module) that needs the proper theme at an app entry point (i.e. where MaterialTheme would not already be initiated properly)Mark
02/04/2024, 9:46 AMLocalContentColor.current and LocalTextStyle.current.color are not set, so I need to do:
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
MaterialTheme(
colors = if (darkTheme) DarkColors else LightColors,
) {
CompositionLocalProvider(
LocalContentColor provides MaterialTheme.colors.onSurface,
LocalTextStyle provides LocalTextStyle.current.merge(color = MaterialTheme.colors.onSurface),
content = content,
)
}
}
Is that expected?Stylianos Gakis
02/04/2024, 1:46 PMMark
02/05/2024, 10:55 AMLocalContentColor. I still think (for my use case at least), it’s better to provide the colors using DI. One benefit is that they are accessible outside of the Composable context.
One thing I haven’t seen mentioned is how to migrate legacy dimens.xml resources. Presumably, just add a Dimension.kt file and add a bunch of top-level properties there.Joel Denke
02/05/2024, 11:00 AMJoel Denke
02/05/2024, 11:01 AMMark
02/05/2024, 11:56 AMdimensionResource (It’s pretty much the only sensible way to access dimens.xml from Compose, so not sure how I could access those values otherwise).
There are a couple of motivations for migrating dimens.xml to kotlin:
1. No longer need a Context (nor @Composable) to access the values
2. No longer have theming values spread across different locations (i.e. res/values/ and src
The strongest reason for keep using dimens.xml is to take advantage of different configurations (e.g. sw600 , land)Mark
02/05/2024, 11:58 AMMark
02/05/2024, 12:50 PM@Composable
fun Modifier.topCardPadding(): Modifier {
val horizontalPadding = dimensionResource(id = R.dimen.card_view_horizontal_margin)
val verticalPadding = dimensionResource(id = R.dimen.card_view_vertical_margin)
return this.padding(start = horizontalPadding, end = horizontalPadding, top = verticalPadding, bottom = 0.dp)
}
becomes:
fun Modifier.topCardPadding(): Modifier {
return this.padding(
start = CardDimensions.horizontalMargin,
end = CardDimensions.horizontalMargin,
top = CardDimensions.verticalMargin,
bottom = 0.dp,
)
}
So no longer ComposableJoel Denke
02/05/2024, 1:15 PMPaddingValues perhaps, if that even make sense. In many cases I think need apply "negative" paddings in layers to compensate for Material hard coded 48x48dp touch surface, not always desirable in compact ui designs. Like text or chip buttons.Mark
02/05/2024, 1:40 PMPaddingValues instead of Modifier extension functions, I agree. Not sure why I wasn’t doing that earlier.
fun cardInListPaddingValues(index: Int, itemCount: Int): PaddingValues = when {
itemCount == 1 -> soloCardPaddingValues()
index == 0 -> topCardPaddingValues()
index == itemCount - 1 -> bottomCardPaddingValues()
else -> middleCardPaddingValues()
}
fun soloCardPaddingValues() = PaddingValues(
horizontal = Dimensions.Card.marginHorizontal,
vertical = Dimensions.Card.marginVertical,
)
fun topCardPaddingValues() = PaddingValues(
start = Dimensions.Card.marginHorizontal,
end = Dimensions.Card.marginHorizontal,
top = Dimensions.Card.marginVertical,
bottom = 0.dp,
)
fun bottomCardPaddingValues() = PaddingValues(
start = Dimensions.Card.marginHorizontal,
end = Dimensions.Card.marginHorizontal,
top = 0.dp,
bottom = Dimensions.Card.marginVertical,
)
fun middleCardPaddingValues() = PaddingValues(
start = Dimensions.Card.marginHorizontal,
end = Dimensions.Card.marginHorizontal,
top = 0.dp,
bottom = 0.dp,
)
I’ll have a think about the other things you mentioned.Joel Denke
02/05/2024, 1:44 PMMark
02/05/2024, 1:45 PMJoel Denke
02/05/2024, 1:46 PMinternal object MyDimensionsImpl: MyDimensions {
override val itemDelimiterSpace: Dp = 8.dp
override val componentSpace: Dp = 16.dp
override val windowInsets: Dp = 20.dp
override val icon: Dp = 24.dp
override val illustration: Dp = 56.dp
}
interface MyDimensions {
val itemDelimiterSpace: Dp
val componentSpace: Dp
val windowInsets: Dp
val illustration: Dp
val icon: Dp
}
If I for some reason want to replace the values in a Local composition, like previews or anything else 🙂Joel Denke
02/05/2024, 1:47 PMobject MyTheme {
val typography: MyTypography
@Composable
@ReadOnlyComposable
get() = LocalMyTypography.current
val colorTheme: MyColorTheme
@Composable
@ReadOnlyComposable
get() = LocalMyColorTheme.current
val shapes: MyShapes
@Composable
@ReadOnlyComposable
get() = LocalMyShapes.current
val dimensions: MyDimensions
@Composable
@ReadOnlyComposable
get() = LocalMyDimensions.current
}Joel Denke
02/05/2024, 1:48 PMJoel Denke
02/05/2024, 1:49 PMMark
02/05/2024, 1:51 PMColors extensions which can be accessed through MaterialTheme.colors.X https://developer.android.com/jetpack/compose/designsystems/custom#extending-materialJoel Denke
02/05/2024, 1:53 PMJoel Denke
02/05/2024, 1:55 PMMark
02/05/2024, 1:58 PMJoel Denke
02/05/2024, 2:06 PMMark
02/05/2024, 2:06 PMinterface Impl route, couldn’t you just use a data class instead like this: https://stackoverflow.com/a/73722401/444761 ? Although I suppose then you need something else (e.g. Companion object property) for access outside of ComposableJoel Denke
02/05/2024, 2:07 PMJoel Denke
02/05/2024, 2:08 PMMark
02/06/2024, 8:16 AM?android:attr/listPreferredItemHeight ? Just hard code them?Joel Denke
02/06/2024, 8:35 AMMark
02/06/2024, 10:16 AMAppTheme (which provides a LocalDimensions) at the activity screen level. What happens with things like ComposeView and dialogs? Do I need to apply a theme there? What if I only apply MaterialTheme for those, will the LocalDimensions be somehow carried over, or is that only for MaterialTheme.colors?Joel Denke
02/06/2024, 10:26 AMJoel Denke
02/06/2024, 10:27 AMMark
02/06/2024, 10:28 AMJoel Denke
02/06/2024, 10:28 AMMark
02/06/2024, 10:29 AMComposeView thing. That was only out of interest. My general strategy has been to apply MaterialTheme everywhere except entry level Activity, in which case AppThemeJoel Denke
02/06/2024, 10:29 AMJoel Denke
02/06/2024, 10:30 AMJoel Denke
02/06/2024, 10:32 AMMark
02/06/2024, 10:34 AMAndroidView or ComposeView left. I’m using androidx navigation (XML) and there is a (secondary) screen where I use MaterialTheme . I notice that LocalDimensions has been applied even though I only set it in AppTheme . How is that working?Joel Denke
02/06/2024, 10:37 AMJoel Denke
02/06/2024, 10:38 AMnotice that LocalDimensions has been applied even though I only set it in AppTheme . How is that working?
If you nesting Local compositions in compose, they inherit each other, but also means you can override the child local compositions if that is accessible 🙂
Like AppTheme { MaterialTheme {} } youre AppTheme delegating LocalDimensions so also accssible in MaterialTheme in that case.Joel Denke
02/06/2024, 10:38 AMMark
02/06/2024, 10:39 AMLocalDimensions from one fragment to the next? or is it just using the same Composable context (or whatever you call it)?Joel Denke
02/06/2024, 10:42 AM