Updated on 2026-08-14
This commit is contained in:
parent
3ae32901d4
commit
8d02828096
3 changed files with 140 additions and 84 deletions
|
|
@ -21,10 +21,15 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.geometry.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
|
|
@ -64,8 +69,6 @@ import com.tangem.core.ui.res.TangemThemePreview
|
|||
import com.tangem.core.ui.test.MainScreenTestTags
|
||||
import com.tangem.core.ui.test.MarketTooltipTestTags
|
||||
import com.tangem.core.ui.utils.TangemSharedTransitionLayout
|
||||
import com.tangem.core.ui.utils.lineTo
|
||||
import com.tangem.core.ui.utils.moveTo
|
||||
import com.tangem.core.ui.utils.toPx
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.feature.wallet.presentation.common.preview.WalletScreenPreviewDataLegacy.accountScreenState
|
||||
|
|
@ -396,17 +399,10 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
}
|
||||
|
||||
BottomSheetScrim(
|
||||
color = if (state.showMarketsOnboarding) {
|
||||
Color.Black.copy(alpha = .65f)
|
||||
} else {
|
||||
Color.Black.copy(alpha = .40f)
|
||||
},
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded ||
|
||||
state.showMarketsOnboarding,
|
||||
color = Color.Black.copy(alpha = .40f),
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded,
|
||||
onDismissRequest = {
|
||||
if (!state.showMarketsOnboarding) {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
}
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -414,7 +410,7 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 8.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
isVisible = state.showMarketsOnboarding,
|
||||
availableHeight = maxHeight,
|
||||
|
|
@ -527,33 +523,22 @@ private fun MarketsHint(isVisible: Boolean, modifier: Modifier = Modifier) {
|
|||
|
||||
@Composable
|
||||
private fun MarketsTooltipContent(onCloseClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val backgroundColor = TangemTheme.colors.background.primary
|
||||
val cornerRadius = CornerRadius(x = 16.dp.toPx())
|
||||
val backgroundColor = TangemTheme.colors.background.action
|
||||
val tipDpSize = DpSize(width = 20.dp, height = 8.dp)
|
||||
val tooltipShape = remember(tipDpSize) { TooltipShape(cornerRadius = 16.dp, tipSize = tipDpSize) }
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(bottom = tipDpSize.height)
|
||||
.drawBehind {
|
||||
val rect = size.toRect()
|
||||
val tipSize = tipDpSize.toSize()
|
||||
val tipRect = Rect(
|
||||
offset = Offset(
|
||||
x = rect.center.x - tipSize.center.x,
|
||||
y = rect.bottom,
|
||||
),
|
||||
size = tipSize,
|
||||
)
|
||||
drawRoundRect(color = backgroundColor, cornerRadius = cornerRadius)
|
||||
|
||||
val tipPath = Path().apply {
|
||||
moveTo(tipRect.topLeft)
|
||||
lineTo(tipRect.bottomCenter)
|
||||
lineTo(tipRect.topRight)
|
||||
}
|
||||
drawPath(color = backgroundColor, path = tipPath)
|
||||
}
|
||||
.padding(all = 12.dp),
|
||||
.shadow(
|
||||
elevation = TangemTheme.dimens.elevation12,
|
||||
shape = tooltipShape,
|
||||
clip = false,
|
||||
ambientColor = Color.Black.copy(alpha = 0.7f),
|
||||
)
|
||||
.background(backgroundColor, tooltipShape)
|
||||
.clickable(interactionSource = null, indication = null, onClick = {})
|
||||
.padding(all = 12.dp)
|
||||
.padding(bottom = tipDpSize.height),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
|
|
@ -594,6 +579,32 @@ private fun MarketsTooltipContent(onCloseClick: () -> Unit, modifier: Modifier =
|
|||
}
|
||||
}
|
||||
|
||||
private class TooltipShape(
|
||||
private val cornerRadius: Dp,
|
||||
private val tipSize: DpSize,
|
||||
) : Shape {
|
||||
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
|
||||
val cornerRadiusPx = with(density) { cornerRadius.toPx() }
|
||||
val tipWidth = with(density) { tipSize.width.toPx() }
|
||||
val tipHeight = with(density) { tipSize.height.toPx() }
|
||||
val bodyHeight = size.height - tipHeight
|
||||
|
||||
val path = Path().apply {
|
||||
addRoundRect(
|
||||
RoundRect(
|
||||
rect = Rect(left = 0f, top = 0f, right = size.width, bottom = bodyHeight),
|
||||
cornerRadius = CornerRadius(cornerRadiusPx),
|
||||
),
|
||||
)
|
||||
moveTo(size.width / 2 - tipWidth / 2, bodyHeight)
|
||||
lineTo(size.width / 2, size.height)
|
||||
lineTo(size.width / 2 + tipWidth / 2, bodyHeight)
|
||||
close()
|
||||
}
|
||||
return Outline.Generic(path)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomSheetScrim(color: Color, visible: Boolean, onDismissRequest: () -> Unit) {
|
||||
val alpha by animateFloatAsState(
|
||||
|
|
|
|||
|
|
@ -262,10 +262,12 @@ private fun WalletContent2(
|
|||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(bottom = 24.dp)
|
||||
.fillMaxWidth(fraction = 0.7f),
|
||||
.padding(horizontal = 12.dp)
|
||||
.fillMaxWidth(),
|
||||
isVisible = state.showMarketsOnboarding,
|
||||
availableHeight = LocalWindowSize.current.height,
|
||||
bottomSheetState = bottomSheetState,
|
||||
onCloseClick = state.onDismissMarketsTooltip,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -370,16 +372,10 @@ private inline fun BaseScaffoldWithMarkets(
|
|||
appBarContent()
|
||||
|
||||
BottomSheetScrim(
|
||||
color = if (state.showMarketsOnboarding) {
|
||||
Color.Black.copy(alpha = .65f)
|
||||
} else {
|
||||
Color.Black.copy(alpha = .40f)
|
||||
},
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded ||
|
||||
state.showMarketsOnboarding,
|
||||
color = Color.Black.copy(alpha = .40f),
|
||||
visible = bottomSheetState.targetValue == TangemSheetValue.Expanded,
|
||||
onDismissRequest = {
|
||||
coroutineScope.launch { bottomSheetState.partialExpand() }
|
||||
state.onDismissMarketsTooltip()
|
||||
},
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,31 +8,40 @@ import androidx.compose.animation.core.spring
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideIn
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.components.sheetscaffold.TangemSheetState
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreviewRedesign
|
||||
import com.tangem.core.ui.test.MarketTooltipTestTags
|
||||
import com.tangem.core.ui.utils.lineTo
|
||||
import com.tangem.core.ui.utils.moveTo
|
||||
import com.tangem.core.ui.utils.toPx
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -43,6 +52,7 @@ internal fun MarketsTooltip(
|
|||
availableHeight: Dp,
|
||||
bottomSheetState: TangemSheetState,
|
||||
isVisible: Boolean,
|
||||
onCloseClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
|
|
@ -83,62 +93,101 @@ internal fun MarketsTooltip(
|
|||
) + fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
MarketsTooltipContent()
|
||||
MarketsTooltipContent(onCloseClick = onCloseClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun MarketsTooltipContent(modifier: Modifier = Modifier) {
|
||||
internal fun MarketsTooltipContent(onCloseClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val backgroundColor = TangemTheme.colors.background.action
|
||||
val cornerRadius = CornerRadius(x = 14.dp.toPx())
|
||||
val tipDpSize = DpSize(width = 20.dp, height = 8.dp)
|
||||
val tooltipShape = remember(tipDpSize) { TooltipShape(cornerRadius = 16.dp, tipSize = tipDpSize) }
|
||||
|
||||
Column(
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(bottom = tipDpSize.height)
|
||||
.drawBehind {
|
||||
val rect = size.toRect()
|
||||
val tipSize = tipDpSize.toSize()
|
||||
val tipRect = Rect(
|
||||
offset = Offset(
|
||||
x = rect.center.x - tipSize.center.x,
|
||||
y = rect.bottom,
|
||||
),
|
||||
size = tipSize,
|
||||
)
|
||||
drawRoundRect(color = backgroundColor, cornerRadius = cornerRadius)
|
||||
|
||||
val tipPath = Path().apply {
|
||||
moveTo(tipRect.topLeft)
|
||||
lineTo(tipRect.bottomCenter)
|
||||
lineTo(tipRect.topRight)
|
||||
}
|
||||
drawPath(color = backgroundColor, path = tipPath)
|
||||
}
|
||||
.padding(all = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
.shadow(
|
||||
elevation = TangemTheme.dimens.elevation12,
|
||||
shape = tooltipShape,
|
||||
clip = false,
|
||||
ambientColor = Color.Black.copy(alpha = 0.7f),
|
||||
)
|
||||
.background(backgroundColor, tooltipShape)
|
||||
.clickable(interactionSource = null, indication = null, onClick = {})
|
||||
.padding(all = 12.dp)
|
||||
.padding(bottom = tipDpSize.height),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 18.dp),
|
||||
painter = painterResource(id = R.drawable.ic_plus_18),
|
||||
tint = Color.Unspecified,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_message),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 2.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_v2_title),
|
||||
style = TangemTheme.typography.subtitle2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
Text(
|
||||
text = stringResourceSafe(id = R.string.markets_tooltip_message),
|
||||
style = TangemTheme.typography.caption2,
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
)
|
||||
}
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(size = 16.dp)
|
||||
.clickable(
|
||||
interactionSource = null,
|
||||
indication = null,
|
||||
onClick = onCloseClick,
|
||||
)
|
||||
.testTag(MarketTooltipTestTags.CLOSE_BUTTON),
|
||||
painter = painterResource(id = R.drawable.ic_close_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class TooltipShape(
|
||||
private val cornerRadius: Dp,
|
||||
private val tipSize: DpSize,
|
||||
) : Shape {
|
||||
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
|
||||
val cornerRadiusPx = with(density) { cornerRadius.toPx() }
|
||||
val tipWidth = with(density) { tipSize.width.toPx() }
|
||||
val tipHeight = with(density) { tipSize.height.toPx() }
|
||||
val bodyHeight = size.height - tipHeight
|
||||
|
||||
val path = Path().apply {
|
||||
addRoundRect(
|
||||
RoundRect(
|
||||
rect = Rect(left = 0f, top = 0f, right = size.width, bottom = bodyHeight),
|
||||
cornerRadius = CornerRadius(cornerRadiusPx),
|
||||
),
|
||||
)
|
||||
moveTo(size.width / 2 - tipWidth / 2, bodyHeight)
|
||||
lineTo(size.width / 2, size.height)
|
||||
lineTo(size.width / 2 + tipWidth / 2, bodyHeight)
|
||||
close()
|
||||
}
|
||||
return Outline.Generic(path)
|
||||
}
|
||||
}
|
||||
|
||||
// region Preview
|
||||
@Composable
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun MarketsTooltip_Preview() {
|
||||
TangemThemePreviewRedesign {
|
||||
MarketsTooltipContent()
|
||||
MarketsTooltipContent(onCloseClick = {})
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
Loading…
Add table
Add a link
Reference in a new issue