diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt b/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt index 3381dcd5..a3bb9584 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt @@ -19,6 +19,7 @@ package com.google.android.samples.socialite.ui.camera import android.Manifest import android.annotation.SuppressLint import android.view.Surface +import android.widget.Toast import androidx.camera.core.CameraSelector import androidx.camera.core.Preview import androidx.camera.view.RotationProvider @@ -91,6 +92,18 @@ fun Camera( val lifecycleOwner = LocalLifecycleOwner.current val context = LocalContext.current + LaunchedEffect(lifecycleOwner, context) { + viewModel.imageCaptureState.collect { state -> + when (state) { + ImageCaptureState.IMAGE_CAPTURE_SUCCESS -> + Toast.makeText(context, "Photo saved.", Toast.LENGTH_SHORT).show() + ImageCaptureState.IMAGE_CAPTURE_FAIL -> + Toast.makeText(context, "Photo capture failed.", Toast.LENGTH_SHORT).show() + ImageCaptureState.PENDING -> Unit + } + } + } + var isLayoutUnfolded by remember { mutableStateOf(null) } LaunchedEffect(lifecycleOwner, context) { diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/camera/CameraViewModel.kt b/app/src/main/java/com/google/android/samples/socialite/ui/camera/CameraViewModel.kt index 7036fe3e..fbed5037 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/camera/CameraViewModel.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/camera/CameraViewModel.kt @@ -22,7 +22,6 @@ import android.content.Context import android.os.Build import android.provider.MediaStore import android.view.Display -import android.widget.Toast import androidx.annotation.RequiresPermission import androidx.camera.core.AspectRatio import androidx.camera.core.Camera @@ -58,6 +57,7 @@ import java.text.SimpleDateFormat import java.util.Locale import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @HiltViewModel @@ -72,6 +72,8 @@ class CameraViewModel @Inject constructor( val chatId: Long? = savedStateHandle.get("chatId") var viewFinderState = MutableStateFlow(ViewFinderState()) + private val _imageCaptureState = MutableStateFlow(ImageCaptureState.PENDING) + val imageCaptureState: StateFlow = _imageCaptureState val aspectRatioStrategy = AspectRatioStrategy(AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_NONE) @@ -189,19 +191,20 @@ class CameraViewModel @Inject constructor( ContextCompat.getMainExecutor(context), object : ImageCapture.OnImageSavedCallback { override fun onError(exc: ImageCaptureException) { - val msg = "Photo capture failed." - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() + _imageCaptureState.value = ImageCaptureState.IMAGE_CAPTURE_FAIL } override fun onImageSaved(output: ImageCapture.OutputFileResults) { + val state: ImageCaptureState val savedUri = output.savedUri if (savedUri != null) { + state = ImageCaptureState.IMAGE_CAPTURE_SUCCESS sendPhotoMessage(savedUri.toString()) onMediaCaptured(Media(savedUri, MediaType.PHOTO)) } else { - val msg = "Photo capture failed." - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() + state = ImageCaptureState.IMAGE_CAPTURE_FAIL } + _imageCaptureState.value = state } }, ) @@ -310,6 +313,12 @@ data class ViewFinderState( val lensFacing: Int = CameraSelector.LENS_FACING_BACK, ) +enum class ImageCaptureState { + PENDING, + IMAGE_CAPTURE_SUCCESS, + IMAGE_CAPTURE_FAIL, +} + /** * Defines the current state of the camera. */ diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt index ef6db537..269812c8 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt @@ -19,6 +19,7 @@ package com.google.android.samples.socialite.ui.videoedit import android.media.MediaMetadataRetriever import android.net.Uri import android.util.Log +import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -59,6 +60,7 @@ import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -71,6 +73,7 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -92,6 +95,7 @@ fun VideoEditScreen( onCloseButtonClicked: () -> Unit, navController: NavController, ) { + val lifecycleOwner = LocalLifecycleOwner.current val context = LocalContext.current val viewModel: VideoEditScreenViewModel = hiltViewModel() @@ -104,6 +108,19 @@ fun VideoEditScreen( val isProcessing = viewModel.isProcessing.collectAsState() + LaunchedEffect(lifecycleOwner, context) { + viewModel.videoSaveState.collect { state -> + when (state) { + VideoSaveState.VIDEO_SAVE_SUCCESS -> + Toast.makeText(context, "Edited video saved", Toast.LENGTH_LONG).show() + VideoSaveState.VIDEO_SAVE_FAIL -> + Toast.makeText(context, "Error applying edits on video", Toast.LENGTH_LONG) + .show() + VideoSaveState.PENDING -> Unit + } + } + } + var removeAudioEnabled by rememberSaveable { mutableStateOf(false) } var overlayText by rememberSaveable { mutableStateOf("") } var redOverlayTextEnabled by rememberSaveable { mutableStateOf(false) } diff --git a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreenViewModel.kt b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreenViewModel.kt index 8b9d52d8..618bd6ce 100644 --- a/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreenViewModel.kt +++ b/app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreenViewModel.kt @@ -23,7 +23,6 @@ import android.text.SpannableString import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan import android.text.style.RelativeSizeSpan -import android.widget.Toast import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.media3.common.MediaItem @@ -42,7 +41,6 @@ import com.google.android.samples.socialite.repository.ChatRepository import com.google.android.samples.socialite.ui.camera.CameraViewModel import com.google.common.collect.ImmutableList import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import java.io.File import java.io.IOException import java.text.SimpleDateFormat @@ -54,7 +52,6 @@ import kotlinx.coroutines.launch @HiltViewModel class VideoEditScreenViewModel @Inject constructor( - @ApplicationContext private val application: Context, private val repository: ChatRepository, ) : ViewModel() { @@ -67,6 +64,9 @@ class VideoEditScreenViewModel @Inject constructor( private val _isProcessing = MutableStateFlow(false) val isProcessing: StateFlow = _isProcessing + private val _videoSaveState = MutableStateFlow(VideoSaveState.PENDING) + val videoSaveState: StateFlow = _videoSaveState + fun setChatId(chatId: Long) { this.chatId.value = chatId } @@ -74,7 +74,7 @@ class VideoEditScreenViewModel @Inject constructor( private val transformerListener: Transformer.Listener = @UnstableApi object : Transformer.Listener { override fun onCompleted(composition: Composition, exportResult: ExportResult) { - Toast.makeText(application, "Edited video saved", Toast.LENGTH_LONG).show() + _videoSaveState.value = VideoSaveState.VIDEO_SAVE_SUCCESS sendVideo() @@ -88,8 +88,7 @@ class VideoEditScreenViewModel @Inject constructor( exportException: ExportException, ) { exportException.printStackTrace() - Toast.makeText(application, "Error applying edits on video", Toast.LENGTH_LONG) - .show() + _videoSaveState.value = VideoSaveState.VIDEO_SAVE_FAIL _isProcessing.value = false } } @@ -183,3 +182,9 @@ class VideoEditScreenViewModel @Inject constructor( } } } + +enum class VideoSaveState { + PENDING, + VIDEO_SAVE_SUCCESS, + VIDEO_SAVE_FAIL, +}