mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-09 18:32:37 +02:00
Support for video uploads.
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
package com.vitorpamplona.amethyst.ui
|
package com.vitorpamplona.amethyst.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
@@ -94,3 +97,13 @@ class MainActivity : FragmentActivity() {
|
|||||||
ServiceManager.cleanUp()
|
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/*"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -19,13 +19,16 @@ object ImageUploader {
|
|||||||
onError: (Throwable) -> Unit
|
onError: (Throwable) -> Unit
|
||||||
) {
|
) {
|
||||||
val contentType = contentResolver.getType(uri)
|
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 client = OkHttpClient.Builder().build()
|
||||||
|
|
||||||
val requestBody: RequestBody = MultipartBody.Builder()
|
val requestBody: RequestBody = MultipartBody.Builder()
|
||||||
.setType(MultipartBody.FORM)
|
.setType(MultipartBody.FORM)
|
||||||
.addFormDataPart(
|
.addFormDataPart(
|
||||||
"image",
|
category,
|
||||||
"${UUID.randomUUID()}",
|
"${UUID.randomUUID()}",
|
||||||
object : RequestBody() {
|
object : RequestBody() {
|
||||||
override fun contentType(): MediaType? =
|
override fun contentType(): MediaType? =
|
||||||
@@ -46,7 +49,7 @@ object ImageUploader {
|
|||||||
val request: Request = Request.Builder()
|
val request: Request = Request.Builder()
|
||||||
.header("Authorization", "Client-ID e6aea87296f3f96")
|
.header("Authorization", "Client-ID e6aea87296f3f96")
|
||||||
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
||||||
.url("https://api.imgur.com/3/image")
|
.url(url)
|
||||||
.post(requestBody)
|
.post(requestBody)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@@ -14,6 +14,8 @@ import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
|||||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||||
import com.vitorpamplona.amethyst.ui.components.isValidURL
|
import com.vitorpamplona.amethyst.ui.components.isValidURL
|
||||||
import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator
|
import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -140,12 +142,16 @@ class NewPostViewModel : ViewModel() {
|
|||||||
onSuccess = { imageUrl ->
|
onSuccess = { imageUrl ->
|
||||||
isUploadingImage = false
|
isUploadingImage = false
|
||||||
message = TextFieldValue(message.text + "\n\n" + imageUrl)
|
message = TextFieldValue(message.text + "\n\n" + imageUrl)
|
||||||
urlPreview = findUrlInMessage()
|
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
delay(2000)
|
||||||
|
urlPreview = findUrlInMessage()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError = {
|
onError = {
|
||||||
isUploadingImage = false
|
isUploadingImage = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
imageUploadingError.emit("Failed to upload the image")
|
imageUploadingError.emit("Failed to upload the image / video")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@@ -3,7 +3,6 @@ package com.vitorpamplona.amethyst.ui.actions
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.animation.core.LinearEasing
|
import androidx.compose.animation.core.LinearEasing
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
import androidx.compose.animation.core.infiniteRepeatable
|
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.isGranted
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.ui.GetMediaActivityResultContract
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
@OptIn(ExperimentalPermissionsApi::class)
|
@OptIn(ExperimentalPermissionsApi::class)
|
||||||
@@ -150,7 +150,7 @@ fun GallerySelect(
|
|||||||
) {
|
) {
|
||||||
var hasLaunched by remember { mutableStateOf(AtomicBoolean(false)) }
|
var hasLaunched by remember { mutableStateOf(AtomicBoolean(false)) }
|
||||||
val launcher = rememberLauncherForActivityResult(
|
val launcher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.GetContent(),
|
contract = GetMediaActivityResultContract(),
|
||||||
onResult = { uri: Uri? ->
|
onResult = { uri: Uri? ->
|
||||||
onImageUri(uri)
|
onImageUri(uri)
|
||||||
hasLaunched.set(false)
|
hasLaunched.set(false)
|
||||||
@@ -161,7 +161,7 @@ fun GallerySelect(
|
|||||||
fun LaunchGallery() {
|
fun LaunchGallery() {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
if (!hasLaunched.getAndSet(true)) {
|
if (!hasLaunched.getAndSet(true)) {
|
||||||
launcher.launch("image/*")
|
launcher.launch("*/*")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user