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