Skip to content

Commit

Permalink
fix: multiline topbar title not centered [WPB-9608] (#3239)
Browse files Browse the repository at this point in the history
  • Loading branch information
saleniuk authored Jul 29, 2024
1 parent 7389744 commit c63fbc7
Showing 1 changed file with 83 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@

package com.wire.android.ui.common.topappbar

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
Expand All @@ -30,24 +33,32 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes
import kotlin.math.ceil

@Composable
fun WireCenterAlignedTopAppBar(
title: String,
modifier: Modifier = Modifier,
titleStyle: TextStyle = MaterialTheme.wireTypography.title01,
maxLines: Int = 2,
subtitleContent: @Composable ColumnScope.() -> Unit = {},
onNavigationPressed: () -> Unit = {},
navigationIconType: NavigationIconType? = NavigationIconType.Back,
elevation: Dp = MaterialTheme.wireDimensions.topBarShadowElevation,
actions: @Composable RowScope.() -> Unit = {},
modifier: Modifier = Modifier,
bottomContent: @Composable ColumnScope.() -> Unit = {}
) {
WireCenterAlignedTopAppBar(
Expand All @@ -72,12 +83,12 @@ fun WireCenterAlignedTopAppBar(
@Composable
fun WireCenterAlignedTopAppBar(
titleContent: @Composable ColumnScope.() -> Unit,
modifier: Modifier = Modifier,
subtitleContent: @Composable ColumnScope.() -> Unit = {},
onNavigationPressed: () -> Unit = {},
navigationIconType: NavigationIconType? = NavigationIconType.Back,
elevation: Dp = MaterialTheme.wireDimensions.topBarShadowElevation,
actions: @Composable RowScope.() -> Unit = {},
modifier: Modifier = Modifier,
bottomContent: @Composable ColumnScope.() -> Unit = {}
) {
Surface(
Expand Down Expand Up @@ -106,16 +117,76 @@ fun WireCenterAlignedTopAppBar(
fun WireTopAppBarTitle(
title: String,
style: TextStyle,
modifier: Modifier = Modifier,
maxLines: Int = 2
) {
Text(
modifier = Modifier.padding(
start = dimensions().spacing6x,
end = dimensions().spacing6x
),
text = title,
style = style,
maxLines = maxLines,
overflow = TextOverflow.Ellipsis
)
// There's an ongoing issue about multiline text taking all width available instead of wrapping visible text.
// https://issuetracker.google.com/issues/206039942
// It's very noticeable on TopAppBar because due to that issue, the title is not centered, even if there are large enough empty spaces
// on both sides and all lines of text are actually shorter and could fit at the center.
// This workaround is based on this: https://stackoverflow.com/a/69947555, but instead of using SubcomposeLayout, we just measure text.
BoxWithConstraints(
modifier = modifier
) {
val textMeasurer = rememberTextMeasurer()
val textLayoutResult: TextLayoutResult = textMeasurer.measure(
text = title,
style = style,
maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
constraints = Constraints(
minWidth = 0,
minHeight = 0,
maxWidth = constraints.maxWidth,
maxHeight = constraints.maxHeight
)
)
val width = with(LocalDensity.current) {
(0 until textLayoutResult.lineCount).maxOf { line ->
ceil(textLayoutResult.getLineRight(line) - textLayoutResult.getLineLeft(line)).toInt()
}.toDp()
}
Text(
modifier = Modifier
.padding(horizontal = dimensions().spacing6x)
.width(width),
text = title,
style = style,
maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
)
}
}

@PreviewMultipleThemes
@Composable
fun PreviewWireCenterAlignedTopAppBarWithDefaultTitle() = WireTheme {
Box(modifier = Modifier.width(400.dp)) {
WireCenterAlignedTopAppBar(
title = "This is title",
titleStyle = MaterialTheme.wireTypography.title01
)
}
}

@PreviewMultipleThemes
@Composable
fun PreviewWireCenterAlignedTopAppBarWithDefaultTwoLinesTitle() = WireTheme {
Box(modifier = Modifier.width(400.dp)) {
WireCenterAlignedTopAppBar(
title = "This is title is very long this_is_a_very_long_word",
titleStyle = MaterialTheme.wireTypography.title01
)
}
}

@PreviewMultipleThemes
@Composable
fun PreviewWireCenterAlignedTopAppBarWithDefaultTwoLinesTooLongTitle() = WireTheme {
Box(modifier = Modifier.width(400.dp)) {
WireCenterAlignedTopAppBar(
title = "This is title is even longer than previous one this_is_a_very_long_word",
titleStyle = MaterialTheme.wireTypography.title01
)
}
}

0 comments on commit c63fbc7

Please sign in to comment.