diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt
index 7dd5bb23f..766056a87 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt
@@ -1,14 +1,20 @@
package com.vitorpamplona.amethyst.ui.actions
import android.content.ContentResolver
+import android.content.Context
import android.net.Uri
+import android.provider.OpenableColumns
+import android.util.Log
import android.webkit.MimeTypeMap
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.vitorpamplona.amethyst.BuildConfig
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody.Companion.asRequestBody
import okio.BufferedSink
import okio.source
+import java.io.File
+import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
@@ -21,68 +27,88 @@ object ImageUploader {
fun uploadImage(
uri: Uri,
server: ServersAvailable,
+ context: Context,
contentResolver: ContentResolver,
onSuccess: (String, String?) -> Unit,
onError: (Throwable) -> Unit
) {
val contentType = contentResolver.getType(uri)
val imageInputStream = contentResolver.openInputStream(uri)
-
checkNotNull(imageInputStream) {
"Can't open the image input stream"
}
-
val myServer = if (server == ServersAvailable.IMGUR) {
ImgurServer()
} else if (server == ServersAvailable.NOSTRIMG) {
NostrImgServer()
+ } else if (server == ServersAvailable.NOSTR_BUILD) {
+ NostrBuildServer()
} else {
ImgurServer()
}
- uploadImage(imageInputStream, contentType, myServer, onSuccess, onError)
+ val file = getRealPathFromURI(uri, context)?.let { File(it) } // create path from uri
+ if (file != null) {
+ uploadImage(file, imageInputStream, contentType, myServer, server, onSuccess, onError)
+ }
}
fun uploadImage(
+ file: File,
inputStream: InputStream,
contentType: String?,
server: FileServer,
+ serverType: ServersAvailable,
onSuccess: (String, String?) -> Unit,
onError: (Throwable) -> Unit
) {
val category = contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image"
+
val fileName = randomChars()
val extension = contentType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } ?: ""
val client = OkHttpClient.Builder().build()
-
- val requestBody: RequestBody = MultipartBody.Builder()
- .setType(MultipartBody.FORM)
- .addFormDataPart(
- category,
- "$fileName.$extension",
- object : RequestBody() {
- override fun contentType(): MediaType? =
- contentType?.toMediaType()
-
- override fun writeTo(sink: BufferedSink) {
- inputStream.source().use(sink::writeAll)
- }
- }
- )
- .build()
-
+ val requestBody: RequestBody
val requestBuilder = Request.Builder()
+ if (serverType == ServersAvailable.NOSTR_BUILD) {
+ requestBuilder.addHeader("Content-Type", "multipart/form-data")
+ requestBody = MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .addFormDataPart(
+ "fileToUpload",
+ "$fileName.$extension",
+ file.asRequestBody(contentType?.toMediaType())
+
+ )
+ .build()
+ } else {
+ requestBody = MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .addFormDataPart(
+ category,
+ "$fileName.$extension",
+
+ object : RequestBody() {
+ override fun contentType(): MediaType? =
+ contentType?.toMediaType()
+
+ override fun writeTo(sink: BufferedSink) {
+ inputStream.source().use(sink::writeAll)
+ }
+ }
+ )
+ .build()
+ }
+
server.clientID()?.let {
- requestBuilder.header("Authorization", it)
+ requestBuilder.addHeader("Authorization", it)
}
requestBuilder
- .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
+ .addHeader("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
.url(server.postUrl(contentType))
.post(requestBody)
-
val request = requestBuilder.build()
client.newCall(request).enqueue(object : Callback {
@@ -111,6 +137,38 @@ object ImageUploader {
}
}
+fun getRealPathFromURI(uri: Uri, context: Context): String? {
+ val returnCursor = context.contentResolver.query(uri, null, null, null, null)
+ val nameIndex = returnCursor!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
+ returnCursor.moveToFirst()
+ val name = returnCursor.getString(nameIndex)
+ val file = File(context.filesDir, name)
+ try {
+ val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
+ val outputStream = FileOutputStream(file)
+ var read = 0
+ val maxBufferSize = 1 * 1024 * 1024
+ val bytesAvailable: Int = inputStream?.available() ?: 0
+ val bufferSize = Math.min(bytesAvailable, maxBufferSize)
+ val buffers = ByteArray(bufferSize)
+ while (inputStream?.read(buffers).also {
+ if (it != null) {
+ read = it
+ }
+ } != -1
+ ) {
+ outputStream.write(buffers, 0, read)
+ }
+ Log.e("File Size", "Size " + file.length())
+ inputStream?.close()
+ outputStream.close()
+ Log.e("File Path", "Path " + file.path)
+ } catch (e: java.lang.Exception) {
+ Log.e("Exception", e.message!!)
+ }
+ return file.path
+}
+
abstract class FileServer {
abstract fun postUrl(contentType: String?): String
abstract fun parseUrlFromSucess(body: String): String?
@@ -146,12 +204,10 @@ class ImgurServer : FileServer() {
}
class NostrBuildServer : FileServer() {
- override fun postUrl(contentType: String?) = "https://nostr.build/api/upload/amethyst.php"
-
+ override fun postUrl(contentType: String?) = "https://nostr.build/api/upload/android.php"
override fun parseUrlFromSucess(body: String): String? {
- val tree = jacksonObjectMapper().readTree(body)
- val url = tree?.get("data")?.get("link")?.asText()
- return url
+ val url = jacksonObjectMapper().readTree(body) // return url.toString()
+ return url.toString().replace("\"", "")
}
override fun clientID() = null
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 880192257..9827c6bb2 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
@@ -44,6 +44,8 @@ open class NewMediaModel : ViewModel() {
selectedServer = ServersAvailable.IMGUR_NIP_94
} else if (selectedServer == ServersAvailable.NOSTRIMG) {
selectedServer = ServersAvailable.NOSTRIMG_NIP_94
+ } else if (selectedServer == ServersAvailable.NOSTR_BUILD) {
+ selectedServer = ServersAvailable.NOSTR_BUILD_NIP_94
}
}
@@ -75,6 +77,7 @@ open class NewMediaModel : ViewModel() {
ImageUploader.uploadImage(
uri = uri,
server = serverToUse,
+ context = context,
contentResolver = contentResolver,
onSuccess = { imageUrl, mimeType ->
createNIP94Record(imageUrl, mimeType, description)
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 477ca586d..c1489f126 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
@@ -116,6 +116,7 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) {
val fileServers = listOf(
Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)),
Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)),
+ Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)),
Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer))
)
@@ -192,6 +193,7 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) {
if (postViewModel.selectedServer == ServersAvailable.NOSTRIMG_NIP_94 ||
postViewModel.selectedServer == ServersAvailable.IMGUR_NIP_94 ||
+ postViewModel.selectedServer == ServersAvailable.NOSTR_BUILD_NIP_94 ||
postViewModel.selectedServer == ServersAvailable.NIP95
) {
Row(
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 e6fe1e9a4..370bf8728 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
@@ -590,6 +590,7 @@ enum class ServersAvailable {
NOSTRIMG,
IMGUR_NIP_94,
NOSTRIMG_NIP_94,
+ NOSTR_BUILD_NIP_94,
NIP95
}
@@ -610,8 +611,10 @@ fun ImageVideoDescription(
val fileServers = listOf(
Triple(ServersAvailable.IMGUR, stringResource(id = R.string.upload_server_imgur), stringResource(id = R.string.upload_server_imgur_explainer)),
Triple(ServersAvailable.NOSTRIMG, stringResource(id = R.string.upload_server_nostrimg), stringResource(id = R.string.upload_server_nostrimg_explainer)),
+ Triple(ServersAvailable.NOSTR_BUILD, stringResource(id = R.string.upload_server_nostrbuild), stringResource(id = R.string.upload_server_nostrbuild_explainer)),
Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)),
Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)),
+ Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)),
Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer))
)
@@ -741,6 +744,7 @@ fun ImageVideoDescription(
if (selectedServer == ServersAvailable.NOSTRIMG_NIP_94 ||
selectedServer == ServersAvailable.IMGUR_NIP_94 ||
+ selectedServer == ServersAvailable.NOSTR_BUILD_NIP_94 ||
selectedServer == ServersAvailable.NIP95
) {
Row(
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 fd38e3031..42590becc 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
@@ -145,9 +145,10 @@ open class NewPostViewModel : ViewModel() {
ImageUploader.uploadImage(
uri = it,
server = server,
+ context = context,
contentResolver = contentResolver,
onSuccess = { imageUrl, mimeType ->
- if (server == ServersAvailable.IMGUR_NIP_94 || server == ServersAvailable.NOSTRIMG_NIP_94) {
+ if (server == ServersAvailable.IMGUR_NIP_94 || server == ServersAvailable.NOSTRIMG_NIP_94 || server == ServersAvailable.NOSTR_BUILD_NIP_94) {
createNIP94Record(imageUrl, mimeType, description)
} else {
isUploadingImage = false
diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt
index 269f22871..80abdf2cf 100644
--- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt
+++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt
@@ -171,6 +171,7 @@ class NewUserMetadataViewModel : ViewModel() {
ImageUploader.uploadImage(
uri = it,
server = account.defaultFileServer,
+ context = context,
contentResolver = context.contentResolver,
onSuccess = { imageUrl, mimeType ->
onUploading(false)
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index b85757a84..e4760f5af 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -280,9 +280,56 @@
"Zoeken naar event %1$s"
Een openbaar bericht toevoegen
+ Een privébericht toevoegen
+ Een invoice bericht toevoegen
Bedankt voor al jullie werk!
Maken en toevoegen
Poll auteurs kunnen niet stemmen in hun eigen poll.
#zappoll
+
+ De afbeelding is onveranderd sinds de post
+ De afbeelding is veranderd. De auteur heeft de wijziging misschien niet gezien
+
+ Afbeelding toevoegen
+ Video toevoegen
+ Document toevoegen
+
+ Voeg toe aan bericht
+ Beschrijving van de inhoud
+ Een blauwe boot in een wit zandstrand bij zonsondergang
+
+ Zap type
+ Zap type voor alle opties
+
+ Publiek
+ Iedereen kan de transactie en het bericht zien
+
+ Privé
+ Verzender en ontvanger kunnen elkaar zien en het bericht lezen
+
+ Anoniem
+ Ontvanger en het publiek weten niet wie de betaling verzond
+
+ Non-Zap
+ Geen spoor binnen Nostr, alleen in Lightning
+
+
+ File server
+ LnAddress of @User
+
+ imgur.com - minder beveiligd
+ Upload naar Imgur. Imgur kan uw afbeelding/video op elk moment wijzigen
+
+ nostrimg.com - minder beveiligd
+ Upload naar NostrImg. NostrImg kan uw afbeelding/video op elk moment wijzigen
+
+ Verifieerbare Imgur (NIP-94)
+ Beschermt tegen het achteraf wijzigen van de inhoud door Imgur. Dit is een nieuwe NIP: andere clients zien de afbeelding misschien niet.
+
+ Verifieerbare NostrImg (NIP-94)
+ Beschermt tegen het achteraf wijzigen van de inhoud door NostrImg. Dit is een nieuwe NIP: andere clients zien de afbeelding misschien niet.
+
+ Uw relays (NIP-95)
+ Bestanden worden geüpload naar en gehost door relays. Ze zijn vrij van een vaste url (afhankelijkheid van derden). Zorg ervoor dat u een NIP-95 relay in uw lijst met relays hebt.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 64fcffb60..cbc905e1d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -333,12 +333,18 @@
nostrimg.com - less secure
Uploads to NostrImg. NostrImg can change your image at any time
+ nostr.build- less secure
+ Uploads to nostr.build. Nostr.build can change your image at any time
+
Verifiable Imgur (NIP-94)
Protects from Imgur modifying the content afterwards. This is a new NIP: other clients might not see the image
Verifiable NostrImg (NIP-94)
Protects from NostrImg modifying the content afterwards. This is a new NIP: other clients might not see the image
+ Verifiable Nostr.build (NIP-94)
+ Protects from Nostr.build modifying the content afterwards. This is a new NIP: other clients might not see the image
+
Your relays (NIP-95)
Files are uploaded to and hosted by relays. They are free from a fixed url (third-party dependency). Make sure to have a NIP-95 relay in your relay list