fixes the need for coroutine scopes

This commit is contained in:
Vitor Pamplona
2026-03-28 15:26:29 -04:00
parent c0212c09e5
commit 4db617aeef
23 changed files with 273 additions and 87 deletions
@@ -0,0 +1,43 @@
/*
* 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.desktop
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.Clipboard
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection
import java.awt.datatransfer.Transferable
@OptIn(androidx.compose.ui.ExperimentalComposeUiApi::class)
suspend fun Clipboard.setText(text: String) {
setClipEntry(ClipEntry(StringSelection(text)))
}
@OptIn(androidx.compose.ui.ExperimentalComposeUiApi::class)
suspend fun Clipboard.getText(): String? {
val entry = getClipEntry() ?: return null
val transferable = entry.nativeClipEntry as? Transferable ?: return null
return try {
transferable.getTransferData(DataFlavor.stringFlavor) as? String
} catch (_: Exception) {
null
}
}
@@ -80,6 +80,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
import com.vitorpamplona.amethyst.commons.ui.components.LoadingState
import com.vitorpamplona.amethyst.desktop.account.AccountState
import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
import com.vitorpamplona.amethyst.desktop.getText
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
import com.vitorpamplona.amethyst.desktop.service.highlights.DesktopHighlightStore
import com.vitorpamplona.amethyst.desktop.subscriptions.DesktopRelaySubscriptionsCoordinator
@@ -99,6 +100,7 @@ import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
import kotlinx.coroutines.launch
import java.awt.SystemColor.text
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
@@ -573,19 +575,26 @@ fun ArticleReaderScreen(
) {
HighlightContextMenuRepresentation(
delegate = defaultRepresentation,
clipboardManager = clipboardManager,
onHighlight = { text ->
onHighlight = {
scope.launch {
highlightStore?.addHighlight(
articleAddressTag = addressTag,
text = text,
note = null,
articleTitle = title,
)
val text = clipboardManager.getText()
if (!text.isNullOrBlank()) {
highlightStore?.addHighlight(
articleAddressTag = addressTag,
text = text,
note = null,
articleTitle = title,
)
}
}
},
onHighlightWithNote = { text ->
showAnnotationDialog = text
onHighlightWithNote = {
scope.launch {
val text = clipboardManager.getText()
if (!text.isNullOrBlank()) {
showAnnotationDialog = text
}
}
},
)
}
@@ -695,9 +704,8 @@ fun ArticleReaderScreen(
*/
private class HighlightContextMenuRepresentation(
private val delegate: ContextMenuRepresentation,
private val clipboardManager: androidx.compose.ui.platform.ClipboardManager,
private val onHighlight: (String) -> Unit,
private val onHighlightWithNote: (String) -> Unit,
private val onHighlight: () -> Unit,
private val onHighlightWithNote: () -> Unit,
) : ContextMenuRepresentation {
@Composable
override fun Representation(
@@ -713,17 +721,11 @@ private class HighlightContextMenuRepresentation(
listOf(
ContextMenuItem("Highlight") {
copyItem.onClick()
val text = clipboardManager.getText()?.text
if (!text.isNullOrBlank()) {
onHighlight(text)
}
onHighlight()
},
ContextMenuItem("Highlight with Note") {
copyItem.onClick()
val text = clipboardManager.getText()?.text
if (!text.isNullOrBlank()) {
onHighlightWithNote(text)
}
onHighlightWithNote()
},
)
} else {
@@ -50,7 +50,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -63,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.resources.login_card_title
import com.vitorpamplona.amethyst.commons.resources.login_generate_button
import com.vitorpamplona.amethyst.desktop.account.LoginProgress
import com.vitorpamplona.amethyst.desktop.account.validateBunkerUri
import com.vitorpamplona.amethyst.desktop.setText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -318,7 +318,11 @@ private fun NostrConnectContent(
Spacer(Modifier.height(8.dp))
OutlinedButton(
onClick = { clipboardManager.setText(AnnotatedString(uri)) },
onClick = {
scope.launch {
clipboardManager.setText(uri)
}
},
modifier = Modifier.fillMaxWidth(),
) {
Text("Copy URI")