mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-20 19:30:46 +02:00
Showing progress bars when Zaps are requested
This commit is contained in:
@@ -130,12 +130,14 @@ class LightningAddressResolver {
|
||||
)
|
||||
}
|
||||
|
||||
fun lnAddressInvoice(lnaddress: String, milliSats: Long, message: String, nostrRequest: String? = null, onSuccess: (String) -> Unit, onError: (String) -> Unit) {
|
||||
fun lnAddressInvoice(lnaddress: String, milliSats: Long, message: String, nostrRequest: String? = null, onSuccess: (String) -> Unit, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit) {
|
||||
val mapper = jacksonObjectMapper()
|
||||
|
||||
fetchLightningAddressJson(
|
||||
lnaddress,
|
||||
onSuccess = { lnAddressJson ->
|
||||
onProgress(0.4f)
|
||||
|
||||
val lnurlp = try {
|
||||
mapper.readTree(lnAddressJson)
|
||||
} catch (t: Throwable) {
|
||||
@@ -158,6 +160,8 @@ class LightningAddressResolver {
|
||||
message,
|
||||
if (allowsNostr) nostrRequest else null,
|
||||
onSuccess = {
|
||||
onProgress(0.6f)
|
||||
|
||||
val lnInvoice = try {
|
||||
mapper.readTree(it)
|
||||
} catch (t: Throwable) {
|
||||
@@ -169,6 +173,7 @@ class LightningAddressResolver {
|
||||
// Forces LN Invoice amount to be the requested amount.
|
||||
val invoiceAmount = LnInvoiceUtil.getAmountInSats(pr)
|
||||
if (invoiceAmount.multiply(BigDecimal(1000)).toLong() == BigDecimal(milliSats).toLong()) {
|
||||
onProgress(0.7f)
|
||||
onSuccess(pr)
|
||||
} else {
|
||||
onError("Incorrect invoice amount (${invoiceAmount.toLong()} sats) from server")
|
||||
|
@@ -149,6 +149,8 @@ fun InvoiceRequest(lud16: String, toUserPubKeyHex: String, account: Account, onC
|
||||
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
|
||||
onClose()
|
||||
}
|
||||
},
|
||||
onProgress = {
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
@@ -33,6 +34,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
@@ -307,7 +309,10 @@ fun ZapReaction(
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var zappingProgress by remember { mutableStateOf(0f) }
|
||||
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier
|
||||
.then(Modifier.size(20.dp))
|
||||
.combinedClickable(
|
||||
@@ -336,17 +341,26 @@ fun ZapReaction(
|
||||
.show()
|
||||
}
|
||||
} else if (account.zapAmountChoices.size == 1) {
|
||||
accountViewModel.zap(
|
||||
baseNote,
|
||||
account.zapAmountChoices.first() * 1000,
|
||||
"",
|
||||
context
|
||||
) {
|
||||
scope.launch {
|
||||
Toast
|
||||
.makeText(context, it, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
scope.launch(Dispatchers.IO) {
|
||||
accountViewModel.zap(
|
||||
baseNote,
|
||||
account.zapAmountChoices.first() * 1000,
|
||||
"",
|
||||
context,
|
||||
onError = {
|
||||
scope.launch {
|
||||
zappingProgress = 0f
|
||||
Toast
|
||||
.makeText(context, it, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
},
|
||||
onProgress = {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
zappingProgress = it
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else if (account.zapAmountChoices.size > 1) {
|
||||
wantsToZap = true
|
||||
@@ -363,6 +377,7 @@ fun ZapReaction(
|
||||
accountViewModel,
|
||||
onDismiss = {
|
||||
wantsToZap = false
|
||||
zappingProgress = 0f
|
||||
},
|
||||
onChangeAmount = {
|
||||
wantsToZap = false
|
||||
@@ -370,8 +385,14 @@ fun ZapReaction(
|
||||
},
|
||||
onError = {
|
||||
scope.launch {
|
||||
zappingProgress = 0f
|
||||
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
onProgress = {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
zappingProgress = it
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -380,6 +401,7 @@ fun ZapReaction(
|
||||
}
|
||||
|
||||
if (zappedNote?.isZappedBy(account.userProfile()) == true) {
|
||||
zappingProgress = 1f
|
||||
Icon(
|
||||
imageVector = Icons.Default.Bolt,
|
||||
contentDescription = stringResource(R.string.zaps),
|
||||
@@ -387,12 +409,19 @@ fun ZapReaction(
|
||||
tint = BitcoinOrange
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Bolt,
|
||||
contentDescription = stringResource(id = R.string.zaps),
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = grayTint
|
||||
)
|
||||
if (zappingProgress < 0.1 || zappingProgress > 0.99) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Bolt,
|
||||
contentDescription = stringResource(id = R.string.zaps),
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = grayTint
|
||||
)
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
progress = zappingProgress,
|
||||
modifier = Modifier.size(15.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,12 +514,21 @@ private fun BoostTypeChoicePopup(baseNote: Note, accountViewModel: AccountViewMo
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ZapAmountChoicePopup(baseNote: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit, onChangeAmount: () -> Unit, onError: (text: String) -> Unit) {
|
||||
fun ZapAmountChoicePopup(
|
||||
baseNote: Note,
|
||||
accountViewModel: AccountViewModel,
|
||||
onDismiss: () -> Unit,
|
||||
onChangeAmount: () -> Unit,
|
||||
onError: (text: String) -> Unit,
|
||||
onProgress: (percent: Float) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Popup(
|
||||
alignment = Alignment.BottomCenter,
|
||||
offset = IntOffset(0, -50),
|
||||
@@ -501,8 +539,17 @@ fun ZapAmountChoicePopup(baseNote: Note, accountViewModel: AccountViewModel, onD
|
||||
Button(
|
||||
modifier = Modifier.padding(horizontal = 3.dp),
|
||||
onClick = {
|
||||
accountViewModel.zap(baseNote, amountInSats * 1000, "", context, onError)
|
||||
onDismiss()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
accountViewModel.zap(
|
||||
baseNote,
|
||||
amountInSats * 1000,
|
||||
"",
|
||||
context,
|
||||
onError,
|
||||
onProgress
|
||||
)
|
||||
onDismiss()
|
||||
}
|
||||
},
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = ButtonDefaults
|
||||
@@ -516,8 +563,17 @@ fun ZapAmountChoicePopup(baseNote: Note, accountViewModel: AccountViewModel, onD
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {
|
||||
accountViewModel.zap(baseNote, amountInSats * 1000, "", context, onError)
|
||||
onDismiss()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
accountViewModel.zap(
|
||||
baseNote,
|
||||
amountInSats * 1000,
|
||||
"",
|
||||
context,
|
||||
onError,
|
||||
onProgress
|
||||
)
|
||||
onDismiss()
|
||||
}
|
||||
},
|
||||
onLongClick = {
|
||||
onChangeAmount()
|
||||
|
@@ -7,6 +7,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.AccountState
|
||||
@@ -14,6 +15,9 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver
|
||||
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Locale
|
||||
|
||||
class AccountViewModel(private val account: Account) : ViewModel() {
|
||||
@@ -48,7 +52,7 @@ class AccountViewModel(private val account: Account) : ViewModel() {
|
||||
account.delete(account.boostsTo(note))
|
||||
}
|
||||
|
||||
fun zap(note: Note, amount: Long, message: String, context: Context, onError: (String) -> Unit) {
|
||||
suspend fun zap(note: Note, amount: Long, message: String, context: Context, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit) {
|
||||
val lud16 = note.author?.info?.lud16?.trim() ?: note.author?.info?.lud06?.trim()
|
||||
|
||||
if (lud16.isNullOrBlank()) {
|
||||
@@ -58,22 +62,34 @@ class AccountViewModel(private val account: Account) : ViewModel() {
|
||||
|
||||
val zapRequest = account.createZapRequestFor(note)
|
||||
|
||||
onProgress(0.10f)
|
||||
|
||||
LightningAddressResolver().lnAddressInvoice(
|
||||
lud16,
|
||||
amount,
|
||||
message,
|
||||
zapRequest?.toJson(),
|
||||
onSuccess = {
|
||||
onProgress(0.7f)
|
||||
if (account.hasWalletConnectSetup()) {
|
||||
account.sendZapPaymentRequestFor(it)
|
||||
onProgress(0.8f)
|
||||
|
||||
// Awaits for the event to come back to LocalCache.
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
delay(1000)
|
||||
onProgress(0f)
|
||||
}
|
||||
} else {
|
||||
runCatching {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("lightning:$it"))
|
||||
ContextCompat.startActivity(context, intent, null)
|
||||
}
|
||||
onProgress(0f)
|
||||
}
|
||||
},
|
||||
onError = onError
|
||||
onError = onError,
|
||||
onProgress = onProgress
|
||||
)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user