Wallet backup message
This commit is contained in:
parent
9cd31dfee4
commit
0209bec72b
|
@ -551,8 +551,8 @@ val DarkZashiColorsInternal =
|
||||||
utilityEspresso600 = Espresso.`300`,
|
utilityEspresso600 = Espresso.`300`,
|
||||||
utilityEspresso500 = Espresso.`400`,
|
utilityEspresso500 = Espresso.`400`,
|
||||||
utilityEspresso200 = Espresso.`700`,
|
utilityEspresso200 = Espresso.`700`,
|
||||||
utilityEspresso50 = Espresso.`900`,
|
utilityEspresso50 = Espresso.`950`,
|
||||||
utilityEspresso100 = Espresso.`800`,
|
utilityEspresso100 = Espresso.`900`,
|
||||||
utilityEspresso400 = Espresso.`500`,
|
utilityEspresso400 = Espresso.`500`,
|
||||||
utilityEspresso300 = Espresso.`600`,
|
utilityEspresso300 = Espresso.`600`,
|
||||||
utilityEspresso900 = Espresso.`50`,
|
utilityEspresso900 = Espresso.`50`,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package co.electriccoin.zcash.ui.screen.home
|
package co.electriccoin.zcash.ui.screen.home
|
||||||
|
|
||||||
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
|
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
|
||||||
|
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState
|
||||||
|
|
||||||
data class HomeState(
|
data class HomeState(
|
||||||
val firstButton: BigIconButtonState,
|
val firstButton: BigIconButtonState,
|
||||||
|
@ -10,11 +11,6 @@ data class HomeState(
|
||||||
val message: HomeMessageState?
|
val message: HomeMessageState?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class HomeMessageState(
|
|
||||||
val text: String,
|
|
||||||
val onClick: () -> Unit
|
|
||||||
)
|
|
||||||
|
|
||||||
data class HomeRestoreDialogState(
|
data class HomeRestoreDialogState(
|
||||||
val onClick: () -> Unit
|
val onClick: () -> Unit
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
package co.electriccoin.zcash.ui.screen.home
|
package co.electriccoin.zcash.ui.screen.home
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.animation.EnterTransition
|
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.animation.fadeOut
|
|
||||||
import androidx.compose.animation.slideOutVertically
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
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.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
@ -18,9 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
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
|
||||||
|
@ -28,20 +18,8 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||||
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.draw.drawWithCache
|
|
||||||
import androidx.compose.ui.draw.shadow
|
|
||||||
import androidx.compose.ui.geometry.Size
|
|
||||||
import androidx.compose.ui.graphics.ClipOp
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.DefaultShadowColor
|
|
||||||
import androidx.compose.ui.graphics.Path
|
|
||||||
import androidx.compose.ui.graphics.Shape
|
|
||||||
import androidx.compose.ui.graphics.addOutline
|
|
||||||
import androidx.compose.ui.graphics.drawscope.clipPath
|
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.appbar.ZashiMainTopAppBarState
|
import co.electriccoin.zcash.ui.common.appbar.ZashiMainTopAppBarState
|
||||||
import co.electriccoin.zcash.ui.common.appbar.ZashiTopAppBarWithAccountSelection
|
import co.electriccoin.zcash.ui.common.appbar.ZashiTopAppBarWithAccountSelection
|
||||||
|
@ -50,13 +28,14 @@ import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
|
||||||
import co.electriccoin.zcash.ui.design.component.ZashiBigIconButton
|
import co.electriccoin.zcash.ui.design.component.ZashiBigIconButton
|
||||||
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
|
|
||||||
import co.electriccoin.zcash.ui.design.util.scaffoldPadding
|
import co.electriccoin.zcash.ui.design.util.scaffoldPadding
|
||||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||||
import co.electriccoin.zcash.ui.fixture.BalanceStateFixture
|
import co.electriccoin.zcash.ui.fixture.BalanceStateFixture
|
||||||
import co.electriccoin.zcash.ui.fixture.ZashiMainTopAppBarStateFixture
|
import co.electriccoin.zcash.ui.fixture.ZashiMainTopAppBarStateFixture
|
||||||
import co.electriccoin.zcash.ui.screen.balances.BalanceState
|
import co.electriccoin.zcash.ui.screen.balances.BalanceState
|
||||||
import co.electriccoin.zcash.ui.screen.balances.BalanceWidget
|
import co.electriccoin.zcash.ui.screen.balances.BalanceWidget
|
||||||
|
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessage
|
||||||
|
import co.electriccoin.zcash.ui.screen.home.messages.HomeMessageState
|
||||||
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetState
|
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetState
|
||||||
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetStateFixture
|
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.TransactionHistoryWidgetStateFixture
|
||||||
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.createTransactionHistoryWidgets
|
import co.electriccoin.zcash.ui.screen.transactionhistory.widget.createTransactionHistoryWidgets
|
||||||
|
@ -110,7 +89,7 @@ private fun Content(
|
||||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
NavButtons(paddingValues, state)
|
NavButtons(paddingValues, state)
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
Message(state.message)
|
HomeMessage(state.message)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
|
@ -125,112 +104,6 @@ private fun Content(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun Message(state: HomeMessageState?) {
|
|
||||||
val cutoutHeight = 16.dp
|
|
||||||
var normalizedState: HomeMessageState? by remember { mutableStateOf(state) }
|
|
||||||
var isVisible by remember { mutableStateOf(state != null) }
|
|
||||||
val bottomCornerSize by animateDpAsState(
|
|
||||||
if (isVisible) cutoutHeight else 0.dp,
|
|
||||||
animationSpec = tween(350)
|
|
||||||
)
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.background(Color.Gray)
|
|
||||||
.clickable(onClick = { normalizedState?.onClick?.invoke() })
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(cutoutHeight)
|
|
||||||
.zIndex(2f)
|
|
||||||
.bottomOnlyShadow(
|
|
||||||
elevation = 2.dp,
|
|
||||||
shape = RoundedCornerShape(bottomStart = 32.dp, bottomEnd = 32.dp),
|
|
||||||
backgroundColor = ZashiColors.Surfaces.bgPrimary
|
|
||||||
)
|
|
||||||
,
|
|
||||||
)
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(cutoutHeight)
|
|
||||||
.zIndex(1f)
|
|
||||||
.align(Alignment.BottomCenter)
|
|
||||||
.topOnlyShadow(
|
|
||||||
elevation = 2.dp,
|
|
||||||
shape = RoundedCornerShape(topStart = bottomCornerSize, topEnd = bottomCornerSize),
|
|
||||||
backgroundColor = ZashiColors.Surfaces.bgPrimary
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(state) {
|
|
||||||
if (state != null) {
|
|
||||||
normalizedState = state
|
|
||||||
isVisible = true
|
|
||||||
} else {
|
|
||||||
isVisible = false
|
|
||||||
delay(350)
|
|
||||||
normalizedState = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Modifier.bottomOnlyShadow(
|
|
||||||
elevation: Dp,
|
|
||||||
shape: Shape,
|
|
||||||
backgroundColor: Color,
|
|
||||||
clip: Boolean = elevation > 0.dp,
|
|
||||||
ambientColor: Color = DefaultShadowColor,
|
|
||||||
spotColor: Color = DefaultShadowColor,
|
|
||||||
): Modifier = this
|
|
||||||
.drawWithCache {
|
|
||||||
// bottom shadow offset in Px based on elevation
|
|
||||||
val bottomOffsetPx = elevation.toPx()
|
|
||||||
// Adjust the size to extend the bottom by the bottom shadow offset
|
|
||||||
val adjustedSize = Size(size.width, size.height + bottomOffsetPx)
|
|
||||||
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
|
|
||||||
val path = Path().apply { addOutline(outline) }
|
|
||||||
onDrawWithContent {
|
|
||||||
clipPath(path, ClipOp.Intersect) {
|
|
||||||
this@onDrawWithContent.drawContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.shadow(elevation, shape, clip, ambientColor, spotColor)
|
|
||||||
.background(
|
|
||||||
backgroundColor,
|
|
||||||
shape
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun Modifier.topOnlyShadow(
|
|
||||||
elevation: Dp,
|
|
||||||
shape: Shape,
|
|
||||||
backgroundColor: Color,
|
|
||||||
clip: Boolean = elevation > 0.dp,
|
|
||||||
ambientColor: Color = DefaultShadowColor,
|
|
||||||
spotColor: Color = DefaultShadowColor,
|
|
||||||
): Modifier = this
|
|
||||||
.drawWithCache {
|
|
||||||
// Adjust the size to extend the bottom by the bottom shadow offset
|
|
||||||
val adjustedSize = Size(size.width, size.height)
|
|
||||||
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
|
|
||||||
val path = Path().apply { addOutline(outline) }
|
|
||||||
onDrawWithContent {
|
|
||||||
clipPath(path, ClipOp.Intersect) {
|
|
||||||
this@onDrawWithContent.drawContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.shadow(elevation, shape, clip, ambientColor, spotColor)
|
|
||||||
.background(
|
|
||||||
backgroundColor,
|
|
||||||
shape
|
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NavButtons(
|
private fun NavButtons(
|
||||||
paddingValues: PaddingValues,
|
paddingValues: PaddingValues,
|
||||||
|
@ -301,18 +174,7 @@ private fun Preview() {
|
||||||
icon = R.drawable.ic_warning,
|
icon = R.drawable.ic_warning,
|
||||||
onClick = {}
|
onClick = {}
|
||||||
),
|
),
|
||||||
message = HomeMessageState(
|
message = null.takeIf { isHomeMessageStateVisible }
|
||||||
text = "Test string",
|
|
||||||
onClick = {
|
|
||||||
isHomeMessageStateVisible = !isHomeMessageStateVisible
|
|
||||||
if (!isHomeMessageStateVisible) {
|
|
||||||
scope.launch {
|
|
||||||
delay(1000)
|
|
||||||
isHomeMessageStateVisible = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).takeIf { isHomeMessageStateVisible }
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,20 @@ import co.electriccoin.zcash.ui.NavigationTargets
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.model.DistributionDimension
|
import co.electriccoin.zcash.ui.common.model.DistributionDimension
|
||||||
import co.electriccoin.zcash.ui.common.model.KeystoneAccount
|
import co.electriccoin.zcash.ui.common.model.KeystoneAccount
|
||||||
|
import co.electriccoin.zcash.ui.common.model.WalletAccount
|
||||||
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
|
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
|
||||||
import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase
|
import co.electriccoin.zcash.ui.common.usecase.GetSelectedWalletAccountUseCase
|
||||||
import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseCase
|
import co.electriccoin.zcash.ui.common.usecase.IsRestoreSuccessDialogVisibleUseCase
|
||||||
import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase
|
import co.electriccoin.zcash.ui.common.usecase.NavigateToCoinbaseUseCase
|
||||||
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
|
import co.electriccoin.zcash.ui.design.component.BigIconButtonState
|
||||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||||
|
import co.electriccoin.zcash.ui.screen.home.messages.WalletBackupMessageState
|
||||||
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
|
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
|
||||||
import co.electriccoin.zcash.ui.screen.receive.Receive
|
import co.electriccoin.zcash.ui.screen.receive.Receive
|
||||||
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
|
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
|
||||||
import co.electriccoin.zcash.ui.screen.scan.Scan
|
import co.electriccoin.zcash.ui.screen.scan.Scan
|
||||||
import co.electriccoin.zcash.ui.screen.scan.ScanFlow
|
import co.electriccoin.zcash.ui.screen.scan.ScanFlow
|
||||||
|
import co.electriccoin.zcash.ui.screen.seed.backup.SeedBackup
|
||||||
import co.electriccoin.zcash.ui.screen.send.Send
|
import co.electriccoin.zcash.ui.screen.send.Send
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
@ -28,7 +31,6 @@ import kotlinx.coroutines.flow.WhileSubscribed
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class HomeViewModel(
|
class HomeViewModel(
|
||||||
|
@ -64,7 +66,18 @@ class HomeViewModel(
|
||||||
|
|
||||||
val state: StateFlow<HomeState?> =
|
val state: StateFlow<HomeState?> =
|
||||||
combine(getSelectedWalletAccountUseCase.observe(), isMessageVisible) { selectedAccount, isMessageVisible ->
|
combine(getSelectedWalletAccountUseCase.observe(), isMessageVisible) { selectedAccount, isMessageVisible ->
|
||||||
HomeState(
|
createState(getVersionInfoProvider, selectedAccount, isMessageVisible)
|
||||||
|
}.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
|
||||||
|
initialValue = null
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createState(
|
||||||
|
getVersionInfoProvider: GetVersionInfoProvider,
|
||||||
|
selectedAccount: WalletAccount?,
|
||||||
|
isMessageVisible: Boolean
|
||||||
|
) = HomeState(
|
||||||
firstButton =
|
firstButton =
|
||||||
BigIconButtonState(
|
BigIconButtonState(
|
||||||
text = stringRes("Receive"),
|
text = stringRes("Receive"),
|
||||||
|
@ -106,20 +119,18 @@ class HomeViewModel(
|
||||||
onClick = ::onMoreButtonClick,
|
onClick = ::onMoreButtonClick,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
message = HomeMessageState(
|
message = createWalletBackupMessageState().takeIf { isMessageVisible }
|
||||||
text = "Test string",
|
|
||||||
onClick = {
|
|
||||||
this@HomeViewModel.isMessageVisible.update { !it }
|
|
||||||
}
|
|
||||||
).takeIf { isMessageVisible }
|
|
||||||
)
|
|
||||||
}.stateIn(
|
|
||||||
scope = viewModelScope,
|
|
||||||
started = SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT),
|
|
||||||
initialValue = null
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun onRestoreDialogSeenClick() =
|
private fun createWalletBackupMessageState(): WalletBackupMessageState {
|
||||||
|
return WalletBackupMessageState(
|
||||||
|
onClick = {
|
||||||
|
navigationRouter.forward(SeedBackup)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onRestoreDialogSeenClick() =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
isRestoreSuccessDialogVisible.setSeen()
|
isRestoreSuccessDialogVisible.setSeen()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.home.messages
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.expandIn
|
||||||
|
import androidx.compose.animation.shrinkOut
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithCache
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.geometry.Size
|
||||||
|
import androidx.compose.ui.graphics.ClipOp
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.DefaultShadowColor
|
||||||
|
import androidx.compose.ui.graphics.Path
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.graphics.addOutline
|
||||||
|
import androidx.compose.ui.graphics.drawscope.clipPath
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HomeMessage(state: HomeMessageState?) {
|
||||||
|
val cutoutHeight = 16.dp
|
||||||
|
var normalizedState: HomeMessageState? by remember { mutableStateOf(state) }
|
||||||
|
var isVisible by remember { mutableStateOf(state != null) }
|
||||||
|
val bottomCornerSize by animateDpAsState(
|
||||||
|
if (isVisible) cutoutHeight else 0.dp,
|
||||||
|
animationSpec = tween(350)
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(Color.Gray)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(cutoutHeight)
|
||||||
|
.zIndex(2f)
|
||||||
|
.bottomOnlyShadow(
|
||||||
|
elevation = 2.dp,
|
||||||
|
shape = RoundedCornerShape(bottomStart = 32.dp, bottomEnd = 32.dp),
|
||||||
|
backgroundColor = ZashiColors.Surfaces.bgPrimary
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.zIndex(0f),
|
||||||
|
visible = isVisible,
|
||||||
|
enter = expandIn(animationSpec = tween(350)),
|
||||||
|
exit = shrinkOut(animationSpec = tween(350))
|
||||||
|
) {
|
||||||
|
when (normalizedState) {
|
||||||
|
is WalletBackupMessageState -> WalletBackupMessage(
|
||||||
|
state = normalizedState as WalletBackupMessageState,
|
||||||
|
contentPadding = PaddingValues(
|
||||||
|
vertical = cutoutHeight
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
null -> {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(cutoutHeight)
|
||||||
|
.zIndex(1f)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.topOnlyShadow(
|
||||||
|
elevation = 2.dp,
|
||||||
|
shape = RoundedCornerShape(topStart = bottomCornerSize, topEnd = bottomCornerSize),
|
||||||
|
backgroundColor = ZashiColors.Surfaces.bgPrimary
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
if (state != null) {
|
||||||
|
normalizedState = state
|
||||||
|
isVisible = true
|
||||||
|
} else {
|
||||||
|
isVisible = false
|
||||||
|
delay(350)
|
||||||
|
normalizedState = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Modifier.bottomOnlyShadow(
|
||||||
|
elevation: Dp,
|
||||||
|
shape: Shape,
|
||||||
|
backgroundColor: Color,
|
||||||
|
clip: Boolean = elevation > 0.dp,
|
||||||
|
ambientColor: Color = DefaultShadowColor,
|
||||||
|
spotColor: Color = DefaultShadowColor,
|
||||||
|
): Modifier = this
|
||||||
|
.drawWithCache {
|
||||||
|
// bottom shadow offset in Px based on elevation
|
||||||
|
val bottomOffsetPx = elevation.toPx()
|
||||||
|
// Adjust the size to extend the bottom by the bottom shadow offset
|
||||||
|
val adjustedSize = Size(size.width, size.height + bottomOffsetPx)
|
||||||
|
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
|
||||||
|
val path = Path().apply { addOutline(outline) }
|
||||||
|
onDrawWithContent {
|
||||||
|
clipPath(path, ClipOp.Intersect) {
|
||||||
|
this@onDrawWithContent.drawContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shadow(elevation, shape, clip, ambientColor, spotColor)
|
||||||
|
.background(
|
||||||
|
backgroundColor,
|
||||||
|
shape
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Modifier.topOnlyShadow(
|
||||||
|
elevation: Dp,
|
||||||
|
shape: Shape,
|
||||||
|
backgroundColor: Color,
|
||||||
|
clip: Boolean = elevation > 0.dp,
|
||||||
|
ambientColor: Color = DefaultShadowColor,
|
||||||
|
spotColor: Color = DefaultShadowColor,
|
||||||
|
): Modifier = this
|
||||||
|
.drawWithCache {
|
||||||
|
// Adjust the size to extend the bottom by the bottom shadow offset
|
||||||
|
val adjustedSize = Size(size.width, size.height)
|
||||||
|
val outline = shape.createOutline(adjustedSize, layoutDirection, this)
|
||||||
|
val path = Path().apply { addOutline(outline) }
|
||||||
|
onDrawWithContent {
|
||||||
|
clipPath(path, ClipOp.Intersect) {
|
||||||
|
this@onDrawWithContent.drawContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shadow(elevation, shape, clip, ambientColor, spotColor)
|
||||||
|
.background(
|
||||||
|
backgroundColor,
|
||||||
|
shape
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.home.messages
|
||||||
|
|
||||||
|
sealed interface HomeMessageState
|
|
@ -0,0 +1,37 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.home.messages
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HomeMessageWrapper(
|
||||||
|
color: Color,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
|
content: @Composable RowScope.() -> Unit,
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
color = color,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(contentPadding)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
horizontal = 16.dp,
|
||||||
|
vertical = 14.dp
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package co.electriccoin.zcash.ui.screen.home.messages
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import co.electriccoin.zcash.ui.R
|
||||||
|
import co.electriccoin.zcash.ui.design.component.BlankSurface
|
||||||
|
import co.electriccoin.zcash.ui.design.component.ButtonState
|
||||||
|
import co.electriccoin.zcash.ui.design.component.HorizontalSpacer
|
||||||
|
import co.electriccoin.zcash.ui.design.component.VerticalSpacer
|
||||||
|
import co.electriccoin.zcash.ui.design.component.ZashiButton
|
||||||
|
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.colors.ZashiColors
|
||||||
|
import co.electriccoin.zcash.ui.design.theme.typography.ZashiTypography
|
||||||
|
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WalletBackupMessage(state: WalletBackupMessageState, contentPadding: PaddingValues) {
|
||||||
|
HomeMessageWrapper(
|
||||||
|
color = ZashiColors.Utility.Espresso.utilityEspresso100,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.ic_warning_triangle),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
HorizontalSpacer(16.dp)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.home_message_backup_required_title),
|
||||||
|
style = ZashiTypography.textSm,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = ZashiColors.Utility.Espresso.utilityEspresso900
|
||||||
|
)
|
||||||
|
VerticalSpacer(2.dp)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_message_backup_required_subtitle),
|
||||||
|
style = ZashiTypography.textXs,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = ZashiColors.Utility.Espresso.utilityEspresso700
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ZashiButton(
|
||||||
|
modifier = Modifier.height(36.dp),
|
||||||
|
state = ButtonState(
|
||||||
|
onClick = state.onClick,
|
||||||
|
text = stringRes("Start")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class WalletBackupMessageState(
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
) : HomeMessageState
|
||||||
|
|
||||||
|
@PreviewScreens
|
||||||
|
@Composable
|
||||||
|
private fun Preview() = ZcashTheme {
|
||||||
|
BlankSurface {
|
||||||
|
WalletBackupMessage(
|
||||||
|
state = WalletBackupMessageState(
|
||||||
|
onClick = {}
|
||||||
|
),
|
||||||
|
contentPadding = PaddingValues()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.window.DialogWindowProvider
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
@ -21,7 +22,6 @@ import org.koin.compose.koinInject
|
||||||
fun AndroidSeedInfo() {
|
fun AndroidSeedInfo() {
|
||||||
val parent = LocalView.current.parent
|
val parent = LocalView.current.parent
|
||||||
val navigationRouter = koinInject<NavigationRouter>()
|
val navigationRouter = koinInject<NavigationRouter>()
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
SideEffect {
|
SideEffect {
|
||||||
(parent as? DialogWindowProvider)?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
(parent as? DialogWindowProvider)?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||||
|
@ -40,21 +40,8 @@ fun AndroidSeedInfo() {
|
||||||
|
|
||||||
SeedInfoView(
|
SeedInfoView(
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
state =
|
state = remember { SeedInfoState(onBack = { navigationRouter.back() }) },
|
||||||
SeedInfoState(
|
onDismissRequest = { navigationRouter.back() }
|
||||||
onBack = {
|
|
||||||
scope.launch {
|
|
||||||
// sheetState.hide()
|
|
||||||
navigationRouter.back()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
onDismissRequest = {
|
|
||||||
scope.launch {
|
|
||||||
// sheetState.hide()
|
|
||||||
navigationRouter.back()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="20"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M10,7.5V10.833M10,14.167H10.009M8.846,3.243L1.992,15.082C1.612,15.739 1.422,16.067 1.45,16.336C1.474,16.571 1.598,16.785 1.789,16.924C2.008,17.083 2.387,17.083 3.146,17.083H16.854C17.613,17.083 17.992,17.083 18.212,16.924C18.403,16.785 18.526,16.571 18.55,16.336C18.578,16.067 18.388,15.739 18.008,15.082L11.154,3.243C10.775,2.589 10.586,2.262 10.339,2.152C10.123,2.056 9.877,2.056 9.662,2.152C9.414,2.262 9.225,2.589 8.846,3.243Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="1.66667"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#EBE9E9"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="20"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M10,7.5V10.833M10,14.167H10.009M8.846,3.243L1.992,15.082C1.612,15.739 1.422,16.067 1.45,16.336C1.474,16.572 1.598,16.785 1.789,16.924C2.008,17.083 2.387,17.083 3.146,17.083H16.854C17.613,17.083 17.992,17.083 18.212,16.924C18.403,16.785 18.526,16.572 18.55,16.336C18.578,16.067 18.388,15.739 18.008,15.082L11.154,3.243C10.775,2.589 10.586,2.262 10.339,2.152C10.123,2.056 9.877,2.056 9.662,2.152C9.414,2.262 9.225,2.589 8.846,3.243Z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="1.66667"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#332424"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="home_message_backup_required_title">Wallet Backup Required</string>
|
||||||
|
<string name="home_message_backup_required_subtitle">Prevent potential loss of funds</string>
|
||||||
|
</resources>
|
Loading…
Reference in New Issue