diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt index ead2b5c032..30348fd85b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionActivity.kt @@ -214,6 +214,10 @@ class MediaSelectionActivity : .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::handleError) + lifecycleDisposable += viewModel.videoTrimmedEvents + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { Toast.makeText(this, R.string.MediaReviewFragment__video_trimmed_to_fit, Toast.LENGTH_SHORT).show() } + onBackPressedDispatcher.addCallback(OnBackPressed()) if (savedInstanceState == null && intent.getBooleanExtra(IS_FOR_QUICK_RESTORE, false)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt index 9bfd1a045c..978a553768 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt @@ -82,6 +82,9 @@ class MediaSelectionViewModel( val mediaErrors: BehaviorSubject = BehaviorSubject.createDefault(MediaValidator.FilterError.None) val hudCommands: Observable = internalHudCommands + private val _videoTrimmedEvents = PublishSubject.create() + val videoTrimmedEvents: Observable = _videoTrimmedEvents + private val disposables = CompositeDisposable() private val isMeteredDisposable: Disposable = repository.isMetered.subscribe { metered -> @@ -167,19 +170,20 @@ class MediaSelectionViewModel( .populateAndFilterMedia(newSelectionList, getMediaConstraints(), store.state.maxSelection, store.state.isStory) .subscribe { filterResult -> if (filterResult.filteredMedia.isNotEmpty()) { - store.update { - val initializedVideoEditorStates = filterResult.filteredMedia.filterNot { media -> it.editorStateMap.containsKey(media.uri) } - .filter { media -> MediaUtil.isNonGifVideo(media) } - .associate { video: Media -> - val duration = video.duration.milliseconds.inWholeMicroseconds - val maxDuration = it.calculateMaxVideoDurationUs(video.duration.milliseconds) - if (MediaConstraints.isVideoTranscodeAvailable() && duration >= maxDuration) { - video.uri to VideoTrimData(true, duration, 0, maxDuration) - } else { - video.uri to VideoTrimData(false, duration, 0, duration) - } + val existingState = store.state + val initializedVideoEditorStates = filterResult.filteredMedia.filterNot { media -> existingState.editorStateMap.containsKey(media.uri) } + .filter { media -> MediaUtil.isNonGifVideo(media) } + .associate { video: Media -> + val duration = video.duration.milliseconds.inWholeMicroseconds + val maxDuration = existingState.calculateMaxVideoDurationUs(video.duration.milliseconds) + if (MediaConstraints.isVideoTranscodeAvailable() && duration >= maxDuration) { + video.uri to VideoTrimData(true, duration, 0, maxDuration) + } else { + video.uri to VideoTrimData(false, duration, 0, duration) } + } + store.update { val updatedCameraFirstCapture = if (it.cameraFirstCapture != null) { filterResult.filteredMedia.find { filtered -> filtered.uri == it.cameraFirstCapture.uri } } else { @@ -194,6 +198,10 @@ class MediaSelectionViewModel( ) } + if (initializedVideoEditorStates.any { (_, data) -> data.isDurationEdited }) { + _videoTrimmedEvents.onNext(Unit) + } + selectedMediaSubject.onNext(filterResult.filteredMedia) val newMedia = filterResult.filteredMedia.toSet().intersect(media).toList() @@ -335,13 +343,22 @@ class MediaSelectionViewModel( store.update { it.copy(quality = sentMediaQuality, isPreUploadEnabled = false, transcodingConfigs = TranscodingConfigProvider.getConfigsForMediaQuality(sentMediaQuality)) } repository.uploadRepository.cancelAllUploads() + var videoTrimmed = false store.state.selectedMedia.forEach { mediaItem -> if (MediaUtil.isVideoType(mediaItem.contentType) && MediaConstraints.isVideoTranscodeAvailable()) { val uri = mediaItem.uri - val data = store.state.getOrCreateVideoTrimData(uri) - onEditVideoDuration(totalDurationUs = data.totalInputDurationUs, startTimeUs = data.startTimeUs, endTimeUs = data.endTimeUs, touchEnabled = true, uri = uri) + val before = store.state.getOrCreateVideoTrimData(uri) + onEditVideoDuration(totalDurationUs = before.totalInputDurationUs, startTimeUs = before.startTimeUs, endTimeUs = before.endTimeUs, touchEnabled = true, uri = uri) + val after = store.state.getOrCreateVideoTrimData(uri) + if (after.getDuration() < before.getDuration()) { + videoTrimmed = true + } } } + + if (videoTrimmed) { + _videoTrimmedEvents.onNext(Unit) + } } fun setMessage(text: CharSequence?) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 137176592c..0bfd378097 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -6392,6 +6392,7 @@ One or more items were too large One or more items were invalid Too many items selected + Your video was trimmed to fit within the size limit Video set to view once diff --git a/feature/media-send/src/main/java/org/signal/mediasend/MediaSendViewModel.kt b/feature/media-send/src/main/java/org/signal/mediasend/MediaSendViewModel.kt index 756277e9d3..938b60f75e 100644 --- a/feature/media-send/src/main/java/org/signal/mediasend/MediaSendViewModel.kt +++ b/feature/media-send/src/main/java/org/signal/mediasend/MediaSendViewModel.kt @@ -469,6 +469,10 @@ class MediaSendViewModel( ) } + if (initializedVideoEditorStates.any { (_, editorState) -> editorState.videoTrimData.isDurationEdited }) { + internalSnackbarEvents.trySend(SnackbarEvent(message = R.string.MediaSendViewModel__video_trimmed_to_fit)) + } + // Update story requirements updateStorySendRequirements(filterResult.filteredMedia) @@ -607,11 +611,11 @@ class MediaSendViewModel( preUploadController.cancelAllUploads() // Re-clamp video durations based on new quality + var videoTrimmed = false snapshot.selectedMedia.forEach { mediaItem -> if (isNonGifVideo(mediaItem) && repository.isVideoTranscodeAvailable()) { val existingData = snapshot.editorStateMap[mediaItem.uri] as? EditorState.VideoTrim if (existingData != null) { - val maxVideoDurationUs = getMaxVideoDurationUs(existingData.videoTrimData.totalInputDurationUs.microseconds) onEditVideoDuration( totalDurationUs = existingData.videoTrimData.totalInputDurationUs, startTimeUs = existingData.videoTrimData.startTimeUs, @@ -619,9 +623,17 @@ class MediaSendViewModel( touchEnabled = true, uri = mediaItem.uri ) + val updatedData = state.value.editorStateMap[mediaItem.uri] as? EditorState.VideoTrim + if (updatedData != null && updatedData.videoTrimData.getDuration() < existingData.videoTrimData.getDuration()) { + videoTrimmed = true + } } } } + + if (videoTrimmed) { + internalSnackbarEvents.trySend(SnackbarEvent(message = R.string.MediaSendViewModel__video_trimmed_to_fit)) + } } //endregion diff --git a/feature/media-send/src/main/res/values/strings.xml b/feature/media-send/src/main/res/values/strings.xml index 975edcf728..9c06cc8d86 100644 --- a/feature/media-send/src/main/res/values/strings.xml +++ b/feature/media-send/src/main/res/values/strings.xml @@ -97,6 +97,8 @@ Error recording video Error taking photo + + Your video was trimmed to fit within the size limit Found %1$s