Continues to move away from starting co-routines directly in composables
This commit is contained in:
@@ -463,10 +463,6 @@ open class Note(val idHex: String) {
|
|||||||
}.flatten()
|
}.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun countReactions(): Int {
|
|
||||||
return reactions.values.sumOf { it.size }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun zappedAmount(privKey: ByteArray?, walletServicePubkey: ByteArray?): BigDecimal {
|
fun zappedAmount(privKey: ByteArray?, walletServicePubkey: ByteArray?): BigDecimal {
|
||||||
// Regular Zap Receipts
|
// Regular Zap Receipts
|
||||||
val completedZaps = zaps.asSequence()
|
val completedZaps = zaps.asSequence()
|
||||||
@@ -683,6 +679,10 @@ class NoteLiveSet(u: Note) {
|
|||||||
it.note.replies.size
|
it.note.replies.size
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
|
|
||||||
|
val reactionCount = reactions.map {
|
||||||
|
it.note.reactions.values.sumOf { it.size }
|
||||||
|
}.distinctUntilChanged()
|
||||||
|
|
||||||
val boostCount = boosts.map {
|
val boostCount = boosts.map {
|
||||||
it.note.boosts.size
|
it.note.boosts.size
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ abstract class NostrDataSource(val debugName: String) {
|
|||||||
private val bundler = BundledUpdate(300, Dispatchers.IO)
|
private val bundler = BundledUpdate(300, Dispatchers.IO)
|
||||||
|
|
||||||
fun invalidateFilters() {
|
fun invalidateFilters() {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
bundler.invalidate() {
|
bundler.invalidate() {
|
||||||
// println("DataSource: ${this.javaClass.simpleName} InvalidateFilters")
|
// println("DataSource: ${this.javaClass.simpleName} InvalidateFilters")
|
||||||
|
|
||||||
@@ -119,6 +120,7 @@ abstract class NostrDataSource(val debugName: String) {
|
|||||||
resetFiltersSuspend()
|
resetFiltersSuspend()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun resetFilters() {
|
fun resetFilters() {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import com.vitorpamplona.amethyst.model.ConnectivityType
|
|||||||
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
||||||
import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus
|
import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UrlPreview(url: String, urlText: String, accountViewModel: AccountViewModel) {
|
fun UrlPreview(url: String, urlText: String, accountViewModel: AccountViewModel) {
|
||||||
@@ -37,13 +35,11 @@ fun UrlPreview(url: String, urlText: String, accountViewModel: AccountViewModel)
|
|||||||
// Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are created).
|
// Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are created).
|
||||||
if (urlPreviewState == UrlPreviewState.Loading) {
|
if (urlPreviewState == UrlPreviewState.Loading) {
|
||||||
LaunchedEffect(url) {
|
LaunchedEffect(url) {
|
||||||
launch(Dispatchers.IO) {
|
accountViewModel.urlPreview(url) {
|
||||||
UrlCachedPreviewer.previewInfo(url) {
|
|
||||||
urlPreviewState = it
|
urlPreviewState = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Crossfade(
|
Crossfade(
|
||||||
targetState = urlPreviewState,
|
targetState = urlPreviewState,
|
||||||
|
|||||||
@@ -285,23 +285,19 @@ private fun EditStatusBox(baseAccountUser: User, accountViewModel: AccountViewMo
|
|||||||
),
|
),
|
||||||
keyboardActions = KeyboardActions(
|
keyboardActions = KeyboardActions(
|
||||||
onSend = {
|
onSend = {
|
||||||
scope.launch(Dispatchers.IO) {
|
|
||||||
accountViewModel.createStatus(currentStatus.value)
|
accountViewModel.createStatus(currentStatus.value)
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
),
|
),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
if (hasChanged) {
|
if (hasChanged) {
|
||||||
UserStatusSendButton() {
|
UserStatusSendButton() {
|
||||||
scope.launch(Dispatchers.IO) {
|
|
||||||
accountViewModel.createStatus(currentStatus.value)
|
accountViewModel.createStatus(currentStatus.value)
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
statuses.forEach {
|
statuses.forEach {
|
||||||
@@ -335,31 +331,24 @@ private fun EditStatusBox(baseAccountUser: User, accountViewModel: AccountViewMo
|
|||||||
),
|
),
|
||||||
keyboardActions = KeyboardActions(
|
keyboardActions = KeyboardActions(
|
||||||
onSend = {
|
onSend = {
|
||||||
scope.launch(Dispatchers.IO) {
|
|
||||||
accountViewModel.updateStatus(it, thisStatus.value)
|
accountViewModel.updateStatus(it, thisStatus.value)
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
),
|
),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
if (hasChanged) {
|
if (hasChanged) {
|
||||||
UserStatusSendButton() {
|
UserStatusSendButton() {
|
||||||
scope.launch(Dispatchers.IO) {
|
|
||||||
accountViewModel.updateStatus(it, thisStatus.value)
|
accountViewModel.updateStatus(it, thisStatus.value)
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
UserStatusDeleteButton() {
|
UserStatusDeleteButton() {
|
||||||
scope.launch(Dispatchers.IO) {
|
accountViewModel.deleteStatus(it)
|
||||||
accountViewModel.updateStatus(it, "")
|
|
||||||
accountViewModel.delete(it)
|
|
||||||
focusManager.clearFocus(true)
|
focusManager.clearFocus(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.ui.components.ImageUrlType
|
import com.vitorpamplona.amethyst.ui.components.ImageUrlType
|
||||||
@@ -52,7 +51,6 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
import com.vitorpamplona.amethyst.ui.screen.CombinedZap
|
||||||
import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
|
import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifier
|
import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifierSmaller
|
import com.vitorpamplona.amethyst.ui.theme.NotificationIconModifierSmaller
|
||||||
@@ -70,8 +68,6 @@ import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.overPictureBackground
|
import com.vitorpamplona.amethyst.ui.theme.overPictureBackground
|
||||||
import com.vitorpamplona.amethyst.ui.theme.profile35dpModifier
|
import com.vitorpamplona.amethyst.ui.theme.profile35dpModifier
|
||||||
import com.vitorpamplona.quartz.events.ImmutableListOfLists
|
import com.vitorpamplona.quartz.events.ImmutableListOfLists
|
||||||
import com.vitorpamplona.quartz.events.LnZapEvent
|
|
||||||
import com.vitorpamplona.quartz.events.LnZapRequestEvent
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -352,8 +348,7 @@ private fun ParseAuthorCommentAndAmount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(key1 = zapRequest.idHex, key2 = zapEvent?.idHex) {
|
LaunchedEffect(key1 = zapRequest.idHex, key2 = zapEvent?.idHex) {
|
||||||
launch(Dispatchers.IO) {
|
accountViewModel.decryptAmountMessage(zapRequest, zapEvent) { newState ->
|
||||||
val newState = loadAmountState(zapRequest, zapEvent, accountViewModel)
|
|
||||||
if (newState != null) {
|
if (newState != null) {
|
||||||
content.value = newState
|
content.value = newState
|
||||||
}
|
}
|
||||||
@@ -363,34 +358,6 @@ private fun ParseAuthorCommentAndAmount(
|
|||||||
onReady(content)
|
onReady(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadAmountState(
|
|
||||||
zapRequest: Note,
|
|
||||||
zapEvent: Note?,
|
|
||||||
accountViewModel: AccountViewModel
|
|
||||||
): ZapAmountCommentNotification? {
|
|
||||||
(zapRequest.event as? LnZapRequestEvent)?.let {
|
|
||||||
val decryptedContent = accountViewModel.decryptZap(zapRequest)
|
|
||||||
val amount = (zapEvent?.event as? LnZapEvent)?.amount
|
|
||||||
if (decryptedContent != null) {
|
|
||||||
val newAuthor = LocalCache.getOrCreateUser(decryptedContent.pubKey)
|
|
||||||
return ZapAmountCommentNotification(
|
|
||||||
newAuthor,
|
|
||||||
decryptedContent.content.ifBlank { null },
|
|
||||||
showAmountAxis(amount)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if (!zapRequest.event?.content().isNullOrBlank() || amount != null) {
|
|
||||||
return ZapAmountCommentNotification(
|
|
||||||
zapRequest.author,
|
|
||||||
zapRequest.event?.content()?.ifBlank { null },
|
|
||||||
showAmountAxis(amount)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RenderState(
|
private fun RenderState(
|
||||||
content: MutableState<ZapAmountCommentNotification>,
|
content: MutableState<ZapAmountCommentNotification>,
|
||||||
|
|||||||
@@ -98,10 +98,8 @@ private fun WatchZapsAndUpdateTallies(
|
|||||||
val zapsState by baseNote.live().zaps.observeAsState()
|
val zapsState by baseNote.live().zaps.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(key1 = zapsState) {
|
LaunchedEffect(key1 = zapsState) {
|
||||||
launch(Dispatchers.Default) {
|
|
||||||
pollViewModel.refreshTallies()
|
pollViewModel.refreshTallies()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.quartz.events.*
|
import com.vitorpamplona.quartz.events.*
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
|
|
||||||
@@ -52,12 +55,12 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
closedAt = pollEvent?.getTagInt(CLOSED_AT)
|
closedAt = pollEvent?.getTagInt(CLOSED_AT)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun refreshTallies() {
|
fun refreshTallies() {
|
||||||
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
totalZapped = totalZapped()
|
totalZapped = totalZapped()
|
||||||
wasZappedByLoggedInAccount = pollNote?.let { account?.calculateIfNoteWasZappedByAccount(it) } ?: false
|
wasZappedByLoggedInAccount = pollNote?.let { account?.calculateIfNoteWasZappedByAccount(it) } ?: false
|
||||||
|
|
||||||
_tallies.emit(
|
val newOptions = pollOptions?.keys?.map {
|
||||||
pollOptions?.keys?.map {
|
|
||||||
val zappedInOption = zappedPollOptionAmount(it)
|
val zappedInOption = zappedPollOptionAmount(it)
|
||||||
|
|
||||||
val myTally = if (totalZapped.compareTo(BigDecimal.ZERO) > 0) {
|
val myTally = if (totalZapped.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
@@ -71,9 +74,13 @@ class PollNoteViewModel : ViewModel() {
|
|||||||
val consensus = consensusThreshold != null && myTally >= consensusThreshold!!
|
val consensus = consensusThreshold != null && myTally >= consensusThreshold!!
|
||||||
|
|
||||||
PollOption(it, pollOptions?.get(it) ?: "", zappedInOption, myTally, consensus, zappedByLoggedIn)
|
PollOption(it, pollOptions?.get(it) ?: "", zappedInOption, myTally, consensus, zappedByLoggedIn)
|
||||||
} ?: emptyList()
|
}
|
||||||
|
|
||||||
|
_tallies.emit(
|
||||||
|
newOptions ?: emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun canZap(): Boolean {
|
fun canZap(): Boolean {
|
||||||
val account = account ?: return false
|
val account = account ?: return false
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import androidx.compose.material.ProgressIndicatorDefaults
|
|||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
@@ -241,7 +242,7 @@ private fun LoadAndDisplayZapraiser(
|
|||||||
wantsToSeeReactions: MutableState<Boolean>,
|
wantsToSeeReactions: MutableState<Boolean>,
|
||||||
accountViewModel: AccountViewModel
|
accountViewModel: AccountViewModel
|
||||||
) {
|
) {
|
||||||
val zapraiserAmount by remember {
|
val zapraiserAmount by remember(baseNote) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
baseNote.event?.zapraiserAmount() ?: 0
|
baseNote.event?.zapraiserAmount() ?: 0
|
||||||
}
|
}
|
||||||
@@ -261,42 +262,26 @@ private fun LoadAndDisplayZapraiser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ZapraiserStatus(val progress: Float, val left: String)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, accountViewModel: AccountViewModel) {
|
fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, accountViewModel: AccountViewModel) {
|
||||||
val zapsState by baseNote.live().zaps.observeAsState()
|
val zapsState by baseNote.live().zaps.observeAsState()
|
||||||
|
|
||||||
var zapraiserProgress by remember { mutableStateOf(0F) }
|
var zapraiserStatus by remember { mutableStateOf(ZapraiserStatus(0F, "$zapraiserAmount")) }
|
||||||
var zapraiserLeft by remember { mutableStateOf("$zapraiserAmount") }
|
|
||||||
|
|
||||||
LaunchedEffect(key1 = zapsState) {
|
LaunchedEffect(key1 = zapsState) {
|
||||||
launch(Dispatchers.Default) {
|
|
||||||
zapsState?.note?.let {
|
zapsState?.note?.let {
|
||||||
val newZapAmount = accountViewModel.calculateZapAmount(it)
|
accountViewModel.calculateZapraiser(baseNote) { newStatus ->
|
||||||
var percentage = newZapAmount.div(zapraiserAmount.toBigDecimal()).toFloat()
|
if (zapraiserStatus != newStatus) {
|
||||||
|
zapraiserStatus = newStatus
|
||||||
if (percentage > 1) {
|
|
||||||
percentage = 1f
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.abs(zapraiserProgress - percentage) > 0.001) {
|
|
||||||
val newZapraiserProgress = percentage
|
|
||||||
val newZapraiserLeft = if (percentage > 0.99) {
|
|
||||||
"0"
|
|
||||||
} else {
|
|
||||||
showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal())
|
|
||||||
}
|
|
||||||
if (zapraiserLeft != newZapraiserLeft) {
|
|
||||||
zapraiserLeft = newZapraiserLeft
|
|
||||||
}
|
|
||||||
if (zapraiserProgress != newZapraiserProgress) {
|
|
||||||
zapraiserProgress = newZapraiserProgress
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val color = if (zapraiserProgress > 0.99) {
|
val color = if (zapraiserStatus.progress > 0.99) {
|
||||||
DarkerGreen
|
DarkerGreen
|
||||||
} else {
|
} else {
|
||||||
MaterialTheme.colors.mediumImportanceLink
|
MaterialTheme.colors.mediumImportanceLink
|
||||||
@@ -307,7 +292,7 @@ fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, acc
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(if (details) 24.dp else 4.dp),
|
.height(if (details) 24.dp else 4.dp),
|
||||||
color = color,
|
color = color,
|
||||||
progress = zapraiserProgress
|
progress = zapraiserStatus.progress
|
||||||
)
|
)
|
||||||
|
|
||||||
if (details) {
|
if (details) {
|
||||||
@@ -315,14 +300,14 @@ fun RenderZapRaiser(baseNote: Note, zapraiserAmount: Long, details: Boolean, acc
|
|||||||
contentAlignment = Center,
|
contentAlignment = Center,
|
||||||
modifier = TinyBorders
|
modifier = TinyBorders
|
||||||
) {
|
) {
|
||||||
val totalPercentage by remember(zapraiserProgress) {
|
val totalPercentage by remember(zapraiserStatus) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
"${(zapraiserProgress * 100).roundToInt()}%"
|
"${(zapraiserStatus.progress * 100).roundToInt()}%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.sats_to_complete, totalPercentage, zapraiserLeft),
|
text = stringResource(id = R.string.sats_to_complete, totalPercentage, zapraiserStatus.left),
|
||||||
modifier = NoSoTinyBorders,
|
modifier = NoSoTinyBorders,
|
||||||
color = MaterialTheme.colors.placeholderText,
|
color = MaterialTheme.colors.placeholderText,
|
||||||
fontSize = Font14SP,
|
fontSize = Font14SP,
|
||||||
@@ -836,10 +821,7 @@ private fun WatchReactionTypeForNote(baseNote: Note, accountViewModel: AccountVi
|
|||||||
val reactionsState by baseNote.live().reactions.observeAsState()
|
val reactionsState by baseNote.live().reactions.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(key1 = reactionsState) {
|
LaunchedEffect(key1 = reactionsState) {
|
||||||
launch(Dispatchers.Default) {
|
accountViewModel.loadReactionTo(reactionsState?.note, onNewReactionType)
|
||||||
val reactionNote = reactionsState?.note?.getReactionBy(accountViewModel.userProfile())
|
|
||||||
onNewReactionType(reactionNote)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,32 +856,9 @@ private fun RenderReactionType(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LikeText(baseNote: Note, grayTint: Color) {
|
fun LikeText(baseNote: Note, grayTint: Color) {
|
||||||
val reactionsCount = remember(baseNote) {
|
val reactionCount by baseNote.live().reactionCount.observeAsState(0)
|
||||||
mutableStateOf(baseNote.reactions.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
SlidingAnimationCount(reactionCount, grayTint)
|
||||||
|
|
||||||
WatchReactionCountForNote(baseNote) { newReactionsCount ->
|
|
||||||
if (reactionsCount.value != newReactionsCount) {
|
|
||||||
scope.launch(Dispatchers.Main) {
|
|
||||||
reactionsCount.value = newReactionsCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SlidingAnimationCount(reactionsCount, grayTint)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun WatchReactionCountForNote(baseNote: Note, onNewReactionCount: (Int) -> Unit) {
|
|
||||||
val reactionsState by baseNote.live().reactions.observeAsState()
|
|
||||||
|
|
||||||
LaunchedEffect(key1 = reactionsState) {
|
|
||||||
launch(Dispatchers.Default) {
|
|
||||||
onNewReactionCount(reactionsState?.note?.countReactions() ?: 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun likeClick(
|
private fun likeClick(
|
||||||
@@ -1139,9 +1098,7 @@ private fun WatchZapsForNote(baseNote: Note, accountViewModel: AccountViewModel,
|
|||||||
val zapsState by baseNote.live().zaps.observeAsState()
|
val zapsState by baseNote.live().zaps.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(key1 = zapsState) {
|
LaunchedEffect(key1 = zapsState) {
|
||||||
launch(Dispatchers.Default) {
|
accountViewModel.calculateIfNoteWasZappedByAccount(baseNote, onWasZapped)
|
||||||
onWasZapped(accountViewModel.calculateIfNoteWasZappedByAccount(baseNote))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,9 +1128,7 @@ fun WatchZapAmountsForNote(baseNote: Note, accountViewModel: AccountViewModel, o
|
|||||||
val zapsState by baseNote.live().zaps.observeAsState()
|
val zapsState by baseNote.live().zaps.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(key1 = zapsState) {
|
LaunchedEffect(key1 = zapsState) {
|
||||||
launch(Dispatchers.Default) {
|
accountViewModel.calculateZapAmount(baseNote, onZapAmount)
|
||||||
onZapAmount(showAmount(accountViewModel.calculateZapAmount(baseNote)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.vitorpamplona.amethyst.ui.note.MultiSetCompose
|
|||||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||||
import com.vitorpamplona.amethyst.ui.note.ZapUserSetCompose
|
import com.vitorpamplona.amethyst.ui.note.ZapUserSetCompose
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -102,13 +101,11 @@ private fun WatchScrollToTop(
|
|||||||
val scrollToTop by viewModel.scrollToTop.collectAsState()
|
val scrollToTop by viewModel.scrollToTop.collectAsState()
|
||||||
|
|
||||||
LaunchedEffect(scrollToTop) {
|
LaunchedEffect(scrollToTop) {
|
||||||
launch {
|
|
||||||
if (scrollToTop > 0 && viewModel.scrolltoTopPending) {
|
if (scrollToTop > 0 && viewModel.scrolltoTopPending) {
|
||||||
listState.scrollToItem(index = 0)
|
listState.scrollToItem(index = 0)
|
||||||
viewModel.sentToTop()
|
viewModel.sentToTop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel(), I
|
|||||||
|
|
||||||
fun checkKeysInvalidateDataAndSendToTop() {
|
fun checkKeysInvalidateDataAndSendToTop() {
|
||||||
if (lastFeedKey != localFilter.feedKey()) {
|
if (lastFeedKey != localFilter.feedKey()) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
bundler.invalidate(false) {
|
bundler.invalidate(false) {
|
||||||
// adds the time to perform the refresh into this delay
|
// adds the time to perform the refresh into this delay
|
||||||
// holding off new updates in case of heavy refresh routines.
|
// holding off new updates in case of heavy refresh routines.
|
||||||
@@ -309,6 +310,7 @@ abstract class FeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel(), I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun invalidateInsertData(newItems: Set<Note>) {
|
fun invalidateInsertData(newItems: Set<Note>) {
|
||||||
bundlerInsert.invalidateList(newItems) {
|
bundlerInsert.invalidateList(newItems) {
|
||||||
|
|||||||
+97
-4
@@ -16,14 +16,22 @@ import com.vitorpamplona.amethyst.model.Account
|
|||||||
import com.vitorpamplona.amethyst.model.AccountState
|
import com.vitorpamplona.amethyst.model.AccountState
|
||||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||||
import com.vitorpamplona.amethyst.model.ConnectivityType
|
import com.vitorpamplona.amethyst.model.ConnectivityType
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.model.UserState
|
import com.vitorpamplona.amethyst.model.UserState
|
||||||
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver
|
import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.UrlPreviewState
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
import com.vitorpamplona.quartz.events.Event
|
import com.vitorpamplona.quartz.events.Event
|
||||||
import com.vitorpamplona.quartz.events.GiftWrapEvent
|
import com.vitorpamplona.quartz.events.GiftWrapEvent
|
||||||
import com.vitorpamplona.quartz.events.LnZapEvent
|
import com.vitorpamplona.quartz.events.LnZapEvent
|
||||||
|
import com.vitorpamplona.quartz.events.LnZapRequestEvent
|
||||||
import com.vitorpamplona.quartz.events.PayInvoiceErrorResponse
|
import com.vitorpamplona.quartz.events.PayInvoiceErrorResponse
|
||||||
import com.vitorpamplona.quartz.events.ReportEvent
|
import com.vitorpamplona.quartz.events.ReportEvent
|
||||||
import com.vitorpamplona.quartz.events.SealedGossipEvent
|
import com.vitorpamplona.quartz.events.SealedGossipEvent
|
||||||
@@ -121,21 +129,86 @@ class AccountViewModel(val account: Account) : ViewModel() {
|
|||||||
account.delete(account.boostsTo(note))
|
account.delete(account.boostsTo(note))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateIfNoteWasZappedByAccount(zappedNote: Note): Boolean {
|
fun calculateIfNoteWasZappedByAccount(zappedNote: Note, onWasZapped: (Boolean) -> Unit) {
|
||||||
return account.calculateIfNoteWasZappedByAccount(zappedNote)
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
|
onWasZapped(account.calculateIfNoteWasZappedByAccount(zappedNote))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateZapAmount(zappedNote: Note): BigDecimal {
|
suspend fun calculateZapAmount(zappedNote: Note): BigDecimal {
|
||||||
return account.calculateZappedAmount(zappedNote)
|
return account.calculateZappedAmount(zappedNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun calculateZapAmount(zappedNote: Note, onZapAmount: (String) -> Unit) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
onZapAmount(showAmount(account.calculateZappedAmount(zappedNote)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateZapraiser(zappedNote: Note, onZapraiserStatus: (ZapraiserStatus) -> Unit) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val zapraiserAmount = zappedNote.event?.zapraiserAmount() ?: 0
|
||||||
|
val newZapAmount = calculateZapAmount(zappedNote)
|
||||||
|
var percentage = newZapAmount.div(zapraiserAmount.toBigDecimal()).toFloat()
|
||||||
|
|
||||||
|
if (percentage > 1) {
|
||||||
|
percentage = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
val newZapraiserProgress = percentage
|
||||||
|
val newZapraiserLeft = if (percentage > 0.99) {
|
||||||
|
"0"
|
||||||
|
} else {
|
||||||
|
showAmount((zapraiserAmount * (1 - percentage)).toBigDecimal())
|
||||||
|
}
|
||||||
|
onZapraiserStatus(ZapraiserStatus(newZapraiserProgress, newZapraiserLeft))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decryptAmountMessage(
|
||||||
|
zapRequest: Note,
|
||||||
|
zapEvent: Note?,
|
||||||
|
onNewState: (ZapAmountCommentNotification?) -> Unit
|
||||||
|
) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
onNewState(innerDecryptAmountMessage(zapRequest, zapEvent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun innerDecryptAmountMessage(
|
||||||
|
zapRequest: Note,
|
||||||
|
zapEvent: Note?
|
||||||
|
): ZapAmountCommentNotification? {
|
||||||
|
(zapRequest.event as? LnZapRequestEvent)?.let {
|
||||||
|
val decryptedContent = decryptZap(zapRequest)
|
||||||
|
val amount = (zapEvent?.event as? LnZapEvent)?.amount
|
||||||
|
if (decryptedContent != null) {
|
||||||
|
val newAuthor = LocalCache.getOrCreateUser(decryptedContent.pubKey)
|
||||||
|
return ZapAmountCommentNotification(
|
||||||
|
newAuthor,
|
||||||
|
decryptedContent.content.ifBlank { null },
|
||||||
|
showAmountAxis(amount)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (!zapRequest.event?.content().isNullOrBlank() || amount != null) {
|
||||||
|
return ZapAmountCommentNotification(
|
||||||
|
zapRequest.author,
|
||||||
|
zapRequest.event?.content()?.ifBlank { null },
|
||||||
|
showAmountAxis(amount)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun zap(note: Note, amount: Long, pollOption: Int?, message: String, context: Context, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit, zapType: LnZapEvent.ZapType) {
|
fun zap(note: Note, amount: Long, pollOption: Int?, message: String, context: Context, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit, zapType: LnZapEvent.ZapType) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
innerZap(note, amount, pollOption, message, context, onError, onProgress, zapType)
|
innerZap(note, amount, pollOption, message, context, onError, onProgress, zapType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun innerZap(note: Note, amount: Long, pollOption: Int?, message: String, context: Context, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit, zapType: LnZapEvent.ZapType) {
|
private suspend fun innerZap(note: Note, amount: Long, pollOption: Int?, message: String, context: Context, onError: (String) -> Unit, onProgress: (percent: Float) -> Unit, zapType: LnZapEvent.ZapType) {
|
||||||
val lud16 = note.event?.zapAddress() ?: note.author?.info?.lud16?.trim() ?: note.author?.info?.lud06?.trim()
|
val lud16 = note.event?.zapAddress() ?: note.author?.info?.lud16?.trim() ?: note.author?.info?.lud06?.trim()
|
||||||
|
|
||||||
if (lud16.isNullOrBlank()) {
|
if (lud16.isNullOrBlank()) {
|
||||||
@@ -388,6 +461,26 @@ class AccountViewModel(val account: Account) : ViewModel() {
|
|||||||
|
|
||||||
fun updateStatus(it: AddressableNote, newStatus: String) {
|
fun updateStatus(it: AddressableNote, newStatus: String) {
|
||||||
account.updateStatus(it, newStatus)
|
account.updateStatus(it, newStatus)
|
||||||
|
|
||||||
|
fun checkIfOnline(url: String, onResult: (Boolean) -> Unit) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val isOnline = OnlineChecker.isOnline(url)
|
||||||
|
onResult(isOnline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun urlPreview(url: String, onResult: suspend (UrlPreviewState) -> Unit) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
UrlCachedPreviewer.previewInfo(url, onResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadReactionTo(note: Note?, onNewReactionType: (String?) -> Unit) {
|
||||||
|
if (note == null) return
|
||||||
|
|
||||||
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
|
onNewReactionType(note.getReactionBy(userProfile()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Factory(val account: Account) : ViewModelProvider.Factory {
|
class Factory(val account: Account) : ViewModelProvider.Factory {
|
||||||
|
|||||||
@@ -623,7 +623,7 @@ fun ShowVideoStreaming(
|
|||||||
}
|
}
|
||||||
|
|
||||||
url?.let {
|
url?.let {
|
||||||
CheckIfUrlIsOnline(url) {
|
CheckIfUrlIsOnline(url, accountViewModel) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = remember { Modifier.heightIn(max = 300.dp) }
|
modifier = remember { Modifier.heightIn(max = 300.dp) }
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleEventObserver
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
import com.vitorpamplona.amethyst.service.OnlineChecker
|
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.FeedViewModel
|
||||||
@@ -42,7 +41,6 @@ import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@@ -136,12 +134,14 @@ private fun HomePages(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CheckIfUrlIsOnline(url: String, whenOnline: @Composable () -> Unit) {
|
fun CheckIfUrlIsOnline(url: String, accountViewModel: AccountViewModel, whenOnline: @Composable () -> Unit) {
|
||||||
var online by remember { mutableStateOf(false) }
|
var online by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(key1 = url) {
|
LaunchedEffect(key1 = url) {
|
||||||
launch(Dispatchers.IO) {
|
accountViewModel.checkIfOnline(url) { isOnline ->
|
||||||
online = OnlineChecker.isOnline(url)
|
if (online != isOnline) {
|
||||||
|
online = isOnline
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,12 +162,10 @@ fun WatchAccountForHomeScreen(
|
|||||||
val followState by accountViewModel.account.userProfile().live().follows.observeAsState()
|
val followState by accountViewModel.account.userProfile().live().follows.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(accountViewModel, accountState?.account?.defaultHomeFollowList, followState) {
|
LaunchedEffect(accountViewModel, accountState?.account?.defaultHomeFollowList, followState) {
|
||||||
launch(Dispatchers.IO) {
|
|
||||||
NostrHomeDataSource.invalidateFilters()
|
NostrHomeDataSource.invalidateFilters()
|
||||||
homeFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
homeFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
||||||
repliesFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
repliesFeedViewModel.checkKeysInvalidateDataAndSendToTop()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|||||||
+1
-5
@@ -73,11 +73,8 @@ fun LoadRedirectScreen(eventId: String?, accountViewModel: AccountViewModel, nav
|
|||||||
fun LoadRedirectScreen(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
fun LoadRedirectScreen(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
val noteState by baseNote.live().metadata.observeAsState()
|
val noteState by baseNote.live().metadata.observeAsState()
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
LaunchedEffect(key1 = noteState) {
|
LaunchedEffect(key1 = noteState) {
|
||||||
scope.launch {
|
val note = noteState?.note ?: return@LaunchedEffect
|
||||||
val note = noteState?.note ?: return@launch
|
|
||||||
var event = note.event
|
var event = note.event
|
||||||
val channelHex = note.channelHex()
|
val channelHex = note.channelHex()
|
||||||
|
|
||||||
@@ -110,7 +107,6 @@ fun LoadRedirectScreen(baseNote: Note, accountViewModel: AccountViewModel, nav:
|
|||||||
nav("Note/${note.idHex}")
|
nav("Note/${note.idHex}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
|
|||||||
@@ -50,5 +50,18 @@ class StatusEvent(
|
|||||||
val sig = CryptoUtils.sign(id, privateKey)
|
val sig = CryptoUtils.sign(id, privateKey)
|
||||||
return StatusEvent(id.toHexKey(), pubKey, createdAt, tags, newStatus, sig.toHexKey())
|
return StatusEvent(id.toHexKey(), pubKey, createdAt, tags, newStatus, sig.toHexKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear(
|
||||||
|
event: StatusEvent,
|
||||||
|
privateKey: ByteArray,
|
||||||
|
createdAt: Long = TimeUtils.now()
|
||||||
|
): StatusEvent {
|
||||||
|
val msg = ""
|
||||||
|
val tags = event.tags.filter { it.size > 1 && it[0] == "d" }
|
||||||
|
val pubKey = event.pubKey()
|
||||||
|
val id = generateId(pubKey, createdAt, kind, tags, msg)
|
||||||
|
val sig = CryptoUtils.sign(id, privateKey)
|
||||||
|
return StatusEvent(id.toHexKey(), pubKey, createdAt, tags, msg, sig.toHexKey())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user