mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-02 20:44:57 +02:00
- Makes zap calculation a sync routine
- Optimizes the display of the yellow zap when the zap event comes before the pay payment confirmation - Fixes animations for a new zap over an existing zap.
This commit is contained in:
@@ -516,10 +516,8 @@ class Account(
|
|||||||
|
|
||||||
suspend fun calculateIfNoteWasZappedByAccount(
|
suspend fun calculateIfNoteWasZappedByAccount(
|
||||||
zappedNote: Note?,
|
zappedNote: Note?,
|
||||||
onWasZapped: () -> Unit,
|
afterTimeInSeconds: Long,
|
||||||
) {
|
): Boolean = zappedNote?.isZappedBy(userProfile(), afterTimeInSeconds, this) == true
|
||||||
zappedNote?.isZappedBy(userProfile(), this, onWasZapped)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun calculateZappedAmount(zappedNote: Note): BigDecimal = zappedNote.zappedAmountWithNWCPayments(nip47SignerState)
|
suspend fun calculateZappedAmount(zappedNote: Note): BigDecimal = zappedNote.zappedAmountWithNWCPayments(nip47SignerState)
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.model
|
|||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import coil3.util.CoilUtils.result
|
||||||
import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState
|
import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState
|
||||||
import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState
|
import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
@@ -472,28 +473,28 @@ open class Note(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun isPaidByCalculation(
|
private suspend fun isPaidByCalculation(
|
||||||
|
zapPayments: List<Pair<Note, Note?>>,
|
||||||
|
afterTimeInSeconds: Long,
|
||||||
account: Account,
|
account: Account,
|
||||||
zapEvents: List<Pair<Note, Note?>>,
|
): Boolean {
|
||||||
onWasZappedByAuthor: () -> Unit,
|
if (zapPayments.isEmpty()) {
|
||||||
) {
|
return false
|
||||||
if (zapEvents.isEmpty()) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSentOne = false
|
return anyAsync(zapPayments) { next ->
|
||||||
|
|
||||||
launchAndWaitAll(zapEvents) { next ->
|
|
||||||
val zapResponseEvent = next.second?.event as? LnZapPaymentResponseEvent
|
val zapResponseEvent = next.second?.event as? LnZapPaymentResponseEvent
|
||||||
|
|
||||||
if (zapResponseEvent != null) {
|
if (zapResponseEvent != null) {
|
||||||
account.nip47SignerState.decryptResponse(zapResponseEvent)?.let { response ->
|
val response = account.nip47SignerState.decryptResponse(zapResponseEvent)
|
||||||
val result = response is PayInvoiceSuccessResponse && account.nip47SignerState.isNIP47Author(zapResponseEvent.requestAuthor())
|
if (response != null) {
|
||||||
|
response is PayInvoiceSuccessResponse &&
|
||||||
if (!hasSentOne && result == true) {
|
account.nip47SignerState.isNIP47Author(zapResponseEvent.requestAuthor()) &&
|
||||||
hasSentOne = true
|
zapResponseEvent.createdAt > afterTimeInSeconds
|
||||||
onWasZappedByAuthor()
|
} else {
|
||||||
}
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -501,75 +502,81 @@ open class Note(
|
|||||||
private suspend fun isZappedByCalculation(
|
private suspend fun isZappedByCalculation(
|
||||||
option: Int?,
|
option: Int?,
|
||||||
user: User,
|
user: User,
|
||||||
|
afterTimeInSeconds: Long,
|
||||||
account: Account,
|
account: Account,
|
||||||
zapEvents: Map<Note, Note?>,
|
zapEvents: Map<Note, Note?>,
|
||||||
onWasZappedByAuthor: () -> Unit,
|
): Boolean {
|
||||||
) {
|
|
||||||
if (zapEvents.isEmpty()) {
|
if (zapEvents.isEmpty()) {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val parallelDecrypt = mutableListOf<Pair<LnZapRequestEvent, LnZapEvent?>>()
|
val parallelDecrypt = mutableListOf<Pair<LnZapRequestEvent, LnZapEvent>>()
|
||||||
|
|
||||||
zapEvents.forEach { next ->
|
zapEvents.forEach { next ->
|
||||||
val zapRequest = next.key.event as LnZapRequestEvent
|
val zapRequest = next.key.event as LnZapRequestEvent
|
||||||
val zapEvent = next.value?.event as? LnZapEvent
|
val zapEvent = next.value?.event as? LnZapEvent
|
||||||
|
|
||||||
if (!zapRequest.isPrivateZap()) {
|
if (zapEvent != null) {
|
||||||
// public events
|
if (!zapRequest.isPrivateZap()) {
|
||||||
if (zapRequest.pubKey == user.pubkeyHex && (option == null || option == zapEvent?.zappedPollOption())) {
|
// public events
|
||||||
onWasZappedByAuthor()
|
if (zapRequest.pubKey == user.pubkeyHex &&
|
||||||
return
|
zapEvent.createdAt > afterTimeInSeconds &&
|
||||||
}
|
(option == null || option == zapEvent.zappedPollOption())
|
||||||
} else {
|
) {
|
||||||
// private events
|
return true
|
||||||
|
|
||||||
// if has already decrypted
|
|
||||||
val privateZap = account.privateZapsDecryptionCache.cachedPrivateZap(zapRequest)
|
|
||||||
if (privateZap != null) {
|
|
||||||
if (privateZap.pubKey == user.pubkeyHex && (option == null || option == zapEvent?.zappedPollOption())) {
|
|
||||||
onWasZappedByAuthor()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (account.isWriteable()) {
|
// private events
|
||||||
parallelDecrypt.add(Pair(zapRequest, zapEvent))
|
|
||||||
|
// if has already decrypted
|
||||||
|
val privateZap = account.privateZapsDecryptionCache.cachedPrivateZap(zapRequest)
|
||||||
|
if (privateZap != null) {
|
||||||
|
if (privateZap.pubKey == user.pubkeyHex &&
|
||||||
|
zapEvent.createdAt > afterTimeInSeconds &&
|
||||||
|
(option == null || option == zapEvent.zappedPollOption())
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (account.isWriteable()) {
|
||||||
|
parallelDecrypt.add(Pair(zapRequest, zapEvent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val result =
|
if (parallelDecrypt.isEmpty()) {
|
||||||
anyAsync(parallelDecrypt) { pair ->
|
return false
|
||||||
val result = account.privateZapsDecryptionCache.decryptPrivateZap(pair.first)
|
}
|
||||||
|
|
||||||
result?.pubKey == user.pubkeyHex && (option == null || option == pair.second?.zappedPollOption())
|
return anyAsync(parallelDecrypt) { pair ->
|
||||||
}
|
val result = account.privateZapsDecryptionCache.decryptPrivateZap(pair.first)
|
||||||
|
result?.pubKey == user.pubkeyHex &&
|
||||||
if (result) {
|
pair.second.createdAt > afterTimeInSeconds &&
|
||||||
onWasZappedByAuthor()
|
(option == null || option == pair.second.zappedPollOption())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun isZappedBy(
|
suspend fun isZappedBy(
|
||||||
user: User,
|
user: User,
|
||||||
|
afterTimeInSeconds: Long,
|
||||||
account: Account,
|
account: Account,
|
||||||
onWasZappedByAuthor: () -> Unit,
|
): Boolean {
|
||||||
) {
|
val first = isZappedByCalculation(null, user, afterTimeInSeconds, account, zaps)
|
||||||
isZappedByCalculation(null, user, account, zaps, onWasZappedByAuthor)
|
if (first) return true
|
||||||
if (account.userProfile() == user) {
|
if (account.userProfile() == user) {
|
||||||
isPaidByCalculation(account, zapPayments.toList(), onWasZappedByAuthor)
|
return isPaidByCalculation(zapPayments.toList(), afterTimeInSeconds, account)
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun isZappedBy(
|
suspend fun isZappedBy(
|
||||||
option: Int?,
|
option: Int?,
|
||||||
user: User,
|
user: User,
|
||||||
|
afterTimeInSeconds: Long,
|
||||||
account: Account,
|
account: Account,
|
||||||
onWasZappedByAuthor: () -> Unit,
|
): Boolean = isZappedByCalculation(option, user, afterTimeInSeconds, account, zaps)
|
||||||
) {
|
|
||||||
isZappedByCalculation(option, user, account, zaps, onWasZappedByAuthor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getReactionBy(user: User): String? =
|
fun getReactionBy(user: User): String? =
|
||||||
reactions.firstNotNullOfOrNull {
|
reactions.firstNotNullOfOrNull {
|
||||||
|
@@ -52,6 +52,7 @@ import androidx.compose.runtime.MutableState
|
|||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@@ -90,6 +91,7 @@ import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
import com.vitorpamplona.amethyst.ui.theme.Font14SP
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size14Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
|
||||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||||
@@ -100,6 +102,7 @@ import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists
|
|||||||
import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists
|
import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists
|
||||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -517,6 +520,8 @@ fun ZapVote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
||||||
|
var zapStartingTime by remember { mutableLongStateOf(0L) }
|
||||||
|
|
||||||
var showErrorMessageDialog by remember { mutableStateOf<StringToastMsg?>(null) }
|
var showErrorMessageDialog by remember { mutableStateOf<StringToastMsg?>(null) }
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -558,6 +563,7 @@ fun ZapVote(
|
|||||||
accountViewModel.zapAmountChoices().size == 1 &&
|
accountViewModel.zapAmountChoices().size == 1 &&
|
||||||
pollViewModel.isValidInputVoteAmount(accountViewModel.zapAmountChoices().first())
|
pollViewModel.isValidInputVoteAmount(accountViewModel.zapAmountChoices().first())
|
||||||
) {
|
) {
|
||||||
|
zapStartingTime = TimeUtils.now()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel.zapAmountChoices().first() * 1000,
|
accountViewModel.zapAmountChoices().first() * 1000,
|
||||||
@@ -583,6 +589,7 @@ fun ZapVote(
|
|||||||
accountViewModel,
|
accountViewModel,
|
||||||
pollViewModel,
|
pollViewModel,
|
||||||
poolOption.option,
|
poolOption.option,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
wantsToZap = false
|
wantsToZap = false
|
||||||
zappingProgress = 0f
|
zappingProgress = 0f
|
||||||
@@ -660,9 +667,10 @@ fun ZapVote(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Spacer(Modifier.width(3.dp))
|
Spacer(Modifier.width(3.dp))
|
||||||
|
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
progress = { zappingProgress },
|
progress = { zappingProgress },
|
||||||
modifier = Modifier.size(14.dp),
|
modifier = Size14Modifier,
|
||||||
strokeWidth = 2.dp,
|
strokeWidth = 2.dp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -688,6 +696,7 @@ fun FilteredZapAmountChoicePopup(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
pollViewModel: PollNoteViewModel,
|
pollViewModel: PollNoteViewModel,
|
||||||
pollOption: Int,
|
pollOption: Int,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onChangeAmount: () -> Unit,
|
onChangeAmount: () -> Unit,
|
||||||
onError: (title: String, text: String, toUser: User?) -> Unit,
|
onError: (title: String, text: String, toUser: User?) -> Unit,
|
||||||
@@ -717,6 +726,7 @@ fun FilteredZapAmountChoicePopup(
|
|||||||
Button(
|
Button(
|
||||||
modifier = Modifier.padding(horizontal = 3.dp),
|
modifier = Modifier.padding(horizontal = 3.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
amountInSats * 1000,
|
amountInSats * 1000,
|
||||||
@@ -743,6 +753,7 @@ fun FilteredZapAmountChoicePopup(
|
|||||||
modifier =
|
modifier =
|
||||||
Modifier.combinedClickable(
|
Modifier.combinedClickable(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
amountInSats * 1000,
|
amountInSats * 1000,
|
||||||
|
@@ -103,10 +103,8 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
totalZapped = totalZapped()
|
totalZapped = totalZapped()
|
||||||
wasZappedByLoggedInAccount = false
|
wasZappedByLoggedInAccount = false
|
||||||
account?.calculateIfNoteWasZappedByAccount(pollNote) {
|
wasZappedByLoggedInAccount = account.calculateIfNoteWasZappedByAccount(pollNote, 0)
|
||||||
wasZappedByLoggedInAccount = true
|
canZap.value = checkIfCanZap()
|
||||||
canZap.value = checkIfCanZap()
|
|
||||||
}
|
|
||||||
|
|
||||||
tallies.forEach {
|
tallies.forEach {
|
||||||
val zappedValue = zappedPollOptionAmount(it.option)
|
val zappedValue = zappedPollOptionAmount(it.option)
|
||||||
@@ -210,10 +208,8 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
suspend fun isPollOptionZappedBy(
|
suspend fun isPollOptionZappedBy(
|
||||||
option: Int,
|
option: Int,
|
||||||
user: User,
|
user: User,
|
||||||
onWasZappedByAuthor: () -> Unit,
|
afterTimeInSeconds: Long,
|
||||||
) {
|
): Boolean = pollNote?.isZappedBy(option, user, afterTimeInSeconds, account) == true
|
||||||
pollNote?.isZappedBy(option, user, account!!, onWasZappedByAuthor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cachedIsPollOptionZappedBy(
|
fun cachedIsPollOptionZappedBy(
|
||||||
option: Int,
|
option: Int,
|
||||||
|
@@ -66,6 +66,7 @@ import androidx.compose.runtime.State
|
|||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -154,11 +155,13 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.reactionBox
|
import com.vitorpamplona.amethyst.ui.theme.reactionBox
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ripple24dp
|
import com.vitorpamplona.amethyst.ui.theme.ripple24dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.selectedReactionBoxModifier
|
import com.vitorpamplona.amethyst.ui.theme.selectedReactionBoxModifier
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.EmptyClientListener.onError
|
||||||
import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent
|
import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent
|
||||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
||||||
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
||||||
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.ImmutableSet
|
import kotlinx.collections.immutable.ImmutableSet
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
@@ -994,6 +997,7 @@ fun ZapReaction(
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
||||||
|
var zapStartingTime by remember { mutableLongStateOf(0L) }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = CenterVertically,
|
verticalAlignment = CenterVertically,
|
||||||
@@ -1008,6 +1012,7 @@ fun ZapReaction(
|
|||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
context,
|
context,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onZappingProgress = { progress: Float -> scope.launch { zappingProgress = progress } },
|
onZappingProgress = { progress: Float -> scope.launch { zappingProgress = progress } },
|
||||||
onMultipleChoices = {
|
onMultipleChoices = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -1033,6 +1038,7 @@ fun ZapReaction(
|
|||||||
baseNote = baseNote,
|
baseNote = baseNote,
|
||||||
popupYOffset = iconSize,
|
popupYOffset = iconSize,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
wantsToZap = false
|
wantsToZap = false
|
||||||
zappingProgress = 0f
|
zappingProgress = 0f
|
||||||
@@ -1083,6 +1089,7 @@ fun ZapReaction(
|
|||||||
|
|
||||||
if (wantsToSetCustomZap) {
|
if (wantsToSetCustomZap) {
|
||||||
ZapCustomDialog(
|
ZapCustomDialog(
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onClose = { wantsToSetCustomZap = false },
|
onClose = { wantsToSetCustomZap = false },
|
||||||
onError = { _, message, user ->
|
onError = { _, message, user ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -1106,11 +1113,23 @@ fun ZapReaction(
|
|||||||
label = "ZapIconIndicator",
|
label = "ZapIconIndicator",
|
||||||
)
|
)
|
||||||
|
|
||||||
CircularProgressIndicator(
|
ObserveZapIcon(
|
||||||
progress = { animatedProgress },
|
baseNote,
|
||||||
modifier = animationModifier,
|
accountViewModel,
|
||||||
strokeWidth = 2.dp,
|
zapStartingTime,
|
||||||
)
|
) { wasZappedByLoggedInUser ->
|
||||||
|
CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) {
|
||||||
|
if (it) {
|
||||||
|
ZappedIcon(iconSizeModifier)
|
||||||
|
} else {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
progress = { animatedProgress },
|
||||||
|
modifier = animationModifier,
|
||||||
|
strokeWidth = 2.dp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ObserveZapIcon(
|
ObserveZapIcon(
|
||||||
baseNote,
|
baseNote,
|
||||||
@@ -1136,6 +1155,7 @@ fun zapClick(
|
|||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onZappingProgress: (Float) -> Unit,
|
onZappingProgress: (Float) -> Unit,
|
||||||
onMultipleChoices: () -> Unit,
|
onMultipleChoices: () -> Unit,
|
||||||
onError: (String, String, User?) -> Unit,
|
onError: (String, String, User?) -> Unit,
|
||||||
@@ -1162,6 +1182,7 @@ fun zapClick(
|
|||||||
R.string.login_with_a_private_key_to_be_able_to_send_zaps,
|
R.string.login_with_a_private_key_to_be_able_to_send_zaps,
|
||||||
)
|
)
|
||||||
} else if (choices.size == 1) {
|
} else if (choices.size == 1) {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
choices.first() * 1000,
|
choices.first() * 1000,
|
||||||
@@ -1181,6 +1202,7 @@ fun zapClick(
|
|||||||
fun ObserveZapIcon(
|
fun ObserveZapIcon(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
|
afterTimeInSeconds: Long = 0,
|
||||||
inner: @Composable (MutableState<Boolean>) -> Unit,
|
inner: @Composable (MutableState<Boolean>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val wasZappedByLoggedInUser = remember { mutableStateOf(false) }
|
val wasZappedByLoggedInUser = remember { mutableStateOf(false) }
|
||||||
@@ -1196,10 +1218,9 @@ fun ObserveZapIcon(
|
|||||||
|
|
||||||
LaunchedEffect(key1 = zapsState) {
|
LaunchedEffect(key1 = zapsState) {
|
||||||
if (zapsState?.note?.zapPayments?.isNotEmpty() == true || zapsState?.note?.zaps?.isNotEmpty() == true) {
|
if (zapsState?.note?.zapPayments?.isNotEmpty() == true || zapsState?.note?.zaps?.isNotEmpty() == true) {
|
||||||
accountViewModel.calculateIfNoteWasZappedByAccount(baseNote) { newWasZapped ->
|
val newWasZapped = accountViewModel.calculateIfNoteWasZappedByAccount(baseNote, afterTimeInSeconds)
|
||||||
if (wasZappedByLoggedInUser.value != newWasZapped) {
|
if (wasZappedByLoggedInUser.value != newWasZapped) {
|
||||||
wasZappedByLoggedInUser.value = newWasZapped
|
wasZappedByLoggedInUser.value = newWasZapped
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1552,6 +1573,7 @@ fun ZapAmountChoicePopup(
|
|||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
popupYOffset: Dp,
|
popupYOffset: Dp,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onChangeAmount: () -> Unit,
|
onChangeAmount: () -> Unit,
|
||||||
onError: (title: String, text: String, user: User?) -> Unit,
|
onError: (title: String, text: String, user: User?) -> Unit,
|
||||||
@@ -1562,7 +1584,7 @@ fun ZapAmountChoicePopup(
|
|||||||
accountViewModel.account.settings.syncedSettings.zaps.zapAmountChoices
|
accountViewModel.account.settings.syncedSettings.zaps.zapAmountChoices
|
||||||
.collectAsStateWithLifecycle()
|
.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
ZapAmountChoicePopup(baseNote, zapAmountChoices, accountViewModel, popupYOffset, onDismiss, onChangeAmount, onError, onProgress, onPayViaIntent)
|
ZapAmountChoicePopup(baseNote, zapAmountChoices, accountViewModel, popupYOffset, onZapStarts, onDismiss, onChangeAmount, onError, onProgress, onPayViaIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -1571,6 +1593,7 @@ fun ZapAmountChoicePopup(
|
|||||||
zapAmountChoices: ImmutableList<Long>,
|
zapAmountChoices: ImmutableList<Long>,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
popupYOffset: Dp,
|
popupYOffset: Dp,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onChangeAmount: () -> Unit,
|
onChangeAmount: () -> Unit,
|
||||||
onError: (title: String, text: String, user: User?) -> Unit,
|
onError: (title: String, text: String, user: User?) -> Unit,
|
||||||
@@ -1578,7 +1601,7 @@ fun ZapAmountChoicePopup(
|
|||||||
onPayViaIntent: (ImmutableList<ZapPaymentHandler.Payable>) -> Unit,
|
onPayViaIntent: (ImmutableList<ZapPaymentHandler.Payable>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val visibilityState = rememberVisibilityState(onDismiss)
|
val visibilityState = rememberVisibilityState(onDismiss)
|
||||||
ZapAmountChoicePopup(baseNote, zapAmountChoices, accountViewModel, popupYOffset, visibilityState, onChangeAmount, onError, onProgress, onPayViaIntent)
|
ZapAmountChoicePopup(baseNote, zapAmountChoices, accountViewModel, popupYOffset, visibilityState, onZapStarts, onChangeAmount, onError, onProgress, onPayViaIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalLayoutApi::class)
|
||||||
@@ -1589,6 +1612,7 @@ fun ZapAmountChoicePopup(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
popupYOffset: Dp,
|
popupYOffset: Dp,
|
||||||
visibilityState: MutableTransitionState<Boolean>,
|
visibilityState: MutableTransitionState<Boolean>,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onChangeAmount: () -> Unit,
|
onChangeAmount: () -> Unit,
|
||||||
onError: (title: String, text: String, user: User?) -> Unit,
|
onError: (title: String, text: String, user: User?) -> Unit,
|
||||||
onProgress: (percent: Float) -> Unit,
|
onProgress: (percent: Float) -> Unit,
|
||||||
@@ -1615,6 +1639,7 @@ fun ZapAmountChoicePopup(
|
|||||||
Button(
|
Button(
|
||||||
modifier = Modifier.padding(horizontal = 3.dp),
|
modifier = Modifier.padding(horizontal = 3.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
amountInSats * 1000,
|
amountInSats * 1000,
|
||||||
@@ -1641,6 +1666,7 @@ fun ZapAmountChoicePopup(
|
|||||||
modifier =
|
modifier =
|
||||||
Modifier.combinedClickable(
|
Modifier.combinedClickable(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
amountInSats * 1000,
|
amountInSats * 1000,
|
||||||
|
@@ -103,6 +103,7 @@ class ZapOptionViewModel : ViewModel() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ZapCustomDialog(
|
fun ZapCustomDialog(
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onClose: () -> Unit,
|
onClose: () -> Unit,
|
||||||
onError: (title: String, text: String, user: User?) -> Unit,
|
onError: (title: String, text: String, user: User?) -> Unit,
|
||||||
onProgress: (percent: Float) -> Unit,
|
onProgress: (percent: Float) -> Unit,
|
||||||
@@ -172,6 +173,7 @@ fun ZapCustomDialog(
|
|||||||
ZapButton(
|
ZapButton(
|
||||||
isActive = postViewModel.canSend() && !baseNote.isDraft(),
|
isActive = postViewModel.canSend() && !baseNote.isDraft(),
|
||||||
) {
|
) {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
postViewModel.value()!! * 1000L,
|
postViewModel.value()!! * 1000L,
|
||||||
|
@@ -40,6 +40,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@@ -83,12 +84,14 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp
|
import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size14Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.amethyst.ui.theme.imageModifier
|
import com.vitorpamplona.amethyst.ui.theme.imageModifier
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
@@ -285,7 +288,7 @@ fun ZapDonationButton(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
iconSize: Dp = Size35dp,
|
iconSize: Dp = Size35dp,
|
||||||
iconSizeModifier: Modifier = Size20Modifier,
|
iconSizeModifier: Modifier = Size20Modifier,
|
||||||
animationSize: Dp = 14.dp,
|
animationModifier: Modifier = Size14Modifier,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
var wantsToZap by remember { mutableStateOf<ImmutableList<Long>?>(null) }
|
var wantsToZap by remember { mutableStateOf<ImmutableList<Long>?>(null) }
|
||||||
@@ -300,6 +303,8 @@ fun ZapDonationButton(
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
||||||
|
var zapStartingTime by remember { mutableLongStateOf(0L) }
|
||||||
|
|
||||||
var hasZapped by remember { mutableStateOf(false) }
|
var hasZapped by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
@@ -308,6 +313,7 @@ fun ZapDonationButton(
|
|||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
context,
|
context,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onZappingProgress = { progress: Float ->
|
onZappingProgress = { progress: Float ->
|
||||||
scope.launch { zappingProgress = progress }
|
scope.launch { zappingProgress = progress }
|
||||||
},
|
},
|
||||||
@@ -329,6 +335,7 @@ fun ZapDonationButton(
|
|||||||
zapAmountChoices = it,
|
zapAmountChoices = it,
|
||||||
popupYOffset = iconSize,
|
popupYOffset = iconSize,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
wantsToZap = null
|
wantsToZap = null
|
||||||
zappingProgress = 0f
|
zappingProgress = 0f
|
||||||
@@ -376,17 +383,30 @@ fun ZapDonationButton(
|
|||||||
if (zappingProgress > 0.00001 && zappingProgress < 0.99999) {
|
if (zappingProgress > 0.00001 && zappingProgress < 0.99999) {
|
||||||
Spacer(ModifierWidth3dp)
|
Spacer(ModifierWidth3dp)
|
||||||
|
|
||||||
CircularProgressIndicator(
|
val animatedProgress by animateFloatAsState(
|
||||||
progress =
|
targetValue = zappingProgress,
|
||||||
animateFloatAsState(
|
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec,
|
||||||
targetValue = zappingProgress,
|
label = "ZapIconIndicator",
|
||||||
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec,
|
|
||||||
label = "ZapIconIndicator",
|
|
||||||
).value,
|
|
||||||
modifier = remember { Modifier.size(animationSize) },
|
|
||||||
strokeWidth = 2.dp,
|
|
||||||
color = grayTint,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ObserveZapIcon(
|
||||||
|
baseNote,
|
||||||
|
accountViewModel,
|
||||||
|
zapStartingTime,
|
||||||
|
) { wasZappedByLoggedInUser ->
|
||||||
|
CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) {
|
||||||
|
if (it) {
|
||||||
|
ZappedIcon(iconSizeModifier)
|
||||||
|
} else {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
progress = { animatedProgress },
|
||||||
|
modifier = animationModifier,
|
||||||
|
strokeWidth = 2.dp,
|
||||||
|
color = grayTint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ObserveZapIcon(
|
ObserveZapIcon(
|
||||||
baseNote,
|
baseNote,
|
||||||
@@ -423,6 +443,7 @@ fun customZapClick(
|
|||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
onZapStarts: () -> Unit,
|
||||||
onZappingProgress: (Float) -> Unit,
|
onZappingProgress: (Float) -> Unit,
|
||||||
onMultipleChoices: (List<Long>) -> Unit,
|
onMultipleChoices: (List<Long>) -> Unit,
|
||||||
onError: (String, String, User?) -> Unit,
|
onError: (String, String, User?) -> Unit,
|
||||||
@@ -452,6 +473,7 @@ fun customZapClick(
|
|||||||
val amount = choices.first()
|
val amount = choices.first()
|
||||||
|
|
||||||
if (amount > 1100) {
|
if (amount > 1100) {
|
||||||
|
onZapStarts()
|
||||||
accountViewModel.zap(
|
accountViewModel.zap(
|
||||||
baseNote,
|
baseNote,
|
||||||
amount * 1000,
|
amount * 1000,
|
||||||
|
@@ -395,12 +395,11 @@ class AccountViewModel(
|
|||||||
|
|
||||||
suspend fun calculateIfNoteWasZappedByAccount(
|
suspend fun calculateIfNoteWasZappedByAccount(
|
||||||
zappedNote: Note,
|
zappedNote: Note,
|
||||||
onWasZapped: (Boolean) -> Unit,
|
afterTimeInSeconds: Long,
|
||||||
) {
|
): Boolean =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
account.calculateIfNoteWasZappedByAccount(zappedNote) { onWasZapped(true) }
|
account.calculateIfNoteWasZappedByAccount(zappedNote, afterTimeInSeconds)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun calculateZapAmount(zappedNote: Note): String =
|
suspend fun calculateZapAmount(zappedNote: Note): String =
|
||||||
if (zappedNote.zapPayments.isNotEmpty()) {
|
if (zappedNote.zapPayments.isNotEmpty()) {
|
||||||
|
@@ -40,6 +40,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@@ -97,6 +98,7 @@ import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent
|
|||||||
import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppMetadata
|
import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppMetadata
|
||||||
import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent
|
import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent
|
||||||
import com.vitorpamplona.quartz.nip90Dvms.NIP90StatusEvent
|
import com.vitorpamplona.quartz.nip90Dvms.NIP90StatusEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -472,6 +474,7 @@ fun ZapDVMButton(
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
var zappingProgress by remember { mutableFloatStateOf(0f) }
|
||||||
|
var zapStartingTime by remember { mutableLongStateOf(0L) }
|
||||||
var hasZapped by remember { mutableStateOf(false) }
|
var hasZapped by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
@@ -480,6 +483,7 @@ fun ZapDVMButton(
|
|||||||
baseNote,
|
baseNote,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
context,
|
context,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onZappingProgress = { progress: Float ->
|
onZappingProgress = { progress: Float ->
|
||||||
scope.launch { zappingProgress = progress }
|
scope.launch { zappingProgress = progress }
|
||||||
},
|
},
|
||||||
@@ -501,6 +505,7 @@ fun ZapDVMButton(
|
|||||||
zapAmountChoices = persistentListOf(amount / 1000),
|
zapAmountChoices = persistentListOf(amount / 1000),
|
||||||
popupYOffset = iconSize,
|
popupYOffset = iconSize,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
|
onZapStarts = { zapStartingTime = TimeUtils.now() },
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
wantsToZap = null
|
wantsToZap = null
|
||||||
zappingProgress = 0f
|
zappingProgress = 0f
|
||||||
@@ -554,12 +559,24 @@ fun ZapDVMButton(
|
|||||||
label = "ZapIconIndicator",
|
label = "ZapIconIndicator",
|
||||||
)
|
)
|
||||||
|
|
||||||
CircularProgressIndicator(
|
ObserveZapIcon(
|
||||||
progress = { animatedProgress },
|
baseNote,
|
||||||
modifier = remember { Modifier.size(animationSize) },
|
accountViewModel,
|
||||||
strokeWidth = 2.dp,
|
zapStartingTime,
|
||||||
color = grayTint,
|
) { wasZappedByLoggedInUser ->
|
||||||
)
|
CrossfadeIfEnabled(targetState = wasZappedByLoggedInUser.value, label = "ZapIcon", accountViewModel = accountViewModel) {
|
||||||
|
if (it) {
|
||||||
|
ZappedIcon(iconSizeModifier)
|
||||||
|
} else {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
progress = { animatedProgress },
|
||||||
|
modifier = remember { Modifier.size(animationSize) },
|
||||||
|
strokeWidth = 2.dp,
|
||||||
|
color = grayTint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ObserveZapIcon(
|
ObserveZapIcon(
|
||||||
baseNote,
|
baseNote,
|
||||||
|
Reference in New Issue
Block a user