Skip to content

Commit e56c7e1

Browse files
bmartyChelseaDHElementBot
authored
Floating toolbar (#6147)
* Use floating toolbar on homepage * Fix deprecation issue * Create HorizontalFloatingToolbar wrapper in our components. * Fix Konsist test. * Fix compilation issue after rebase. * Fix lint issue. `floatingActionButton` must be the last parameter. * Add Preview for the case empty space. * Fix navigation bar overlapping buttons in empty space view. * Increase content padding, and apply it to the space tab too. * Update screenshots --------- Co-authored-by: chelsea <git@cdhildit.ch> Co-authored-by: ElementBot <android@element.io>
2 parents 78d9815 + 58b8a37 commit e56c7e1

File tree

50 files changed

+395
-165
lines changed

Some content is hidden

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

50 files changed

+395
-165
lines changed

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ data class HomeState(
3333
val eventSink: (HomeEvent) -> Unit,
3434
) {
3535
val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected
36-
val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats
3736
val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters
3837
val showNavigationBar = homeSpacesState.canCreateSpaces || homeSpacesState.spaceRooms.isNotEmpty()
3938
}

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStateProvider.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ open class HomeStateProvider : PreviewParameterProvider<HomeState> {
4545
),
4646
) + RoomListStateProvider().values.map {
4747
aHomeState(roomListState = it)
48-
}
48+
} + aHomeState(
49+
currentHomeNavigationBarItem = HomeNavigationBarItem.Spaces,
50+
homeSpacesState = aHomeSpacesState(
51+
spaceRooms = emptyList(),
52+
),
53+
)
4954
}
5055

