Skip to content

Commit e124a3a

Browse files
committed
Move Toast invocations out of Camera/VideoEdit ViewModels.
1 parent f81a4bd commit e124a3a

File tree

4 files changed

+70
-10
lines changed

4 files changed

+70
-10
lines changed

Diff for: app/src/main/java/com/google/android/samples/socialite/ui/camera/Camera.kt

+17
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.google.android.samples.socialite.ui.camera
1919
import android.Manifest
2020
import android.annotation.SuppressLint
2121
import android.view.Surface
22+
import android.widget.Toast
2223
import androidx.camera.core.CameraSelector
2324
import androidx.camera.core.Preview
2425
import androidx.camera.view.RotationProvider
@@ -64,6 +65,7 @@ import androidx.window.layout.FoldingFeature
6465
import androidx.window.layout.WindowInfoTracker
6566
import com.google.accompanist.permissions.ExperimentalPermissionsApi
6667
import com.google.accompanist.permissions.rememberMultiplePermissionsState
68+
import kotlin.coroutines.coroutineContext
6769
import kotlin.reflect.KFunction1
6870
import kotlinx.coroutines.Dispatchers
6971
import kotlinx.coroutines.asExecutor
@@ -91,6 +93,21 @@ fun Camera(
9193
val lifecycleOwner = LocalLifecycleOwner.current
9294
val context = LocalContext.current
9395

96+
LaunchedEffect(lifecycleOwner, context) {
97+
viewModel.imageCaptureState.collect { state ->
98+
when (state) {
99+
ImageCaptureState.IMAGE_CAPTURE_SUCCESS ->
100+
Toast.makeText(context, "Photo saved.", Toast.LENGTH_SHORT).show()
101+
ImageCaptureState.IMAGE_CAPTURE_FAIL ->
102+
Toast.makeText(context, "Photo capture failed.", Toast.LENGTH_SHORT).show()
103+
else -> {
104+
/* no-op */
105+
}
106+
}
107+
108+
}
109+
}
110+
94111
var isLayoutUnfolded by remember { mutableStateOf<Boolean?>(null) }
95112

96113
LaunchedEffect(lifecycleOwner, context) {

Diff for: app/src/main/java/com/google/android/samples/socialite/ui/camera/CameraViewModel.kt

+18-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import android.content.Context
2222
import android.os.Build
2323
import android.provider.MediaStore
2424
import android.view.Display
25-
import android.widget.Toast
2625
import androidx.annotation.RequiresPermission
2726
import androidx.camera.core.AspectRatio
2827
import androidx.camera.core.Camera
@@ -58,6 +57,7 @@ import java.text.SimpleDateFormat
5857
import java.util.Locale
5958
import javax.inject.Inject
6059
import kotlinx.coroutines.flow.MutableStateFlow
60+
import kotlinx.coroutines.flow.SharedFlow
6161
import kotlinx.coroutines.launch
6262

6363
@HiltViewModel
@@ -72,6 +72,8 @@ class CameraViewModel @Inject constructor(
7272

7373
val chatId: Long? = savedStateHandle.get("chatId")
7474
var viewFinderState = MutableStateFlow(ViewFinderState())
75+
private var _imageCaptureState = MutableStateFlow(ImageCaptureState.PENDING)
76+
val imageCaptureState: SharedFlow<ImageCaptureState> = _imageCaptureState
7577

7678
val aspectRatioStrategy =
7779
AspectRatioStrategy(AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_NONE)
@@ -189,18 +191,23 @@ class CameraViewModel @Inject constructor(
189191
ContextCompat.getMainExecutor(context),
190192
object : ImageCapture.OnImageSavedCallback {
191193
override fun onError(exc: ImageCaptureException) {
192-
val msg = "Photo capture failed."
193-
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
194+
viewModelScope.launch {
195+
_imageCaptureState.emit(ImageCaptureState.IMAGE_CAPTURE_FAIL)
196+
}
194197
}
195198

196199
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
200+
var state = ImageCaptureState.PENDING
197201
val savedUri = output.savedUri
198202
if (savedUri != null) {
203+
state = ImageCaptureState.IMAGE_CAPTURE_SUCCESS
199204
sendPhotoMessage(savedUri.toString())
200205
onMediaCaptured(Media(savedUri, MediaType.PHOTO))
201206
} else {
202-
val msg = "Photo capture failed."
203-
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
207+
state = ImageCaptureState.IMAGE_CAPTURE_FAIL
208+
}
209+
viewModelScope.launch {
210+
_imageCaptureState.emit(state)
204211
}
205212
}
206213
},
@@ -310,6 +317,12 @@ data class ViewFinderState(
310317
val lensFacing: Int = CameraSelector.LENS_FACING_BACK,
311318
)
312319

320+
enum class ImageCaptureState {
321+
PENDING,
322+
IMAGE_CAPTURE_SUCCESS,
323+
IMAGE_CAPTURE_FAIL
324+
}
325+
313326
/**
314327
* Defines the current state of the camera.
315328
*/

Diff for: app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreen.kt

+19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.google.android.samples.socialite.ui.videoedit
1919
import android.media.MediaMetadataRetriever
2020
import android.net.Uri
2121
import android.util.Log
22+
import android.widget.Toast
2223
import androidx.compose.foundation.Image
2324
import androidx.compose.foundation.background
2425
import androidx.compose.foundation.layout.Arrangement
@@ -59,6 +60,7 @@ import androidx.compose.material3.TextFieldDefaults
5960
import androidx.compose.material3.TopAppBar
6061
import androidx.compose.material3.TopAppBarDefaults
6162
import androidx.compose.runtime.Composable
63+
import androidx.compose.runtime.LaunchedEffect
6264
import androidx.compose.runtime.collectAsState
6365
import androidx.compose.runtime.getValue
6466
import androidx.compose.runtime.mutableStateOf
@@ -71,6 +73,7 @@ import androidx.compose.ui.graphics.asImageBitmap
7173
import androidx.compose.ui.graphics.vector.ImageVector
7274
import androidx.compose.ui.platform.LocalContext
7375
import androidx.compose.ui.platform.LocalInspectionMode
76+
import androidx.compose.ui.platform.LocalLifecycleOwner
7477
import androidx.compose.ui.res.colorResource
7578
import androidx.compose.ui.res.stringResource
7679
import androidx.compose.ui.tooling.preview.Preview
@@ -92,6 +95,7 @@ fun VideoEditScreen(
9295
onCloseButtonClicked: () -> Unit,
9396
navController: NavController,
9497
) {
98+
val lifecycleOwner = LocalLifecycleOwner.current
9599
val context = LocalContext.current
96100

97101
val viewModel: VideoEditScreenViewModel = hiltViewModel()
@@ -104,6 +108,21 @@ fun VideoEditScreen(
104108

105109
val isProcessing = viewModel.isProcessing.collectAsState()
106110

111+
LaunchedEffect(lifecycleOwner, context) {
112+
viewModel.videoSaveState.collect { state ->
113+
when (state) {
114+
VideoSaveState.VIDEO_SAVE_SUCCESS ->
115+
Toast.makeText(context, "Edited video saved", Toast.LENGTH_LONG).show()
116+
VideoSaveState.VIDEO_SAVE_FAIL ->
117+
Toast.makeText(context, "Error applying edits on video", Toast.LENGTH_LONG)
118+
.show()
119+
else -> {
120+
/* no-op */
121+
}
122+
}
123+
}
124+
}
125+
107126
var removeAudioEnabled by rememberSaveable { mutableStateOf(false) }
108127
var overlayText by rememberSaveable { mutableStateOf("") }
109128
var redOverlayTextEnabled by rememberSaveable { mutableStateOf(false) }

Diff for: app/src/main/java/com/google/android/samples/socialite/ui/videoedit/VideoEditScreenViewModel.kt

+16-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import android.text.SpannableString
2323
import android.text.SpannableStringBuilder
2424
import android.text.style.ForegroundColorSpan
2525
import android.text.style.RelativeSizeSpan
26-
import android.widget.Toast
2726
import androidx.lifecycle.ViewModel
2827
import androidx.lifecycle.viewModelScope
2928
import androidx.media3.common.MediaItem
@@ -49,12 +48,12 @@ import java.text.SimpleDateFormat
4948
import java.util.Locale
5049
import javax.inject.Inject
5150
import kotlinx.coroutines.flow.MutableStateFlow
51+
import kotlinx.coroutines.flow.SharedFlow
5252
import kotlinx.coroutines.flow.StateFlow
5353
import kotlinx.coroutines.launch
5454

5555
@HiltViewModel
5656
class VideoEditScreenViewModel @Inject constructor(
57-
@ApplicationContext private val application: Context,
5857
private val repository: ChatRepository,
5958
) : ViewModel() {
6059

@@ -67,14 +66,19 @@ class VideoEditScreenViewModel @Inject constructor(
6766
private val _isProcessing = MutableStateFlow(false)
6867
val isProcessing: StateFlow<Boolean> = _isProcessing
6968

69+
private var _videoSaveState = MutableStateFlow(VideoSaveState.PENDING)
70+
val videoSaveState: SharedFlow<VideoSaveState> = _videoSaveState
71+
7072
fun setChatId(chatId: Long) {
7173
this.chatId.value = chatId
7274
}
7375

7476
private val transformerListener: Transformer.Listener =
7577
@UnstableApi object : Transformer.Listener {
7678
override fun onCompleted(composition: Composition, exportResult: ExportResult) {
77-
Toast.makeText(application, "Edited video saved", Toast.LENGTH_LONG).show()
79+
viewModelScope.launch {
80+
_videoSaveState.emit(VideoSaveState.VIDEO_SAVE_SUCCESS)
81+
}
7882

7983
sendVideo()
8084

@@ -88,8 +92,9 @@ class VideoEditScreenViewModel @Inject constructor(
8892
exportException: ExportException,
8993
) {
9094
exportException.printStackTrace()
91-
Toast.makeText(application, "Error applying edits on video", Toast.LENGTH_LONG)
92-
.show()
95+
viewModelScope.launch {
96+
_videoSaveState.emit(VideoSaveState.VIDEO_SAVE_FAIL)
97+
}
9398
_isProcessing.value = false
9499
}
95100
}
@@ -183,3 +188,9 @@ class VideoEditScreenViewModel @Inject constructor(
183188
}
184189
}
185190
}
191+
192+
enum class VideoSaveState {
193+
PENDING,
194+
VIDEO_SAVE_SUCCESS,
195+
VIDEO_SAVE_FAIL
196+
}

0 commit comments

Comments
 (0)