Skip to content
Merged
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
40 changes: 32 additions & 8 deletions app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberTooltipState
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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -25,30 +26,40 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.graphics.createBitmap
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import to.bitkit.R
import to.bitkit.ui.shared.util.clickableAlpha
import to.bitkit.ui.theme.AppThemeSurface
import to.bitkit.ui.theme.Colors
import androidx.core.graphics.createBitmap

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun QrCodeImage(
content: String,
modifier: Modifier = Modifier,
logoPainter: Painter? = null,
tipMessage: String = "",
size: Dp = LocalConfiguration.current.screenWidthDp.dp,
) {
val clipboard = LocalClipboardManager.current

val tooltipState = rememberTooltipState()
val coroutineScope = rememberCoroutineScope()

Box(
contentAlignment = Alignment.TopCenter,
modifier = modifier
Expand All @@ -59,11 +70,24 @@ fun QrCodeImage(
val bitmap = rememberQrBitmap(content, size)

if (bitmap != null) {
Image(
painter = remember(bitmap) { BitmapPainter(bitmap.asImageBitmap()) },
contentDescription = null,
contentScale = ContentScale.Inside,
)
Tooltip(
text = tipMessage,
tooltipState = tooltipState
) {
Image(
painter = remember(bitmap) { BitmapPainter(bitmap.asImageBitmap()) },
contentDescription = null,
contentScale = ContentScale.Inside,
modifier = if (tipMessage.isNotBlank()) {
Modifier.clickableAlpha {
coroutineScope.launch {
clipboard.setText(AnnotatedString(content))
tooltipState.show()
}
}
} else Modifier
)
}
logoPainter?.let {
Box(
contentAlignment = Alignment.Center,
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/to/bitkit/ui/components/Text.kt
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ fun CaptionB(
text: String,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.primary,
textAlign: TextAlign = TextAlign.Start,
) {
Text(
text = text,
Expand All @@ -359,7 +360,7 @@ fun CaptionB(
letterSpacing = 0.4.sp,
fontFamily = InterFontFamily,
color = color,
textAlign = TextAlign.Start,
textAlign = textAlign,
),
modifier = modifier,
)
Expand Down
54 changes: 54 additions & 0 deletions app/src/main/java/to/bitkit/ui/components/Tooltip.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package to.bitkit.ui.components

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.TooltipState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import to.bitkit.ui.theme.Colors

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Tooltip(
text: String,
tooltipState: TooltipState,
modifier: Modifier = Modifier,
content: @Composable (() -> Unit)
) {

TooltipBox(
modifier = modifier,
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = {
PlainTooltip(
caretSize = DpSize(
width = 16.dp,
height = 12.dp
),
containerColor = Colors.Black92,
contentColor = Colors.White,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp)
) {
CaptionB(
text,
color = Colors.White,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 37.dp, vertical = 24.dp)
)
}
},
state = tooltipState,
content = content
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
Expand All @@ -27,6 +29,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
Expand Down Expand Up @@ -59,6 +62,7 @@ import to.bitkit.ui.components.Caption13Up
import to.bitkit.ui.components.Headline
import to.bitkit.ui.components.PrimaryButton
import to.bitkit.ui.components.QrCodeImage
import to.bitkit.ui.components.Tooltip
import to.bitkit.ui.scaffold.SheetTopBar
import to.bitkit.ui.screens.wallets.send.AddTagScreen
import to.bitkit.ui.shared.PagerWithIndicator
Expand Down Expand Up @@ -100,7 +104,7 @@ fun ReceiveQrSheet(
val cjitInvoice = remember { mutableStateOf<String?>(null) }
val showCreateCjit = remember { mutableStateOf(false) }
val cjitEntryDetails = remember { mutableStateOf<CjitEntryDetails?>(null) }
val lightningState : LightningState by wallet.lightningState.collectAsStateWithLifecycle()
val lightningState: LightningState by wallet.lightningState.collectAsStateWithLifecycle()

LaunchedEffect(Unit) {
try {
Expand Down Expand Up @@ -130,7 +134,7 @@ fun ReceiveQrSheet(

LaunchedEffect(Unit) {
wallet.walletEffect.collect { effect ->
when(effect) {
when (effect) {
WalletViewModelEffects.NavigateGeoBlockScreen -> {
navController.navigate(ReceiveRoutes.LOCATION_BLOCK)
}
Expand All @@ -150,6 +154,7 @@ fun ReceiveQrSheet(
showCreateCjit.value = false
cjitInvoice.value = null
}

active && cjitInvoice.value == null -> {
showCreateCjit.value = true
navController.navigate(ReceiveRoutes.AMOUNT)
Expand Down Expand Up @@ -419,6 +424,7 @@ private fun ReceiveLightningFunds(
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ReceiveQrSlide(
uri: String,
Expand All @@ -429,14 +435,18 @@ private fun ReceiveQrSlide(
val context = LocalContext.current
val clipboard = LocalClipboardManager.current

val qrButtonTooltipState = rememberTooltipState()
val coroutineScope = rememberCoroutineScope()

Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
QrCodeImage(
content = uri,
logoPainter = qrLogoPainter,
modifier = Modifier.weight(1f, fill = false)
tipMessage = stringResource(R.string.wallet__receive_copied),
modifier = Modifier.weight(1f, fill = false),
)

Spacer(modifier = Modifier.height(16.dp))
Expand All @@ -459,21 +469,29 @@ private fun ReceiveQrSlide(
)
}
)
PrimaryButton(
text = stringResource(R.string.common__copy),
size = ButtonSize.Small,
onClick = { clipboard.setText(AnnotatedString(uri)) },
fullWidth = false,
color = Colors.White10,
icon = {
Icon(
painter = painterResource(R.drawable.ic_copy),
contentDescription = null,
tint = Colors.Brand,
modifier = Modifier.size(18.dp)
)
}
)
Tooltip(
text = stringResource(R.string.wallet__receive_copied),
tooltipState = qrButtonTooltipState
) {
PrimaryButton(
text = stringResource(R.string.common__copy),
size = ButtonSize.Small,
onClick = {
clipboard.setText(AnnotatedString(uri))
coroutineScope.launch { qrButtonTooltipState.show() }
},
fullWidth = false,
color = Colors.White10,
icon = {
Icon(
painter = painterResource(R.drawable.ic_copy),
contentDescription = null,
tint = Colors.Brand,
modifier = Modifier.size(18.dp)
)
}
)
}
PrimaryButton(
text = stringResource(R.string.common__share),
size = ButtonSize.Small,
Expand Down Expand Up @@ -532,6 +550,7 @@ private fun CopyValuesSlide(

enum class CopyAddressType { ONCHAIN, LIGHTNING }

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CopyAddressCard(
title: String,
Expand All @@ -540,6 +559,10 @@ private fun CopyAddressCard(
) {
val clipboard = LocalClipboardManager.current
val context = LocalContext.current

val tooltipState = rememberTooltipState()
val coroutineScope = rememberCoroutineScope()

Column(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -559,21 +582,30 @@ private fun CopyAddressCard(
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
PrimaryButton(
text = stringResource(R.string.common__copy),
size = ButtonSize.Small,
onClick = { clipboard.setText(AnnotatedString(address)) },
fullWidth = false,
color = Colors.White10,
icon = {
Icon(
painter = painterResource(R.drawable.ic_copy),
contentDescription = null,
tint = if (type == CopyAddressType.ONCHAIN) Colors.Brand else Colors.Purple,
modifier = Modifier.size(18.dp)
)
}
)

Tooltip(
text = stringResource(R.string.wallet__receive_copied),
tooltipState = tooltipState
) {
PrimaryButton(
text = stringResource(R.string.common__copy),
size = ButtonSize.Small,
onClick = {
clipboard.setText(AnnotatedString(address))
coroutineScope.launch { tooltipState.show() }
},
fullWidth = false,
color = Colors.White10,
icon = {
Icon(
painter = painterResource(R.drawable.ic_copy),
contentDescription = null,
tint = if (type == CopyAddressType.ONCHAIN) Colors.Brand else Colors.Purple,
modifier = Modifier.size(18.dp)
)
}
)
}
PrimaryButton(
text = stringResource(R.string.common__share),
size = ButtonSize.Small,
Expand Down