feat(media): wire encrypted media, server settings, and server preferences

- ChatPane: display ChatFileAttachment for encrypted file header events
- DesktopPreferences: add blossom server list persistence
- Settings: add MediaServerSettings section above relay settings
- ComposeNoteDialog: use preferred blossom server from preferences

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-03-16 12:23:57 +02:00
parent e654d48cdf
commit 7773844d2f
4 changed files with 40 additions and 9 deletions
@@ -68,4 +68,17 @@ object DesktopPreferences {
set(value) { set(value) {
prefs.put(KEY_LAYOUT_MODE, value) prefs.put(KEY_LAYOUT_MODE, value)
} }
private const val KEY_BLOSSOM_SERVERS = "blossom_servers"
private const val DEFAULT_BLOSSOM_SERVER = "https://blossom.primal.net"
var blossomServers: List<String>
get() {
val raw = prefs.get(KEY_BLOSSOM_SERVERS, DEFAULT_BLOSSOM_SERVER)
return if (raw.isBlank()) emptyList() else raw.split(",")
}
set(value) = prefs.put(KEY_BLOSSOM_SERVERS, value.joinToString(","))
val preferredBlossomServer: String
get() = blossomServers.firstOrNull() ?: DEFAULT_BLOSSOM_SERVER
} }
@@ -91,6 +91,7 @@ import com.vitorpamplona.amethyst.desktop.ui.deck.DeckState
import com.vitorpamplona.amethyst.desktop.ui.deck.SinglePaneLayout import com.vitorpamplona.amethyst.desktop.ui.deck.SinglePaneLayout
import com.vitorpamplona.amethyst.desktop.ui.profile.ProfileInfoCard import com.vitorpamplona.amethyst.desktop.ui.profile.ProfileInfoCard
import com.vitorpamplona.amethyst.desktop.ui.relay.RelayStatusCard import com.vitorpamplona.amethyst.desktop.ui.relay.RelayStatusCard
import com.vitorpamplona.amethyst.desktop.ui.settings.MediaServerSettings
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -877,6 +878,15 @@ fun RelaySettingsScreen(
HorizontalDivider() HorizontalDivider()
Spacer(Modifier.height(24.dp)) Spacer(Modifier.height(24.dp))
// Media Server Settings
MediaServerSettings(
initialServers = DesktopPreferences.blossomServers,
onServersChanged = { DesktopPreferences.blossomServers = it },
)
Spacer(Modifier.height(24.dp))
HorizontalDivider()
Spacer(Modifier.height(24.dp))
// Developer Settings Section (only in debug mode) // Developer Settings Section (only in debug mode)
if (DebugConfig.isDebugMode) { if (DebugConfig.isDebugMode) {
com.vitorpamplona.amethyst.desktop.ui com.vitorpamplona.amethyst.desktop.ui
@@ -46,6 +46,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.vitorpamplona.amethyst.commons.model.nip10TextNotes.PublishAction import com.vitorpamplona.amethyst.commons.model.nip10TextNotes.PublishAction
import com.vitorpamplona.amethyst.desktop.DesktopPreferences
import com.vitorpamplona.amethyst.desktop.account.AccountState import com.vitorpamplona.amethyst.desktop.account.AccountState
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
import com.vitorpamplona.amethyst.desktop.service.upload.DesktopUploadOrchestrator import com.vitorpamplona.amethyst.desktop.service.upload.DesktopUploadOrchestrator
@@ -58,8 +59,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
private const val DEFAULT_BLOSSOM_SERVER = "https://blossom.primal.net"
@Composable @Composable
fun ComposeNoteDialog( fun ComposeNoteDialog(
onDismiss: () -> Unit, onDismiss: () -> Unit,
@@ -189,7 +188,7 @@ fun ComposeNoteDialog(
orchestrator.upload( orchestrator.upload(
file = file, file = file,
alt = null, alt = null,
serverBaseUrl = DEFAULT_BLOSSOM_SERVER, serverBaseUrl = DesktopPreferences.preferredBlossomServer,
signer = account.signer, signer = account.signer,
) )
uploadTracker.onSuccess(result) uploadTracker.onSuccess(result)
@@ -92,6 +92,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent
import com.vitorpamplona.quartz.nip17Dm.NIP17Factory import com.vitorpamplona.quartz.nip17Dm.NIP17Factory
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey
import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
private val isMacOS = System.getProperty("os.name").lowercase().contains("mac") private val isMacOS = System.getProperty("os.name").lowercase().contains("mac")
@@ -436,12 +437,20 @@ private fun MessageWithReactions(
} }
}, },
) { _ -> ) { _ ->
SelectionContainer { when (note.event) {
Text( is ChatMessageEncryptedFileHeaderEvent -> {
text = decryptedContent ?: "", ChatFileAttachment(event = note.event as ChatMessageEncryptedFileHeaderEvent)
style = MaterialTheme.typography.bodyMedium, }
color = MaterialTheme.colorScheme.onSurface,
) else -> {
SelectionContainer {
Text(
text = decryptedContent ?: "",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface,
)
}
}
} }
} }
} }