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

added enterprise changes to community for preview screen, fixed crash… #32

Merged
merged 4 commits into from
Oct 7, 2021
Merged
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
4 changes: 4 additions & 0 deletions capture/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'

android {
Expand Down Expand Up @@ -50,4 +51,7 @@ dependencies {
implementation libs.androidx.constraintlayout

implementation libs.mavericks

implementation libs.epoxy.core
kapt libs.epoxy.processor
}
46 changes: 39 additions & 7 deletions capture/src/main/kotlin/com/alfresco/capture/CameraFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.camera.core.CameraInfoUnavailableException
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
Expand All @@ -31,6 +32,8 @@ import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import coil.ImageLoader
import coil.fetch.VideoFrameFileFetcher
import com.airbnb.mvrx.MavericksView
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
Expand All @@ -39,6 +42,8 @@ import com.alfresco.content.PermissionFragment
import com.alfresco.content.data.LocationData
import com.alfresco.ui.KeyHandler
import com.alfresco.ui.WindowCompat
import java.io.File
import java.lang.ref.WeakReference
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlinx.coroutines.launch
Expand All @@ -49,20 +54,29 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
private val viewModel: CaptureViewModel by activityViewModel()

private lateinit var layout: CameraLayout

private var discardPhotoDialog = WeakReference<AlertDialog>(null)
private val locationData: LocationData by lazy {
LocationData(requireContext())
}

private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
private var mode: CaptureMode = CaptureMode.Photo
private var cameraProvider: ProcessCameraProvider? = null
private var cameraController: AlfrescoCameraController? = null

/** Blocking camera operations are performed using this executor */
private lateinit var cameraExecutor: ExecutorService

private val imageLoader: ImageLoader by lazy {
ImageLoader.Builder(requireContext())
.componentRegistry {
add(VideoFrameFileFetcher(requireContext()))
}
.build()
}

override fun onResume() {
super.onResume()

// Enter fullscreen
setFullscreen(true)

Expand Down Expand Up @@ -204,6 +218,10 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
layout.shutterButton.simulateClick()
true
}
KeyEvent.KEYCODE_BACK -> {
goBack()
true
}
else -> false
}
}
Expand All @@ -227,11 +245,12 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
// Listener for button used to capture photo
layout.shutterButton.setOnClickListener {
val controller = requireNotNull(cameraController)

if (controller.isImageCaptureEnabled) {
onTakePhotoButtonClick(controller)
} else if (controller.isVideoCaptureEnabled) {
onTakeVideoButtonClick(controller)
} else {
Logger.d("either image or video is on processing")
}
}

Expand Down Expand Up @@ -260,6 +279,13 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
}

layout.closeButton.setOnClickListener {
goBack()
}
}

private fun goBack() {
withState(viewModel) {
viewModel.clearCaptures()
requireActivity().finish()
}
}
Expand Down Expand Up @@ -292,6 +318,7 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
Logger.d("Photo capture succeeded: $savedUri")

viewModel.onCapturePhoto(savedUri)
navigateToSave()
}
Expand Down Expand Up @@ -334,8 +361,14 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
override fun onVideoSaved(output: OutputFileResults) {
val savedUri = output.savedUri ?: Uri.fromFile(videoFile)
Logger.d("Video capture succeeded: $savedUri")
viewModel.onCaptureVideo(savedUri)
navigateToSave()
savedUri.path?.let {
val length = File(it).length()
if (length > 0L) {
viewModel.onCaptureVideo(savedUri)

navigateToSave()
}
}
}

override fun onError(
Expand Down Expand Up @@ -394,7 +427,6 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
layout.flashMenu.isVisible = false

val flashMode = cameraController?.imageCaptureFlashMode ?: viewModel.flashMode
println("CameraFragment.updateFlashControlState $flashMode ${viewModel.flashMode}")
layout.flashButton.setImageResource(flashModeIcon(flashMode))
}

