zaps in background

This commit is contained in:
greenart7c3
2023-09-15 13:53:05 -03:00
parent 87dbf86129
commit 6876a7f0d2
7 changed files with 100 additions and 364 deletions

View File

@@ -454,7 +454,7 @@ class Account(
)
}
LnZapEvent.ZapType.PUBLIC -> {
return LnZapRequestEvent.createPublic(
val unsignedEvent = LnZapRequestEvent.createPublic(
event,
userProfile().latestContactList?.relays()?.keys?.ifEmpty { null }
?: localRelays.map { it.url }.toSet(),
@@ -462,10 +462,18 @@ class Account(
pollOption,
message
)
AmberUtils.openAmber(unsignedEvent)
val content = AmberUtils.content[unsignedEvent.id] ?: ""
if (content.isBlank()) return null
return LnZapRequestEvent.create(
unsignedEvent,
content
)
}
LnZapEvent.ZapType.PRIVATE -> {
return LnZapRequestEvent.createPrivateZap(
val unsignedEvent = LnZapRequestEvent.createPrivateZap(
event,
userProfile().latestContactList?.relays()?.keys?.ifEmpty { null }
?: localRelays.map { it.url }.toSet(),
@@ -473,6 +481,11 @@ class Account(
pollOption,
message
)
AmberUtils.openAmber(unsignedEvent)
val content = AmberUtils.content[unsignedEvent.id] ?: ""
if (content.isBlank()) return null
return Event.fromJson(content) as LnZapRequestEvent
}
else -> null
}

View File

@@ -466,7 +466,6 @@ object LocalCache {
}
fun consume(event: PrivateDmEvent, relay: Relay?): Note {
Log.e("isRunning", event.toJson())
val note = getOrCreateNote(event.id)
val author = getOrCreateUser(event.pubKey)

View File

@@ -1,9 +1,6 @@
package com.vitorpamplona.amethyst.ui.note
import android.app.Activity
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -25,12 +22,8 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.AmberUtils
import com.vitorpamplona.amethyst.ui.actions.SignerType
import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
@@ -39,10 +32,8 @@ import com.vitorpamplona.amethyst.ui.theme.Font14SP
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.ImmutableListOfLists
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapRequestEvent
import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -300,60 +291,6 @@ fun ZapVote(
nonClickablePrepend()
val event = remember { mutableStateOf<LnZapRequestEvent?>(null) }
val activityResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = {
if (it.resultCode != Activity.RESULT_OK) {
scope.launch(Dispatchers.Main) {
Toast.makeText(
Amethyst.instance,
"Sign request rejected",
Toast.LENGTH_SHORT
).show()
}
} else {
val json = it.data?.getStringExtra("event") ?: ""
val signedEvent = Event.fromJson(json) as LnZapRequestEvent
if (signedEvent.hasValidSignature()) {
accountViewModel.zap(
baseNote,
accountViewModel.account.zapAmountChoices.first() * 1000,
null,
"",
context,
{
scope.launch {
zappingProgress = 0f
showErrorMessageDialog = it
}
},
{ progress: Float ->
zappingProgress = progress
},
accountViewModel.account.defaultZapType,
null
)
}
}
AmberUtils.isActivityRunning = false
ServiceManager.shouldPauseService = true
event.value = null
}
)
LaunchedEffect(event.value) {
if (event.value != null) {
AmberUtils.openAmber(
event.value!!.toJson(),
SignerType.SIGN_EVENT,
activityResult,
"",
event.value!!.id()
)
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.combinedClickable(
@@ -361,7 +298,7 @@ fun ZapVote(
// interactionSource = remember { MutableInteractionSource() },
// indication = rememberRipple(bounded = false, radius = 24.dp),
onClick = {
if (!accountViewModel.isWriteable()) {
if (!accountViewModel.isWriteable() && !accountViewModel.loggedInWithAmber()) {
scope.launch {
Toast
.makeText(
@@ -425,8 +362,7 @@ fun ZapVote(
zappingProgress = it
}
},
zapType = accountViewModel.account.defaultZapType,
null
zapType = accountViewModel.account.defaultZapType
)
} else {
wantsToZap = true
@@ -566,8 +502,7 @@ fun FilteredZapAmountChoicePopup(
context,
onError,
onProgress,
defaultZapType,
null
defaultZapType
)
onDismiss()
},
@@ -591,8 +526,7 @@ fun FilteredZapAmountChoicePopup(
context,
onError,
onProgress,
defaultZapType,
null
defaultZapType
)
onDismiss()
},

View File

@@ -1,11 +1,8 @@
package com.vitorpamplona.amethyst.ui.note
import android.app.Activity
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
@@ -49,7 +46,6 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -80,13 +76,9 @@ import androidx.lifecycle.map
import coil.compose.AsyncImage
import coil.request.CachePolicy
import coil.request.ImageRequest
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.AmberUtils
import com.vitorpamplona.amethyst.ui.actions.NewPostView
import com.vitorpamplona.amethyst.ui.actions.SignerType
import com.vitorpamplona.amethyst.ui.components.ImageUrlType
import com.vitorpamplona.amethyst.ui.components.InLineIconRenderer
import com.vitorpamplona.amethyst.ui.components.TextType
@@ -115,9 +107,6 @@ import com.vitorpamplona.amethyst.ui.theme.TinyBorders
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.placeholderTextColorFilter
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapRequestEvent
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.CoroutineScope
@@ -962,63 +951,6 @@ fun ZapReaction(
var zappingProgress by remember { mutableStateOf(0f) }
val event = remember { mutableStateOf<LnZapRequestEvent?>(null) }
val activityResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = {
if (it.resultCode != Activity.RESULT_OK) {
wantsToZap = false
zappingProgress = 0f
scope.launch(Dispatchers.Main) {
Toast.makeText(
Amethyst.instance,
"Sign request rejected",
Toast.LENGTH_SHORT
).show()
}
} else {
val json = it.data?.getStringExtra("event") ?: ""
val signedEvent = Event.fromJson(json) as LnZapRequestEvent
if (signedEvent.hasValidSignature()) {
accountViewModel.zap(
baseNote,
accountViewModel.account.zapAmountChoices.first() * 1000,
null,
"",
context,
{
scope.launch {
zappingProgress = 0f
showErrorMessageDialog = it
}
},
{ progress: Float ->
zappingProgress = progress
},
accountViewModel.account.defaultZapType,
signedEvent
)
}
}
AmberUtils.isActivityRunning = false
ServiceManager.shouldPauseService = true
event.value = null
wantsToZap = false
}
)
LaunchedEffect(event.value) {
if (event.value != null) {
AmberUtils.openAmber(
event.value!!.toJson(),
SignerType.SIGN_EVENT,
activityResult,
"",
event.value!!.id()
)
}
}
Row(
verticalAlignment = CenterVertically,
modifier = Modifier
@@ -1044,8 +976,7 @@ fun ZapReaction(
zappingProgress = 0f
showErrorMessageDialog = it
}
},
event
}
)
},
onLongClick = {
@@ -1152,8 +1083,7 @@ private fun zapClick(
context: Context,
onZappingProgress: (Float) -> Unit,
onMultipleChoices: () -> Unit,
onError: (String) -> Unit,
event: MutableState<LnZapRequestEvent?>
onError: (String) -> Unit
) {
if (accountViewModel.account.zapAmountChoices.isEmpty()) {
scope.launch {
@@ -1165,46 +1095,15 @@ private fun zapClick(
)
.show()
}
} else if (!accountViewModel.isWriteable()) {
if (accountViewModel.loggedInWithAmber()) {
if (accountViewModel.account.zapAmountChoices.size == 1) {
if (accountViewModel.account.defaultZapType != LnZapEvent.ZapType.ANONYMOUS && accountViewModel.account.defaultZapType != LnZapEvent.ZapType.NONZAP) {
event.value = accountViewModel.account.createZapRequestFor(
baseNote,
null,
"",
accountViewModel.account.defaultZapType
)
} else {
accountViewModel.zap(
baseNote,
accountViewModel.account.zapAmountChoices.first() * 1000,
null,
"",
context,
onError = onError,
onProgress = {
scope.launch(Dispatchers.Main) {
onZappingProgress(it)
}
},
zapType = accountViewModel.account.defaultZapType,
null
)
}
} else if (accountViewModel.account.zapAmountChoices.size > 1) {
onMultipleChoices()
}
} else {
scope.launch {
Toast
.makeText(
context,
context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps),
Toast.LENGTH_SHORT
)
.show()
}
} else if (!accountViewModel.isWriteable() && !accountViewModel.loggedInWithAmber()) {
scope.launch {
Toast
.makeText(
context,
context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps),
Toast.LENGTH_SHORT
)
.show()
}
} else if (accountViewModel.account.zapAmountChoices.size == 1) {
accountViewModel.zap(
@@ -1219,8 +1118,7 @@ private fun zapClick(
onZappingProgress(it)
}
},
zapType = accountViewModel.account.defaultZapType,
null
zapType = accountViewModel.account.defaultZapType
)
} else if (accountViewModel.account.zapAmountChoices.size > 1) {
onMultipleChoices()
@@ -1543,55 +1441,6 @@ fun ZapAmountChoicePopup(
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account ?: return
val zapMessage = ""
var event by remember { mutableStateOf<LnZapRequestEvent?>(null) }
var amount by remember { mutableLongStateOf(0L) }
val activityResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = {
if (it.resultCode != Activity.RESULT_OK) {
scope.launch(Dispatchers.Main) {
Toast.makeText(
Amethyst.instance,
"Sign request rejected",
Toast.LENGTH_SHORT
).show()
}
} else {
val json = it.data?.getStringExtra("event") ?: ""
val signedEvent = Event.fromJson(json) as LnZapRequestEvent
if (signedEvent.hasValidSignature()) {
accountViewModel.zap(
baseNote,
amount,
null,
zapMessage,
context,
onError,
onProgress,
account.defaultZapType,
signedEvent
)
amount = 0
}
}
AmberUtils.isActivityRunning = false
ServiceManager.shouldPauseService = true
event = null
onDismiss()
}
)
LaunchedEffect(event) {
if (event != null) {
AmberUtils.openAmber(
event!!.toJson(),
SignerType.SIGN_EVENT,
activityResult,
"",
event!!.id()
)
}
}
Popup(
alignment = Alignment.BottomCenter,
@@ -1603,23 +1452,17 @@ fun ZapAmountChoicePopup(
Button(
modifier = Modifier.padding(horizontal = 3.dp),
onClick = {
if (accountViewModel.loggedInWithAmber() && account.defaultZapType != LnZapEvent.ZapType.NONZAP && account.defaultZapType != LnZapEvent.ZapType.ANONYMOUS) {
amount = amountInSats * 1000
event = account.createZapRequestFor(baseNote, null, zapMessage, account.defaultZapType)
} else {
accountViewModel.zap(
baseNote,
amountInSats * 1000,
null,
zapMessage,
context,
onError,
onProgress,
account.defaultZapType,
null
)
onDismiss()
}
accountViewModel.zap(
baseNote,
amountInSats * 1000,
null,
zapMessage,
context,
onError,
onProgress,
account.defaultZapType
)
onDismiss()
},
shape = ButtonBorder,
colors = ButtonDefaults
@@ -1633,23 +1476,17 @@ fun ZapAmountChoicePopup(
textAlign = TextAlign.Center,
modifier = Modifier.combinedClickable(
onClick = {
if (accountViewModel.loggedInWithAmber() && account.defaultZapType != LnZapEvent.ZapType.NONZAP && account.defaultZapType != LnZapEvent.ZapType.ANONYMOUS) {
amount = amountInSats * 1000
event = account.createZapRequestFor(baseNote, null, zapMessage, account.defaultZapType)
} else {
accountViewModel.zap(
baseNote,
amountInSats * 1000,
null,
zapMessage,
context,
onError,
onProgress,
account.defaultZapType,
null
)
onDismiss()
}
accountViewModel.zap(
baseNote,
amountInSats * 1000,
null,
zapMessage,
context,
onError,
onProgress,
account.defaultZapType
)
onDismiss()
},
onLongClick = {
onChangeAmount()

View File

@@ -1,15 +1,31 @@
package com.vitorpamplona.amethyst.ui.note
import android.app.Activity
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Done
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -23,26 +39,17 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.AmberUtils
import com.vitorpamplona.amethyst.ui.actions.CloseButton
import com.vitorpamplona.amethyst.ui.actions.SignerType
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.LnZapEvent
import com.vitorpamplona.quartz.events.LnZapRequestEvent
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class ZapOptionstViewModel : ViewModel() {
private var account: Account? = null
@@ -96,55 +103,6 @@ fun ZapCustomDialog(
val zapOptionExplainers = remember { zapTypes.map { it.third }.toImmutableList() }
var selectedZapType by remember(accountViewModel) { mutableStateOf(accountViewModel.account.defaultZapType) }
val event = remember { mutableStateOf<LnZapRequestEvent?>(null) }
val activityResult = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
onResult = {
if (it.resultCode != Activity.RESULT_OK) {
postViewModel.viewModelScope.launch(Dispatchers.Main) {
Toast.makeText(
Amethyst.instance,
"Sign request rejected",
Toast.LENGTH_SHORT
).show()
}
event.value = null
} else {
val json = it.data?.getStringExtra("event") ?: ""
val signedEvent = Event.fromJson(json) as LnZapRequestEvent
if (signedEvent.hasValidSignature()) {
accountViewModel.zap(
baseNote,
postViewModel.value()!! * 1000L,
null,
postViewModel.customMessage.text,
context,
onError,
onProgress,
selectedZapType,
signedEvent
)
event.value = null
onClose()
}
}
AmberUtils.isActivityRunning = false
ServiceManager.shouldPauseService = true
}
)
LaunchedEffect(event.value) {
if (event.value != null) {
AmberUtils.openAmber(
event.value!!.toJson(),
SignerType.SIGN_EVENT,
activityResult,
"",
event.value!!.id()
)
}
}
Dialog(
onDismissRequest = { onClose() },
properties = DialogProperties(
@@ -167,22 +125,16 @@ fun ZapCustomDialog(
ZapButton(
isActive = postViewModel.canSend()
) {
if (accountViewModel.loggedInWithAmber() && selectedZapType != LnZapEvent.ZapType.ANONYMOUS && selectedZapType != LnZapEvent.ZapType.PUBLIC) {
event.value = accountViewModel.account.createZapRequestFor(baseNote, null, postViewModel.customMessage.text, selectedZapType)
} else {
accountViewModel.zap(
baseNote,
postViewModel.value()!! * 1000L,
null,
postViewModel.customMessage.text,
context,
onError = onError,
onProgress = onProgress,
zapType = selectedZapType,
null
)
onClose()
}
accountViewModel.zap(
baseNote,
postViewModel.value()!! * 1000L,
null,
postViewModel.customMessage.text,
context,
onError = onError,
onProgress = onProgress,
zapType = selectedZapType
)
}
}

View File

@@ -225,11 +225,10 @@ class AccountViewModel(val account: Account) : ViewModel() {
context: Context,
onError: (String) -> Unit,
onProgress: (percent: Float) -> Unit,
zapType: LnZapEvent.ZapType,
zapRequest: LnZapRequestEvent?
zapType: LnZapEvent.ZapType
) {
viewModelScope.launch(Dispatchers.IO) {
innerZap(note, amount, pollOption, message, context, onError, onProgress, zapType, zapRequest)
innerZap(note, amount, pollOption, message, context, onError, onProgress, zapType)
}
}
@@ -241,8 +240,7 @@ class AccountViewModel(val account: Account) : ViewModel() {
context: Context,
onError: (String) -> Unit,
onProgress: (percent: Float) -> Unit,
zapType: LnZapEvent.ZapType,
zapRequest: LnZapRequestEvent?
zapType: LnZapEvent.ZapType
) {
val lud16 = note.event?.zapAddress() ?: note.author?.info?.lud16?.trim() ?: note.author?.info?.lud06?.trim()
@@ -253,13 +251,9 @@ class AccountViewModel(val account: Account) : ViewModel() {
var zapRequestJson = ""
if (zapType != LnZapEvent.ZapType.NONZAP) {
if (zapRequest != null) {
zapRequestJson = zapRequest.toJson()
} else {
val localZapRequest = account.createZapRequestFor(note, pollOption, message, zapType)
if (localZapRequest != null) {
zapRequestJson = localZapRequest.toJson()
}
val localZapRequest = account.createZapRequestFor(note, pollOption, message, zapType)
if (localZapRequest != null) {
zapRequestJson = localZapRequest.toJson()
}
}

View File

@@ -99,6 +99,13 @@ class LnZapRequestEvent(
return LnZapRequestEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
}
fun create(
unsignedEvent: LnZapRequestEvent,
signature: String
): LnZapRequestEvent {
return LnZapRequestEvent(unsignedEvent.id, unsignedEvent.pubKey, unsignedEvent.createdAt, unsignedEvent.tags, unsignedEvent.content, signature)
}
fun createPublic(
originalNote: EventInterface,
relays: Set<String>,
@@ -146,7 +153,7 @@ class LnZapRequestEvent(
tags = tags + listOf(listOf("anon", ""))
return LnZapRequestEvent("", pubKey, createdAt, tags, content, "")
return LnZapRequestEvent("zap", pubKey, createdAt, tags, content, "")
}
fun createAnonymous(