PM-10851 make the default top app bar reactive (#3726)

This commit is contained in:
Dave Severns 2024-08-14 13:42:08 -04:00 committed by GitHub
parent 2876d75a21
commit ab279e2264
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -5,12 +5,17 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
@ -64,8 +69,12 @@ fun BitwardenTopAppBar(
* - a [actions] lambda containing the set of actions (usually icons or similar) to display * - a [actions] lambda containing the set of actions (usually icons or similar) to display
* in the app bar's trailing side. This lambda extends [RowScope], allowing flexibility in * in the app bar's trailing side. This lambda extends [RowScope], allowing flexibility in
* defining the layout of the actions. * defining the layout of the actions.
* - if the title text causes an overflow in the standard material [TopAppBar] a [MediumTopAppBar]
* will be used instead, droping the title text to a second row beneath the [navigationIcon] and
* [actions].
*/ */
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Suppress("LongMethod")
@Composable @Composable
fun BitwardenTopAppBar( fun BitwardenTopAppBar(
title: String, title: String,
@ -74,16 +83,12 @@ fun BitwardenTopAppBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
actions: @Composable RowScope.() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {},
) { ) {
TopAppBar( var titleTextHasOverflow by remember {
colors = TopAppBarDefaults.largeTopAppBarColors( mutableStateOf(false)
containerColor = MaterialTheme.colorScheme.surface, }
scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer,
navigationIconContentColor = MaterialTheme.colorScheme.onSurface, val navigationIconContent: @Composable () -> Unit = remember(navigationIcon) {
titleContentColor = MaterialTheme.colorScheme.onSurface, {
actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
),
scrollBehavior = scrollBehavior,
navigationIcon = {
navigationIcon?.let { navigationIcon?.let {
IconButton( IconButton(
onClick = it.onNavigationIconClick, onClick = it.onNavigationIconClick,
@ -96,20 +101,57 @@ fun BitwardenTopAppBar(
) )
} }
} }
}, }
title = { }
Text(
text = title, val topAppBarColors = TopAppBarDefaults.largeTopAppBarColors(
style = MaterialTheme.typography.titleLarge, containerColor = MaterialTheme.colorScheme.surface,
maxLines = 1, scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer,
softWrap = false, navigationIconContentColor = MaterialTheme.colorScheme.onSurface,
overflow = TextOverflow.Ellipsis, titleContentColor = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.testTag("PageTitleLabel"), actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
)
},
modifier = modifier.testTag("HeaderBarComponent"),
actions = actions,
) )
if (titleTextHasOverflow) {
MediumTopAppBar(
colors = topAppBarColors,
scrollBehavior = scrollBehavior,
navigationIcon = navigationIconContent,
title = {
// The height of the component is controlled and will only allow for 1 extra row,
// making adding any arguments for softWrap and minLines superfluous.
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.testTag("PageTitleLabel"),
)
},
modifier = modifier.testTag("HeaderBarComponent"),
actions = actions,
)
} else {
TopAppBar(
colors = topAppBarColors,
scrollBehavior = scrollBehavior,
navigationIcon = navigationIconContent,
title = {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
maxLines = 1,
softWrap = false,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.testTag("PageTitleLabel"),
onTextLayout = {
titleTextHasOverflow = it.hasVisualOverflow
},
)
},
modifier = modifier.testTag("HeaderBarComponent"),
actions = actions,
)
}
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -132,6 +174,46 @@ private fun BitwardenTopAppBar_preview() {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun BitwardenTopAppBarOverflow_preview() {
BitwardenTheme {
BitwardenTopAppBar(
title = "Title that is too long for the top line",
scrollBehavior = TopAppBarDefaults
.exitUntilCollapsedScrollBehavior(
rememberTopAppBarState(),
),
navigationIcon = NavigationIcon(
navigationIcon = rememberVectorPainter(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = { },
),
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun BitwardenTopAppBarOverflowCutoff_preview() {
BitwardenTheme {
BitwardenTopAppBar(
title = "Title that is too long for the top line and the bottom line",
scrollBehavior = TopAppBarDefaults
.exitUntilCollapsedScrollBehavior(
rememberTopAppBarState(),
),
navigationIcon = NavigationIcon(
navigationIcon = rememberVectorPainter(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = { },
),
)
}
}
/** /**
* Represents all data required to display a [navigationIcon]. * Represents all data required to display a [navigationIcon].
* *