diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt index 27751b7915..a4461e6f26 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.badges.gifts.flow import android.content.DialogInterface import android.view.KeyEvent -import android.widget.EditText import android.widget.FrameLayout import android.widget.ImageView import androidx.activity.OnBackPressedCallback diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryViewerFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryViewerFragment.kt index 07f0b85184..2df3937109 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryViewerFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryViewerFragment.kt @@ -4,12 +4,13 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.LiveDataReactiveStreams import androidx.viewpager2.widget.ViewPager2 +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.stories.StoryViewerArgs import org.thoughtcrime.securesms.stories.viewer.page.StoryViewerPageFragment +import org.thoughtcrime.securesms.util.LifecycleDisposable /** * Fragment which manages a vertical pager fragment of stories. @@ -26,6 +27,8 @@ class StoryViewerFragment : Fragment(R.layout.stories_viewer_fragment), StoryVie } ) + private val lifecycleDisposable = LifecycleDisposable() + private val storyViewerArgs: StoryViewerArgs by lazy { requireArguments().getParcelable(ARGS)!! } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -38,7 +41,8 @@ class StoryViewerFragment : Fragment(R.layout.stories_viewer_fragment), StoryVie storyPager.isUserInputEnabled = !it } - LiveDataReactiveStreams.fromPublisher(viewModel.state).observe(viewLifecycleOwner) { state -> + lifecycleDisposable.bindTo(viewLifecycleOwner) + lifecycleDisposable += viewModel.state.observeOn(AndroidSchedulers.mainThread()).subscribe { state -> adapter.setPages(state.pages) if (state.pages.isNotEmpty() && storyPager.currentItem != state.page) { storyPager.setCurrentItem(state.page, state.previousPage > -1) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt index c7bad611f3..044ba951ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt @@ -268,14 +268,19 @@ class StoryViewerPageFragment : when (parentState.crossfadeSource) { is StoryViewerState.CrossfadeSource.TextModel -> storyCrossfader.setSourceView(parentState.crossfadeSource.storyTextPostModel) is StoryViewerState.CrossfadeSource.ImageUri -> storyCrossfader.setSourceView(parentState.crossfadeSource.imageUri, parentState.crossfadeSource.imageBlur) - else -> onReadyToAnimate() } + + onReadyToAnimate() } else { viewModel.setIsSelectedPage(false) } } lifecycleDisposable += viewModel.state.observeOn(AndroidSchedulers.mainThread()).subscribe { state -> + if (!state.isReady) { + return@subscribe + } + if (state.posts.isNotEmpty() && state.selectedPostIndex in state.posts.indices) { val post = state.posts[state.selectedPostIndex] diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt index 6693b900a1..1f94e59c15 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt @@ -7,6 +7,7 @@ import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.BreakIteratorCompat import org.signal.core.util.concurrent.SignalExecutors +import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.conversation.ConversationMessage import org.thoughtcrime.securesms.database.DatabaseObserver import org.thoughtcrime.securesms.database.NoSuchMessageException @@ -28,6 +29,10 @@ import org.thoughtcrime.securesms.util.Base64 */ open class StoryViewerPageRepository(context: Context) { + companion object { + private val TAG = Log.tag(StoryViewerPageRepository::class.java) + } + private val context = context.applicationContext private fun getStoryRecords(recipientId: RecipientId): Observable> { @@ -104,7 +109,11 @@ open class StoryViewerPageRepository(context: Context) { } val conversationObserver = DatabaseObserver.Observer { - refresh(SignalDatabase.mms.getMessageRecord(record.id)) + try { + refresh(SignalDatabase.mms.getMessageRecord(record.id)) + } catch (e: NoSuchMessageException) { + Log.w(TAG, "Message deleted during content refresh.", e) + } } ApplicationDependencies.getDatabaseObserver().registerConversationObserver(record.threadId, conversationObserver) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageState.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageState.kt index 52e8f47c69..429735d503 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageState.kt @@ -5,7 +5,8 @@ data class StoryViewerPageState( val selectedPostIndex: Int = 0, val replyState: ReplyState = ReplyState.NONE, val isFirstPage: Boolean = false, - val isDisplayingInitialState: Boolean = false + val isDisplayingInitialState: Boolean = false, + val isReady: Boolean = false ) { /** * Indicates which Reply method is available when the user swipes on the dialog diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageViewModel.kt index 7f197ed1c0..f43665e710 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageViewModel.kt @@ -63,6 +63,7 @@ class StoryViewerPageViewModel( } state.copy( + isReady = true, posts = posts, replyState = resolveSwipeToReplyState(state, startIndex), selectedPostIndex = startIndex,