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 Composable
Joel 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 Composable
Joel 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 AppTheme
Joel 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