Skip to content

Commit 03a0e4f

Browse files
committed
Pinned event : hide/show banner on timeline scroll
1 parent 56e1957 commit 03a0e4f

File tree

4 files changed

+67
-5
lines changed

4 files changed

+67
-5
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package io.element.android.features.messages.impl
1818

19+
import androidx.compose.animation.AnimatedVisibility
20+
import androidx.compose.animation.expandVertically
21+
import androidx.compose.animation.shrinkVertically
1922
import androidx.compose.foundation.background
2023
import androidx.compose.foundation.clickable
2124
import androidx.compose.foundation.layout.Arrangement
@@ -33,6 +36,7 @@ import androidx.compose.foundation.layout.navigationBarsPadding
3336
import androidx.compose.foundation.layout.padding
3437
import androidx.compose.foundation.layout.statusBars
3538
import androidx.compose.foundation.layout.width
39+
import androidx.compose.foundation.lazy.rememberLazyListState
3640
import androidx.compose.foundation.shape.RoundedCornerShape
3741
import androidx.compose.material3.ExperimentalMaterial3Api
3842
import androidx.compose.material3.MaterialTheme
@@ -101,6 +105,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
101105
import io.element.android.libraries.designsystem.theme.components.TopAppBar
102106
import io.element.android.libraries.designsystem.utils.KeepScreenOn
103107
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
108+
import io.element.android.libraries.designsystem.utils.isScrollingUp
104109
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
105110
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
106111
import io.element.android.libraries.matrix.api.core.UserId
@@ -375,6 +380,7 @@ private fun MessagesViewContent(
375380
},
376381
content = { paddingValues ->
377382
Box(modifier = Modifier.padding(paddingValues)) {
383+
val timelineLazyListState = rememberLazyListState()
378384
TimelineView(
379385
state = state.timelineState,
380386
typingNotificationState = state.typingNotificationState,
@@ -389,8 +395,17 @@ private fun MessagesViewContent(
389395
onReadReceiptClick = onReadReceiptClick,
390396
forceJumpToBottomVisibility = forceJumpToBottomVisibility,
391397
onJoinCallClick = onJoinCallClick,
398+
lazyListState = timelineLazyListState,
392399
)
393-
PinnedMessagesBannerView(state = state.pinnedMessagesBannerState)
400+
AnimatedVisibility(
401+
visible = state.pinnedMessagesBannerState.displayBanner && timelineLazyListState.isScrollingUp(),
402+
enter = expandVertically(),
403+
exit = shrinkVertically(),
404+
) {
405+
PinnedMessagesBannerView(
406+
state = state.pinnedMessagesBannerState,
407+
)
408+
}
394409
}
395410
},
396411
sheetContent = { subcomposing: Boolean ->

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerView.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ import androidx.compose.foundation.layout.heightIn
3232
import androidx.compose.foundation.layout.size
3333
import androidx.compose.foundation.layout.width
3434
import androidx.compose.foundation.lazy.LazyColumn
35+
import androidx.compose.foundation.lazy.LazyListState
3536
import androidx.compose.foundation.lazy.rememberLazyListState
3637
import androidx.compose.runtime.Composable
3738
import androidx.compose.runtime.LaunchedEffect
3839
import androidx.compose.runtime.derivedStateOf
3940
import androidx.compose.runtime.getValue
41+
import androidx.compose.runtime.mutableIntStateOf
4042
import androidx.compose.runtime.remember
43+
import androidx.compose.runtime.setValue
4144
import androidx.compose.ui.Alignment
4245
import androidx.compose.ui.Modifier
4346
import androidx.compose.ui.draw.drawBehind
@@ -63,8 +66,6 @@ fun PinnedMessagesBannerView(
6366
state: PinnedMessagesBannerState,
6467
modifier: Modifier = Modifier,
6568
) {
66-
if (!state.displayBanner) return
67-
6869
val borderColor = ElementTheme.colors.pinnedMessageBannerBorder
6970
Row(
7071
modifier = modifier
@@ -199,6 +200,6 @@ private fun PinnedMessageItem(
199200
@Composable
200201
fun PinnedMessagesBannerViewPreview(@PreviewParameter(PinnedMessagesBannerStateProvider::class) state: PinnedMessagesBannerState) = ElementPreview {
201202
PinnedMessagesBannerView(
202-
state = state
203+
state = state,
203204
)
204205
}

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ fun TimelineView(
9090
onReadReceiptClick: (TimelineItem.Event) -> Unit,
9191
onJoinCallClick: () -> Unit,
9292
modifier: Modifier = Modifier,
93+
lazyListState: LazyListState = rememberLazyListState(),
9394
forceJumpToBottomVisibility: Boolean = false
9495
) {
9596
fun clearFocusRequestState() {
@@ -109,7 +110,6 @@ fun TimelineView(
109110
}
110111

111112
val context = LocalContext.current
112-
val lazyListState = rememberLazyListState()
113113
// Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version
114114
val useReverseLayout = remember {
115115
val accessibilityManager = context.getSystemService(AccessibilityManager::class.java)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2024 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.libraries.designsystem.utils
18+
19+
import androidx.compose.foundation.lazy.LazyListState
20+
import androidx.compose.runtime.Composable
21+
import androidx.compose.runtime.derivedStateOf
22+
import androidx.compose.runtime.getValue
23+
import androidx.compose.runtime.mutableIntStateOf
24+
import androidx.compose.runtime.remember
25+
import androidx.compose.runtime.setValue
26+
27+
/**
28+
* Returns whether the lazy list is currently scrolling up.
29+
*/
30+
@Composable
31+
fun LazyListState.isScrollingUp(): Boolean {
32+
var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) }
33+
var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) }
34+
return remember(this) {
35+
derivedStateOf {
36+
if (previousIndex != firstVisibleItemIndex) {
37+
previousIndex > firstVisibleItemIndex
38+
} else {
39+
previousScrollOffset >= firstVisibleItemScrollOffset
40+
}.also {
41+
previousIndex = firstVisibleItemIndex
42+
previousScrollOffset = firstVisibleItemScrollOffset
43+
}
44+
}
45+
}.value
46+
}

0 commit comments

Comments
 (0)