Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 168 additions & 25 deletions app/src/main/java/to/bitkit/ui/screens/wallets/send/SendErrorScreen.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package to.bitkit.ui.screens.wallets.send

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
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.platform.testTag
import androidx.compose.ui.res.painterResource
Expand All @@ -27,75 +36,130 @@ import to.bitkit.ui.shared.modifiers.sheetHeight
import to.bitkit.ui.shared.util.gradientBackground
import to.bitkit.ui.theme.AppThemeSurface
import to.bitkit.ui.theme.Colors
import to.bitkit.ui.theme.Shapes

@Composable
fun SendErrorScreen(
errorMessage: String,
errorMessage: String?,
stackTrace: String? = null,
onRetry: () -> Unit,
onClose: () -> Unit,
onSendReportClick: () -> Unit,
) {
var displayDetails by remember { mutableStateOf(false) }

Content(
errorMessage = errorMessage,
stackTrace = stackTrace,
onRetry = onRetry,
onClose = onClose,
displayDetails = displayDetails,
onSendReportClick = onSendReportClick,
onDisplayDetails = {
displayDetails = true
}
)
}

@Composable
private fun Content(
errorMessage: String,
errorMessage: String?,
stackTrace: String?,
displayDetails: Boolean,
modifier: Modifier = Modifier,
onDisplayDetails: () -> Unit = {},
onSendReportClick: () -> Unit = {},
onRetry: () -> Unit = {},
onClose: () -> Unit = {},
) {
val errorText = errorMessage.ifEmpty { "Unknown error." }
val errorText = errorMessage.orEmpty().ifEmpty { "Unknown error." }
Column(
modifier = modifier
.fillMaxSize()
.gradientBackground()
.verticalScroll(rememberScrollState())
.navigationBarsPadding()
) {
SheetTopBar(stringResource(R.string.wallet__send_error_tx_failed))

Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
Box(
modifier = Modifier.weight(1f)
) {
Spacer(modifier = Modifier.height(16.dp))

BodyM(text = errorText, color = Colors.White64)

Spacer(modifier = Modifier.weight(1f))
Image(
painter = painterResource(R.drawable.cross),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(256.dp)
.align(Alignment.Center)
)
Spacer(modifier = Modifier.weight(1f))

Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxWidth()
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
) {
Spacer(modifier = Modifier.height(16.dp))

BodyM(text = errorText, color = Colors.White64)

AnimatedVisibility(
visible = displayDetails && !stackTrace.isNullOrBlank(),
label = ""
) {
BodyM(
text = stackTrace.orEmpty(),
color = Colors.Red,
modifier = Modifier
.padding(vertical = 16.dp)
.fillMaxWidth()
.background(color = Colors.White10, shape = Shapes.medium)
.padding(16.dp)
)
}

Spacer(modifier = Modifier.weight(1f))


}
}

Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) {
AnimatedVisibility(visible = !stackTrace.isNullOrBlank() && !displayDetails) {
SecondaryButton(
text = "Technical Details", // TODO Transifex
onClick = onDisplayDetails,
modifier = Modifier
)
}
AnimatedVisibility(visible = !stackTrace.isNullOrBlank() && displayDetails) {
SecondaryButton(
text = "Send Anonymous Report", // TODO Transifex
onClick = onSendReportClick,
modifier = Modifier
)
}
if (stackTrace.isNullOrBlank()) {
SecondaryButton(
text = stringResource(R.string.common__cancel),
onClick = onClose,
fullWidth = true,
modifier = Modifier
.weight(1f)
.testTag("Close")
)
PrimaryButton(
text = stringResource(R.string.common__try_again),
onClick = onRetry,
modifier = Modifier.weight(1f)
)
}

Spacer(modifier = Modifier.height(16.dp))
PrimaryButton(
text = stringResource(R.string.common__try_again),
onClick = onRetry,
)
}

Spacer(modifier = Modifier.height(16.dp))
}
}

