Skip to content

Commit a066197

Browse files
Make verification screens scrollable and emoji labels multiline (#4449)
* Make self verification screens scrollable * Remove unused fields from `VerificationEmoji` * Make only the header and content scroll in `HeaderFooterPage`. * Use the right 'emoji' icon in both flows (`ReactionSolid`) --------- Co-authored-by: ElementBot <[email protected]>
1 parent dd3a6af commit a066197

File tree

47 files changed

+212
-143
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+212
-143
lines changed

features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fun JoinRoomView(
8585
) {
8686
HeaderFooterPage(
8787
containerColor = Color.Transparent,
88-
paddingValues = PaddingValues(
88+
contentPadding = PaddingValues(
8989
horizontal = 16.dp,
9090
vertical = 32.dp
9191
),

features/roomaliasresolver/impl/src/main/kotlin/io/element/android/features/roomaliasresolver/impl/RoomAliasResolverView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fun RoomAliasResolverView(
5151
) {
5252
HeaderFooterPage(
5353
containerColor = Color.Transparent,
54-
paddingValues = PaddingValues(
54+
contentPadding = PaddingValues(
5555
horizontal = 16.dp,
5656
vertical = 32.dp
5757
),

features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/incoming/IncomingVerificationView.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import androidx.compose.foundation.layout.Column
1313
import androidx.compose.foundation.layout.fillMaxWidth
1414
import androidx.compose.foundation.layout.padding
1515
import androidx.compose.material3.ExperimentalMaterial3Api
16+
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
1617
import androidx.compose.runtime.Composable
1718
import androidx.compose.ui.Alignment
1819
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.graphics.Color
1921
import androidx.compose.ui.res.stringResource
2022
import androidx.compose.ui.text.style.TextAlign
2123
import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -35,6 +37,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton
3537
import io.element.android.libraries.designsystem.preview.ElementPreview
3638
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
3739
import io.element.android.libraries.designsystem.theme.components.Button
40+
import io.element.android.libraries.designsystem.theme.components.InvisibleButton
3841
import io.element.android.libraries.designsystem.theme.components.Text
3942
import io.element.android.libraries.designsystem.theme.components.TextButton
4043
import io.element.android.libraries.designsystem.theme.components.TopAppBar
@@ -67,7 +70,8 @@ fun IncomingVerificationView(
6770
step is Step.Completed -> Unit
6871
else -> BackButton(onClick = { state.eventSink(IncomingVerificationViewEvents.GoBack) })
6972
}
70-
}
73+
},
74+
colors = topAppBarColors(containerColor = Color.Transparent),
7175
)
7276
},
7377
header = {
@@ -77,7 +81,8 @@ fun IncomingVerificationView(
7781
IncomingVerificationBottomMenu(
7882
state = state,
7983
)
80-
}
84+
},
85+
isScrollable = true,
8186
) {
8287
IncomingVerificationContent(
8388
step = step,
@@ -222,7 +227,11 @@ private fun IncomingVerificationBottomMenu(
222227
}
223228
is Step.Verifying -> {
224229
if (step.isWaiting) {
225-
// Show nothing
230+
// Add invisible buttons to keep the same screen layout
231+
VerificationBottomMenu {
232+
InvisibleButton()
233+
InvisibleButton()
234+
}
226235
} else {
227236
VerificationBottomMenu {
228237
Button(

features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/outgoing/VerifySelfSessionView.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import androidx.compose.foundation.layout.fillMaxSize
1616
import androidx.compose.foundation.layout.fillMaxWidth
1717
import androidx.compose.foundation.layout.padding
1818
import androidx.compose.material3.ExperimentalMaterial3Api
19+
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
1920
import androidx.compose.runtime.Composable
2021
import androidx.compose.ui.Alignment
2122
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.graphics.Color
2224
import androidx.compose.ui.res.stringResource
2325
import androidx.compose.ui.tooling.preview.PreviewParameter
2426
import androidx.compose.ui.unit.dp
@@ -91,7 +93,8 @@ fun VerifySelfSessionView(
9193
{ BackButton(onClick = ::cancelOrResetFlow) }
9294
} else {
9395
{}
94-
}
96+
},
97+
colors = topAppBarColors(containerColor = Color.Transparent)
9598
)
9699
},
97100
header = {
@@ -103,7 +106,8 @@ fun VerifySelfSessionView(
103106
onCancelClick = ::cancelOrResetFlow,
104107
onContinueClick = onFinish,
105108
)
106-
}
109+
},
110+
isScrollable = true,
107111
) {
108112
VerifySelfSessionContent(
109113
flowState = step,
@@ -124,13 +128,13 @@ private fun VerifySelfSessionHeader(step: Step, request: VerificationRequest.Out
124128
}
125129
Step.AwaitingOtherDeviceResponse -> BigIcon.Style.Loading
126130
Step.Canceled -> BigIcon.Style.AlertSolid
127-
Step.Ready -> BigIcon.Style.Default(CompoundIcons.Reaction())
131+
Step.Ready -> BigIcon.Style.Default(CompoundIcons.ReactionSolid())
128132
Step.Completed -> BigIcon.Style.SuccessSolid
129133
is Step.Verifying -> {
130134
if (step.state is AsyncData.Loading<Unit>) {
131135
BigIcon.Style.Loading
132136
} else {
133-
BigIcon.Style.Default(CompoundIcons.Reaction())
137+
BigIcon.Style.Default(CompoundIcons.ReactionSolid())
134138
}
135139
}
136140
is Step.Exit -> return
@@ -272,7 +276,11 @@ private fun VerifySelfSessionBottomMenu(
272276
is Step.AwaitingOtherDeviceResponse -> Unit
273277
is Step.Verifying -> {
274278
if (isVerifying) {
275-
// Show nothing
279+
// Add invisible buttons to keep the same screen layout
280+
VerificationBottomMenu {
281+
InvisibleButton()
282+
InvisibleButton()
283+
}
276284
} else {
277285
VerificationBottomMenu {
278286
Button(

features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/ui/Common.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ internal fun aDecimalsSessionVerificationData(
2323
}
2424

2525
private fun aVerificationEmojiList() = listOf(
26-
VerificationEmoji(number = 27, emoji = "🍕", description = "Pizza"),
27-
VerificationEmoji(number = 54, emoji = "🚀", description = "Rocket"),
28-
VerificationEmoji(number = 54, emoji = "🚀", description = "Rocket"),
29-
VerificationEmoji(number = 42, emoji = "📕", description = "Book"),
30-
VerificationEmoji(number = 48, emoji = "🔨", description = "Hammer"),
31-
VerificationEmoji(number = 48, emoji = "🔨", description = "Hammer"),
32-
VerificationEmoji(number = 63, emoji = "📌", description = "Pin"),
26+
VerificationEmoji(number = 27),
27+
VerificationEmoji(number = 54),
28+
VerificationEmoji(number = 54),
29+
VerificationEmoji(number = 42),
30+
VerificationEmoji(number = 48),
31+
VerificationEmoji(number = 48),
32+
VerificationEmoji(number = 63),
3333
)

features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/ui/VerificationContentVerifying.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.Spacer
1616
import androidx.compose.foundation.layout.fillMaxSize
1717
import androidx.compose.foundation.layout.fillMaxWidth
1818
import androidx.compose.foundation.layout.height
19+
import androidx.compose.foundation.layout.padding
1920
import androidx.compose.foundation.layout.size
2021
import androidx.compose.foundation.layout.widthIn
2122
import androidx.compose.runtime.Composable
@@ -38,7 +39,7 @@ internal fun VerificationContentVerifying(
3839
modifier: Modifier = Modifier,
3940
) {
4041
Box(
41-
modifier = modifier.fillMaxSize(),
42+
modifier = modifier.fillMaxSize().padding(bottom = 20.dp),
4243
contentAlignment = Alignment.Center
4344
) {
4445
when (data) {
@@ -86,8 +87,8 @@ private fun EmojiItemView(emoji: VerificationEmoji, modifier: Modifier = Modifie
8687
text = stringResource(id = emojiResource.nameRes),
8788
style = ElementTheme.typography.fontBodyMdRegular,
8889
color = ElementTheme.colors.textSecondary,
89-
maxLines = 1,
90-
overflow = TextOverflow.Ellipsis,
90+
overflow = TextOverflow.Visible,
91+
textAlign = TextAlign.Center,
9192
)
9293
}
9394
}

features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/outgoing/VerifySelfSessionPresenterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class VerifySelfSessionPresenterTest {
185185
@Test
186186
fun `present - When verification is approved, the flow completes if there is no error`() = runTest {
187187
val emojis = listOf(
188-
VerificationEmoji(number = 30, emoji = "😀", description = "Smiley")
188+
VerificationEmoji(number = 30)
189189
)
190190
val service = unverifiedSessionService(
191191
requestSessionVerificationLambda = { },

libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/HeaderFooterPage.kt

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,21 @@ package io.element.android.libraries.designsystem.atomic.pages
1010
import androidx.compose.foundation.layout.Box
1111
import androidx.compose.foundation.layout.Column
1212
import androidx.compose.foundation.layout.PaddingValues
13+
import androidx.compose.foundation.layout.calculateEndPadding
14+
import androidx.compose.foundation.layout.calculateStartPadding
1315
import androidx.compose.foundation.layout.consumeWindowInsets
1416
import androidx.compose.foundation.layout.fillMaxSize
1517
import androidx.compose.foundation.layout.fillMaxWidth
1618
import androidx.compose.foundation.layout.imePadding
1719
import androidx.compose.foundation.layout.padding
18-
import androidx.compose.foundation.lazy.LazyColumn
20+
import androidx.compose.foundation.rememberScrollState
21+
import androidx.compose.foundation.verticalScroll
1922
import androidx.compose.runtime.Composable
20-
import androidx.compose.runtime.movableContentOf
2123
import androidx.compose.runtime.remember
2224
import androidx.compose.ui.Alignment
2325
import androidx.compose.ui.Modifier
2426
import androidx.compose.ui.graphics.Color
27+
import androidx.compose.ui.platform.LocalLayoutDirection
2528
import androidx.compose.ui.unit.dp
2629
import io.element.android.compound.theme.ElementTheme
2730
import io.element.android.libraries.designsystem.preview.ElementPreview
@@ -31,7 +34,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
3134

3235
/**
3336
* @param modifier Classical modifier.
34-
* @param paddingValues padding values to apply to the content.
37+
* @param contentPadding padding values to apply to the content.
3538
* @param containerColor color of the container. Set to [Color.Transparent] if you provide a background in the [modifier].
3639
* @param isScrollable if the whole content should be scrollable.
3740
* @param background optional background component.
@@ -44,7 +47,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
4447
@Composable
4548
fun HeaderFooterPage(
4649
modifier: Modifier = Modifier,
47-
paddingValues: PaddingValues = PaddingValues(20.dp),
50+
contentPadding: PaddingValues = PaddingValues(20.dp),
4851
containerColor: Color = ElementTheme.colors.bgCanvasDefault,
4952
isScrollable: Boolean = false,
5053
background: @Composable () -> Unit = {},
@@ -53,64 +56,67 @@ fun HeaderFooterPage(
5356
footer: @Composable () -> Unit = {},
5457
content: @Composable () -> Unit = {},
5558
) {
56-
val topBar = remember { movableContentOf(topBar) }
57-
val header = remember { movableContentOf(header) }
58-
val footer = remember { movableContentOf(footer) }
59-
val content = remember { movableContentOf(content) }
6059
Scaffold(
6160
modifier = modifier,
6261
topBar = topBar,
6362
containerColor = containerColor,
64-
) { padding ->
63+
) { insetsPadding ->
64+
val layoutDirection = LocalLayoutDirection.current
65+
val contentInsetsPadding = remember(insetsPadding, layoutDirection) {
66+
PaddingValues(
67+
start = insetsPadding.calculateStartPadding(layoutDirection),
68+
top = insetsPadding.calculateTopPadding(),
69+
end = insetsPadding.calculateEndPadding(layoutDirection),
70+
)
71+
}
72+
val footerInsetsPadding = remember(insetsPadding, layoutDirection) {
73+
PaddingValues(
74+
start = insetsPadding.calculateStartPadding(layoutDirection),
75+
end = insetsPadding.calculateEndPadding(layoutDirection),
76+
bottom = insetsPadding.calculateBottomPadding(),
77+
)
78+
}
6579
Box {
6680
background()
67-
if (isScrollable) {
68-
// Render in a LazyColumn
69-
LazyColumn(
81+
82+
// Render in a Column
83+
Column(
84+
modifier = Modifier
85+
.fillMaxSize()
86+
.padding(paddingValues = contentPadding)
87+
.consumeWindowInsets(insetsPadding)
88+
.imePadding(),
89+
) {
90+
// Content
91+
Column(
7092
modifier = Modifier
71-
.padding(paddingValues = paddingValues)
72-
.padding(padding)
73-
.consumeWindowInsets(padding)
74-
.imePadding()
93+
.fillMaxWidth()
94+
.run {
95+
if (isScrollable) {
96+
verticalScroll(rememberScrollState())
97+
} else {
98+
Modifier
99+
}
100+
}
101+
// Apply insets here so if the content is scrollable it can get below the top app bar if needed
102+
.padding(contentInsetsPadding)
103+
.weight(1f),
75104
) {
76105
// Header
77-
item {
78-
header()
79-
}
80-
// Content
81-
item {
106+
header()
107+
Box(modifier = Modifier.weight(1f)) {
82108
content()
83109
}
84-
// Footer
85-
item {
86-
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
87-
footer()
88-
}
89-
}
90110
}
91-
} else {
92-
// Render in a Column
93-
Column(
111+
112+
// Footer
113+
Box(
94114
modifier = Modifier
95-
.padding(paddingValues = paddingValues)
96-
.padding(padding)
97-
.consumeWindowInsets(padding)
98-
.imePadding()
115+
.padding(horizontal = 16.dp)
116+
.fillMaxWidth()
117+
.padding(footerInsetsPadding)
99118
) {
100-
// Header
101-
header()
102-
// Content
103-
Column(
104-
modifier = Modifier
105-
.weight(1f)
106-
.fillMaxWidth(),
107-
) {
108-
content()
109-
}
110-
// Footer
111-
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
112-
footer()
113-
}
119+
footer()
114120
}
115121
}
116122
}
@@ -123,8 +129,7 @@ internal fun HeaderFooterPagePreview() = ElementPreview {
123129
HeaderFooterPage(
124130
content = {
125131
Box(
126-
Modifier
127-
.fillMaxSize(),
132+
modifier = Modifier.fillMaxWidth(),
128133
contentAlignment = Alignment.Center
129134
) {
130135
Text(
@@ -159,3 +164,46 @@ internal fun HeaderFooterPagePreview() = ElementPreview {
159164
}
160165
)
161166
}
167+
168+
@PreviewsDayNight
169+
@Composable
170+
internal fun HeaderFooterPageScrollablePreview() = ElementPreview {
171+
HeaderFooterPage(
172+
content = {
173+
Box(
174+
modifier = Modifier.fillMaxWidth(),
175+
contentAlignment = Alignment.Center
176+
) {
177+
Text(
178+
text = "Content",
179+
style = ElementTheme.typography.fontHeadingXlBold
180+
)
181+
}
182+
},
183+
header = {
184+
Box(
185+
Modifier
186+
.fillMaxWidth(),
187+
contentAlignment = Alignment.Center
188+
) {
189+
Text(
190+
text = "Header",
191+
style = ElementTheme.typography.fontHeadingXlBold
192+
)
193+
}
194+
},
195+
footer = {
196+
Box(
197+
Modifier
198+
.fillMaxWidth(),
199+
contentAlignment = Alignment.Center
200+
) {
201+
Text(
202+
text = "Footer",
203+
style = ElementTheme.typography.fontHeadingXlBold
204+
)
205+
}
206+
},
207+
isScrollable = true,
208+
)
209+
}

0 commit comments

Comments
 (0)