Skip to content

Commit

Permalink
Merge pull request #7262 from thundernest/image_with_baseline
Browse files Browse the repository at this point in the history
Add `ImageWithBaseline`
  • Loading branch information
cketti authored Oct 18, 2023
2 parents b35c96e + d8a8555 commit 8df862b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package app.k9mail.core.ui.compose.common.baseline

import androidx.compose.foundation.layout.RowScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.FirstBaseline
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Dp

/**
* Adds a baseline to a Composable that typically doesn't have one.
*
* This can be used to align e.g. an icon to the baseline of some text next to it. See e.g. [RowScope.alignByBaseline].
*
* @param baseline The number of device-independent pixels (dp) the baseline is from the top of the Composable.
*/
fun Modifier.withBaseline(baseline: Dp) = layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val baselineInPx = baseline.roundToPx()

layout(
width = placeable.width,
height = placeable.height,
alignmentLines = mapOf(
FirstBaseline to baselineInPx,
LastBaseline to baselineInPx,
),
) {
placeable.placeRelative(x = 0, y = 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app.k9mail.core.ui.compose.common.image

import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.Dp

@Immutable
data class ImageWithBaseline(
val image: ImageVector,
val baseline: Dp,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.k9mail.core.ui.compose.theme

import androidx.compose.material.icons.filled.Warning
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.common.image.ImageWithBaseline
import androidx.compose.material.icons.Icons as MaterialIcons

// We're using "by lazy" so not all icons are loaded into memory as soon as a nested object is accessed. But once a
// property is accessed we want to retain the `ImageWithBaseline` instance.
object IconsWithBaseline {
object Filled {
val warning: ImageWithBaseline by lazy {
ImageWithBaseline(image = MaterialIcons.Filled.Warning, baseline = 21.dp)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ package app.k9mail.feature.account.server.certificate.ui

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import app.k9mail.core.ui.compose.common.DevicePreviews
import app.k9mail.core.ui.compose.common.baseline.withBaseline
import app.k9mail.core.ui.compose.common.mvi.observe
import app.k9mail.core.ui.compose.designsystem.atom.Icon
import app.k9mail.core.ui.compose.designsystem.atom.button.Button
import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonOutlined
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBody1
import app.k9mail.core.ui.compose.designsystem.atom.text.TextHeadline4
import app.k9mail.core.ui.compose.designsystem.atom.text.TextSubtitle1
import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
import app.k9mail.core.ui.compose.designsystem.template.Scaffold
import app.k9mail.core.ui.compose.theme.IconsWithBaseline
import app.k9mail.core.ui.compose.theme.K9Theme
import app.k9mail.core.ui.compose.theme.MainTheme
import app.k9mail.feature.account.server.certificate.data.InMemoryServerCertificateErrorRepository
Expand All @@ -32,6 +37,7 @@ import org.koin.androidx.compose.koinViewModel

// Note: This is a placeholder with mostly hardcoded text.
// TODO: Replace with final design.
@Suppress("LongMethod")
@Composable
fun ServerCertificateErrorScreen(
onCertificateAccepted: () -> Unit,
Expand Down Expand Up @@ -79,7 +85,27 @@ fun ServerCertificateErrorScreen(
.verticalScroll(rememberScrollState())
.padding(all = MainTheme.spacings.double),
) {
TextHeadline4(text = "Warning")
Row {
val warningIcon = IconsWithBaseline.Filled.warning
val iconSize = MainTheme.sizes.medium
val iconScalingFactor = iconSize / warningIcon.image.defaultHeight
val iconBaseline = warningIcon.baseline * iconScalingFactor

Icon(
imageVector = warningIcon.image,
tint = MainTheme.colors.warning,
modifier = Modifier
.padding(end = MainTheme.spacings.default)
.requiredSize(iconSize)
.withBaseline(iconBaseline)
.alignByBaseline(),
)
TextHeadline4(
text = "Warning",
modifier = Modifier.alignByBaseline(),
)
}

TextSubtitle1("Invalid certificate")

Spacer(modifier = Modifier.height(MainTheme.spacings.quadruple))
Expand Down

0 comments on commit 8df862b

Please sign in to comment.