mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 17:45:20 +00:00
receive
This commit is contained in:
@@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -31,70 +32,87 @@ fun SuccessAnimation(
|
|||||||
onAnimationComplete: () -> Unit,
|
onAnimationComplete: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
var isVisible by remember { mutableStateOf(true) }
|
var isVisible by remember { mutableStateOf(false) }
|
||||||
|
var startExit by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
// Auto-hide after animation duration
|
// Control animation timing
|
||||||
LaunchedEffect(animationData) {
|
LaunchedEffect(animationData) {
|
||||||
delay(2500) // Show for 2.5 seconds
|
// Start with fade in
|
||||||
isVisible = false
|
isVisible = true
|
||||||
delay(300) // Allow fade out animation to complete
|
delay(2000) // Show for 2 seconds
|
||||||
|
// Start exit animation
|
||||||
|
startExit = true
|
||||||
|
delay(500) // Allow fade out animation to complete
|
||||||
onAnimationComplete()
|
onAnimationComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale animation for the icon
|
// Wobble/tada animation for the icon
|
||||||
val infiniteTransition = rememberInfiniteTransition(label = "success_animation")
|
val infiniteTransition = rememberInfiniteTransition(label = "success_animation")
|
||||||
|
val iconRotation by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = if (isVisible && !startExit) 6f else 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(durationMillis = 150, easing = LinearEasing),
|
||||||
|
repeatMode = RepeatMode.Reverse
|
||||||
|
),
|
||||||
|
label = "icon_wobble"
|
||||||
|
)
|
||||||
|
|
||||||
val iconScale by infiniteTransition.animateFloat(
|
val iconScale by infiniteTransition.animateFloat(
|
||||||
initialValue = 1f,
|
initialValue = 1f,
|
||||||
targetValue = 1.1f,
|
targetValue = if (isVisible && !startExit) 1.05f else 1f,
|
||||||
animationSpec = infiniteRepeatable(
|
animationSpec = infiniteRepeatable(
|
||||||
animation = tween(durationMillis = 1000, easing = FastOutSlowInEasing),
|
animation = tween(durationMillis = 300, easing = FastOutSlowInEasing),
|
||||||
repeatMode = RepeatMode.Reverse
|
repeatMode = RepeatMode.Reverse
|
||||||
),
|
),
|
||||||
label = "icon_scale"
|
label = "icon_scale"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pulsing background effect
|
// Smooth fade in/out animations
|
||||||
val backgroundAlpha by infiniteTransition.animateFloat(
|
val contentScale by animateFloatAsState(
|
||||||
initialValue = 0.9f,
|
targetValue = if (isVisible && !startExit) 1f else 0.9f,
|
||||||
targetValue = 1f,
|
animationSpec = spring(
|
||||||
animationSpec = infiniteRepeatable(
|
dampingRatio = 0.7f,
|
||||||
animation = tween(durationMillis = 1500, easing = FastOutSlowInEasing),
|
stiffness = Spring.StiffnessMedium
|
||||||
repeatMode = RepeatMode.Reverse
|
|
||||||
),
|
),
|
||||||
label = "background_alpha"
|
label = "content_scale"
|
||||||
)
|
|
||||||
|
|
||||||
// Entry animation
|
|
||||||
val scale by animateFloatAsState(
|
|
||||||
targetValue = if (isVisible) 1f else 0.8f,
|
|
||||||
animationSpec = spring(dampingRatio = 0.6f, stiffness = Spring.StiffnessLow),
|
|
||||||
label = "entry_scale"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val alpha by animateFloatAsState(
|
val alpha by animateFloatAsState(
|
||||||
targetValue = if (isVisible) 1f else 0f,
|
targetValue = if (isVisible && !startExit) 1f else 0f,
|
||||||
animationSpec = tween(durationMillis = 300),
|
animationSpec = tween(
|
||||||
label = "entry_alpha"
|
durationMillis = if (startExit) 400 else 600,
|
||||||
|
easing = if (startExit) FastOutLinearInEasing else LinearOutSlowInEasing
|
||||||
|
),
|
||||||
|
label = "content_alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
val backgroundAlpha by animateFloatAsState(
|
||||||
|
targetValue = if (isVisible && !startExit) 0.95f else 0f,
|
||||||
|
animationSpec = tween(
|
||||||
|
durationMillis = if (startExit) 400 else 600
|
||||||
|
),
|
||||||
|
label = "background_alpha"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (alpha > 0f) {
|
if (alpha > 0f) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(Color.Black.copy(alpha = backgroundAlpha * alpha)),
|
.background(Color.Black.copy(alpha = backgroundAlpha)),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||||
modifier = Modifier.scale(scale)
|
modifier = Modifier.scale(contentScale)
|
||||||
) {
|
) {
|
||||||
// Success icon with pulsing circle background
|
// Success icon with wobble/tada effect
|
||||||
Box(
|
Box(
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
modifier = Modifier.size(120.dp)
|
modifier = Modifier.size(120.dp)
|
||||||
) {
|
) {
|
||||||
// Pulsing background circle
|
// Outer glow circle
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(100.dp)
|
.size(100.dp)
|
||||||
@@ -104,7 +122,7 @@ fun SuccessAnimation(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inner circle
|
// Main success circle with wobble
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(80.dp)
|
.size(80.dp)
|
||||||
@@ -112,7 +130,10 @@ fun SuccessAnimation(
|
|||||||
Color(0xFF00C851),
|
Color(0xFF00C851),
|
||||||
CircleShape
|
CircleShape
|
||||||
)
|
)
|
||||||
.scale(iconScale),
|
.scale(iconScale)
|
||||||
|
.graphicsLayer {
|
||||||
|
rotationZ = iconRotation
|
||||||
|
},
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -124,62 +145,202 @@ fun SuccessAnimation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success message
|
// Success message with smooth fade
|
||||||
Text(
|
Column(
|
||||||
text = "SUCCESS!",
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
color = Color(0xFF00C851),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
fontSize = 28.sp,
|
modifier = Modifier.graphicsLayer { this.alpha = alpha }
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
letterSpacing = 2.sp
|
|
||||||
)
|
|
||||||
|
|
||||||
// Amount
|
|
||||||
Text(
|
|
||||||
text = formatAmount(animationData.amount, animationData.unit),
|
|
||||||
color = Color.White,
|
|
||||||
fontSize = 24.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontFamily = FontFamily.Monospace
|
|
||||||
)
|
|
||||||
|
|
||||||
// Description
|
|
||||||
Text(
|
|
||||||
text = animationData.description,
|
|
||||||
color = Color.Gray,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier.padding(horizontal = 32.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Animated checkmark or icon indicator
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
) {
|
||||||
for (i in 0..2) {
|
Text(
|
||||||
val dotAlpha by infiniteTransition.animateFloat(
|
text = "SUCCESS!",
|
||||||
initialValue = 0.3f,
|
color = Color(0xFF00C851),
|
||||||
targetValue = 1f,
|
fontSize = 28.sp,
|
||||||
animationSpec = infiniteRepeatable(
|
fontWeight = FontWeight.Bold,
|
||||||
animation = tween(durationMillis = 600),
|
fontFamily = FontFamily.Monospace,
|
||||||
repeatMode = RepeatMode.Reverse,
|
letterSpacing = 2.sp
|
||||||
initialStartOffset = StartOffset(i * 200)
|
)
|
||||||
),
|
|
||||||
label = "dot_$i"
|
// Amount
|
||||||
)
|
Text(
|
||||||
|
text = formatAmount(animationData.amount, animationData.unit),
|
||||||
Box(
|
color = Color.White,
|
||||||
modifier = Modifier
|
fontSize = 24.sp,
|
||||||
.size(8.dp)
|
fontWeight = FontWeight.Bold,
|
||||||
.background(
|
fontFamily = FontFamily.Monospace
|
||||||
Color(0xFF00C851).copy(alpha = dotAlpha),
|
)
|
||||||
CircleShape
|
|
||||||
)
|
// Description
|
||||||
|
Text(
|
||||||
|
text = animationData.description,
|
||||||
|
color = Color.Gray,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 32.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fullscreen failure animation component for wallet operations
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun FailureAnimation(
|
||||||
|
errorMessage: String,
|
||||||
|
operationType: String = "Operation",
|
||||||
|
onAnimationComplete: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
var isVisible by remember { mutableStateOf(false) }
|
||||||
|
var startExit by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
// Control animation timing
|
||||||
|
LaunchedEffect(errorMessage) {
|
||||||
|
// Start with fade in
|
||||||
|
isVisible = true
|
||||||
|
delay(3000) // Show for 3 seconds (longer for error message)
|
||||||
|
// Start exit animation
|
||||||
|
startExit = true
|
||||||
|
delay(500) // Allow fade out animation to complete
|
||||||
|
onAnimationComplete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shake animation for the error icon
|
||||||
|
val infiniteTransition = rememberInfiniteTransition(label = "failure_animation")
|
||||||
|
val iconShake by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0f,
|
||||||
|
targetValue = if (isVisible && !startExit) 3f else 0f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(durationMillis = 100, easing = LinearEasing),
|
||||||
|
repeatMode = RepeatMode.Reverse
|
||||||
|
),
|
||||||
|
label = "icon_shake"
|
||||||
|
)
|
||||||
|
|
||||||
|
val iconScale by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 1f,
|
||||||
|
targetValue = if (isVisible && !startExit) 1.03f else 1f,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(durationMillis = 400, easing = FastOutSlowInEasing),
|
||||||
|
repeatMode = RepeatMode.Reverse
|
||||||
|
),
|
||||||
|
label = "icon_scale"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Smooth fade in/out animations
|
||||||
|
val contentScale by animateFloatAsState(
|
||||||
|
targetValue = if (isVisible && !startExit) 1f else 0.9f,
|
||||||
|
animationSpec = spring(
|
||||||
|
dampingRatio = 0.7f,
|
||||||
|
stiffness = Spring.StiffnessMedium
|
||||||
|
),
|
||||||
|
label = "content_scale"
|
||||||
|
)
|
||||||
|
|
||||||
|
val alpha by animateFloatAsState(
|
||||||
|
targetValue = if (isVisible && !startExit) 1f else 0f,
|
||||||
|
animationSpec = tween(
|
||||||
|
durationMillis = if (startExit) 400 else 600,
|
||||||
|
easing = if (startExit) FastOutLinearInEasing else LinearOutSlowInEasing
|
||||||
|
),
|
||||||
|
label = "content_alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
val backgroundAlpha by animateFloatAsState(
|
||||||
|
targetValue = if (isVisible && !startExit) 0.95f else 0f,
|
||||||
|
animationSpec = tween(
|
||||||
|
durationMillis = if (startExit) 400 else 600
|
||||||
|
),
|
||||||
|
label = "background_alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (alpha > 0f) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.Black.copy(alpha = backgroundAlpha)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||||
|
modifier = Modifier.scale(contentScale)
|
||||||
|
) {
|
||||||
|
// Error icon with shake effect
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier.size(120.dp)
|
||||||
|
) {
|
||||||
|
// Outer glow circle (red)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(100.dp)
|
||||||
|
.background(
|
||||||
|
Color(0xFFFF4444).copy(alpha = 0.2f),
|
||||||
|
CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Main error circle with shake
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(80.dp)
|
||||||
|
.background(
|
||||||
|
Color(0xFFFF4444),
|
||||||
|
CircleShape
|
||||||
|
)
|
||||||
|
.scale(iconScale)
|
||||||
|
.graphicsLayer {
|
||||||
|
translationX = iconShake
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Close,
|
||||||
|
contentDescription = "Error",
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(40.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error message with smooth fade
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier.graphicsLayer { this.alpha = alpha }
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "FAILED",
|
||||||
|
color = Color(0xFFFF4444),
|
||||||
|
fontSize = 28.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
letterSpacing = 2.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
// Operation type
|
||||||
|
Text(
|
||||||
|
text = "$operationType Failed",
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontFamily = FontFamily.Monospace
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error message
|
||||||
|
Text(
|
||||||
|
text = errorMessage,
|
||||||
|
color = Color.Gray,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(horizontal = 32.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ fun WalletScreen(
|
|||||||
val showReceiveDialog by walletViewModel.showReceiveDialog.observeAsState(false)
|
val showReceiveDialog by walletViewModel.showReceiveDialog.observeAsState(false)
|
||||||
val showSuccessAnimation by walletViewModel.showSuccessAnimation.observeAsState(false)
|
val showSuccessAnimation by walletViewModel.showSuccessAnimation.observeAsState(false)
|
||||||
val successAnimationData by walletViewModel.successAnimationData.observeAsState()
|
val successAnimationData by walletViewModel.successAnimationData.observeAsState()
|
||||||
|
val showFailureAnimation by walletViewModel.showFailureAnimation.observeAsState(false)
|
||||||
|
val failureAnimationData by walletViewModel.failureAnimationData.observeAsState()
|
||||||
|
|
||||||
// Back handler for the wallet
|
// Back handler for the wallet
|
||||||
fun handleBackPress(): Boolean {
|
fun handleBackPress(): Boolean {
|
||||||
@@ -135,6 +137,18 @@ fun WalletScreen(
|
|||||||
modifier = Modifier.zIndex(10f)
|
modifier = Modifier.zIndex(10f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Failure animation overlay
|
||||||
|
if (showFailureAnimation && failureAnimationData != null) {
|
||||||
|
FailureAnimation(
|
||||||
|
errorMessage = failureAnimationData!!.errorMessage,
|
||||||
|
operationType = failureAnimationData!!.operationType,
|
||||||
|
onAnimationComplete = {
|
||||||
|
walletViewModel.hideFailureAnimation()
|
||||||
|
},
|
||||||
|
modifier = Modifier.zIndex(10f)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle dialog states - sync local view state with ViewModel dialog state
|
// Handle dialog states - sync local view state with ViewModel dialog state
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
private val _successAnimationData = MutableLiveData<SuccessAnimationData?>(null)
|
private val _successAnimationData = MutableLiveData<SuccessAnimationData?>(null)
|
||||||
val successAnimationData: LiveData<SuccessAnimationData?> = _successAnimationData
|
val successAnimationData: LiveData<SuccessAnimationData?> = _successAnimationData
|
||||||
|
|
||||||
|
// Failure animation state
|
||||||
|
private val _showFailureAnimation = MutableLiveData<Boolean>(false)
|
||||||
|
val showFailureAnimation: LiveData<Boolean> = _showFailureAnimation
|
||||||
|
|
||||||
|
private val _failureAnimationData = MutableLiveData<FailureAnimationData?>(null)
|
||||||
|
val failureAnimationData: LiveData<FailureAnimationData?> = _failureAnimationData
|
||||||
|
|
||||||
// State management
|
// State management
|
||||||
private var pollingJob: kotlinx.coroutines.Job? = null
|
private var pollingJob: kotlinx.coroutines.Job? = null
|
||||||
|
|
||||||
@@ -109,6 +116,14 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
val description: String
|
val description: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for failure animation display
|
||||||
|
*/
|
||||||
|
data class FailureAnimationData(
|
||||||
|
val errorMessage: String,
|
||||||
|
val operationType: String = "Token Receive"
|
||||||
|
)
|
||||||
|
|
||||||
enum class SuccessAnimationType {
|
enum class SuccessAnimationType {
|
||||||
CASHU_RECEIVED,
|
CASHU_RECEIVED,
|
||||||
CASHU_SENT,
|
CASHU_SENT,
|
||||||
@@ -434,6 +449,17 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
_successAnimationData.value = null
|
_successAnimationData.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Failure animation management
|
||||||
|
fun showFailureAnimation(animationData: FailureAnimationData) {
|
||||||
|
_failureAnimationData.value = animationData
|
||||||
|
_showFailureAnimation.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hideFailureAnimation() {
|
||||||
|
_showFailureAnimation.value = false
|
||||||
|
_failureAnimationData.value = null
|
||||||
|
}
|
||||||
|
|
||||||
// Back navigation handler
|
// Back navigation handler
|
||||||
private var backHandler: (() -> Boolean)? = null
|
private var backHandler: (() -> Boolean)? = null
|
||||||
|
|
||||||
@@ -560,11 +586,54 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||||||
|
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Log.e(TAG, "Failed to save transaction", error)
|
Log.e(TAG, "Failed to save transaction", error)
|
||||||
_errorMessage.value = "Failed to save transaction: ${error.message}"
|
|
||||||
|
// Clear token input and close dialog
|
||||||
|
clearTokenInput()
|
||||||
|
|
||||||
|
// Show failure animation for transaction save error
|
||||||
|
val failureData = FailureAnimationData(
|
||||||
|
errorMessage = "Failed to save transaction: ${error.message}",
|
||||||
|
operationType = "Token Receive"
|
||||||
|
)
|
||||||
|
showFailureAnimation(failureData)
|
||||||
|
|
||||||
|
// Close receive dialog after animation starts
|
||||||
|
delay(500)
|
||||||
|
hideReceiveDialog()
|
||||||
}
|
}
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
_errorMessage.value = "Failed to receive token: ${error.message}"
|
Log.e(TAG, "Failed to receive token", error)
|
||||||
|
|
||||||
|
// Clear token input and close dialog
|
||||||
|
clearTokenInput()
|
||||||
|
|
||||||
|
// Show failure animation for token receive error
|
||||||
|
val failureData = FailureAnimationData(
|
||||||
|
errorMessage = error.message ?: "Unknown error occurred",
|
||||||
|
operationType = "Token Receive"
|
||||||
|
)
|
||||||
|
showFailureAnimation(failureData)
|
||||||
|
|
||||||
|
// Close receive dialog after animation starts
|
||||||
|
delay(500)
|
||||||
|
hideReceiveDialog()
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Exception in receiveCashuToken", e)
|
||||||
|
|
||||||
|
// Clear token input and close dialog
|
||||||
|
clearTokenInput()
|
||||||
|
|
||||||
|
// Show failure animation for unexpected error
|
||||||
|
val failureData = FailureAnimationData(
|
||||||
|
errorMessage = e.message ?: "Unexpected error occurred",
|
||||||
|
operationType = "Token Receive"
|
||||||
|
)
|
||||||
|
showFailureAnimation(failureData)
|
||||||
|
|
||||||
|
// Close receive dialog after animation starts
|
||||||
|
delay(500)
|
||||||
|
hideReceiveDialog()
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user