From d730eeb9a10018f80b7c160fc43a48afcd3917fb Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 17 Jul 2023 11:15:19 -0300 Subject: [PATCH] add relay selection to nip 94 and 95 uploads --- .../vitorpamplona/amethyst/model/Account.kt | 10 ++-- .../amethyst/ui/actions/NewMediaModel.kt | 15 +++--- .../amethyst/ui/actions/NewMediaView.kt | 47 ++++++++++++++++++- .../amethyst/ui/actions/NewPostView.kt | 2 +- .../amethyst/ui/actions/NewPostViewModel.kt | 12 ++--- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 47b27033d..45688e602 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -628,19 +628,19 @@ class Account( return Pair(data, signedEvent) } - fun sendNip95(data: FileStorageEvent, signedEvent: FileStorageHeaderEvent): Note? { + fun sendNip95(data: FileStorageEvent, signedEvent: FileStorageHeaderEvent, relayList: List? = null): Note? { if (!isWriteable()) return null - Client.send(data) + Client.send(data, relayList = relayList) LocalCache.consume(data, null) - Client.send(signedEvent) + Client.send(signedEvent, relayList = relayList) LocalCache.consume(signedEvent, null) return LocalCache.notes[signedEvent.id] } - fun sendHeader(headerInfo: FileHeader): Note? { + fun sendHeader(headerInfo: FileHeader, relayList: List? = null): Note? { if (!isWriteable()) return null val signedEvent = FileHeaderEvent.create( @@ -655,7 +655,7 @@ class Account( privateKey = loggedIn.privKey!! ) - Client.send(signedEvent) + Client.send(signedEvent, relayList = relayList) LocalCache.consume(signedEvent, null) return LocalCache.notes[signedEvent.id] diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index a8e8c513c..610d77ced 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -11,6 +11,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.* import com.vitorpamplona.amethyst.service.FileHeader +import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.ui.components.MediaCompressor import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow @@ -56,7 +57,7 @@ open class NewMediaModel : ViewModel() { } } - fun upload(context: Context) { + fun upload(context: Context, relayList: List? = null) { isUploadingImage = true val contentResolver = context.contentResolver @@ -78,7 +79,7 @@ open class NewMediaModel : ViewModel() { uploadingPercentage.value = 0.2f uploadingDescription.value = "Loading" contentResolver.openInputStream(fileUri)?.use { - createNIP95Record(it.readBytes(), contentType, description, sensitiveContent) + createNIP95Record(it.readBytes(), contentType, description, sensitiveContent, relayList = relayList) } ?: run { viewModelScope.launch { @@ -98,7 +99,7 @@ open class NewMediaModel : ViewModel() { server = serverToUse, contentResolver = contentResolver, onSuccess = { imageUrl, mimeType -> - createNIP94Record(imageUrl, mimeType, description, sensitiveContent) + createNIP94Record(imageUrl, mimeType, description, sensitiveContent, relayList = relayList) }, onError = { isUploadingImage = false @@ -138,7 +139,7 @@ open class NewMediaModel : ViewModel() { return !isUploadingImage && galleryUri != null && selectedServer != null } - fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean) { + fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean, relayList: List? = null) { uploadingPercentage.value = 0.40f viewModelScope.launch(Dispatchers.IO) { uploadingDescription.value = "Server Processing" @@ -162,7 +163,7 @@ open class NewMediaModel : ViewModel() { onReady = { uploadingPercentage.value = 0.90f uploadingDescription.value = "Sending" - account?.sendHeader(it) + account?.sendHeader(it, relayList) uploadingPercentage.value = 1.00f isUploadingImage = false onceUploaded() @@ -191,7 +192,7 @@ open class NewMediaModel : ViewModel() { } } - fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean) { + fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean, relayList: List? = null) { uploadingPercentage.value = 0.30f uploadingDescription.value = "Hashing" @@ -210,7 +211,7 @@ open class NewMediaModel : ViewModel() { if (nip95 != null) { uploadingDescription.value = "Sending" uploadingPercentage.value = 0.60f - account?.sendNip95(nip95.first, nip95.second) + account?.sendNip95(nip95.first, nip95.second, relayList) } uploadingPercentage.value = 1.00f diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index ef708495f..014e69e99 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -7,17 +7,21 @@ import android.util.Size import android.widget.Toast import androidx.compose.foundation.Image 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.WindowInsets import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedTextField import androidx.compose.material.Surface @@ -33,6 +37,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp @@ -70,6 +75,17 @@ fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, ac } } + var showRelaysDialog by remember { + mutableStateOf(false) + } + var relayList = account.activeRelays()?.filter { + it.write + }?.map { + it + } ?: account.convertLocalRelays().filter { + it.write + } + Dialog( onDismissRequest = { onClose() }, properties = DialogProperties( @@ -82,6 +98,19 @@ fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, ac modifier = Modifier .fillMaxWidth() ) { + if (showRelaysDialog) { + RelaySelectionDialog( + list = relayList, + onClose = { + showRelaysDialog = false + }, + onPost = { + relayList = it + }, + account = account + ) + } + Column( modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 10.dp) .fillMaxWidth() @@ -97,10 +126,26 @@ fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, ac onClose() }) + Box { + IconButton( + modifier = Modifier.align(Alignment.Center), + onClick = { + showRelaysDialog = true + } + ) { + Icon( + painter = painterResource(R.drawable.relays), + contentDescription = null, + modifier = Modifier.height(25.dp), + tint = MaterialTheme.colors.onBackground + ) + } + } + PostButton( onPost = { onClose() - postViewModel.upload(context) + postViewModel.upload(context, relayList) postViewModel.selectedServer?.let { account.changeDefaultFileServer(it) } }, isActive = postViewModel.canPost() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index ce20c7400..7f0649c2f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -300,7 +300,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n url, account.defaultFileServer, onAdd = { description, server, sensitiveContent -> - postViewModel.upload(url, description, sensitiveContent, server, context) + postViewModel.upload(url, description, sensitiveContent, server, context, relayList) account.changeDefaultFileServer(server) }, onCancel = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index dcaa20007..5c366c367 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -194,7 +194,7 @@ open class NewPostViewModel() : ViewModel() { cancel() } - fun upload(galleryUri: Uri, description: String, sensitiveContent: Boolean, server: ServersAvailable, context: Context) { + fun upload(galleryUri: Uri, description: String, sensitiveContent: Boolean, server: ServersAvailable, context: Context, relayList: List? = null) { isUploadingImage = true contentToAddUrl = null @@ -209,7 +209,7 @@ open class NewPostViewModel() : ViewModel() { onReady = { fileUri, contentType, size -> if (server == ServersAvailable.NIP95) { contentResolver.openInputStream(fileUri)?.use { - createNIP95Record(it.readBytes(), contentType, description, sensitiveContent) + createNIP95Record(it.readBytes(), contentType, description, sensitiveContent, relayList = relayList) } } else { ImageUploader.uploadImage( @@ -385,7 +385,7 @@ open class NewPostViewModel() : ViewModel() { } } - fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean) { + fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean, relayList: List? = null) { viewModelScope.launch(Dispatchers.IO) { // Images don't seem to be ready immediately after upload FileHeader.prepare( @@ -394,7 +394,7 @@ open class NewPostViewModel() : ViewModel() { description, sensitiveContent, onReady = { - val note = account?.sendHeader(it) + val note = account?.sendHeader(it, relayList = relayList) isUploadingImage = false @@ -416,7 +416,7 @@ open class NewPostViewModel() : ViewModel() { } } - fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean) { + fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean, relayList: List? = null) { viewModelScope.launch(Dispatchers.IO) { FileHeader.prepare( bytes, @@ -426,7 +426,7 @@ open class NewPostViewModel() : ViewModel() { sensitiveContent, onReady = { val nip95 = account?.createNip95(bytes, headerInfo = it) - val note = nip95?.let { it1 -> account?.sendNip95(it1.first, it1.second) } + val note = nip95?.let { it1 -> account?.sendNip95(it1.first, it1.second, relayList = relayList) } isUploadingImage = false