Expand All @@ -106,7 +170,83 @@ private fun Preview() {
BottomSheetPreview {
Content(
errorMessage = stringResource(R.string.wallet__send_error_create_tx),
stackTrace = "Test render error\n" +
"\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in WalletsStack (at SceneView.tsx:132)",
modifier = Modifier.sheetHeight(),
displayDetails = true,
onDisplayDetails = {}
)
}
}
}

@Preview(showSystemUi = true)
@Composable
private fun PreviewDontDisplayDetails() {
AppThemeSurface {
BottomSheetPreview {
Content(
errorMessage = stringResource(R.string.wallet__send_error_create_tx),
stackTrace = "Test render error\n" +
"\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in Tabbar (at WalletNavigator.tsx:59)\n" +
" in WalletsStack (at SceneView.tsx:132)",
modifier = Modifier.sheetHeight(),
displayDetails = false,
onDisplayDetails = {}
)
}
}
Expand All @@ -119,7 +259,10 @@ private fun PreviewUnknown() {
BottomSheetPreview {
Content(
errorMessage = "",
stackTrace = null,
modifier = Modifier.sheetHeight(),
displayDetails = false,
onDisplayDetails = {}
)
}
}
Expand Down
12 changes: 11 additions & 1 deletion app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,18 @@ fun SendSheet(
appViewModel.clearClipboardForAutoRead()
navController.navigate(SendRoute.Success)
}

is SendEffect.NavigateToQuickPay -> navController.navigate(SendRoute.QuickPay)
is SendEffect.NavigateToWithdrawConfirm -> navController.navigate(SendRoute.WithdrawConfirm)
is SendEffect.NavigateToWithdrawError -> navController.navigate(SendRoute.WithdrawError)
is SendEffect.NavigateToFee -> navController.navigate(SendRoute.FeeRate)
is SendEffect.NavigateToFeeCustom -> navController.navigate(SendRoute.FeeCustom)
is SendEffect.PaymentError -> navController.navigate(
SendRoute.Error(
errorMessage = it.errorMessage,
stackTrace = it.stackTrace
)
)
}
}
}
Expand Down Expand Up @@ -238,6 +245,9 @@ fun SendSheet(
} else {
navController.navigate(SendRoute.Success)
}
},
onSendReportClick = {

},
onClose = {
appViewModel.hideSheet()
Expand Down Expand Up @@ -298,5 +308,5 @@ sealed interface SendRoute {
data object Success : SendRoute

@Serializable
data class Error(val errorMessage: String) : SendRoute
data class Error(val errorMessage: String?, val stackTrace: String? = null) : SendRoute
}
12 changes: 4 additions & 8 deletions app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -947,12 +947,7 @@ class AppViewModel @Inject constructor(
lightningRepo.sync()
}.onFailure { e ->
Logger.error(msg = "Error sending onchain payment", e = e, context = TAG)
toast(
type = Toast.ToastType.ERROR,
title = "Error Sending",
description = e.message ?: "Unknown error"
)
hideSheet()
setSendEffect(SendEffect.PaymentError(errorMessage = e.message, stackTrace = e.stackTraceToString()))
}
}

Expand All @@ -976,8 +971,7 @@ class AppViewModel @Inject constructor(
setSendEffect(SendEffect.PaymentSuccess())
}.onFailure { e ->
Logger.error("Error sending lightning payment", e, context = TAG)
toast(e)
hideSheet()
setSendEffect(SendEffect.PaymentError(errorMessage = e.message, stackTrace = e.stackTraceToString()))
}
}
}
Expand Down Expand Up @@ -1502,6 +1496,8 @@ sealed class SendEffect {
data object NavigateToQuickPay : SendEffect()
data object NavigateToFee : SendEffect()
data object NavigateToFeeCustom : SendEffect()

data class PaymentError(val errorMessage: String?, val stackTrace: String) : SendEffect()
data class PaymentSuccess(val sheet: NewTransactionSheetDetails? = null) : SendEffect()
}

Expand Down