5156
internal fun aHomeState(

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@ import androidx.compose.foundation.layout.fillMaxSize
2121
import androidx.compose.foundation.layout.padding
2222
import androidx.compose.foundation.lazy.rememberLazyListState
2323
import androidx.compose.material3.ExperimentalMaterial3Api
24+
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
25+
import androidx.compose.material3.FabPosition
26+
import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
2427
import androidx.compose.material3.TopAppBarDefaults
2528
import androidx.compose.material3.rememberTopAppBarState
2629
import androidx.compose.runtime.Composable
2730
import androidx.compose.runtime.remember
2831
import androidx.compose.runtime.rememberCoroutineScope
2932
import androidx.compose.ui.Modifier
30-
import androidx.compose.ui.graphics.Color
3133
import androidx.compose.ui.input.nestedscroll.nestedScroll
3234
import androidx.compose.ui.platform.LocalLayoutDirection
3335
import androidx.compose.ui.res.stringResource
3436
import androidx.compose.ui.tooling.preview.Preview
3537
import androidx.compose.ui.tooling.preview.PreviewParameter
3638
import androidx.compose.ui.unit.dp
39+
import androidx.compose.ui.zIndex
3740
import dev.chrisbanes.haze.hazeEffect
3841
import dev.chrisbanes.haze.hazeSource
3942
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
@@ -58,15 +61,15 @@ import io.element.android.libraries.androidutils.throttler.FirstThrottler
5861
import io.element.android.libraries.designsystem.preview.ElementPreview
5962
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
6063
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
64+
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbar
65+
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarItem
66+
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarSeparator
6167
import io.element.android.libraries.designsystem.theme.components.Icon
62-
import io.element.android.libraries.designsystem.theme.components.NavigationBar
63-
import io.element.android.libraries.designsystem.theme.components.NavigationBarIcon
64-
import io.element.android.libraries.designsystem.theme.components.NavigationBarItem
65-
import io.element.android.libraries.designsystem.theme.components.NavigationBarText
6668
import io.element.android.libraries.designsystem.theme.components.Scaffold
6769
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
6870
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
6971
import io.element.android.libraries.matrix.api.core.RoomId
72+
import io.element.android.libraries.ui.strings.CommonStrings
7073
import kotlinx.coroutines.launch
7174

7275
@Composable
@@ -185,20 +188,18 @@ private fun HomeScaffold(
185188
onAccountSwitch = {
186189
state.eventSink(HomeEvent.SwitchToAccount(it))
187190
},
188-
onCreateSpace = onCreateSpaceClick,
189191
scrollBehavior = scrollBehavior,
190192
displayFilters = state.displayRoomListFilters,
191193
filtersState = roomListState.filtersState,
192194
spaceFiltersState = roomListState.spaceFiltersState,
193-
canCreateSpaces = state.homeSpacesState.canCreateSpaces,
194195
canReportBug = state.canReportBug,
195196
modifier = Modifier.hazeEffect(
196197
state = hazeState,
197198
style = HazeMaterials.thick(),
198199
)
199200
)
200201
},
201-
bottomBar = {
202+
floatingActionButton = {
202203
if (state.showNavigationBar) {
203204
val coroutineScope = rememberCoroutineScope()
204205
HomeBottomBar(
@@ -222,14 +223,29 @@ private fun HomeScaffold(
222223
state.eventSink(HomeEvent.SelectHomeNavigationBarItem(item))
223224
}
224225
},
225-
modifier = Modifier.hazeEffect(
226-
state = hazeState,
227-
style = HazeMaterials.thick(),
228-
)
226+
floatingActionButton = when (state.currentHomeNavigationBarItem) {
227+
HomeNavigationBarItem.Chats -> {
228+
{
229+
HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_room)
230+
}
231+
}
232+
HomeNavigationBarItem.Spaces -> if (state.homeSpacesState.canCreateSpaces) {
233+
{
234+
HomeFloatingActionButton(onCreateSpaceClick, CommonStrings.action_create_space)
235+
}
236+
} else {
237+
// No FAB for spaces if we cannot create spaces
238+
null
239+
}
240+
},
229241
)
230242
}
231243
},
244+
floatingActionButtonPosition = FabPosition.Center,
232245
content = { padding ->
246+
val contentPadding = PaddingValues(
247+
bottom = 112.dp,
248+
)
233249
when (state.currentHomeNavigationBarItem) {
234250
HomeNavigationBarItem.Chats -> {
235251
RoomListContentView(
@@ -243,15 +259,7 @@ private fun HomeScaffold(
243259
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
244260
onRoomClick = ::onRoomClick,
245261
onCreateRoomClick = onStartChatClick,
246-
contentPadding = PaddingValues(
247-
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80,
248-
// and include provided bottom padding
249-
// Disable contentPadding due to navigation issue using the keyboard
250-
// See https://issuetracker.google.com/issues/436432313
251-
bottom = 80.dp,
252-
// bottom = 80.dp + padding.calculateBottomPadding(),
253-
// top = padding.calculateTopPadding()
254-
),
262+
contentPadding = contentPadding,
255263
modifier = Modifier
256264
.padding(
257265
PaddingValues(
@@ -274,6 +282,7 @@ private fun HomeScaffold(
274282
.padding(padding)
275283
.consumeWindowInsets(padding)
276284
.hazeSource(state = hazeState),
285+
contentPadding = contentPadding,
277286
state = state.homeSpacesState,
278287
lazyListState = spacesLazyListState,
279288
onSpaceClick = { spaceId ->
@@ -286,49 +295,48 @@ private fun HomeScaffold(
286295
}
287296
}
288297
},
289-
floatingActionButton = {
290-
if (state.displayActions) {
291-
FloatingActionButton(
292-
onClick = onStartChatClick,
293-
) {
294-
Icon(
295-
imageVector = CompoundIcons.Plus(),
296-
contentDescription = stringResource(id = R.string.screen_roomlist_a11y_create_message),
297-
)
298-
}
299-
}
300-
},
301298
snackbarHost = { SnackbarHost(snackbarHostState) },
302299
)
303300
}
304301

302+
@Composable
303+
private fun HomeFloatingActionButton(
304+
onClick: () -> Unit,
305+
contentDescription: Int,
306+
modifier: Modifier = Modifier,
307+
) {
308+
FloatingActionButton(onClick = onClick, modifier = modifier) {
309+
Icon(
310+
imageVector = CompoundIcons.Plus(),
311+
contentDescription = stringResource(id = contentDescription),
312+
)
313+
}
314+
}
315+
316+
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
305317
@Composable
306318
private fun HomeBottomBar(
307319
currentHomeNavigationBarItem: HomeNavigationBarItem,
308320
onItemClick: (HomeNavigationBarItem) -> Unit,
309321
modifier: Modifier = Modifier,
322+
floatingActionButton: (@Composable () -> Unit)?,
310323
) {
311-
NavigationBar(
312-
containerColor = Color.Transparent,
324+
HorizontalFloatingToolbar(
325+
floatingActionButton = floatingActionButton,
313326
modifier = modifier
327+
.padding(bottom = ScreenOffset)
328+
.zIndex(1f),
314329
) {
315-
HomeNavigationBarItem.entries.forEach { item ->
330+
HomeNavigationBarItem.entries.forEachIndexed { index, item ->
331+
if (index > 0) {
332+
HorizontalFloatingToolbarSeparator()
333+
}
316334
val isSelected = currentHomeNavigationBarItem == item
317-
NavigationBarItem(
318-
selected = isSelected,
319-
onClick = {
320-
onItemClick(item)
321-
},
322-
icon = {
323-
NavigationBarIcon(
324-
imageVector = item.icon(isSelected),
325-
)
326-
},
327-
label = {
328-
NavigationBarText(
329-
text = stringResource(item.labelRes),
330-
)
331-
}
335+
HorizontalFloatingToolbarItem(
336+
icon = item.icon(isSelected),
337+
tooltipLabel = stringResource(item.labelRes),
338+
isSelected = isSelected,
339+
onClick = { onItemClick(item) },
332340
)
333341
}
334342
}

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ fun HomeTopBar(
8787
onMenuActionClick: (RoomListMenuAction) -> Unit,
8888
onOpenSettings: () -> Unit,
8989
onAccountSwitch: (SessionId) -> Unit,
90-
onCreateSpace: () -> Unit,
9190
scrollBehavior: TopAppBarScrollBehavior,
92-
canCreateSpaces: Boolean,
9391
canReportBug: Boolean,
9492
displayFilters: Boolean,
9593
filtersState: RoomListFiltersState,
@@ -134,17 +132,13 @@ fun HomeTopBar(
134132
)
135133
},
136134
actions = {
137-
when (selectedNavigationItem) {
138-
HomeNavigationBarItem.Chats -> RoomListMenuItems(
135+
if (selectedNavigationItem == HomeNavigationBarItem.Chats) {
136+
RoomListMenuItems(
139137
onToggleSearch = onToggleSearch,
140138
onMenuActionClick = onMenuActionClick,
141139
canReportBug = canReportBug,
142140
spaceFiltersState = spaceFiltersState,
143141
)
144-
HomeNavigationBarItem.Spaces -> SpacesMenuItems(
145-
canCreateSpaces = canCreateSpaces,
146-
onCreateSpace = onCreateSpace
147-
)
148142
}
149143
},
150144
// We want a 16dp left padding for the navigationIcon :
@@ -230,21 +224,6 @@ private fun RoomListMenuItems(
230224
}
231225
}
232226

233-
@Composable
234-
private fun SpacesMenuItems(
235-
canCreateSpaces: Boolean,
236-
onCreateSpace: () -> Unit
237-
) {
238-
if (canCreateSpaces) {
239-
IconButton(onClick = onCreateSpace) {
240-
Icon(
241-
imageVector = CompoundIcons.Plus(),
242-
contentDescription = stringResource(CommonStrings.action_create_space)
243-
)
244-
}
245-
}
246-
}
247-
248227
@Composable
249228
private fun SpaceFilterButton(
250229
spaceFiltersState: SpaceFiltersState,
@@ -365,8 +344,6 @@ internal fun HomeTopBarPreview() = ElementPreview {
365344
onOpenSettings = {},
366345
onAccountSwitch = {},
367346
onToggleSearch = {},
368-
onCreateSpace = {},
369-
canCreateSpaces = true,
370347
canReportBug = true,
371348
displayFilters = true,
372349
filtersState = aRoomListFiltersState(),
@@ -388,8 +365,6 @@ internal fun HomeTopBarSpaceFiltersSelectedPreview() = ElementPreview {
388365
onOpenSettings = {},
389366
onAccountSwitch = {},
390367
onToggleSearch = {},
391-
onCreateSpace = {},
392-
canCreateSpaces = true,
393368
canReportBug = true,
394369
displayFilters = true,
395370
filtersState = aRoomListFiltersState(),
@@ -411,8 +386,6 @@ internal fun HomeTopBarSpacesPreview() = ElementPreview {
411386
onOpenSettings = {},
412387
onAccountSwitch = {},
413388
onToggleSearch = {},
414-
onCreateSpace = {},
415-
canCreateSpaces = true,
416389
canReportBug = true,
417390
displayFilters = false,
418391
filtersState = aRoomListFiltersState(),
@@ -434,8 +407,6 @@ internal fun HomeTopBarWithIndicatorPreview() = ElementPreview {
434407
onOpenSettings = {},
435408
onAccountSwitch = {},
436409
onToggleSearch = {},
437-
onCreateSpace = {},
438-
canCreateSpaces = true,
439410
canReportBug = true,
440411
displayFilters = true,
441412
filtersState = aRoomListFiltersState(),
@@ -457,8 +428,6 @@ internal fun HomeTopBarMultiAccountPreview() = ElementPreview {
457428
onOpenSettings = {},
458429
onAccountSwitch = {},
459430
onToggleSearch = {},
460-
onCreateSpace = {},
461-
canCreateSpaces = true,
462431
canReportBug = true,
463432
displayFilters = true,
464433
filtersState = aRoomListFiltersState(),

features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package io.element.android.features.home.impl.spaces
1010

1111
import androidx.compose.foundation.layout.Arrangement
1212
import androidx.compose.foundation.layout.Column
13+
import androidx.compose.foundation.layout.PaddingValues
1314
import androidx.compose.foundation.layout.fillMaxWidth
1415
import androidx.compose.foundation.layout.padding
1516
import androidx.compose.foundation.lazy.LazyColumn
@@ -48,22 +49,24 @@ import kotlinx.collections.immutable.toImmutableList
4849
fun HomeSpacesView(
4950
state: HomeSpacesState,
5051
lazyListState: LazyListState,
52+
contentPadding: PaddingValues,
5153
onSpaceClick: (RoomId) -> Unit,
5254
onCreateSpaceClick: () -> Unit,
5355
onExploreClick: () -> Unit,
5456
modifier: Modifier = Modifier,
5557
) {
5658
if (state.canCreateSpaces && state.spaceRooms.isEmpty()) {
5759
EmptySpaceHomeView(
58-
modifier = modifier,
60+
modifier = modifier.padding(contentPadding),
5961
onCreateSpaceClick = onCreateSpaceClick,
6062
onExploreClick = onExploreClick,
6163
canExploreSpaces = state.canExploreSpaces,
6264
)
6365
} else {
6466
LazyColumn(
6567
modifier = modifier,
66-
state = lazyListState
68+
state = lazyListState,
69+
contentPadding = contentPadding,
6770
) {
6871
val space = state.space
6972
when (space) {
@@ -115,6 +118,9 @@ fun HomeSpacesView(
115118
}
116119
}
117120

121+
/**
122+
* Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=1763-74215&t=9IGKMXHDfTGAqzQK-4
123+
*/
118124
@Composable
119125
private fun EmptySpaceHomeView(
120126
onCreateSpaceClick: () -> Unit,
@@ -159,8 +165,7 @@ private fun EmptySpaceHomeView(
159165
}
160166
}
161167
}
162-
) {
163-
}
168+
)
164169
}
165170

166171
@PreviewsDayNight
@@ -174,5 +179,6 @@ internal fun HomeSpacesViewPreview(
174179
onSpaceClick = {},
175180
onCreateSpaceClick = {},
176181
onExploreClick = {},
182+
contentPadding = PaddingValues(bottom = 112.dp),
177183
)
178184
}

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ androidx_preference = "androidx.preference:preference:1.2.1"
120120
androidx_webkit = "androidx.webkit:webkit:1.15.0"
121121

122122
androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" }
123-
androidx_compose_material3 = { module = "androidx.compose.material3:material3" }
123+
androidx_compose_material3 = { module = "androidx.compose.material3:material3", version = '1.5.0-alpha11' }
124124
androidx_compose_material3_windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class" }
125125
androidx_compose_material3_adaptive = "androidx.compose.material3:material3-adaptive-android:1.0.0-alpha06"
126126
androidx_compose_ui = { module = "androidx.compose.ui:ui" }

0 commit comments

Comments
 (0)