mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
android, desktop: scrolling moves title to app bar (#4703)
* android, desktop: scrolling moves title to app bar * one place should be without padding * scroll related changes for both platforms * adapt code to universal ColumnWithScrollBar * show in center * small adjustments * new chat sheet fix * divider + mix background color for desktop * coerce * different transition * desktop title starts from left * host starts from left too * different coefficient * settings title
This commit is contained in:
committed by
GitHub
parent
75a468434c
commit
885aa9cfa5
+3
@@ -77,6 +77,9 @@ actual fun windowOrientation(): WindowOrientation =
|
||||
@Composable
|
||||
actual fun windowWidth(): Dp = simplexWindowState.windowState.size.width
|
||||
|
||||
@Composable
|
||||
actual fun windowHeight(): Dp = simplexWindowState.windowState.size.height
|
||||
|
||||
actual fun desktopExpandWindowToWidth(width: Dp) {
|
||||
if (simplexWindowState.windowState.size.width >= width) return
|
||||
simplexWindowState.windowState.size = simplexWindowState.windowState.size.copy(width = width)
|
||||
|
||||
+84
-45
@@ -13,16 +13,18 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.input.pointer.*
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.views.helpers.detectCursorMove
|
||||
import chat.simplex.common.views.helpers.mixWith
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@Composable
|
||||
actual fun LazyColumnWithScrollBar(
|
||||
modifier: Modifier,
|
||||
state: LazyListState,
|
||||
state: LazyListState?,
|
||||
contentPadding: PaddingValues,
|
||||
reverseLayout: Boolean,
|
||||
verticalArrangement: Arrangement.Vertical,
|
||||
@@ -30,44 +32,6 @@ actual fun LazyColumnWithScrollBar(
|
||||
flingBehavior: FlingBehavior,
|
||||
userScrollEnabled: Boolean,
|
||||
content: LazyListScope.() -> Unit
|
||||
) {
|
||||
if (appPlatform.isAndroid) {
|
||||
LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
|
||||
} else {
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollBarAlpha = remember { Animatable(0f) }
|
||||
val scrollJob: MutableState<Job> = remember { mutableStateOf(Job()) }
|
||||
val scrollModifier = remember {
|
||||
Modifier
|
||||
.pointerInput(Unit) {
|
||||
detectCursorMove {
|
||||
scope.launch {
|
||||
scrollBarAlpha.animateTo(1f)
|
||||
}
|
||||
scrollJob.value.cancel()
|
||||
scrollJob.value = scope.launch {
|
||||
delay(1000L)
|
||||
scrollBarAlpha.animateTo(0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Box {
|
||||
LazyColumn(modifier.then(if (appPlatform.isDesktop) scrollModifier else Modifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
|
||||
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun ColumnWithScrollBar(
|
||||
modifier: Modifier,
|
||||
verticalArrangement: Arrangement.Vertical,
|
||||
horizontalAlignment: Alignment.Horizontal,
|
||||
state: ScrollState,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollBarAlpha = remember { Animatable(0f) }
|
||||
@@ -87,20 +51,95 @@ actual fun ColumnWithScrollBar(
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(modifier.verticalScroll(state).then(scrollModifier), verticalArrangement, horizontalAlignment, content)
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
|
||||
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false)
|
||||
val state = state ?: LocalAppBarHandler.current?.listState ?: rememberLazyListState()
|
||||
val connection = LocalAppBarHandler.current?.connection
|
||||
// When scroll bar is dragging, there is no scroll event in nested scroll modifier. So, listen for changes on lazy column state
|
||||
// (only first visible row is useful because LazyColumn doesn't have absolute scroll position, only relative to row)
|
||||
val scrollBarDraggingState = remember { mutableStateOf(false) }
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { state.firstVisibleItemScrollOffset }
|
||||
.filter { state.firstVisibleItemIndex == 0 }
|
||||
.collect { scrollPosition ->
|
||||
val offset = connection?.appBarOffset
|
||||
if (offset != null && ((offset + scrollPosition).absoluteValue > 1 || scrollBarDraggingState.value)) {
|
||||
connection.appBarOffset = -scrollPosition.toFloat()
|
||||
// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(if (connection != null) Modifier.nestedScroll(connection) else Modifier) {
|
||||
LazyColumn(modifier.then(scrollModifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content)
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
|
||||
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout, scrollBarDraggingState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean) {
|
||||
actual fun ColumnWithScrollBar(
|
||||
modifier: Modifier,
|
||||
verticalArrangement: Arrangement.Vertical,
|
||||
horizontalAlignment: Alignment.Horizontal,
|
||||
state: ScrollState?,
|
||||
maxIntrinsicSize: Boolean,
|
||||
content: @Composable() (ColumnScope.() -> Unit)
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollBarAlpha = remember { Animatable(0f) }
|
||||
val scrollJob: MutableState<Job> = remember { mutableStateOf(Job()) }
|
||||
val scrollModifier = remember {
|
||||
Modifier
|
||||
.pointerInput(Unit) {
|
||||
detectCursorMove {
|
||||
scope.launch {
|
||||
scrollBarAlpha.animateTo(1f)
|
||||
}
|
||||
scrollJob.value.cancel()
|
||||
scrollJob.value = scope.launch {
|
||||
delay(1000L)
|
||||
scrollBarAlpha.animateTo(0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val state = state ?: LocalAppBarHandler.current?.scrollState ?: rememberScrollState()
|
||||
val connection = LocalAppBarHandler.current?.connection
|
||||
// When scroll bar is dragging, there is no scroll event in nested scroll modifier. So, listen for changes on column state
|
||||
// (exact scroll position is available but in Int, not Float)
|
||||
val scrollBarDraggingState = remember { mutableStateOf(false) }
|
||||
LaunchedEffect(Unit) {
|
||||
snapshotFlow { state.value }
|
||||
.collect { scrollPosition ->
|
||||
val offset = connection?.appBarOffset
|
||||
if (offset != null && ((offset + scrollPosition).absoluteValue > 1 || scrollBarDraggingState.value)) {
|
||||
connection.appBarOffset = -scrollPosition.toFloat()
|
||||
// Log.d(TAG, "Scrolling position changed from $offset to ${connection.appBarOffset}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(if (connection != null) Modifier.nestedScroll(connection) else Modifier) {
|
||||
Column(
|
||||
if (maxIntrinsicSize) {
|
||||
modifier.verticalScroll(state).height(IntrinsicSize.Max).then(scrollModifier)
|
||||
} else {
|
||||
modifier.verticalScroll(state).then(scrollModifier)
|
||||
},
|
||||
verticalArrangement, horizontalAlignment, content)
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
|
||||
DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, false, scrollBarDraggingState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable<Float, AnimationVector1D>, scrollJob: MutableState<Job>, reversed: Boolean, updateDraggingState: MutableState<Boolean> = remember { mutableStateOf(false) }) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val isHovered by interactionSource.collectIsHoveredAsState()
|
||||
val isDragged by interactionSource.collectIsDraggedAsState()
|
||||
LaunchedEffect(isHovered, isDragged) {
|
||||
scrollJob.value.cancel()
|
||||
updateDraggingState.value = isDragged
|
||||
if (isHovered || isDragged) {
|
||||
scrollBarAlpha.animateTo(1f)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user