Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Start video recording on camera icon clicked when "OnlyVideo" is enabled #411

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener

override fun onPrepareOptionsMenu(menu: Menu): Boolean {
if (!isCameraOnly) {
menu.findItem(R.id.menu_camera).isVisible = config?.isShowCamera ?: true
menu.findItem(R.id.menu_camera).isVisible =
config?.isShowCamera == true && config?.isOnlyVideo == false
menu.findItem(R.id.menu_video).isVisible = config?.isShowVideoCamera ?: true
menu.findItem(R.id.menu_done).apply {
title = ConfigUtils.getDoneButtonText(this@ImagePickerActivity, config!!)
isVisible = imagePickerFragment.isShowDoneButton
Expand All @@ -113,6 +115,10 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
imagePickerFragment.captureImage()
return true
}
if (id == R.id.menu_video) {
imagePickerFragment.captureVideo()
return true
}
return super.onOptionsItemSelected(item)
}

Expand Down Expand Up @@ -179,4 +185,4 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
setResult(RESULT_OK, result)
finish()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ object ImagePickerComponentsHolder : ImagePickerComponents {
fun setInternalComponent(components: ImagePickerComponents) {
internalComponents = components
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ class ImagePickerConfig(
var isOnlyVideo: Boolean = false,
var isIncludeAnimation: Boolean = false,
var isShowCamera: Boolean = true,
var isShowVideoCamera: Boolean = false,
var selectedImages: List<Image> = emptyList(),
var excludedImages: List<File> = emptyList(),
override var savePath: ImagePickerSavePath = ImagePickerSavePath.DEFAULT,
override var returnMode: ReturnMode = ReturnMode.NONE,
override var isSaveImage: Boolean = true,
override var isSaveVideo: Boolean = true,
var showDoneButtonAlways: Boolean = false
) : BaseConfig(), Parcelable {

Expand All @@ -50,4 +52,4 @@ fun ImagePickerConfig.enableLog(isEnable: Boolean) {
IpLogger.setEnable(isEnable)
}

fun List<Image>.toFiles() = this.map { File(it.path) }
fun List<Image>.toFiles() = this.map { File(it.path) }
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,18 @@ class ImagePickerFragment : Fragment() {
if (!checkCameraAvailability(requireActivity())) {
return
}
presenter.captureImage(this, config, RC_CAPTURE)
if (config.isOnlyVideo) {
presenter.captureVideo(this, config, RC_CAPTURE)
} else {
presenter.captureImage(this, config, RC_CAPTURE)
}
}

fun captureVideo() {
if (!checkCameraAvailability(requireActivity())) {
return
}
presenter.captureVideo(this, config, RC_CAPTURE)
}

override fun onDestroy() {
Expand Down Expand Up @@ -391,4 +402,4 @@ class ImagePickerFragment : Fragment() {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ internal class ImagePickerPresenter(
) : ImagePickerAction {

private val cameraModule: CameraModule = ImagePickerComponentsHolder.cameraModule

private val stateObs = LiveDataObservableState(
ImagePickerState(isLoading = true),
usePostValue = true
Expand Down Expand Up @@ -95,6 +94,20 @@ internal class ImagePickerPresenter(
fragment.startActivityForResult(intent, requestCode)
}

fun captureVideo(fragment: Fragment, config: BaseConfig, requestCode: Int) {
val context = fragment.requireContext().applicationContext
val intent = cameraModule.getVideoCameraIntent(fragment.requireContext(), config)
if (intent == null) {
Toast.makeText(
context,
context.getString(R.string.ef_error_create_image_file),
esafirm marked this conversation as resolved.
Show resolved Hide resolved
Toast.LENGTH_LONG
).show()
return
}
fragment.startActivityForResult(intent, requestCode)
}

fun finishCaptureImage(context: Context, data: Intent?, config: BaseConfig?) {
cameraModule.getImage(context, data) { images ->
if (ConfigUtils.shouldReturn(config!!, true)) {
Expand All @@ -112,4 +125,4 @@ internal class ImagePickerPresenter(
fun abortCaptureImage(context: Context) {
cameraModule.removeImage(context)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ typealias OnImageReadyListener = (List<Image>?) -> Unit

interface CameraModule {
fun getCameraIntent(context: Context, config: BaseConfig): Intent?
fun getVideoCameraIntent(context: Context, config: BaseConfig): Intent?
fun getImage(context: Context, intent: Intent?, imageReadyListener: OnImageReadyListener)
fun removeImage(context: Context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ class DefaultCameraModule : CameraModule {
return intent
}

override fun getVideoCameraIntent(context: Context, config: BaseConfig): Intent? {
prepareForNewIntent()

val intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
val imageFile = ImagePickerUtils.createVideoFile(config.savePath, context)

if (config.isSaveVideo && imageFile != null) {
val appContext = context.applicationContext
val uri = createVideoUri(appContext, imageFile)
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
ImagePickerUtils.grantAppPermission(context, intent, uri)
currentUri = uri.toString()
}
return intent
}

private fun prepareForNewIntent() {
currentImagePath = null
currentUri = null
Expand All @@ -55,6 +71,21 @@ class DefaultCameraModule : CameraModule {
return UriUtils.uriForFile(appContext, imageFile)
}

private fun createVideoUri(appContext: Context, videoFile: File): Uri? {
currentImagePath = "file:" + videoFile.absolutePath
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

val values = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, videoFile.name)
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
}
val collection =
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
return appContext.contentResolver.insert(collection, values)
}
return UriUtils.uriForFile(appContext, videoFile)
}

override fun getImage(
context: Context,
intent: Intent?,
Expand Down Expand Up @@ -109,4 +140,4 @@ class DefaultCameraModule : CameraModule {
e.printStackTrace()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ import kotlinx.android.parcel.Parcelize
class CameraOnlyConfig(
override var savePath: ImagePickerSavePath = ImagePickerSavePath.DEFAULT,
override var returnMode: ReturnMode = ReturnMode.ALL,
override var isSaveImage: Boolean = true
override var isSaveImage: Boolean = true,
override var isSaveVideo: Boolean = true
) : BaseConfig(), Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ abstract class BaseConfig {
abstract var savePath: ImagePickerSavePath
abstract var returnMode: ReturnMode
abstract var isSaveImage: Boolean
abstract var isSaveVideo: Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,27 @@ object ImagePickerUtils {
return mediaStorageDir
}

private fun createFileInDirectoryVideo(savePath: ImagePickerSavePath, context: Context): File? {
val path = savePath.path
val mediaStorageDir: File = if (savePath.isRelative) {
val parent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
} else {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
}
File(parent, path)
} else {
File(path)
}
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
d("Oops! Failed create $path")
return null
}
}
return mediaStorageDir
}

fun createImageFile(savePath: ImagePickerSavePath, context: Context): File? {
val mediaStorageDir = createFileInDirectory(savePath, context) ?: return null

Expand All @@ -62,6 +83,18 @@ object ImagePickerUtils {
return result
}

fun createVideoFile(savePath: ImagePickerSavePath, context: Context): File? {
val mediaStorageDir = createFileInDirectoryVideo(savePath, context) ?: return null
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.getDefault()).format(Date())
var result = File(mediaStorageDir, "VID_$timeStamp.mp4")
var counter = 0
while (result.exists()) {
counter++
result = File(mediaStorageDir, "VID_$timeStamp($counter).mp4")
}
return result
}

fun getNameFromFilePath(path: String): String {
return if (path.contains(File.separator)) {
path.substring(path.lastIndexOf(File.separator) + 1)
Expand Down
12 changes: 12 additions & 0 deletions imagepicker/src/main/res/drawable/ef_video_placeholder.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="1.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
</vector>
6 changes: 6 additions & 0 deletions imagepicker/src/main/res/menu/ef_image_picker_menu_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
app:showAsAction="always"
tools:ignore="AlwaysShowAction" />

<item
android:id="@+id/menu_video"
android:icon="@drawable/ef_video_placeholder"
android:title="@string/ef_video"
app:showAsAction="always"/>

<item
android:id="@+id/menu_done"
android:title="@string/ef_done"
Expand Down
2 changes: 2 additions & 0 deletions imagepicker/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">وافق</string>
<string name="ef_done">انهي</string>
<string name="ef_camera">كاميرا</string>
<string name="ef_video">فيديو</string>

<string name="ef_title_folder">دليل</string>
<string name="ef_title_select_image">أنقر لإختيار الصور</string>
Expand All @@ -14,6 +15,7 @@
<string name="ef_selected_with_limit">إخترت %1$d/%2$d</string>

<string name="ef_error_create_image_file">حدث خطأ في تسجيل الصوره</string>
<string name="ef_error_create_video_file">فشل إنشاء ملف الفيديو</string>
<string name="ef_error_no_camera">لا يوجد كاميرا</string>
<string name="ef_error_null_cursor">عذراً، هناك خطأ ما!</string>

Expand Down
3 changes: 3 additions & 0 deletions imagepicker/src/main/res/values-ca/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">OK</string>
<string name="ef_done">FET</string>
<string name="ef_camera">CÀMERA</string>
<string name="ef_video">VÍDEO</string>

<string name="ef_title_folder">Carpeta</string>
<string name="ef_title_select_image">Toqueu per seleccionar imatges</string>
Expand All @@ -14,6 +15,8 @@
<string name="ef_selected_with_limit">%1$d/%2$d seleccionades</string>

<string name="ef_error_create_image_file">Error al crear el fitxer d\'imatge</string>
<string name="ef_error_create_video_file">No s\'ha pogut crear el fitxer de vídeo</string>

<string name="ef_error_no_camera">No s\'ha trobat cap càmera</string>
<string name="ef_error_null_cursor">Oops, alguna cosa no ha anat bé!</string>

Expand Down
5 changes: 4 additions & 1 deletion imagepicker/src/main/res/values-da/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">Ok</string>
<string name="ef_done">Færdig</string>
<string name="ef_camera">Kamera</string>
<string name="ef_video">VIDEO</string>

<string name="ef_title_folder">Mappe</string>
<string name="ef_title_select_image">Tryk for at vælge billeder</string>
Expand All @@ -14,6 +15,8 @@
<string name="ef_selected_with_limit">%1$d/%2$d valgt</string>

<string name="ef_error_create_image_file">Fejl, kunne ikke oprette billedfilen</string>
<string name="ef_error_create_video_file">Kunne ikke oprette videofil</string>

<string name="ef_error_no_camera">Kamera blev ikke fundet</string>
<string name="ef_error_null_cursor">Beklager, der er sket en fejl!</string>

Expand All @@ -27,4 +30,4 @@
<string name="ef_content_desc_folder" translatable="false">Folder</string>
<string name="ef_content_desc_image" translatable="false">Image</string>

</resources>
</resources>
2 changes: 2 additions & 0 deletions imagepicker/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">OK</string>
<string name="ef_done">FERTIG</string>
<string name="ef_camera">KAMERA</string>
<string name="ef_video">VIDEO</string>

<string name="ef_title_folder">Verzeichnis</string>
<string name="ef_title_select_image">Tippen um Bilder auszuwählen</string>
Expand All @@ -14,6 +15,7 @@
<string name="ef_selected_with_limit">%1$d/%2$d ausgewählt</string>

<string name="ef_error_create_image_file">Fehler beim Erstellen der Bilddatei</string>
<string name="ef_error_create_video_file">Videodatei konnte nicht erstellt werden</string>
<string name="ef_error_no_camera">Keine Kamera gefunden</string>
<string name="ef_error_null_cursor">Ups, da ist was schiefgegangen!</string>

Expand Down
2 changes: 2 additions & 0 deletions imagepicker/src/main/res/values-es-rES/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">OK</string>
<string name="ef_done">HECHO</string>
<string name="ef_camera">CÁMARA</string>
<string name="ef_video">VIDEO</string>

<string name="ef_title_folder">Carpeta</string>
<string name="ef_title_select_image">Toque para seleccionar imágenes</string>
Expand All @@ -14,6 +15,7 @@
<string name="ef_selected_with_limit">%1$d/%2$d seleccionadas</string>

<string name="ef_error_create_image_file">Error al crear el fichero de imágen</string>
<string name="ef_error_create_video_file">No se pudo crear el archivo de video</string>
<string name="ef_error_no_camera">No se encontró la cámara</string>
<string name="ef_error_null_cursor">Oops, algo ha ido mal!</string>

Expand Down
2 changes: 2 additions & 0 deletions imagepicker/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">OK</string>
<string name="ef_done">TERMINER</string>
<string name="ef_camera">CAMERA</string>
<string name="ef_video">VIDÉO</string>

<string name="ef_title_folder">Dossier</string>
<string name="ef_title_select_image">Toucher pour sélectionner des images</string>
Expand All @@ -14,6 +15,7 @@
<string name="ef_selected_with_limit">%1$d/%2$d sélectionnées</string>

<string name="ef_error_create_image_file">Impossible de créer le fichier photo</string>
<string name="ef_error_create_video_file">Échec de la création du fichier vidéo</string>
<string name="ef_error_no_camera">Aucune caméra détectée</string>
<string name="ef_error_null_cursor">Oups, quelque chose s\'est mal déroulé!</string>

Expand Down
2 changes: 2 additions & 0 deletions imagepicker/src/main/res/values-in/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="ef_ok">OK</string>
<string name="ef_done">SELESAI</string>
<string name="ef_camera">KAMERA</string>
<string name="ef_video">VIDEO</string>

<string name="ef_title_folder">Folder</string>
<string name="ef_title_select_image">Ketuk untuk memilih gambar</string>
Expand All @@ -14,6 +15,7 @@
<string name="ef_selected_with_limit">%1$d/%2$d terpilih</string>

<string name="ef_error_create_image_file">Gagal membuat berkas gambar</string>
<string name="ef_error_create_video_file">Gagal membuat file video</string>
<string name="ef_error_no_camera">Kamera tidak ditemukan</string>
<string name="ef_error_null_cursor">Ups, ada yang tidak beres!</string>

Expand Down
Loading