Expand Down Expand Up @@ -423,7 +455,7 @@ class CameraFragment : Fragment(), KeyHandler, MavericksView {
super.onStart()
invokeLocation()
withState(viewModel) {
if (it.capture != null) {
if (it.listCapture.isNotEmpty()) {
layout.captureDurationView.isVisible = false
navigateToSave()
}
Expand Down
136 changes: 117 additions & 19 deletions capture/src/main/kotlin/com/alfresco/capture/CaptureViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package com.alfresco.capture

import android.content.Context
import android.location.Location
import android.net.Uri
import androidx.camera.core.ImageCapture
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.alfresco.content.session.SessionManager
import java.io.File

data class CaptureState(
val capture: CaptureItem? = null
val visibleItem: CaptureItem? = null,
val listCapture: List<CaptureItem> = emptyList()
) : MavericksState

class CaptureViewModel(
val context: Context,
state: CaptureState
) : MavericksViewModel<CaptureState>(state) {
var onSaveComplete: ((List<CaptureItem>) -> Unit)? = null

var longitude = "0"
var latitude = "0"
var onSaveComplete: ((CaptureItem) -> Unit)? = null
private val captureDir = SessionManager.requireSession.captureDir
var mode: CaptureMode = CaptureMode.Photo
var flashMode = ImageCapture.FLASH_MODE_AUTO
Expand All @@ -30,36 +36,57 @@ class CaptureViewModel(

fun clearCaptures() {
captureDir.listFiles()?.forEach { it.delete() }
withState {
it.capture?.let {
setState {
copy(capture = null)
}
setState {
copy(listCapture = emptyList())
}
}

/**
* remove all the capture from the list
*/
fun clearCaptureList() = setState {
copy(listCapture = listOf())
}

/**
* remove capture object from the list and delete it's uri from capture directory
*/
fun clearSingleCaptures(captureItem: CaptureItem) {
captureDir.listFiles()?.forEach {
if (captureItem.uri.toString().contains(it.name)) {
it.delete()
}
}
deleteCapture(captureItem)
}

private fun deleteCapture(captureItem: CaptureItem) =
setState {
copy(listCapture = listCapture.filter {
it.uri != captureItem.uri
})
}

fun prepareCaptureFile(mode: CaptureMode) =
File(captureDir, "${System.currentTimeMillis() / 1000}${extensionFor(mode)}")
File(captureDir, "${System.currentTimeMillis()}${extensionFor(mode)}")

private fun extensionFor(mode: CaptureMode) =
when (mode) {
CaptureMode.Photo -> CaptureItem.PHOTO_EXTENSION
CaptureMode.Video -> CaptureItem.VIDEO_EXTENSION
}

fun save(
filename: String,
description: String
) = withState {
requireNotNull(it.capture)
/**
* send capture list as result to the previous controller
*/
fun save() = withState {
requireNotNull(it.listCapture)

onSaveComplete?.invoke(
it.capture.copy(
name = filename,
description = description
it.listCapture.let { capturedList ->
onSaveComplete?.invoke(
capturedList
)
)
}
}

fun onCapturePhoto(uri: Uri) =
Expand All @@ -69,13 +96,77 @@ class CaptureViewModel(
onCaptureMedia(CaptureItem.videoCapture(uri))

private fun onCaptureMedia(media: CaptureItem) =
setState { copy(capture = media) }
setState {
val list = listCapture + listOf(media)
copy(listCapture = list)
}

fun isFilenameValid(filename: String): Boolean {
val reservedChars = "?:\"*|/\\<>\u0000"
return filename.all { c -> reservedChars.indexOf(c) == -1 }
}

/**
* validate the filename in the give list
*/
fun isAllFileNameValid(listCapture: List<CaptureItem?>): Boolean {

var isValidNotEmpty = false

listCapture.forEach {
it?.let { capture ->
val valid = isFilenameValid(capture.name)
val empty = capture.name.isEmpty()
isValidNotEmpty = valid && !empty
if (!isValidNotEmpty)
return isValidNotEmpty
}
}

return isValidNotEmpty
}

/**
* update the name for the current visible capture on carousel
*/
fun updateName(newFileName: String) = withState {
val newList = it.listCapture.map { captureItem ->
if (captureItem == it.visibleItem) {
val updateCapture = captureItem?.copy(name = newFileName)
setState { copy(visibleItem = updateCapture) }
updateCapture
} else {
captureItem
}
}
setState { copy(listCapture = newList) }
}

/**
* update the description for the current visible capture on carousel
*/
fun updateDescription(newDescription: String) = withState {
val newList = it.listCapture.map { captureItem ->
if (captureItem == it.visibleItem) {
val updateCapture = captureItem?.copy(description = newDescription)
setState { copy(visibleItem = updateCapture) }
updateCapture
} else {
captureItem
}
}
setState { copy(listCapture = newList) }
}

/**
* copy the visible item from the carousel as current item
*/
fun copyVisibleItem(item: CaptureItem) {
setState {
copy(visibleItem = item)
}
}

fun getMetaData(): ImageCapture.Metadata {
val metadata = ImageCapture.Metadata()

Expand All @@ -88,4 +179,11 @@ class CaptureViewModel(

return metadata
}

companion object : MavericksViewModelFactory<CaptureViewModel, CaptureState> {
override fun create(
viewModelContext: ViewModelContext,
state: CaptureState
) = CaptureViewModel(viewModelContext.activity(), state)
}
}
Loading