From 2d7b4a0bf8fcd24a7df11ddf7580805de6609bd7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 5 Jun 2023 13:01:16 +0200 Subject: [PATCH] Introduce HeaderFooterPage. --- .../impl/VerifySelfSessionView.kt | 49 ++------ .../atomic/pages/HeaderFooterPage.kt | 119 ++++++++++++++++++ 2 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt index 081da5d84e..2173c74897 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt @@ -21,10 +21,10 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.MaterialTheme import androidx.compose.material3.TextButton @@ -34,24 +34,21 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import io.element.android.libraries.architecture.Async import io.element.android.libraries.designsystem.ElementTextStyles import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule +import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.components.button.ButtonWithProgress import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator -import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep as FlowStep @@ -77,24 +74,18 @@ fun VerifySelfSessionView( val buttonsVisible by remember(verificationFlowStep) { derivedStateOf { verificationFlowStep != FlowStep.AwaitingOtherDeviceResponse && verificationFlowStep != FlowStep.Completed } } - Surface { - Column( - modifier = modifier - .systemBarsPadding() - .padding(horizontal = 20.dp) - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - ) { - HeaderContent(verificationFlowStep = verificationFlowStep) - Content(modifier = Modifier.weight(1f), flowState = verificationFlowStep) - } + HeaderFooterPage( + modifier = modifier, + header = { + HeaderContent(verificationFlowStep = verificationFlowStep) + }, + footer = { if (buttonsVisible) { BottomMenu(screenState = state, goBack = ::goBackAndCancelIfNeeded) } } + ) { + Content(flowState = verificationFlowStep) } } @@ -120,7 +111,7 @@ internal fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier = } IconTitleSubtitleMolecule( - modifier = modifier.padding(top = 80.dp), + modifier = modifier.padding(top = 60.dp), iconResourceId = iconResourceId, title = stringResource(id = titleTextId), subTitle = stringResource(id = subtitleTextId) @@ -129,14 +120,12 @@ internal fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier = @Composable internal fun Content(flowState: FlowStep, modifier: Modifier = Modifier) { - Column(modifier, verticalArrangement = Arrangement.Center) { - Spacer(Modifier.shrinkableHeight(min = 20.dp, max = 56.dp)) + Column(modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) { when (flowState) { FlowStep.Initial, FlowStep.Ready, FlowStep.Canceled, FlowStep.Completed -> Unit FlowStep.AwaitingOtherDeviceResponse -> ContentWaiting() is FlowStep.Verifying -> ContentVerifying(flowState) } - Spacer(Modifier.shrinkableHeight(min = 20.dp, max = 56.dp)) } } @@ -224,7 +213,7 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit) } ButtonColumnMolecule( - modifier = Modifier.padding(bottom = 40.dp) + modifier = Modifier.padding(bottom = 20.dp) ) { ButtonWithProgress( text = positiveButtonTitle?.let { stringResource(it) }, @@ -261,15 +250,3 @@ private fun ContentToPreview(state: VerifySelfSessionState) { goBack = {}, ) } - -private fun Modifier.shrinkableHeight( - min: Dp, - max: Dp, - minScreenHeight: Int = 720 -): Modifier = composed { - if (LocalConfiguration.current.screenHeightDp >= minScreenHeight) { - then(Modifier.height(max)) - } else { - then(Modifier.height(min)) - } -} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt new file mode 100644 index 0000000000..65daa5a8f2 --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.designsystem.atomic.pages + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.preview.ElementPreviewLight +import io.element.android.libraries.designsystem.theme.components.Text + +/** + * @param modifier Classical modifier. + * @param header optional header. + * @param footer optional footer. + * @param content main content. + */ +@Composable +fun HeaderFooterPage( + modifier: Modifier = Modifier, + header: @Composable () -> Unit = {}, + footer: @Composable () -> Unit = {}, + content: @Composable () -> Unit = {}, +) { + Column( + modifier = modifier + .fillMaxSize() + .systemBarsPadding() + .padding(all = 20.dp), + ) { + // Header + header() + // Content + Column( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + ) { + content() + } + // Footer + footer() + } +} + +@Preview +@Composable +internal fun HeaderFooterPageLightPreview() = + ElementPreviewLight { ContentToPreview() } + +@Preview +@Composable +internal fun HeaderFooterPageDarkPreview() = + ElementPreviewDark { ContentToPreview() } + +@Composable +private fun ContentToPreview() { + HeaderFooterPage( + content = { + Box( + Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text( + text = "Content", + fontSize = 40.sp + ) + } + }, + header = { + Box( + Modifier + .fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + Text( + text = "Header", + fontSize = 40.sp + ) + } + }, + footer = { + Box( + Modifier + .fillMaxWidth(), + contentAlignment = Alignment.Center + ) { + Text( + text = "Footer", + fontSize = 40.sp + ) + } + } + ) +}