From dd9ea5f27eae96b4ca444c34deae7d514de06ab4 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 22 Mar 2023 16:50:18 -0400 Subject: [PATCH] Support for video uploads. --- .../com/vitorpamplona/amethyst/ui/MainActivity.kt | 13 +++++++++++++ .../amethyst/ui/actions/ImageUploader.kt | 7 +++++-- .../amethyst/ui/actions/NewPostViewModel.kt | 10 ++++++++-- .../amethyst/ui/actions/UploadFromGallery.kt | 6 +++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 0b8a19a57..3cc32af87 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -1,8 +1,11 @@ package com.vitorpamplona.amethyst.ui +import android.content.Context +import android.content.Intent import android.os.Build.VERSION.SDK_INT import android.os.Bundle import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface @@ -94,3 +97,13 @@ class MainActivity : FragmentActivity() { ServiceManager.cleanUp() } } + +class GetMediaActivityResultContract : ActivityResultContracts.GetContent() { + + override fun createIntent(context: Context, input: String): Intent { + return super.createIntent(context, input).apply { + // Force only images and videos to be selectable + putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*", "video/*")) + } + } +} 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 7518d15a3..574fef2b1 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 @@ -19,13 +19,16 @@ object ImageUploader { onError: (Throwable) -> Unit ) { val contentType = contentResolver.getType(uri) + val category = contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" + + val url = if (category == "image") "https://api.imgur.com/3/image" else "https://api.imgur.com/3/upload" val client = OkHttpClient.Builder().build() val requestBody: RequestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( - "image", + category, "${UUID.randomUUID()}", object : RequestBody() { override fun contentType(): MediaType? = @@ -46,7 +49,7 @@ object ImageUploader { val request: Request = Request.Builder() .header("Authorization", "Client-ID e6aea87296f3f96") .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") - .url("https://api.imgur.com/3/image") + .url(url) .post(requestBody) .build() 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 225f6f8f7..b8a37000c 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 @@ -14,6 +14,8 @@ import com.vitorpamplona.amethyst.service.model.TextNoteEvent import com.vitorpamplona.amethyst.service.nip19.Nip19 import com.vitorpamplona.amethyst.ui.components.isValidURL import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch @@ -140,12 +142,16 @@ class NewPostViewModel : ViewModel() { onSuccess = { imageUrl -> isUploadingImage = false message = TextFieldValue(message.text + "\n\n" + imageUrl) - urlPreview = findUrlInMessage() + + viewModelScope.launch(Dispatchers.IO) { + delay(2000) + urlPreview = findUrlInMessage() + } }, onError = { isUploadingImage = false viewModelScope.launch { - imageUploadingError.emit("Failed to upload the image") + imageUploadingError.emit("Failed to upload the image / video") } } ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt index d8797f355..652fb0738 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt @@ -3,7 +3,6 @@ package com.vitorpamplona.amethyst.ui.actions import android.net.Uri import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable @@ -28,6 +27,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.GetMediaActivityResultContract import java.util.concurrent.atomic.AtomicBoolean @OptIn(ExperimentalPermissionsApi::class) @@ -150,7 +150,7 @@ fun GallerySelect( ) { var hasLaunched by remember { mutableStateOf(AtomicBoolean(false)) } val launcher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.GetContent(), + contract = GetMediaActivityResultContract(), onResult = { uri: Uri? -> onImageUri(uri) hasLaunched.set(false) @@ -161,7 +161,7 @@ fun GallerySelect( fun LaunchGallery() { SideEffect { if (!hasLaunched.getAndSet(true)) { - launcher.launch("image/*") + launcher.launch("*/*") } } }