[Media upload] Media pre-processing (#403)

* Create `mediaupload` module for media pre-processing.

* Split `mediapicker` and `mediaupload` modules.
This commit is contained in:
Jorge Martin Espinosa 2023-05-10 10:06:56 +02:00 committed by GitHub
parent 7c02e7ad4b
commit 5eaa40a14b
33 changed files with 1148 additions and 156 deletions

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.mediapickers.api
import androidx.activity.compose.ManagedActivityResultLauncher
/**
* Wrapper around [ManagedActivityResultLauncher] to be used with media/file pickers.
*/
interface PickerLauncher<Input, Output> {
/** Starts the activity result launcher with its default input. */
fun launch()
/** Starts the activity result launcher with a [customInput]. */
fun launch(customInput: Input)
}
class ComposePickerLauncher<Input, Output>(
private val managedLauncher: ManagedActivityResultLauncher<Input, Output>,
private val defaultRequest: Input,
) : PickerLauncher<Input, Output> {
override fun launch() {
managedLauncher.launch(defaultRequest)
}
override fun launch(customInput: Input) {
managedLauncher.launch(customInput)
}
}
/** Needed for screenshot tests. */
class NoOpPickerLauncher<Input, Output>(
private val onResult: () -> Unit,
) : PickerLauncher<Input, Output> {
override fun launch() = onResult()
override fun launch(customInput: Input) = onResult()
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.mediapickers.api
import android.net.Uri
import androidx.activity.result.PickVisualMediaRequest
import androidx.compose.runtime.Composable
interface PickerProvider {
@Composable
fun registerGalleryPicker(
onResult: (uri: Uri?, mimeType: String?) -> Unit
): PickerLauncher<PickVisualMediaRequest, Uri?>
@Composable
fun registerFilePicker(
mimeType: String,
onResult: (Uri?) -> Unit
): PickerLauncher<String, Uri?>
@Composable
fun registerCameraPhotoPicker(onResult: (Uri?) -> Unit): PickerLauncher<Uri, Boolean>
@Composable
fun registerCameraVideoPicker(onResult: (Uri?) -> Unit): PickerLauncher<Uri, Boolean>
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.mediapickers.api
import android.net.Uri
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
import io.element.android.libraries.core.mimetype.MimeTypes
sealed interface PickerType<Input, Output> {
fun getContract(): ActivityResultContract<Input, Output>
fun getDefaultRequest(): Input
object ImageAndVideo : PickerType<PickVisualMediaRequest, Uri?> {
override fun getContract() = ActivityResultContracts.PickVisualMedia()
override fun getDefaultRequest(): PickVisualMediaRequest {
return PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageAndVideo)
}
}
object Camera {
data class Photo(val destUri: Uri) : PickerType<Uri, Boolean> {
override fun getContract() = ActivityResultContracts.TakePicture()
override fun getDefaultRequest(): Uri {
return destUri
}
}
data class Video(val destUri: Uri) : PickerType<Uri, Boolean> {
override fun getContract() = ActivityResultContracts.CaptureVideo()
override fun getDefaultRequest(): Uri {
return destUri
}
}
}
data class File(val mimeType: String = MimeTypes.Any) : PickerType<String, Uri?> {
override fun getContract() = ActivityResultContracts.GetContent()
override fun getDefaultRequest(): String {
return mimeType
}
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.mediapickers
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContracts
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.mediapickers.api.PickerType
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class PickerTypeTests {
@Test
fun `ImageAndVideo - assert types`() {
val pickerType = PickerType.ImageAndVideo
assertThat(pickerType.getContract()).isInstanceOf(ActivityResultContracts.PickVisualMedia::class.java)
assertThat(pickerType.getDefaultRequest().mediaType).isEqualTo(ActivityResultContracts.PickVisualMedia.ImageAndVideo)
}
@Test
fun `File - assert types`() {
val pickerType = PickerType.File()
assertThat(pickerType.getContract()).isInstanceOf(ActivityResultContracts.GetContent::class.java)
assertThat(pickerType.getDefaultRequest()).isEqualTo(MimeTypes.Any)
val mimeType = MimeTypes.Images
val customPickerType = PickerType.File(mimeType)
assertThat(customPickerType.getContract()).isInstanceOf(ActivityResultContracts.GetContent::class.java)
assertThat(customPickerType.getDefaultRequest()).isEqualTo(mimeType)
}
@Test
fun `CameraPhoto - assert types`() {
val uri = Uri.parse("file:///tmp/test")
val pickerType = PickerType.Camera.Photo(uri)
assertThat(pickerType.getContract()).isInstanceOf(ActivityResultContracts.TakePicture::class.java)
assertThat(pickerType.getDefaultRequest()).isEqualTo(uri)
}
@Test
fun `CameraVideo - assert types`() {
val uri = Uri.parse("file:///tmp/test")
val pickerType = PickerType.Camera.Video(uri)
assertThat(pickerType.getContract()).isInstanceOf(ActivityResultContracts.CaptureVideo::class.java)
assertThat(pickerType.getDefaultRequest()).isEqualTo(uri)
}
}