Delete Relay Selection dialog from all new post screens.
This commit is contained in:
@@ -92,6 +92,7 @@ import com.vitorpamplona.quartz.experimental.profileGallery.dimension
|
||||
import com.vitorpamplona.quartz.experimental.profileGallery.fromEvent
|
||||
import com.vitorpamplona.quartz.experimental.profileGallery.hash
|
||||
import com.vitorpamplona.quartz.experimental.profileGallery.mimeType
|
||||
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
|
||||
@@ -1085,14 +1086,15 @@ class Account(
|
||||
fun consumeAndSendNip95(
|
||||
data: FileStorageEvent,
|
||||
signedEvent: FileStorageHeaderEvent,
|
||||
relayList: List<NormalizedRelayUrl>,
|
||||
): Note? {
|
||||
if (!isWriteable()) return null
|
||||
|
||||
client.send(data, relayList = relayList.toSet())
|
||||
val relayList = computeRelayListToBroadcast(signedEvent)
|
||||
|
||||
client.send(data, relayList = relayList)
|
||||
cache.justConsumeMyOwnEvent(data)
|
||||
|
||||
client.send(signedEvent, relayList = relayList.toSet())
|
||||
client.send(signedEvent, relayList = relayList)
|
||||
cache.justConsumeMyOwnEvent(signedEvent)
|
||||
|
||||
return cache.getNoteIfExists(signedEvent.id)
|
||||
@@ -1161,7 +1163,6 @@ class Account(
|
||||
urlHeaderInfo: Map<String, FileHeader>,
|
||||
caption: String?,
|
||||
contentWarningReason: String?,
|
||||
relayList: Set<NormalizedRelayUrl>,
|
||||
onReady: (Note) -> Unit,
|
||||
) {
|
||||
val iMetas =
|
||||
@@ -1180,7 +1181,7 @@ class Account(
|
||||
)
|
||||
}
|
||||
|
||||
signer.sign(
|
||||
val template =
|
||||
PictureEvent.build(iMetas, caption ?: "") {
|
||||
caption?.let {
|
||||
hashtags(findHashtags(it))
|
||||
@@ -1192,9 +1193,10 @@ class Account(
|
||||
// add geohashes
|
||||
// add title
|
||||
contentWarningReason?.let { contentWarning(contentWarningReason) }
|
||||
},
|
||||
) {
|
||||
sendHeader(it, relayList = relayList, onReady)
|
||||
}
|
||||
|
||||
signAndComputeBroadcast(template) { event ->
|
||||
cache.getNoteIfExists(event.id)?.let { onReady(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,7 +1207,6 @@ class Account(
|
||||
alt: String?,
|
||||
contentWarningReason: String?,
|
||||
originalHash: String? = null,
|
||||
relayList: Set<NormalizedRelayUrl>,
|
||||
onReady: (Note) -> Unit,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
@@ -1273,8 +1274,8 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
signer.sign(template) {
|
||||
sendHeader(it, relayList = relayList, onReady)
|
||||
signAndComputeBroadcast(template) { event ->
|
||||
cache.getNoteIfExists(event.id)?.let { onReady(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1305,6 +1306,30 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Event> signAndComputeBroadcast(
|
||||
template: EventTemplate<T>,
|
||||
broadcast: List<Event> = emptyList(),
|
||||
onDone: (T) -> Unit = {},
|
||||
) {
|
||||
signer.sign(template) { event ->
|
||||
cache.justConsumeMyOwnEvent(event)
|
||||
val note =
|
||||
if (event is AddressableEvent) {
|
||||
cache.getOrCreateAddressableNote(event.address())
|
||||
} else {
|
||||
cache.getOrCreateNote(event.id)
|
||||
}
|
||||
|
||||
val relayList = computeRelayListToBroadcast(note)
|
||||
|
||||
client.send(event, relayList)
|
||||
|
||||
broadcast.forEach { client.send(it, relayList) }
|
||||
|
||||
onDone(event)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Event> signAndSend(
|
||||
template: EventTemplate<T>,
|
||||
relayList: Set<NormalizedRelayUrl>,
|
||||
@@ -1581,7 +1606,7 @@ class Account(
|
||||
originalNote: Note,
|
||||
notify: HexKey?,
|
||||
summary: String? = null,
|
||||
relayList: List<NormalizedRelayUrl>,
|
||||
broadcast: List<Event>,
|
||||
) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
@@ -1593,9 +1618,14 @@ class Account(
|
||||
notify = notify,
|
||||
summary = summary,
|
||||
signer = signer,
|
||||
) {
|
||||
cache.justConsumeMyOwnEvent(it)
|
||||
client.send(it, relayList = relayList.toSet())
|
||||
) { event ->
|
||||
cache.justConsumeMyOwnEvent(event)
|
||||
val note = cache.getOrCreateNote(event.id)
|
||||
val relayList = computeRelayListToBroadcast(note)
|
||||
|
||||
client.send(event, relayList = relayList)
|
||||
|
||||
broadcast.forEach { client.send(it, relayList) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1715,7 +1745,7 @@ class Account(
|
||||
)?.relays()?.ifEmpty { null }?.toSet()
|
||||
|
||||
if (relayList != null) {
|
||||
client.send(signedEvent = wrap, relayList = relayList)
|
||||
client.send(event = wrap, relayList = relayList)
|
||||
} else {
|
||||
val taggedUserInboxRelays =
|
||||
wrap.taggedUserIds().flatMapTo(mutableSetOf()) { pubkey ->
|
||||
|
||||
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.actions
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -96,7 +95,6 @@ import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.messagefield.MessageField
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
@@ -108,7 +106,6 @@ import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.amethyst.ui.theme.replyModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -128,12 +125,6 @@ fun EditPostView(
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
val scope = rememberCoroutineScope()
|
||||
var showRelaysDialog by remember { mutableStateOf(false) }
|
||||
var relayList =
|
||||
remember {
|
||||
accountViewModel.account.outboxRelays.flow.value
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
postViewModel.load(edit, versionLookingAt, accountViewModel)
|
||||
@@ -148,16 +139,6 @@ fun EditPostView(
|
||||
decorFitsSystemWindows = false,
|
||||
),
|
||||
) {
|
||||
if (showRelaysDialog) {
|
||||
RelaySelectionDialog(
|
||||
preSelectedList = relayList,
|
||||
onClose = { showRelaysDialog = false },
|
||||
onPost = { relayList = it },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -169,22 +150,9 @@ fun EditPostView(
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
Box {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
onClick = { showRelaysDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.relays, 2),
|
||||
contentDescription = stringRes(id = R.string.relay_list_selector),
|
||||
modifier = Modifier.height(25.dp),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
PostButton(
|
||||
onPost = {
|
||||
postViewModel.sendPost(relayList = relayList)
|
||||
postViewModel.sendPost()
|
||||
scope.launch {
|
||||
delay(100)
|
||||
onClose()
|
||||
|
||||
@@ -47,7 +47,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.UserSuggestionAnchor
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent
|
||||
import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip92IMeta.IMetaTag
|
||||
import com.vitorpamplona.quartz.nip92IMeta.IMetaTagBuilder
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.alt
|
||||
@@ -120,18 +120,21 @@ open class EditPostViewModel : ViewModel() {
|
||||
editedFromNote = edit
|
||||
}
|
||||
|
||||
fun sendPost(relayList: List<NormalizedRelayUrl>) {
|
||||
viewModelScope.launch(Dispatchers.IO) { innerSendPost(relayList) }
|
||||
fun sendPost() {
|
||||
viewModelScope.launch(Dispatchers.IO) { innerSendPost() }
|
||||
}
|
||||
|
||||
suspend fun innerSendPost(relayList: List<NormalizedRelayUrl>) {
|
||||
suspend fun innerSendPost() {
|
||||
if (accountViewModel == null) {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
|
||||
val extraNotesToBroadcast = mutableListOf<Event>()
|
||||
|
||||
nip95attachments.forEach {
|
||||
account?.sendNip95(it.first, it.second, relayList.toSet())
|
||||
extraNotesToBroadcast.add(it.first)
|
||||
extraNotesToBroadcast.add(it.second)
|
||||
}
|
||||
|
||||
val notify =
|
||||
@@ -147,7 +150,7 @@ open class EditPostViewModel : ViewModel() {
|
||||
originalNote = editedFromNote!!,
|
||||
notify = notify,
|
||||
summary = subject.text.ifBlank { null },
|
||||
relayList = relayList,
|
||||
extraNotesToBroadcast,
|
||||
)
|
||||
|
||||
cancel()
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.joinAll
|
||||
@@ -82,13 +81,11 @@ open class NewMediaModel : ViewModel() {
|
||||
|
||||
fun upload(
|
||||
context: Context,
|
||||
relayList: List<NormalizedRelayUrl>,
|
||||
onSucess: () -> Unit,
|
||||
onError: (String, String) -> Unit,
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val myAccount = account ?: return@launch
|
||||
if (relayList.isEmpty()) return@launch
|
||||
val serverToUse = selectedServer ?: return@launch
|
||||
|
||||
val myMultiOrchestrator = multiOrchestrator ?: return@launch
|
||||
@@ -141,7 +138,7 @@ open class NewMediaModel : ViewModel() {
|
||||
withTimeoutOrNull(30000) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
account?.createNip95(it.bytes, headerInfo = it.fileHeader, caption, if (sensitiveContent) "" else null) { nip95 ->
|
||||
account?.consumeAndSendNip95(nip95.first, nip95.second, relayList)
|
||||
account?.consumeAndSendNip95(nip95.first, nip95.second)
|
||||
continuation.resume(true)
|
||||
}
|
||||
}
|
||||
@@ -156,13 +153,12 @@ open class NewMediaModel : ViewModel() {
|
||||
withTimeoutOrNull(30000) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
account?.sendHeader(
|
||||
it.url,
|
||||
it.magnet,
|
||||
it.fileHeader,
|
||||
caption,
|
||||
if (sensitiveContent) "" else null,
|
||||
it.uploadedHash,
|
||||
relayList.toSet(),
|
||||
url = it.url,
|
||||
magnetUri = it.magnet,
|
||||
headerInfo = it.fileHeader,
|
||||
alt = caption,
|
||||
contentWarningReason = if (sensitiveContent) "" else null,
|
||||
originalHash = it.uploadedHash,
|
||||
) {
|
||||
continuation.resume(true)
|
||||
}
|
||||
@@ -178,10 +174,9 @@ open class NewMediaModel : ViewModel() {
|
||||
withTimeoutOrNull(30000) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
account?.sendAllAsOnePictureEvent(
|
||||
imageUrls,
|
||||
caption,
|
||||
if (sensitiveContent) "" else null,
|
||||
relayList.toSet(),
|
||||
urlHeaderInfo = imageUrls,
|
||||
caption = caption,
|
||||
contentWarningReason = if (sensitiveContent) "" else null,
|
||||
) {
|
||||
continuation.resume(true)
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
@@ -49,7 +47,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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
|
||||
@@ -70,7 +67,6 @@ import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.buttons.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.note.buttons.PostButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.SettingSwitchItem
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer
|
||||
@@ -100,13 +96,6 @@ fun NewMediaView(
|
||||
postViewModel.load(account, uris)
|
||||
}
|
||||
|
||||
var showRelaysDialog by remember { mutableStateOf(false) }
|
||||
var relayList =
|
||||
remember {
|
||||
accountViewModel.account.outboxRelays.flow.value
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = { onClose() },
|
||||
properties =
|
||||
@@ -128,23 +117,9 @@ fun NewMediaView(
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
Box {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
onClick = { showRelaysDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.relays, 3),
|
||||
contentDescription = stringRes(id = R.string.relay_list_selector),
|
||||
modifier = Modifier.height(25.dp),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
PostButton(
|
||||
onPost = {
|
||||
postViewModel.upload(context, relayList, onClose, accountViewModel.toastManager::toast)
|
||||
postViewModel.upload(context, onClose, accountViewModel.toastManager::toast)
|
||||
postViewModel.selectedServer?.let {
|
||||
if (it.type != ServerType.NIP95) {
|
||||
account.settings.changeDefaultFileServer(it)
|
||||
@@ -173,16 +148,6 @@ fun NewMediaView(
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
if (showRelaysDialog) {
|
||||
RelaySelectionDialog(
|
||||
preSelectedList = relayList,
|
||||
onClose = { showRelaysDialog = false },
|
||||
onPost = { relayList = it },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ fun NewPollVoteValueRange(pollViewModel: ShortNotePostViewModel) {
|
||||
onValueChange = { pollViewModel.updateMinZapAmountForPoll(it) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = if (pollViewModel.isValidvalueMinimum.value) colorValid else colorInValid,
|
||||
colors = if (pollViewModel.isValidValueMinimum.value) colorValid else colorInValid,
|
||||
label = {
|
||||
Text(
|
||||
text = stringRes(R.string.poll_zap_value_min),
|
||||
@@ -88,7 +88,7 @@ fun NewPollVoteValueRange(pollViewModel: ShortNotePostViewModel) {
|
||||
onValueChange = { pollViewModel.updateMaxZapAmountForPoll(it) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = if (pollViewModel.isValidvalueMaximum.value) colorValid else colorInValid,
|
||||
colors = if (pollViewModel.isValidValueMaximum.value) colorValid else colorInValid,
|
||||
label = {
|
||||
Text(
|
||||
text = stringRes(R.string.poll_zap_value_max),
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.actions
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
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.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.service.Nip11Retriever
|
||||
import com.vitorpamplona.amethyst.ui.components.SetDialogToEdgeToEdge
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.buttons.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.note.buttons.SaveButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.header.loadRelayInfo
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.RelayInformationDialog
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlin.collections.map
|
||||
|
||||
data class RelayList(
|
||||
val relay: NormalizedRelayUrl,
|
||||
val isSelected: Boolean,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun RelaySelectionDialog(
|
||||
preSelectedList: ImmutableList<NormalizedRelayUrl>,
|
||||
onClose: () -> Unit,
|
||||
onPost: (list: ImmutableList<NormalizedRelayUrl>) -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
var relays by remember {
|
||||
mutableStateOf(
|
||||
accountViewModel.account.client.allAvailableRelays().map {
|
||||
RelayList(
|
||||
relay = it,
|
||||
isSelected = preSelectedList.any { relayUrl -> it == relayUrl },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val hasSelectedRelay by remember { derivedStateOf { relays.any { it.isSelected } } }
|
||||
|
||||
var selected by remember { mutableStateOf(true) }
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = { onClose() },
|
||||
properties =
|
||||
DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnClickOutside = false,
|
||||
decorFitsSystemWindows = false,
|
||||
),
|
||||
) {
|
||||
SetDialogToEdgeToEdge()
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
actions = {
|
||||
SaveButton(
|
||||
onPost = {
|
||||
val selectedRelays = relays.filter { it.isSelected }.map { it.relay }.toImmutableList()
|
||||
onPost(selectedRelays)
|
||||
onClose()
|
||||
},
|
||||
isActive = hasSelectedRelay,
|
||||
)
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
},
|
||||
title = {},
|
||||
navigationIcon = {
|
||||
Row {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
CloseButton(
|
||||
onPress = { onClose() },
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.padding(pad).padding(start = 10.dp, end = 10.dp, top = 10.dp),
|
||||
) {
|
||||
RelaySwitch(
|
||||
text = stringRes(R.string.select_deselect_all),
|
||||
checked = selected,
|
||||
onClick = {
|
||||
selected = !selected
|
||||
relays = relays.mapIndexed { _, item -> item.copy(isSelected = selected) }
|
||||
},
|
||||
)
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = FeedPadding,
|
||||
) {
|
||||
itemsIndexed(
|
||||
relays,
|
||||
key = { _, item -> item.relay.url },
|
||||
) { index, item ->
|
||||
RenderRelaySwitch(
|
||||
item,
|
||||
onClick = {
|
||||
relays =
|
||||
relays.mapIndexed { j, item ->
|
||||
if (index == j) {
|
||||
item.copy(isSelected = !item.isSelected)
|
||||
} else {
|
||||
item
|
||||
}
|
||||
}
|
||||
},
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderRelaySwitch(
|
||||
item: RelayList,
|
||||
onClick: () -> Unit,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val relayInfo by loadRelayInfo(item.relay, accountViewModel)
|
||||
|
||||
var openRelayDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (openRelayDialog) {
|
||||
RelayInformationDialog(
|
||||
onClose = { openRelayDialog = false },
|
||||
relayInfo = relayInfo,
|
||||
relay = item.relay,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
RelaySwitch(
|
||||
text = item.relay.displayUrl(),
|
||||
checked = item.isSelected,
|
||||
onClick = onClick,
|
||||
onLongPress = {
|
||||
openRelayDialog = true
|
||||
accountViewModel.retrieveRelayDocument(
|
||||
relay = item.relay,
|
||||
onInfo = { },
|
||||
onError = { relay, errorCode, exceptionMessage ->
|
||||
val msg =
|
||||
when (errorCode) {
|
||||
Nip11Retriever.ErrorCode.FAIL_TO_ASSEMBLE_URL ->
|
||||
stringRes(
|
||||
context,
|
||||
R.string.relay_information_document_error_assemble_url,
|
||||
relay.url,
|
||||
exceptionMessage,
|
||||
)
|
||||
Nip11Retriever.ErrorCode.FAIL_TO_REACH_SERVER ->
|
||||
stringRes(
|
||||
context,
|
||||
R.string.relay_information_document_error_assemble_url,
|
||||
relay.url,
|
||||
exceptionMessage,
|
||||
)
|
||||
Nip11Retriever.ErrorCode.FAIL_TO_PARSE_RESULT ->
|
||||
stringRes(
|
||||
context,
|
||||
R.string.relay_information_document_error_assemble_url,
|
||||
relay.url,
|
||||
exceptionMessage,
|
||||
)
|
||||
Nip11Retriever.ErrorCode.FAIL_WITH_HTTP_STATUS ->
|
||||
stringRes(
|
||||
context,
|
||||
R.string.relay_information_document_error_assemble_url,
|
||||
relay.url,
|
||||
exceptionMessage,
|
||||
)
|
||||
}
|
||||
|
||||
accountViewModel.toastManager.toast(
|
||||
stringRes(context, R.string.unable_to_download_relay_document),
|
||||
msg,
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun RelaySwitch(
|
||||
text: String,
|
||||
checked: Boolean,
|
||||
onClick: () -> Unit,
|
||||
onLongPress: () -> Unit = {},
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier =
|
||||
Modifier.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongPress,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = text,
|
||||
)
|
||||
Switch(
|
||||
checked = checked,
|
||||
onCheckedChange = { onClick() },
|
||||
)
|
||||
}
|
||||
}
|
||||
+39
-52
@@ -64,7 +64,6 @@ import com.vitorpamplona.quartz.experimental.nip95.data.FileStorageEvent
|
||||
import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohash
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.hasGeohashes
|
||||
@@ -99,13 +98,14 @@ import com.vitorpamplona.quartz.nip94FileMetadata.mimeType
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.originalHash
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.size
|
||||
import com.vitorpamplona.quartz.utils.tryAndWait
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.collections.plus
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@Stable
|
||||
open class CommentPostViewModel :
|
||||
@@ -131,7 +131,7 @@ open class CommentPostViewModel :
|
||||
var account: Account? = null
|
||||
|
||||
var externalIdentity by mutableStateOf<ExternalId?>(null)
|
||||
var replyingTo: Note? by mutableStateOf<Note?>(null)
|
||||
var replyingTo: Note? by mutableStateOf(null)
|
||||
|
||||
val iMetaAttachments = IMetaAttachments()
|
||||
var nip95attachments by mutableStateOf<List<Pair<FileStorageEvent, FileStorageHeaderEvent>>>(
|
||||
@@ -177,9 +177,6 @@ open class CommentPostViewModel :
|
||||
var wantsZapraiser by mutableStateOf(false)
|
||||
override val zapRaiserAmount = mutableStateOf<Long?>(null)
|
||||
|
||||
var showRelaysDialog by mutableStateOf(false)
|
||||
var relayList by mutableStateOf<ImmutableList<NormalizedRelayUrl>?>(null)
|
||||
|
||||
fun lnAddress(): String? = account?.userProfile()?.info?.lnAddress()
|
||||
|
||||
fun hasLnAddress(): Boolean = account?.userProfile()?.info?.lnAddress() != null
|
||||
@@ -270,15 +267,15 @@ open class CommentPostViewModel :
|
||||
canAddZapRaiser = accountViewModel?.userProfile()?.info?.lnAddress() != null
|
||||
multiOrchestrator = null
|
||||
|
||||
val localfowardZapTo = draftEvent.tags.filter { it.size > 1 && it[0] == "zap" }
|
||||
val localForwardZapTo = draftEvent.tags.filter { it.size > 1 && it[0] == "zap" }
|
||||
forwardZapTo.value = SplitBuilder()
|
||||
localfowardZapTo.forEach {
|
||||
localForwardZapTo.forEach {
|
||||
val user = LocalCache.getOrCreateUser(it[1])
|
||||
val value = it.last().toFloatOrNull() ?: 0f
|
||||
forwardZapTo.value.addItem(user, value)
|
||||
}
|
||||
forwardZapToEditting.value = TextFieldValue("")
|
||||
wantsForwardZapTo = localfowardZapTo.isNotEmpty()
|
||||
wantsForwardZapTo = localForwardZapTo.isNotEmpty()
|
||||
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
|
||||
@@ -311,21 +308,23 @@ open class CommentPostViewModel :
|
||||
|
||||
suspend fun sendPostSync() {
|
||||
val template = createTemplate() ?: return
|
||||
val relayList = relayList
|
||||
val extraNotesToBroadcast = mutableListOf<Event>()
|
||||
|
||||
if (nip95attachments.isNotEmpty() && relayList != null && relayList.isNotEmpty()) {
|
||||
if (nip95attachments.isNotEmpty()) {
|
||||
val usedImages = template.tags.taggedQuoteIds().toSet()
|
||||
nip95attachments.forEach {
|
||||
if (usedImages.contains(it.second.id)) {
|
||||
account?.sendNip95(it.first, it.second, relayList.toSet())
|
||||
extraNotesToBroadcast.add(it.first)
|
||||
extraNotesToBroadcast.add(it.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accountViewModel?.account?.signAndSendPrivatelyOrBroadcast(
|
||||
template,
|
||||
relayList = { relayList },
|
||||
)
|
||||
tryAndWait { continuation ->
|
||||
accountViewModel?.account?.signAndComputeBroadcast(template, extraNotesToBroadcast) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
|
||||
accountViewModel?.deleteDraft(draftTag.current)
|
||||
|
||||
@@ -378,7 +377,7 @@ open class CommentPostViewModel :
|
||||
msg = tagger.message,
|
||||
replyingTo = eventHint,
|
||||
) {
|
||||
tagger.pTags?.let { notify(it.map { it.toPTag() }) }
|
||||
tagger.pTags?.let { pTagList -> notify(pTagList.map { it.toPTag() }) }
|
||||
|
||||
hashtags(findHashtags(tagger.message))
|
||||
references(findURLs(tagger.message))
|
||||
@@ -398,7 +397,7 @@ open class CommentPostViewModel :
|
||||
msg = tagger.message,
|
||||
extId = externalIdentity,
|
||||
) {
|
||||
tagger.pTags?.let { notify(it.map { it.toPTag() }) }
|
||||
tagger.pTags?.let { pTagList -> notify(pTagList.map { it.toPTag() }) }
|
||||
|
||||
hashtags(findHashtags(tagger.message))
|
||||
references(findURLs(tagger.message))
|
||||
@@ -458,9 +457,9 @@ open class CommentPostViewModel :
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
results.successful.forEach {
|
||||
if (it.result is UploadOrchestrator.OrchestratorResult.NIP95Result) {
|
||||
account?.createNip95(it.result.bytes, headerInfo = it.result.fileHeader, alt, contentWarningReason) { nip95 ->
|
||||
results.successful.forEach { state ->
|
||||
if (state.result is UploadOrchestrator.OrchestratorResult.NIP95Result) {
|
||||
account?.createNip95(state.result.bytes, headerInfo = state.result.fileHeader, alt, contentWarningReason) { nip95 ->
|
||||
nip95attachments = nip95attachments + nip95
|
||||
val note = nip95.let { it1 -> account?.consumeNip95(it1.first, it1.second) }
|
||||
|
||||
@@ -469,20 +468,20 @@ open class CommentPostViewModel :
|
||||
urlPreviews.update(message)
|
||||
}
|
||||
}
|
||||
} else if (it.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
||||
} else if (state.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
||||
val iMeta =
|
||||
IMetaTagBuilder(it.result.url)
|
||||
IMetaTagBuilder(state.result.url)
|
||||
.apply {
|
||||
hash(it.result.fileHeader.hash)
|
||||
size(it.result.fileHeader.size)
|
||||
it.result.fileHeader.mimeType
|
||||
hash(state.result.fileHeader.hash)
|
||||
size(state.result.fileHeader.size)
|
||||
state.result.fileHeader.mimeType
|
||||
?.let { mimeType(it) }
|
||||
it.result.fileHeader.dim
|
||||
state.result.fileHeader.dim
|
||||
?.let { dims(it) }
|
||||
it.result.fileHeader.blurHash
|
||||
state.result.fileHeader.blurHash
|
||||
?.let { blurhash(it.blurhash) }
|
||||
it.result.magnet?.let { magnet(it) }
|
||||
it.result.uploadedHash?.let { originalHash(it) }
|
||||
state.result.magnet?.let { magnet(it) }
|
||||
state.result.uploadedHash?.let { originalHash(it) }
|
||||
|
||||
alt?.let { alt(it) }
|
||||
contentWarningReason?.let { sensitiveContent(contentWarningReason) }
|
||||
@@ -490,7 +489,7 @@ open class CommentPostViewModel :
|
||||
|
||||
iMetaAttachments.replace(iMeta.url, iMeta)
|
||||
|
||||
message = message.insertUrlAtCursor(it.result.url)
|
||||
message = message.insertUrlAtCursor(state.result.url)
|
||||
urlPreviews.update(message)
|
||||
}
|
||||
}
|
||||
@@ -546,21 +545,9 @@ open class CommentPostViewModel :
|
||||
|
||||
emojiSuggestions?.reset()
|
||||
|
||||
showRelaysDialog = false
|
||||
|
||||
reloadRelaySet()
|
||||
|
||||
draftTag.rotate()
|
||||
}
|
||||
|
||||
fun reloadRelaySet() {
|
||||
val account = accountViewModel?.account ?: return
|
||||
|
||||
relayList =
|
||||
account.outboxRelays.flow.value
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
fun deleteMediaToUpload(selected: SelectedMediaProcessing) {
|
||||
this.multiOrchestrator?.remove(selected)
|
||||
}
|
||||
@@ -569,8 +556,8 @@ open class CommentPostViewModel :
|
||||
notifying = notifying?.filter { it != userToRemove }
|
||||
}
|
||||
|
||||
override fun updateMessage(it: TextFieldValue) {
|
||||
message = it
|
||||
override fun updateMessage(newMessage: TextFieldValue) {
|
||||
message = newMessage
|
||||
urlPreviews.update(message)
|
||||
|
||||
if (message.selection.collapsed) {
|
||||
@@ -627,13 +614,13 @@ open class CommentPostViewModel :
|
||||
val wordToInsert = item.link.url + " "
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
iMetaAttachments.downloadAndPrepare(
|
||||
item.link.url,
|
||||
{
|
||||
Amethyst.Companion.instance.okHttpClients
|
||||
.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false)
|
||||
},
|
||||
)
|
||||
iMetaAttachments.downloadAndPrepare(item.link.url) {
|
||||
Amethyst.Companion.instance.okHttpClients
|
||||
.getHttpClient(
|
||||
accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url)
|
||||
?: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
message = message.replaceCurrentWord(wordToInsert)
|
||||
|
||||
-30
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.note.nip22Comments
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -37,8 +36,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -46,7 +43,6 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -56,7 +52,6 @@ import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.actions.RelaySelectionDialog
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
@@ -85,7 +80,6 @@ import com.vitorpamplona.amethyst.ui.note.creators.zapraiser.AddZapraiserButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapraiser.ZapRaiserRequest
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapToButton
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
@@ -116,7 +110,6 @@ fun ReplyCommentPostScreen(
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
postViewModel.reloadRelaySet()
|
||||
reply?.let {
|
||||
postViewModel.reply(it)
|
||||
}
|
||||
@@ -159,20 +152,6 @@ fun GenericCommentPostScreen(
|
||||
verticalAlignment = CenterVertically,
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
Box {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
onClick = { postViewModel.showRelaysDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.relays, 5),
|
||||
contentDescription = stringRes(id = R.string.relay_list_selector),
|
||||
modifier = Modifier.height(25.dp),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
PostButton(
|
||||
onPost = {
|
||||
// uses the accountViewModel scope to avoid cancelling this
|
||||
@@ -209,15 +188,6 @@ fun GenericCommentPostScreen(
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
if (postViewModel.showRelaysDialog) {
|
||||
RelaySelectionDialog(
|
||||
preSelectedList = postViewModel.relayList ?: persistentListOf(),
|
||||
onClose = { postViewModel.showRelaysDialog = false },
|
||||
onPost = { postViewModel.relayList = it },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
-32
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -37,8 +36,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -47,10 +44,7 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
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.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -60,7 +54,6 @@ import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.actions.RelaySelectionDialog
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
@@ -88,7 +81,6 @@ import com.vitorpamplona.amethyst.ui.note.creators.zapraiser.AddZapraiserButton
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapraiser.ZapRaiserRequest
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapTo
|
||||
import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.ForwardZapToButton
|
||||
import com.vitorpamplona.amethyst.ui.painterRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
@@ -151,8 +143,6 @@ fun NewProductScreen(
|
||||
) {
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
var showRelaysDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -164,19 +154,6 @@ fun NewProductScreen(
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
Box {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
onClick = { showRelaysDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.relays, 1),
|
||||
contentDescription = stringRes(id = R.string.relay_list_selector),
|
||||
modifier = Modifier.height(25.dp),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
PostButton(
|
||||
onPost = {
|
||||
accountViewModel.viewModelScope.launch(Dispatchers.IO) {
|
||||
@@ -210,15 +187,6 @@ fun NewProductScreen(
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
if (showRelaysDialog) {
|
||||
RelaySelectionDialog(
|
||||
preSelectedList = postViewModel.relayList ?: persistentListOf(),
|
||||
onClose = { showRelaysDialog = false },
|
||||
onPost = { postViewModel.relayList = it },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
-1
@@ -54,7 +54,6 @@ fun GeoHashPostScreen(
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
postViewModel.reloadRelaySet()
|
||||
geohash?.let {
|
||||
postViewModel.newPostFor(GeohashId(it))
|
||||
}
|
||||
|
||||
-1
@@ -54,7 +54,6 @@ fun HashtagPostScreen(
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
postViewModel.reloadRelaySet()
|
||||
hashtag?.let {
|
||||
postViewModel.newPostFor(HashtagId(it))
|
||||
}
|
||||
|
||||
+3
-31
@@ -25,7 +25,6 @@ import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -50,8 +49,6 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -62,7 +59,6 @@ import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.actions.RelaySelectionDialog
|
||||
import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
|
||||
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
|
||||
@@ -173,8 +169,6 @@ private fun NewPostScreenInner(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: Nav,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
WatchAndLoadMyEmojiList(accountViewModel)
|
||||
|
||||
Scaffold(
|
||||
@@ -188,19 +182,6 @@ private fun NewPostScreenInner(
|
||||
) {
|
||||
Spacer(modifier = StdHorzSpacer)
|
||||
|
||||
Box {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
onClick = { postViewModel.showRelaysDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterRes(R.drawable.relays, 6),
|
||||
contentDescription = stringRes(id = R.string.relay_list_selector),
|
||||
modifier = Modifier.height(25.dp),
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
PostButton(
|
||||
onPost = {
|
||||
// uses the accountViewModel scope to avoid cancelling this
|
||||
@@ -238,15 +219,6 @@ private fun NewPostScreenInner(
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
if (postViewModel.showRelaysDialog) {
|
||||
RelaySelectionDialog(
|
||||
preSelectedList = postViewModel.relayList ?: persistentListOf(),
|
||||
onClose = { postViewModel.showRelaysDialog = false },
|
||||
onPost = { postViewModel.relayList = it },
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
@@ -419,7 +391,7 @@ private fun NewPostScreenBody(
|
||||
}
|
||||
}
|
||||
|
||||
if (postViewModel.wantsZapraiser && postViewModel.hasLnAddress()) {
|
||||
if (postViewModel.wantsZapRaiser && postViewModel.hasLnAddress()) {
|
||||
Row(
|
||||
verticalAlignment = CenterVertically,
|
||||
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
|
||||
@@ -495,8 +467,8 @@ private fun BottomRowActions(postViewModel: ShortNotePostViewModel) {
|
||||
}
|
||||
|
||||
if (postViewModel.canAddZapRaiser) {
|
||||
AddZapraiserButton(postViewModel.wantsZapraiser) {
|
||||
postViewModel.wantsZapraiser = !postViewModel.wantsZapraiser
|
||||
AddZapraiserButton(postViewModel.wantsZapRaiser) {
|
||||
postViewModel.wantsZapRaiser = !postViewModel.wantsZapRaiser
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+69
-79
@@ -74,7 +74,6 @@ import com.vitorpamplona.quartz.experimental.zapPolls.tags.PollOptionTag
|
||||
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohash
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.geohash.getGeoHash
|
||||
@@ -115,12 +114,13 @@ import com.vitorpamplona.quartz.nip94FileMetadata.mimeType
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.originalHash
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.size
|
||||
import com.vitorpamplona.quartz.utils.tryAndWait
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
enum class UserSuggestionAnchor {
|
||||
MAIN_MESSAGE,
|
||||
@@ -151,8 +151,8 @@ open class ShortNotePostViewModel :
|
||||
var accountViewModel: AccountViewModel? = null
|
||||
var account: Account? = null
|
||||
|
||||
var originalNote: Note? by mutableStateOf<Note?>(null)
|
||||
var forkedFromNote: Note? by mutableStateOf<Note?>(null)
|
||||
var originalNote: Note? by mutableStateOf(null)
|
||||
var forkedFromNote: Note? by mutableStateOf(null)
|
||||
|
||||
var pTags by mutableStateOf<List<User>?>(null)
|
||||
var eTags by mutableStateOf<List<Note>?>(null)
|
||||
@@ -185,9 +185,8 @@ open class ShortNotePostViewModel :
|
||||
var consensusThreshold: Int? = null
|
||||
var closedAt: Long? = null
|
||||
|
||||
var isValidRecipients = mutableStateOf(true)
|
||||
var isValidvalueMaximum = mutableStateOf(true)
|
||||
var isValidvalueMinimum = mutableStateOf(true)
|
||||
var isValidValueMaximum = mutableStateOf(true)
|
||||
var isValidValueMinimum = mutableStateOf(true)
|
||||
var isValidConsensusThreshold = mutableStateOf(true)
|
||||
var isValidClosedAt = mutableStateOf(true)
|
||||
|
||||
@@ -212,12 +211,9 @@ open class ShortNotePostViewModel :
|
||||
|
||||
// ZapRaiser
|
||||
var canAddZapRaiser by mutableStateOf(false)
|
||||
var wantsZapraiser by mutableStateOf(false)
|
||||
var wantsZapRaiser by mutableStateOf(false)
|
||||
override val zapRaiserAmount = mutableStateOf<Long?>(null)
|
||||
|
||||
var showRelaysDialog by mutableStateOf(false)
|
||||
var relayList by mutableStateOf<ImmutableList<NormalizedRelayUrl>?>(null)
|
||||
|
||||
fun lnAddress(): String? = account?.userProfile()?.info?.lnAddress()
|
||||
|
||||
fun hasLnAddress(): Boolean = account?.userProfile()?.info?.lnAddress() != null
|
||||
@@ -295,10 +291,10 @@ open class ShortNotePostViewModel :
|
||||
canUsePoll = originalNote == null
|
||||
multiOrchestrator = null
|
||||
|
||||
quote?.let {
|
||||
message = TextFieldValue(message.text + "\nnostr:${it.toNEvent()}")
|
||||
quote?.let { quotedNote ->
|
||||
message = TextFieldValue(message.text + "\nnostr:${quotedNote.toNEvent()}")
|
||||
|
||||
it.author?.let { quotedUser ->
|
||||
quotedNote.author?.let { quotedUser ->
|
||||
if (quotedUser.pubkeyHex != accountViewModel.userProfile().pubkeyHex) {
|
||||
if (forwardZapTo.value.items.none { it.key.pubkeyHex == quotedUser.pubkeyHex }) {
|
||||
forwardZapTo.value.addItem(quotedUser)
|
||||
@@ -313,21 +309,21 @@ open class ShortNotePostViewModel :
|
||||
}
|
||||
}
|
||||
|
||||
fork?.let {
|
||||
message = TextFieldValue(version?.event?.content ?: it.event?.content ?: "")
|
||||
fork?.let { forkedNoted ->
|
||||
message = TextFieldValue(version?.event?.content ?: forkedNoted.event?.content ?: "")
|
||||
|
||||
it.event?.isSensitiveOrNSFW()?.let {
|
||||
forkedNoted.event?.isSensitiveOrNSFW()?.let {
|
||||
if (it) wantsToMarkAsSensitive = true
|
||||
}
|
||||
|
||||
it.event?.zapraiserAmount()?.let {
|
||||
forkedNoted.event?.zapraiserAmount()?.let {
|
||||
zapRaiserAmount.value = it
|
||||
}
|
||||
|
||||
it.event?.zapSplitSetup()?.let {
|
||||
val totalWeight = it.sumOf { if (it is ZapSplitSetupLnAddress) 0.0 else it.weight }
|
||||
forkedNoted.event?.zapSplitSetup()?.let { setup ->
|
||||
val totalWeight = setup.sumOf { if (it is ZapSplitSetupLnAddress) 0.0 else it.weight }
|
||||
|
||||
it.forEach {
|
||||
setup.forEach {
|
||||
if (it is ZapSplitSetup) {
|
||||
forwardZapTo.value.addItem(LocalCache.getOrCreateUser(it.pubKeyHex), (it.weight / totalWeight).toFloat())
|
||||
}
|
||||
@@ -336,7 +332,7 @@ open class ShortNotePostViewModel :
|
||||
|
||||
// Only adds if it is not already set up.
|
||||
if (forwardZapTo.value.items.isEmpty()) {
|
||||
it.author?.let { forkedAuthor ->
|
||||
forkedNoted.author?.let { forkedAuthor ->
|
||||
if (forkedAuthor.pubkeyHex != accountViewModel.userProfile().pubkeyHex) {
|
||||
if (forwardZapTo.value.items.none { it.key.pubkeyHex == forkedAuthor.pubkeyHex }) forwardZapTo.value.addItem(forkedAuthor)
|
||||
if (forwardZapTo.value.items.none { it.key.pubkeyHex == accountViewModel.userProfile().pubkeyHex }) forwardZapTo.value.addItem(accountViewModel.userProfile())
|
||||
@@ -347,7 +343,7 @@ open class ShortNotePostViewModel :
|
||||
}
|
||||
}
|
||||
|
||||
it.author?.let {
|
||||
forkedNoted.author?.let {
|
||||
if (this.pTags == null) {
|
||||
this.pTags = listOf(it)
|
||||
} else if (this.pTags?.contains(it) != true) {
|
||||
@@ -355,7 +351,7 @@ open class ShortNotePostViewModel :
|
||||
}
|
||||
}
|
||||
|
||||
forkedFromNote = it
|
||||
forkedFromNote = forkedNoted
|
||||
} ?: run {
|
||||
forkedFromNote = null
|
||||
}
|
||||
@@ -380,15 +376,15 @@ open class ShortNotePostViewModel :
|
||||
canAddZapRaiser = accountViewModel?.userProfile()?.info?.lnAddress() != null
|
||||
multiOrchestrator = null
|
||||
|
||||
val localfowardZapTo = draftEvent.tags.filter { it.size > 1 && it[0] == "zap" }
|
||||
val localForwardZapTo = draftEvent.tags.filter { it.size > 1 && it[0] == "zap" }
|
||||
forwardZapTo.value = SplitBuilder()
|
||||
localfowardZapTo.forEach {
|
||||
localForwardZapTo.forEach {
|
||||
val user = LocalCache.getOrCreateUser(it[1])
|
||||
val value = it.last().toFloatOrNull() ?: 0f
|
||||
forwardZapTo.value.addItem(user, value)
|
||||
}
|
||||
forwardZapToEditting.value = TextFieldValue("")
|
||||
wantsForwardZapTo = localfowardZapTo.isNotEmpty()
|
||||
wantsForwardZapTo = localForwardZapTo.isNotEmpty()
|
||||
|
||||
wantsToMarkAsSensitive = draftEvent.isSensitive()
|
||||
|
||||
@@ -398,11 +394,11 @@ open class ShortNotePostViewModel :
|
||||
wantsExclusiveGeoPost = draftEvent.kind == CommentEvent.KIND
|
||||
}
|
||||
|
||||
val zapraiser = draftEvent.zapraiserAmount()
|
||||
wantsZapraiser = zapraiser != null
|
||||
val zapRaiser = draftEvent.zapraiserAmount()
|
||||
wantsZapRaiser = zapRaiser != null
|
||||
zapRaiserAmount.value = null
|
||||
if (zapraiser != null) {
|
||||
zapRaiserAmount.value = zapraiser
|
||||
if (zapRaiser != null) {
|
||||
zapRaiserAmount.value = zapRaiser
|
||||
}
|
||||
|
||||
eTags =
|
||||
@@ -416,7 +412,7 @@ open class ShortNotePostViewModel :
|
||||
LocalCache.getOrCreateUser(it[1])
|
||||
}
|
||||
|
||||
draftEvent.tags.filter { it.size > 3 && (it[0] == "e" || it[0] == "a") && it.get(3) == "fork" }.forEach {
|
||||
draftEvent.tags.filter { it.size > 3 && (it[0] == "e" || it[0] == "a") && it[3] == "fork" }.forEach {
|
||||
val note = LocalCache.checkGetOrCreateNote(it[1])
|
||||
forkedFromNote = note
|
||||
}
|
||||
@@ -470,21 +466,23 @@ open class ShortNotePostViewModel :
|
||||
|
||||
suspend fun sendPostSync() {
|
||||
val template = createTemplate() ?: return
|
||||
val relayList = relayList
|
||||
val extraNotesToBroadcast = mutableListOf<Event>()
|
||||
|
||||
if (nip95attachments.isNotEmpty() && relayList != null && relayList.isNotEmpty()) {
|
||||
if (nip95attachments.isNotEmpty()) {
|
||||
val usedImages = template.tags.taggedQuoteIds().toSet()
|
||||
nip95attachments.forEach {
|
||||
if (usedImages.contains(it.second.id)) {
|
||||
account?.sendNip95(it.first, it.second, relayList.toSet())
|
||||
extraNotesToBroadcast.add(it.first)
|
||||
extraNotesToBroadcast.add(it.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accountViewModel?.account?.signAndSendPrivatelyOrBroadcast(
|
||||
template,
|
||||
relayList = { relayList },
|
||||
)
|
||||
tryAndWait { continuation ->
|
||||
accountViewModel?.account?.signAndComputeBroadcast(template, extraNotesToBroadcast) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
|
||||
accountViewModel?.deleteDraft(draftTag.current)
|
||||
|
||||
@@ -526,7 +524,7 @@ open class ShortNotePostViewModel :
|
||||
val zapReceiver = if (wantsForwardZapTo) forwardZapTo.value.toZapSplitSetup() else null
|
||||
|
||||
val geoHash = (location?.value as? LocationState.LocationResult.Success)?.geoHash?.toString()
|
||||
val localZapRaiserAmount = if (wantsZapraiser) zapRaiserAmount.value else null
|
||||
val localZapRaiserAmount = if (wantsZapRaiser) zapRaiserAmount.value else null
|
||||
|
||||
val emojis = findEmoji(tagger.message, account?.emoji?.myEmojis?.value)
|
||||
val urls = findURLs(tagger.message)
|
||||
@@ -565,7 +563,7 @@ open class ShortNotePostViewModel :
|
||||
replyingTo = originalNote?.toEventHint<TextNoteEvent>(),
|
||||
forkingFrom = forkedFromNote?.toEventHint<TextNoteEvent>(),
|
||||
) {
|
||||
tagger.pTags?.let { notify(it.map { it.toPTag() }) }
|
||||
tagger.pTags?.let { pTagList -> notify(pTagList.map { it.toPTag() }) }
|
||||
|
||||
hashtags(findHashtags(tagger.message))
|
||||
references(findURLs(tagger.message))
|
||||
@@ -619,9 +617,9 @@ open class ShortNotePostViewModel :
|
||||
)
|
||||
|
||||
if (results.allGood) {
|
||||
results.successful.forEach {
|
||||
if (it.result is UploadOrchestrator.OrchestratorResult.NIP95Result) {
|
||||
account?.createNip95(it.result.bytes, headerInfo = it.result.fileHeader, alt, contentWarningReason) { nip95 ->
|
||||
results.successful.forEach { state ->
|
||||
if (state.result is UploadOrchestrator.OrchestratorResult.NIP95Result) {
|
||||
account?.createNip95(state.result.bytes, headerInfo = state.result.fileHeader, alt, contentWarningReason) { nip95 ->
|
||||
nip95attachments = nip95attachments + nip95
|
||||
val note = nip95.let { it1 -> account?.consumeNip95(it1.first, it1.second) }
|
||||
|
||||
@@ -630,20 +628,20 @@ open class ShortNotePostViewModel :
|
||||
urlPreviews.update(message)
|
||||
}
|
||||
}
|
||||
} else if (it.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
||||
} else if (state.result is UploadOrchestrator.OrchestratorResult.ServerResult) {
|
||||
val iMeta =
|
||||
IMetaTagBuilder(it.result.url)
|
||||
IMetaTagBuilder(state.result.url)
|
||||
.apply {
|
||||
hash(it.result.fileHeader.hash)
|
||||
size(it.result.fileHeader.size)
|
||||
it.result.fileHeader.mimeType
|
||||
hash(state.result.fileHeader.hash)
|
||||
size(state.result.fileHeader.size)
|
||||
state.result.fileHeader.mimeType
|
||||
?.let { mimeType(it) }
|
||||
it.result.fileHeader.dim
|
||||
state.result.fileHeader.dim
|
||||
?.let { dims(it) }
|
||||
it.result.fileHeader.blurHash
|
||||
state.result.fileHeader.blurHash
|
||||
?.let { blurhash(it.blurhash) }
|
||||
it.result.magnet?.let { magnet(it) }
|
||||
it.result.uploadedHash?.let { originalHash(it) }
|
||||
state.result.magnet?.let { magnet(it) }
|
||||
state.result.uploadedHash?.let { originalHash(it) }
|
||||
|
||||
alt?.let { alt(it) }
|
||||
contentWarningReason?.let { sensitiveContent(contentWarningReason) }
|
||||
@@ -651,7 +649,7 @@ open class ShortNotePostViewModel :
|
||||
|
||||
iMetaAttachments.replace(iMeta.url, iMeta)
|
||||
|
||||
message = message.insertUrlAtCursor(it.result.url)
|
||||
message = message.insertUrlAtCursor(state.result.url)
|
||||
urlPreviews.update(message)
|
||||
}
|
||||
}
|
||||
@@ -677,7 +675,7 @@ open class ShortNotePostViewModel :
|
||||
pTags = null
|
||||
|
||||
wantsPoll = false
|
||||
zapRecipients = mutableStateListOf<HexKey>()
|
||||
zapRecipients = mutableStateListOf()
|
||||
pollOptions = newStateMapPollOptions()
|
||||
valueMaximum = null
|
||||
valueMinimum = null
|
||||
@@ -685,7 +683,7 @@ open class ShortNotePostViewModel :
|
||||
closedAt = null
|
||||
|
||||
wantsInvoice = false
|
||||
wantsZapraiser = false
|
||||
wantsZapRaiser = false
|
||||
zapRaiserAmount.value = null
|
||||
|
||||
wantsForwardZapTo = false
|
||||
@@ -706,21 +704,9 @@ open class ShortNotePostViewModel :
|
||||
|
||||
emojiSuggestions?.reset()
|
||||
|
||||
showRelaysDialog = false
|
||||
|
||||
reloadRelaySet()
|
||||
|
||||
draftTag.rotate()
|
||||
}
|
||||
|
||||
fun reloadRelaySet() {
|
||||
val account = accountViewModel?.account ?: return
|
||||
|
||||
relayList =
|
||||
account.outboxRelays.flow.value
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
fun deleteMediaToUpload(selected: SelectedMediaProcessing) {
|
||||
this.multiOrchestrator?.remove(selected)
|
||||
}
|
||||
@@ -733,8 +719,8 @@ open class ShortNotePostViewModel :
|
||||
updateMessage(TextFieldValue(message.text + " " + it))
|
||||
}
|
||||
|
||||
override fun updateMessage(it: TextFieldValue) {
|
||||
message = it
|
||||
override fun updateMessage(newMessage: TextFieldValue) {
|
||||
message = newMessage
|
||||
urlPreviews.update(message)
|
||||
|
||||
if (message.selection.collapsed) {
|
||||
@@ -793,8 +779,12 @@ open class ShortNotePostViewModel :
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
iMetaAttachments.downloadAndPrepare(
|
||||
item.link.url,
|
||||
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false) },
|
||||
)
|
||||
) {
|
||||
Amethyst.instance.okHttpClients.getHttpClient(
|
||||
accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url)
|
||||
?: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
message = message.replaceCurrentWord(wordToInsert)
|
||||
@@ -811,13 +801,13 @@ open class ShortNotePostViewModel :
|
||||
message.text.isNotBlank() &&
|
||||
!isUploadingImage &&
|
||||
!wantsInvoice &&
|
||||
(!wantsZapraiser || zapRaiserAmount.value != null) &&
|
||||
(!wantsZapRaiser || zapRaiserAmount.value != null) &&
|
||||
(
|
||||
!wantsPoll ||
|
||||
(
|
||||
pollOptions.values.all { it.isNotEmpty() } &&
|
||||
isValidvalueMinimum.value &&
|
||||
isValidvalueMaximum.value
|
||||
isValidValueMinimum.value &&
|
||||
isValidValueMaximum.value
|
||||
)
|
||||
) &&
|
||||
multiOrchestrator == null
|
||||
@@ -857,11 +847,11 @@ open class ShortNotePostViewModel :
|
||||
|
||||
fun checkMinMax() {
|
||||
if ((valueMinimum ?: 0) > (valueMaximum ?: Long.MAX_VALUE)) {
|
||||
isValidvalueMinimum.value = false
|
||||
isValidvalueMaximum.value = false
|
||||
isValidValueMinimum.value = false
|
||||
isValidValueMaximum.value = false
|
||||
} else {
|
||||
isValidvalueMinimum.value = true
|
||||
isValidvalueMaximum.value = true
|
||||
isValidValueMinimum.value = true
|
||||
isValidValueMaximum.value = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -237,18 +237,18 @@ class NostrClient(
|
||||
}
|
||||
|
||||
fun sendIfExists(
|
||||
signedEvent: Event,
|
||||
event: Event,
|
||||
connectedRelay: NormalizedRelayUrl,
|
||||
) {
|
||||
relayPool.getRelay(connectedRelay)?.send(signedEvent)
|
||||
relayPool.getRelay(connectedRelay)?.send(event)
|
||||
}
|
||||
|
||||
fun send(
|
||||
signedEvent: Event,
|
||||
event: Event,
|
||||
relayList: Set<NormalizedRelayUrl>,
|
||||
) {
|
||||
eventOutbox.markAsSending(signedEvent, relayList)
|
||||
relayPool.send(signedEvent, relayList)
|
||||
eventOutbox.markAsSending(event, relayList)
|
||||
relayPool.send(event, relayList)
|
||||
}
|
||||
|
||||
fun close(subscriptionId: String) {
|
||||
|
||||
Reference in New Issue
Block a user