summaryrefslogtreecommitdiff
path: root/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt
diff options
context:
space:
mode:
Diffstat (limited to 'feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt')
-rw-r--r--feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt118
1 files changed, 107 insertions, 11 deletions
diff --git a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt
index e7b1544..5a43e60 100644
--- a/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt
+++ b/feature/preview/src/main/java/com/google/jetpackcamera/feature/preview/PreviewViewModel.kt
@@ -15,26 +15,37 @@
*/
package com.google.jetpackcamera.feature.preview
+import android.content.ContentResolver
+import android.net.Uri
import android.util.Log
import android.view.Display
-import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview.SurfaceProvider
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import androidx.tracing.traceAsync
import com.google.jetpackcamera.domain.camera.CameraUseCase
+import com.google.jetpackcamera.feature.preview.ui.ToastMessage
import com.google.jetpackcamera.settings.SettingsRepository
import com.google.jetpackcamera.settings.model.AspectRatio
import com.google.jetpackcamera.settings.model.CaptureMode
import com.google.jetpackcamera.settings.model.DEFAULT_CAMERA_APP_SETTINGS
import com.google.jetpackcamera.settings.model.FlashMode
import dagger.hilt.android.lifecycle.HiltViewModel
+import java.lang.Exception
import javax.inject.Inject
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
private const val TAG = "PreviewViewModel"
+private const val IMAGE_CAPTURE_TRACE = "JCA Image Capture"
+
+// toast test descriptions
+const val IMAGE_CAPTURE_SUCCESS_TOAST_TAG = "ImageCaptureSuccessToast"
+const val IMAGE_CAPTURE_FAIL_TOAST_TAG = "ImageCaptureFailureToast"
/**
* [ViewModel] for [PreviewScreen].
@@ -45,7 +56,6 @@ class PreviewViewModel @Inject constructor(
private val settingsRepository: SettingsRepository
// only reads from settingsRepository. do not push changes to repository from here
) : ViewModel() {
-
private val _previewUiState: MutableStateFlow<PreviewUiState> =
MutableStateFlow(PreviewUiState(currentCameraSettings = DEFAULT_CAMERA_APP_SETTINGS))
@@ -54,6 +64,8 @@ class PreviewViewModel @Inject constructor(
private var recordingJob: Job? = null
+ val screenFlash = ScreenFlash(cameraUseCase, viewModelScope)
+
init {
viewModelScope.launch {
settingsRepository.cameraAppSettings.collect {
@@ -112,7 +124,10 @@ class PreviewViewModel @Inject constructor(
)
)
// apply to cameraUseCase
- cameraUseCase.setFlashMode(previewUiState.value.currentCameraSettings.flashMode)
+ cameraUseCase.setFlashMode(
+ previewUiState.value.currentCameraSettings.flashMode,
+ previewUiState.value.currentCameraSettings.isFrontCameraFacing
+ )
}
}
@@ -181,8 +196,10 @@ class PreviewViewModel @Inject constructor(
)
)
// apply to cameraUseCase
- cameraUseCase
- .flipCamera(previewUiState.value.currentCameraSettings.isFrontCameraFacing)
+ cameraUseCase.flipCamera(
+ previewUiState.value.currentCameraSettings.isFrontCameraFacing,
+ previewUiState.value.currentCameraSettings.flashMode
+ )
}
}
}
@@ -190,12 +207,71 @@ class PreviewViewModel @Inject constructor(
fun captureImage() {
Log.d(TAG, "captureImage")
viewModelScope.launch {
- try {
- cameraUseCase.takePicture()
- Log.d(TAG, "cameraUseCase.takePicture success")
- } catch (exception: ImageCaptureException) {
- Log.d(TAG, "cameraUseCase.takePicture error")
- Log.d(TAG, exception.toString())
+ traceAsync(IMAGE_CAPTURE_TRACE, 0) {
+ try {
+ cameraUseCase.takePicture()
+ // todo: remove toast after postcapture screen implemented
+ _previewUiState.emit(
+ previewUiState.value.copy(
+ toastMessageToShow = ToastMessage(
+ stringResource = R.string.toast_image_capture_success,
+ testTag = IMAGE_CAPTURE_SUCCESS_TOAST_TAG
+ )
+ )
+ )
+ Log.d(TAG, "cameraUseCase.takePicture success")
+ } catch (exception: Exception) {
+ // todo: remove toast after postcapture screen implemented
+ _previewUiState.emit(
+ previewUiState.value.copy(
+ toastMessageToShow = ToastMessage(
+ stringResource = R.string.toast_capture_failure,
+ testTag = IMAGE_CAPTURE_FAIL_TOAST_TAG
+ )
+ )
+ )
+ Log.d(TAG, "cameraUseCase.takePicture error")
+ Log.d(TAG, exception.toString())
+ }
+ }
+ }
+ }
+
+ fun captureImage(
+ contentResolver: ContentResolver,
+ imageCaptureUri: Uri?,
+ onImageCapture: (ImageCaptureEvent) -> Unit
+ ) {
+ Log.d(TAG, "captureImageWithUri")
+ viewModelScope.launch {
+ traceAsync(IMAGE_CAPTURE_TRACE, 0) {
+ try {
+ cameraUseCase.takePicture(contentResolver, imageCaptureUri)
+ // todo: remove toast after postcapture screen implemented
+ _previewUiState.emit(
+ previewUiState.value.copy(
+ toastMessageToShow = ToastMessage(
+ stringResource = R.string.toast_image_capture_success,
+ testTag = IMAGE_CAPTURE_SUCCESS_TOAST_TAG
+ )
+ )
+ )
+ onImageCapture(ImageCaptureEvent.ImageSaved)
+ Log.d(TAG, "cameraUseCase.takePicture success")
+ } catch (exception: Exception) {
+ // todo: remove toast after postcapture screen implemented
+ _previewUiState.emit(
+ previewUiState.value.copy(
+ toastMessageToShow = ToastMessage(
+ stringResource = R.string.toast_capture_failure,
+ testTag = IMAGE_CAPTURE_FAIL_TOAST_TAG
+ )
+ )
+ )
+ Log.d(TAG, "cameraUseCase.takePicture error")
+ Log.d(TAG, exception.toString())
+ onImageCapture(ImageCaptureEvent.ImageCaptureError(exception))
+ }
}
}
}
@@ -259,4 +335,24 @@ class PreviewViewModel @Inject constructor(
y = y
)
}
+
+ fun onToastShown() {
+ viewModelScope.launch {
+ // keeps the composable up on screen longer to be detected by UiAutomator
+ delay(2.seconds)
+ _previewUiState.emit(
+ previewUiState.value.copy(
+ toastMessageToShow = null
+ )
+ )
+ }
+ }
+
+ sealed interface ImageCaptureEvent {
+ object ImageSaved : ImageCaptureEvent
+
+ data class ImageCaptureError(
+ val exception: Exception
+ ) : ImageCaptureEvent
+ }
}