Refactor viewer to prepare for enhanced video duration support.
This commit is contained in:
parent
9a5fcdbe4d
commit
bd58c91d2c
13 changed files with 208 additions and 60 deletions
|
@ -101,5 +101,8 @@ public abstract class MediaPreviewFragment extends Fragment {
|
|||
public interface Events {
|
||||
boolean singleTapOnMedia();
|
||||
void mediaNotAvailable();
|
||||
default @Nullable VideoControlsDelegate getVideoControlsDelegate() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package org.thoughtcrime.securesms.mediapreview
|
||||
|
||||
import android.net.Uri
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
import org.thoughtcrime.securesms.video.VideoPlayer
|
||||
|
||||
/**
|
||||
* Class to manage video playback in preview screen.
|
||||
*/
|
||||
class VideoControlsDelegate {
|
||||
|
||||
private val playWhenReady: MutableMap<Uri, Boolean> = mutableMapOf()
|
||||
private val playerSubject = BehaviorSubject.create<Player>()
|
||||
private val playerReadySignal = PublishSubject.create<Unit>()
|
||||
val playerUpdates: Observable<PlayerUpdate> = playerReadySignal
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.flatMap { playerSubject }
|
||||
.filter { it.videoPlayer != null }
|
||||
.map { PlayerUpdate(it.uri, it.videoPlayer?.duration!!) }
|
||||
|
||||
fun pause() = playerSubject.value?.videoPlayer?.pause()
|
||||
|
||||
fun resume(uri: Uri) {
|
||||
val player = playerSubject.value
|
||||
if (player?.uri == uri) {
|
||||
player.videoPlayer?.play()
|
||||
} else {
|
||||
playWhenReady[uri] = true
|
||||
}
|
||||
|
||||
playerSubject.value?.videoPlayer?.play()
|
||||
}
|
||||
|
||||
fun restart() {
|
||||
playerSubject.value?.videoPlayer?.playbackPosition = 0L
|
||||
}
|
||||
|
||||
fun attachPlayer(uri: Uri, videoPlayer: VideoPlayer?) {
|
||||
playerSubject.onNext(Player(uri, videoPlayer))
|
||||
|
||||
if ((videoPlayer?.duration ?: -1L) > 0L) {
|
||||
playerReadySignal.onNext(Unit)
|
||||
} else {
|
||||
videoPlayer?.setPlayerStateCallbacks {
|
||||
playerReadySignal.onNext(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
if (playWhenReady[uri] == true) {
|
||||
playWhenReady[uri] = false
|
||||
videoPlayer?.play()
|
||||
}
|
||||
}
|
||||
|
||||
fun detachPlayer() {
|
||||
playerSubject.onNext(Player())
|
||||
}
|
||||
|
||||
private data class Player(
|
||||
val uri: Uri = Uri.EMPTY,
|
||||
val videoPlayer: VideoPlayer? = null
|
||||
)
|
||||
|
||||
data class PlayerUpdate(
|
||||
val mediaUri: Uri,
|
||||
val duration: Long
|
||||
)
|
||||
}
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
|
@ -28,7 +29,8 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
|||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Bundle savedInstanceState)
|
||||
{
|
||||
View itemView = inflater.inflate(R.layout.media_preview_video_fragment, container, false);
|
||||
Bundle arguments = requireArguments();
|
||||
Uri uri = arguments.getParcelable(DATA_URI);
|
||||
|
@ -70,6 +72,10 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
|||
if (videoView != null && isVideoGif) {
|
||||
videoView.play();
|
||||
}
|
||||
|
||||
if (events.getVideoControlsDelegate() != null) {
|
||||
events.getVideoControlsDelegate().attachPlayer(getUri(), videoView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,10 +83,18 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
|||
if (videoView != null) {
|
||||
videoView.pause();
|
||||
}
|
||||
|
||||
if (events.getVideoControlsDelegate() != null) {
|
||||
events.getVideoControlsDelegate().detachPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getPlaybackControls() {
|
||||
return videoView != null && !isVideoGif ? videoView.getControlView() : null;
|
||||
}
|
||||
|
||||
private @NonNull Uri getUri() {
|
||||
return requireArguments().getParcelable(DATA_URI);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ class StoryPost(
|
|||
val viewCount: Int,
|
||||
val replyCount: Int,
|
||||
val dateInMilliseconds: Long,
|
||||
val durationMillis: Long,
|
||||
val attachment: Attachment,
|
||||
val conversationMessage: ConversationMessage
|
||||
)
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor
|
|||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewFragment
|
||||
import org.thoughtcrime.securesms.mediapreview.VideoControlsDelegate
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||
|
@ -48,6 +49,7 @@ import org.thoughtcrime.securesms.util.fragments.requireListener
|
|||
import org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.abs
|
||||
|
||||
class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page), MediaPreviewFragment.Events, MultiselectForwardBottomSheet.Callback {
|
||||
|
@ -65,6 +67,8 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
}
|
||||
)
|
||||
|
||||
private val videoControlsDelegate = VideoControlsDelegate()
|
||||
|
||||
private val lifecycleDisposable = LifecycleDisposable()
|
||||
|
||||
private val storyRecipientId: RecipientId
|
||||
|
@ -122,10 +126,10 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
cardWrapper.setOnTouchListener { _, event ->
|
||||
val result = gestureDetector.onTouchEvent(event)
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
progressBar.pause()
|
||||
viewModel.setIsUserTouching(true)
|
||||
hideChrome()
|
||||
} else if (event.actionMasked == MotionEvent.ACTION_UP || event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
||||
resumeProgressIfNotDisplayingDialog()
|
||||
viewModel.setIsUserTouching(false)
|
||||
showChrome()
|
||||
}
|
||||
|
||||
|
@ -147,6 +151,10 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
.replace(R.id.story_content_container, createFragmentForPost(viewModel.getPostAt(newPageIndex)))
|
||||
.commit()
|
||||
}
|
||||
|
||||
if (oldPageIndex == newPageIndex) {
|
||||
videoControlsDelegate.restart()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinished() {
|
||||
|
@ -166,27 +174,45 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
presentDistributionList(distributionList, post)
|
||||
presentCaption(caption, largeCaption, largeCaptionOverlay, post)
|
||||
|
||||
if (progressBar.segmentCount != state.posts.size) {
|
||||
val durations: Map<Int, Long> = state.posts
|
||||
.mapIndexed { index, storyPost ->
|
||||
index to (storyPost.attachment.uri?.let { state.durations[it] } ?: TimeUnit.SECONDS.toMillis(5))
|
||||
}
|
||||
.toMap()
|
||||
|
||||
if (progressBar.segmentCount != state.posts.size || progressBar.segmentDurations != durations) {
|
||||
progressBar.segmentCount = state.posts.size
|
||||
progressBar.segmentDurations = state.posts.mapIndexed { index, storyPost -> index to storyPost.durationMillis }.toMap()
|
||||
progressBar.start()
|
||||
progressBar.segmentDurations = durations
|
||||
}
|
||||
|
||||
viewModel.setAreSegmentsInitialized(true)
|
||||
} else if (state.selectedPostIndex >= state.posts.size) {
|
||||
callback.onFinishedPosts(storyRecipientId)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.storyViewerPlaybackState.observe(viewLifecycleOwner) { state ->
|
||||
if (state.isPaused) {
|
||||
pauseProgress()
|
||||
} else {
|
||||
resumeProgress()
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner)
|
||||
lifecycleDisposable += viewModel.groupDirectReplyObservable.subscribe { opt ->
|
||||
if (opt.isPresent) {
|
||||
progressBar.pause()
|
||||
when (val sheet = opt.get()) {
|
||||
is StoryViewerDialog.GroupDirectReply -> {
|
||||
onStartDirectReply(sheet.storyId, sheet.recipientId)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resumeProgress()
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleDisposable += videoControlsDelegate.playerUpdates.subscribe { update ->
|
||||
if (update.duration > 0L) {
|
||||
viewModel.setDuration(update.mediaUri, update.duration)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +221,6 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
progressBar.pause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -205,14 +230,12 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
progressBar.reset()
|
||||
progressBar.setPosition(viewModel.getRestartIndex())
|
||||
}
|
||||
|
||||
resumeProgressIfNotDisplayingDialog()
|
||||
}
|
||||
|
||||
override fun onFinishForwardAction() = Unit
|
||||
|
||||
override fun onDismissForwardSheet() {
|
||||
viewModel.onForwardDismissed()
|
||||
viewModel.setIsDisplayingForwardDialog(false)
|
||||
}
|
||||
|
||||
private fun hideChrome() {
|
||||
|
@ -264,18 +287,18 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
constraintSet.applyTo(requireView() as ConstraintLayout)
|
||||
}
|
||||
|
||||
private fun resumeProgressIfNotDisplayingDialog() {
|
||||
if (childFragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) == null) {
|
||||
resumeProgress()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resumeProgress() {
|
||||
if (progressBar.segmentCount != 0) {
|
||||
progressBar.start()
|
||||
videoControlsDelegate.resume(viewModel.getPost().attachment.uri!!)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pauseProgress() {
|
||||
progressBar.pause()
|
||||
videoControlsDelegate.pause()
|
||||
}
|
||||
|
||||
private fun startReply() {
|
||||
val replyFragment: DialogFragment = when (viewModel.getSwipeToReplyState()) {
|
||||
StoryViewerPageState.ReplyState.NONE -> return
|
||||
|
@ -285,12 +308,17 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
StoryViewerPageState.ReplyState.GROUP_SELF -> StoryViewsAndRepliesDialogFragment.create(viewModel.getPost().id, viewModel.getPost().group!!.id, getViewsAndRepliesDialogStartPage())
|
||||
}
|
||||
|
||||
progressBar.pause()
|
||||
if (viewModel.getSwipeToReplyState() == StoryViewerPageState.ReplyState.PRIVATE) {
|
||||
viewModel.setIsDisplayingDirectReplyDialog(true)
|
||||
} else {
|
||||
viewModel.setIsDisplayingViewsAndRepliesDialog(true)
|
||||
}
|
||||
|
||||
replyFragment.showNow(childFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
}
|
||||
|
||||
private fun onStartDirectReply(storyId: Long, recipientId: RecipientId) {
|
||||
progressBar.pause()
|
||||
viewModel.setIsDisplayingDirectReplyDialog(true)
|
||||
StoryDirectReplyDialogFragment.create(
|
||||
storyId = storyId,
|
||||
recipientId = recipientId
|
||||
|
@ -359,7 +387,7 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
largeCaptionOverlay.setOnClickListener {
|
||||
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
|
||||
}
|
||||
progressBar.pause()
|
||||
viewModel.setIsDisplayingCaptionOverlay(true)
|
||||
}
|
||||
|
||||
private fun onHideCaptionOverlay(caption: TextView, largeCaption: TextView, largeCaptionOverlay: View) {
|
||||
|
@ -367,7 +395,7 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
largeCaption.visible = false
|
||||
largeCaptionOverlay.visible = false
|
||||
largeCaptionOverlay.setOnClickListener(null)
|
||||
resumeProgress()
|
||||
viewModel.setIsDisplayingCaptionOverlay(false)
|
||||
}
|
||||
|
||||
private fun presentFrom(from: TextView, storyPost: StoryPost) {
|
||||
|
@ -420,20 +448,24 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
}
|
||||
|
||||
private fun createFragmentForPost(storyPost: StoryPost): Fragment {
|
||||
return MediaPreviewFragment.newInstance(storyPost.attachment, true)
|
||||
return MediaPreviewFragment.newInstance(storyPost.attachment, false)
|
||||
}
|
||||
|
||||
override fun getVideoControlsDelegate(): VideoControlsDelegate {
|
||||
return videoControlsDelegate
|
||||
}
|
||||
|
||||
private fun displayMoreContextMenu(anchor: View) {
|
||||
progressBar.pause()
|
||||
viewModel.setIsDisplayingContextMenu(true)
|
||||
StoryContextMenu.show(
|
||||
context = requireContext(),
|
||||
anchorView = anchor,
|
||||
storyViewerPageState = viewModel.getStateSnapshot(),
|
||||
onDismiss = {
|
||||
viewModel.onDismissContextMenu()
|
||||
viewModel.setIsDisplayingContextMenu(false)
|
||||
},
|
||||
onForward = { storyPost ->
|
||||
viewModel.startForward()
|
||||
viewModel.setIsDisplayingForwardDialog(true)
|
||||
MultiselectForwardFragmentArgs.create(
|
||||
requireContext(),
|
||||
storyPost.conversationMessage.multiselectCollection.toSet(),
|
||||
|
@ -456,9 +488,9 @@ class StoryViewerPageFragment : Fragment(R.layout.stories_viewer_fragment_page),
|
|||
StoryContextMenu.save(requireContext(), it.conversationMessage.messageRecord)
|
||||
},
|
||||
onDelete = {
|
||||
viewModel.startDelete()
|
||||
viewModel.setIsDisplayingDeleteDialog(true)
|
||||
lifecycleDisposable += StoryContextMenu.delete(requireContext(), setOf(it.conversationMessage.messageRecord)).subscribe { _ ->
|
||||
viewModel.onDeleteDismissed()
|
||||
viewModel.setIsDisplayingDeleteDialog(false)
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,8 +66,7 @@ class StoryViewerPageRepository(context: Context) {
|
|||
viewCount = record.viewedReceiptCount,
|
||||
replyCount = SignalDatabase.mms.getNumberOfStoryReplies(record.id),
|
||||
dateInMilliseconds = record.dateSent,
|
||||
durationMillis = getDurationMillis(record as MmsMessageRecord),
|
||||
attachment = record.slideDeck.firstSlide!!.asAttachment(),
|
||||
attachment = (record as MmsMessageRecord).slideDeck.firstSlide!!.asAttachment(),
|
||||
conversationMessage = ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, record)
|
||||
)
|
||||
|
||||
|
@ -125,16 +124,6 @@ class StoryViewerPageRepository(context: Context) {
|
|||
}.observeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
private fun getDurationMillis(record: MmsMessageRecord): Long {
|
||||
val slide = record.slideDeck.firstSlide!!
|
||||
return if (slide.hasVideo()) {
|
||||
// TODO [stories] Remove duration from this stuff... Videos will need to actually start playback before we know how long they are...
|
||||
5000
|
||||
} else {
|
||||
5000
|
||||
}
|
||||
}
|
||||
|
||||
fun hideStory(recipientId: RecipientId): Completable {
|
||||
return Completable.fromAction {
|
||||
SignalDatabase.recipients.setHideStory(recipientId, true)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package org.thoughtcrime.securesms.stories.viewer.page
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
data class StoryViewerPageState(
|
||||
val posts: List<StoryPost> = emptyList(),
|
||||
val durations: Map<Uri, Long> = emptyMap(),
|
||||
val selectedPostIndex: Int = 0,
|
||||
val replyState: ReplyState = ReplyState.NONE
|
||||
) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.thoughtcrime.securesms.stories.viewer.page
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
@ -28,6 +29,10 @@ class StoryViewerPageViewModel(
|
|||
private val storyViewerDialogSubject: Subject<Optional<StoryViewerDialog>> = BehaviorSubject.createDefault(Optional.empty())
|
||||
private val dismissSubject = PublishSubject.create<StoryViewerDialog.Type>()
|
||||
|
||||
private val storyViewerPlaybackStore = Store(StoryViewerPlaybackState())
|
||||
|
||||
val storyViewerPlaybackState: LiveData<StoryViewerPlaybackState> = storyViewerPlaybackStore.stateLiveData
|
||||
|
||||
val groupDirectReplyObservable: Observable<Optional<StoryViewerDialog>> = Observable.combineLatest(storyViewerDialogSubject, dismissSubject) { sheet, dismissed ->
|
||||
if (sheet.isPresent && sheet.get().type != dismissed) {
|
||||
sheet
|
||||
|
@ -50,6 +55,12 @@ class StoryViewerPageViewModel(
|
|||
refresh()
|
||||
}
|
||||
|
||||
fun setDuration(uri: Uri, duration: Long) {
|
||||
store.update {
|
||||
it.copy(durations = it.durations + (uri to duration))
|
||||
}
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
disposables.clear()
|
||||
disposables += repository.getStoryPostsFor(recipientId).subscribe { posts ->
|
||||
|
@ -95,32 +106,36 @@ class StoryViewerPageViewModel(
|
|||
storyViewerDialogSubject.onNext(Optional.of(StoryViewerDialog.GroupDirectReply(recipientId, storyId)))
|
||||
}
|
||||
|
||||
fun startForward() {
|
||||
storyViewerDialogSubject.onNext(Optional.of(StoryViewerDialog.Forward))
|
||||
fun setIsDisplayingContextMenu(isDisplayingContextMenu: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingContextMenu = isDisplayingContextMenu) }
|
||||
}
|
||||
|
||||
fun startDelete() {
|
||||
storyViewerDialogSubject.onNext(Optional.of(StoryViewerDialog.Delete))
|
||||
fun setIsDisplayingForwardDialog(isDisplayingForwardDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingForwardDialog = isDisplayingForwardDialog) }
|
||||
}
|
||||
|
||||
fun onForwardDismissed() {
|
||||
dismissSubject.onNext(StoryViewerDialog.Type.FORWARD)
|
||||
fun setIsDisplayingDeleteDialog(isDisplayingDeleteDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingDeleteDialog = isDisplayingDeleteDialog) }
|
||||
}
|
||||
|
||||
fun onDeleteDismissed() {
|
||||
dismissSubject.onNext(StoryViewerDialog.Type.DELETE)
|
||||
fun setIsDisplayingViewsAndRepliesDialog(isDisplayingViewsAndRepliesDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingViewsAndRepliesDialog = isDisplayingViewsAndRepliesDialog) }
|
||||
}
|
||||
|
||||
fun onDismissContextMenu() {
|
||||
dismissSubject.onNext(StoryViewerDialog.Type.CONTEXT_MENU)
|
||||
fun setIsDisplayingDirectReplyDialog(isDisplayingDirectReplyDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingDirectReplyDialog = isDisplayingDirectReplyDialog) }
|
||||
}
|
||||
|
||||
fun onViewsAndRepliesSheetDismissed() {
|
||||
dismissSubject.onNext(StoryViewerDialog.Type.VIEWS_AND_REPLIES)
|
||||
fun setIsDisplayingCaptionOverlay(isDisplayingCaptionOverlay: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingCaptionOverlay = isDisplayingCaptionOverlay) }
|
||||
}
|
||||
|
||||
fun onDirectReplyDismissed() {
|
||||
dismissSubject.onNext(StoryViewerDialog.Type.DIRECT_REPLY)
|
||||
fun setIsUserTouching(isUserTouching: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isUserTouching = isUserTouching) }
|
||||
}
|
||||
|
||||
fun setAreSegmentsInitialized(areSegmentsInitialized: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(areSegmentsInitialized = areSegmentsInitialized) }
|
||||
}
|
||||
|
||||
private fun resolveSwipeToReplyState(state: StoryViewerPageState, index: Int = state.selectedPostIndex): StoryViewerPageState.ReplyState {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package org.thoughtcrime.securesms.stories.viewer.page
|
||||
|
||||
data class StoryViewerPlaybackState(
|
||||
val areSegmentsInitialized: Boolean = false,
|
||||
val isUserTouching: Boolean = false,
|
||||
val isDisplayingForwardDialog: Boolean = false,
|
||||
val isDisplayingDeleteDialog: Boolean = false,
|
||||
val isDisplayingContextMenu: Boolean = false,
|
||||
val isDisplayingViewsAndRepliesDialog: Boolean = false,
|
||||
val isDisplayingDirectReplyDialog: Boolean = false,
|
||||
val isDisplayingCaptionOverlay: Boolean = false
|
||||
) {
|
||||
val isPaused: Boolean = !areSegmentsInitialized ||
|
||||
isUserTouching ||
|
||||
isDisplayingCaptionOverlay ||
|
||||
isDisplayingForwardDialog ||
|
||||
isDisplayingDeleteDialog ||
|
||||
isDisplayingContextMenu ||
|
||||
isDisplayingViewsAndRepliesDialog ||
|
||||
isDisplayingDirectReplyDialog ||
|
||||
isDisplayingCaptionOverlay
|
||||
}
|
|
@ -122,7 +122,7 @@ class StoryDirectReplyDialogFragment :
|
|||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
storyViewerPageViewModel.onDirectReplyDismissed()
|
||||
storyViewerPageViewModel.setIsDisplayingDirectReplyDialog(false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -66,7 +66,7 @@ class StoryGroupReplyBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDi
|
|||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
storyViewerPageViewModel.onViewsAndRepliesSheetDismissed()
|
||||
storyViewerPageViewModel.setIsDisplayingViewsAndRepliesDialog(false)
|
||||
}
|
||||
|
||||
override fun onStartDirectReply(recipientId: RecipientId) {
|
||||
|
|
|
@ -102,7 +102,7 @@ class StoryViewsAndRepliesDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
|||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
storyViewerPageViewModel.onViewsAndRepliesSheetDismissed()
|
||||
storyViewerPageViewModel.setIsDisplayingViewsAndRepliesDialog(false)
|
||||
}
|
||||
|
||||
override fun onStartDirectReply(recipientId: RecipientId) {
|
||||
|
|
|
@ -40,7 +40,7 @@ class StoryViewsBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDialogF
|
|||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
storyViewerPageViewModel.onViewsAndRepliesSheetDismissed()
|
||||
storyViewerPageViewModel.setIsDisplayingViewsAndRepliesDialog(false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
Loading…
Add table
Reference in a new issue