Reinventing the wheel, but better this time. Better approach for draggable history list in calculator:

- Using anchored draggable
- Remembering button sizes
- Additional buttons are not resizeable anymore

closes #75
This commit is contained in:
sadellie 2023-07-30 20:39:54 +03:00
parent 19f1f436c3
commit 9cfb35b03e
5 changed files with 231 additions and 256 deletions

View File

@ -20,18 +20,16 @@ package com.sadellie.unitto.feature.calculator
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.rememberSplineBasedDecay
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable import androidx.compose.foundation.gestures.anchoredDraggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -45,18 +43,17 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
@ -73,13 +70,9 @@ import com.sadellie.unitto.core.ui.common.textfield.ExpressionTextField
import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField import com.sadellie.unitto.core.ui.common.textfield.UnformattedTextField
import com.sadellie.unitto.data.model.HistoryItem import com.sadellie.unitto.data.model.HistoryItem
import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard import com.sadellie.unitto.feature.calculator.components.CalculatorKeyboard
import com.sadellie.unitto.feature.calculator.components.DragDownView
import com.sadellie.unitto.feature.calculator.components.HistoryList import com.sadellie.unitto.feature.calculator.components.HistoryList
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import kotlin.math.abs
import kotlin.math.roundToInt
@Composable @Composable
internal fun CalculatorRoute( internal fun CalculatorRoute(
@ -117,24 +110,15 @@ private fun CalculatorScreen(
clearHistory: () -> Unit clearHistory: () -> Unit
) { ) {
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
val dragAmount = remember { Animatable(0f) }
val dragCoroutineScope = rememberCoroutineScope()
val dragAnimSpec = rememberSplineBasedDecay<Float>()
var textThingyHeight by remember { mutableIntStateOf(0) }
var historyItemHeight by remember { mutableIntStateOf(0) }
var showClearHistoryDialog by rememberSaveable { mutableStateOf(false) } var showClearHistoryDialog by rememberSaveable { mutableStateOf(false) }
val showClearHistoryButton by remember(dragAmount.value, historyItemHeight) { var showClearHistoryButton by rememberSaveable { mutableStateOf(false) }
derivedStateOf { dragAmount.value > historyItemHeight }
}
UnittoScreenWithTopBar( UnittoScreenWithTopBar(
title = { Text(stringResource(R.string.calculator)) }, title = { Text(stringResource(R.string.calculator)) },
navigationIcon = { MenuButton { navigateToMenu() } }, navigationIcon = { MenuButton { navigateToMenu() } },
colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceVariant), colors = TopAppBarDefaults.topAppBarColors(MaterialTheme.colorScheme.surfaceVariant),
actions = { actions = {
Crossfade(showClearHistoryButton) { Crossfade(showClearHistoryButton, label = "Clear button reveal") {
if (it) { if (it) {
IconButton( IconButton(
onClick = { showClearHistoryDialog = true }, onClick = { showClearHistoryDialog = true },
@ -151,26 +135,57 @@ private fun CalculatorScreen(
} }
} }
) { paddingValues -> ) { paddingValues ->
DragDownView( BoxWithConstraints(
modifier = Modifier.padding(paddingValues), modifier = Modifier.padding(paddingValues),
drag = dragAmount.value.roundToInt().coerceAtLeast(0), ) {
historyItemHeight = historyItemHeight, val density = LocalDensity.current
historyList = { var historyItemHeight by remember { mutableStateOf(0.dp) }
val textBoxHeight = maxHeight * 0.25f
var dragStateCurrentValue by rememberSaveable { mutableStateOf(DragState.CLOSED) }
val dragState = rememberDragState(
historyItem = historyItemHeight,
max = maxHeight - textBoxHeight,
initialValue = dragStateCurrentValue
)
val dragDp by remember(dragState.requireOffset()) {
derivedStateOf {
focusManager.clearFocus(true)
with(density) { dragState.requireOffset().toDp() }
}
}
val keyboardHeight by remember(dragState.requireOffset()) {
derivedStateOf {
if (dragDp > historyItemHeight) {
maxHeight - textBoxHeight - historyItemHeight
} else {
maxHeight - textBoxHeight - dragDp
}
}
}
LaunchedEffect(dragState.currentValue) {
dragStateCurrentValue = dragState.currentValue
showClearHistoryButton = dragState.currentValue == DragState.OPEN
}
// History
HistoryList( HistoryList(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)) .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
.fillMaxSize(), .fillMaxWidth()
.height(dragDp),
historyItems = uiState.history, historyItems = uiState.history,
historyItemHeightCallback = { historyItemHeight = it }, heightCallback = { historyItemHeight = it },
formatterSymbols = uiState.formatterSymbols, formatterSymbols = uiState.formatterSymbols,
addTokens = addSymbol, addTokens = addSymbol,
) )
},
textFields = { maxDragAmount -> // Input
Column( Column(
Modifier Modifier
.fillMaxHeight(0.25f) .offset(y = dragDp)
.onPlaced { textThingyHeight = it.size.height } .height(textBoxHeight)
.background( .background(
MaterialTheme.colorScheme.surfaceVariant, MaterialTheme.colorScheme.surfaceVariant,
RoundedCornerShape( RoundedCornerShape(
@ -178,29 +193,9 @@ private fun CalculatorScreen(
bottomStartPercent = 20, bottomEndPercent = 20 bottomStartPercent = 20, bottomEndPercent = 20
) )
) )
.draggable( .anchoredDraggable(
orientation = Orientation.Vertical, state = dragState,
state = rememberDraggableState { delta -> orientation = Orientation.Vertical
dragCoroutineScope.launch {
val draggedAmount = (dragAmount.value + delta).coerceAtLeast(0f)
dragAmount.snapTo(draggedAmount)
}
},
onDragStarted = {
// Moving composables with focus causes performance drop
focusManager.clearFocus(true)
},
onDragStopped = { velocity ->
dragCoroutineScope.launch {
dragAmount.animateDecay(velocity, dragAnimSpec)
// Snap to closest anchor (0, one history item, all history items)
val draggedAmount = listOf(0, historyItemHeight, maxDragAmount)
.minBy { abs(dragAmount.value.roundToInt() - it) }
.toFloat()
dragAmount.animateTo(draggedAmount)
}
}
) )
.padding(top = 12.dp), .padding(top = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
@ -268,11 +263,13 @@ private fun CalculatorScreen(
.sizeIn(24.dp, 4.dp) .sizeIn(24.dp, 4.dp)
) )
} }
},
numPad = { // Keyboard
CalculatorKeyboard( CalculatorKeyboard(
modifier = Modifier modifier = Modifier
.fillMaxSize() .offset(y = dragDp + textBoxHeight)
.height(keyboardHeight)
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 4.dp), .padding(horizontal = 8.dp, vertical = 4.dp),
radianMode = uiState.radianMode, radianMode = uiState.radianMode,
fractional = uiState.formatterSymbols.fractional, fractional = uiState.formatterSymbols.fractional,
@ -284,7 +281,6 @@ private fun CalculatorScreen(
evaluate = evaluate evaluate = evaluate
) )
} }
)
} }
if (showClearHistoryDialog) { if (showClearHistoryDialog) {

View File

@ -0,0 +1,53 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.calculator
import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.AnchoredDraggableState
import androidx.compose.foundation.gestures.DraggableAnchors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
internal enum class DragState { CLOSED, HALF, OPEN }
@Composable
internal fun rememberDragState(
initialValue: DragState = DragState.CLOSED,
historyItem: Dp,
max: Dp,
): AnchoredDraggableState<DragState> {
val historyItemHeight = with(LocalDensity.current) { historyItem.toPx() }
val maxHeight = with(LocalDensity.current) { max.toPx() }
return remember(key1 = historyItem) {
AnchoredDraggableState(
initialValue = initialValue,
anchors = DraggableAnchors {
DragState.CLOSED at 0f
DragState.HALF at historyItemHeight
DragState.OPEN at maxHeight
},
positionalThreshold = { 0f },
velocityThreshold = { 0f },
animationSpec = tween()
)
}
}

View File

@ -41,6 +41,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -50,7 +51,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import com.sadellie.unitto.core.base.Token import com.sadellie.unitto.core.base.Token
import com.sadellie.unitto.core.ui.common.ColumnWithConstraints import com.sadellie.unitto.core.ui.common.ColumnWithConstraints
import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional import com.sadellie.unitto.core.ui.common.KeyboardButtonAdditional
@ -160,23 +160,36 @@ private fun PortraitKeyboard(
ColumnWithConstraints( ColumnWithConstraints(
modifier = modifier modifier = modifier
) { constraints -> ) { constraints ->
fun verticalFraction(fraction: Float): Dp = constraints.maxHeight * fraction val mainButtonHorizontalPadding by remember {
fun horizontalFraction(fraction: Float): Dp = constraints.maxWidth * fraction derivedStateOf { (constraints.maxWidth * 0.01f) }
}
val additionalButtonHeight by remember {
mutableStateOf(constraints.maxHeight * 0.09f)
}
val spacerHeight by remember {
mutableStateOf(constraints.maxHeight * 0.025f)
}
val additionalRowSpacedBy by remember {
mutableStateOf(constraints.maxWidth * 0.03f)
}
val weightModifier = Modifier.weight(1f) val weightModifier = Modifier.weight(1f)
val mainButtonModifier = Modifier val mainButtonModifier = Modifier
.fillMaxSize() .fillMaxSize()
.weight(1f) .weight(1f)
.padding(horizontalFraction(0.015f), verticalFraction(0.009f)) .padding(mainButtonHorizontalPadding)
val additionalButtonModifier = Modifier val additionalButtonModifier = Modifier
.weight(1f) .weight(1f)
.height(verticalFraction(0.09f)) .height(additionalButtonHeight)
Spacer(modifier = Modifier.height(verticalFraction(0.025f))) Spacer(modifier = Modifier.height(spacerHeight))
Row( Row(
modifier = Modifier, modifier = Modifier,
horizontalArrangement = Arrangement.spacedBy(horizontalFraction(0.03f)) horizontalArrangement = Arrangement.spacedBy(additionalRowSpacedBy)
) { ) {
// Additional buttons // Additional buttons
Crossfade(invMode, weightModifier) { Crossfade(invMode, weightModifier) {
@ -204,7 +217,7 @@ private fun PortraitKeyboard(
} }
Box( Box(
modifier = Modifier.size(verticalFraction(0.09f)), modifier = Modifier.size(additionalButtonHeight),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
// Expand/Collapse // Expand/Collapse
@ -217,7 +230,7 @@ private fun PortraitKeyboard(
} }
} }
Spacer(modifier = Modifier.height(verticalFraction(0.025f))) Spacer(modifier = Modifier.height(spacerHeight))
Row(weightModifier) { Row(weightModifier) {
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) } KeyboardButtonFilled(mainButtonModifier, UnittoIcons.LeftBracket, allowVibration) { addSymbol(Token.Operator.leftBracket) }
@ -250,7 +263,7 @@ private fun PortraitKeyboard(
KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Equal, allowVibration) { evaluate() } KeyboardButtonFilled(mainButtonModifier, UnittoIcons.Equal, allowVibration) { evaluate() }
} }
Spacer(modifier = Modifier.height(verticalFraction(0.015f))) Spacer(modifier = Modifier.height(spacerHeight))
} }
} }

View File

@ -1,92 +0,0 @@
/*
* Unitto is a unit converter for Android
* Copyright (c) 2023 Elshan Agaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sadellie.unitto.feature.calculator.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.offset
/**
* Screen layout where [historyList] can be seen only when you drag [textFields] down.
*
* @param modifier [Modifier] that will be applied to [SubcomposeLayout].
* @param drag Drag amount. Update this when dragging [textFields].
* @param historyItemHeight Height of one item in [historyList].
* @param textFields This part of the UI should be used as a handle. Offsets when dragging.
* @param numPad Composable with buttons. Offsets when drag amount is higher than [historyItemHeight]
* (otherwise will just shrink).
*/
@Composable
internal fun DragDownView(
modifier: Modifier,
drag: Int,
historyItemHeight: Int,
historyList: @Composable () -> Unit,
textFields: @Composable (maxDragAmount: Int) -> Unit,
numPad: @Composable () -> Unit
) {
SubcomposeLayout(modifier = modifier) { constraints ->
val showHistory = drag < historyItemHeight
val offset = if (showHistory) (drag - historyItemHeight).coerceAtLeast(0) else 0
val textFieldPlaceables = subcompose(DragDownContent.TextFields) {
textFields(constraints.maxHeight)
}.map { it.measure(constraints.offset(offset)) }
val textFieldsHeight = textFieldPlaceables.maxByOrNull { it.height }?.height ?: 0
val historyListPlaceables = subcompose(DragDownContent.HistoryList) {
historyList()
}.map {
it.measure(
constraints.copy(
maxHeight = drag.coerceAtMost(constraints.maxHeight - textFieldsHeight)
)
)
}
val padding = if (showHistory) drag.coerceAtLeast(0) else historyItemHeight
val numPadConstraints = constraints
.offset(offset)
.copy(maxHeight = constraints.maxHeight - textFieldsHeight - padding)
val numPadPlaceables = subcompose(DragDownContent.NumPad, numPad).map {
it.measure(numPadConstraints)
}
layout(constraints.maxWidth, constraints.maxHeight) {
var yPos = 0
historyListPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
textFieldPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
numPadPlaceables.forEach {
it.place(0, yPos)
yPos += it.height
}
}
}
}
private enum class DragDownContent { HistoryList, TextFields, NumPad }

View File

@ -49,6 +49,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalTextInputService import androidx.compose.ui.platform.LocalTextInputService
import androidx.compose.ui.platform.LocalTextToolbar import androidx.compose.ui.platform.LocalTextToolbar
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
@ -57,6 +58,7 @@ import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.sadellie.unitto.core.base.R import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer import com.sadellie.unitto.core.ui.common.textfield.ExpressionTransformer
@ -73,14 +75,14 @@ import java.util.Locale
internal fun HistoryList( internal fun HistoryList(
modifier: Modifier, modifier: Modifier,
historyItems: List<HistoryItem>, historyItems: List<HistoryItem>,
historyItemHeightCallback: (Int) -> Unit, heightCallback: (Dp) -> Unit,
formatterSymbols: FormatterSymbols, formatterSymbols: FormatterSymbols,
addTokens: (String) -> Unit, addTokens: (String) -> Unit,
) { ) {
if (historyItems.isEmpty()) { if (historyItems.isEmpty()) {
HistoryListPlaceholder( HistoryListPlaceholder(
modifier = modifier, modifier = modifier,
historyItemHeightCallback = historyItemHeightCallback heightCallback = heightCallback
) )
} else { } else {
HistoryListContent( HistoryListContent(
@ -88,7 +90,7 @@ internal fun HistoryList(
historyItems = historyItems, historyItems = historyItems,
addTokens = addTokens, addTokens = addTokens,
formatterSymbols = formatterSymbols, formatterSymbols = formatterSymbols,
historyItemHeightCallback = historyItemHeightCallback heightCallback = heightCallback
) )
} }
} }
@ -96,15 +98,17 @@ internal fun HistoryList(
@Composable @Composable
private fun HistoryListPlaceholder( private fun HistoryListPlaceholder(
modifier: Modifier, modifier: Modifier,
historyItemHeightCallback: (Int) -> Unit heightCallback: (Dp) -> Unit,
) { ) {
val density = LocalDensity.current
Column( Column(
modifier = modifier.wrapContentHeight(unbounded = true), modifier = modifier.wrapContentHeight(unbounded = true),
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
.onPlaced { historyItemHeightCallback(it.size.height) } .onPlaced { heightCallback(with(density) { it.size.height.toDp() }) }
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 32.dp), .padding(vertical = 32.dp),
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
@ -122,8 +126,9 @@ private fun HistoryListContent(
historyItems: List<HistoryItem>, historyItems: List<HistoryItem>,
addTokens: (String) -> Unit, addTokens: (String) -> Unit,
formatterSymbols: FormatterSymbols, formatterSymbols: FormatterSymbols,
historyItemHeightCallback: (Int) -> Unit heightCallback: (Dp) -> Unit,
) { ) {
val density = LocalDensity.current
val state = rememberLazyListState() val state = rememberLazyListState()
val firstItem by remember(historyItems) { mutableStateOf(historyItems.first()) } val firstItem by remember(historyItems) { mutableStateOf(historyItems.first()) }
val restOfTheItems by remember(firstItem) { mutableStateOf(historyItems.drop(1)) } val restOfTheItems by remember(firstItem) { mutableStateOf(historyItems.drop(1)) }
@ -139,7 +144,7 @@ private fun HistoryListContent(
// We do this so that callback for items height is called only once // We do this so that callback for items height is called only once
item(firstItem.id) { item(firstItem.id) {
HistoryListItem( HistoryListItem(
modifier = Modifier.onPlaced { historyItemHeightCallback(it.size.height) }, modifier = Modifier.onPlaced { heightCallback(with(density) { it.size.height.toDp() }) },
historyItem = historyItems.first(), historyItem = historyItems.first(),
formatterSymbols = formatterSymbols, formatterSymbols = formatterSymbols,
addTokens = addTokens, addTokens = addTokens,
@ -270,7 +275,7 @@ private fun PreviewHistoryList() {
.fillMaxSize(), .fillMaxSize(),
historyItems = historyItems, historyItems = historyItems,
formatterSymbols = FormatterSymbols.Spaces, formatterSymbols = FormatterSymbols.Spaces,
historyItemHeightCallback = {}, heightCallback = {},
addTokens = {} addTokens = {}
) )
} }