kopia lustrzana https://github.com/ryukoposting/Signal-Android
Display dialog to confirm hiding story in story viewer.
rodzic
115d1fcf63
commit
8141b53c15
|
@ -41,4 +41,21 @@ object StoryDialogs {
|
|||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
fun hideStory(
|
||||
context: Context,
|
||||
recipientName: String,
|
||||
onCancelled: () -> Unit = {},
|
||||
onHideStoryConfirmed: () -> Unit,
|
||||
) {
|
||||
MaterialAlertDialogBuilder(context, R.style.ThemeOverlay_Signal_MaterialAlertDialog)
|
||||
.setTitle(R.string.StoriesLandingFragment__hide_story)
|
||||
.setMessage(context.getString(R.string.StoriesLandingFragment__new_story_updates, recipientName))
|
||||
.setPositiveButton(R.string.StoriesLandingFragment__hide) { _, _ ->
|
||||
onHideStoryConfirmed()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> onCancelled() }
|
||||
.setOnCancelListener { onCancelled() }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import androidx.core.app.SharedElementCallback
|
|||
import androidx.core.view.ViewCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
@ -33,7 +32,6 @@ 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.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState
|
||||
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
|
@ -273,8 +271,8 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
|||
storyThumbTextModel = text,
|
||||
storyThumbUri = image,
|
||||
storyThumbBlur = blur,
|
||||
recipientIds = viewModel.getRecipientIds(model.data.isHidden, true),
|
||||
isUnviewedOnly = model.data.storyViewState == StoryViewState.UNVIEWED,
|
||||
recipientIds = viewModel.getRecipientIds(model.data.isHidden, false),
|
||||
isUnviewedOnly = false,
|
||||
isFromInfoContextMenuAction = isFromInfoContextMenuAction
|
||||
)
|
||||
),
|
||||
|
@ -288,19 +286,14 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
|||
}
|
||||
|
||||
private fun handleHideStory(model: StoriesLandingItem.Model) {
|
||||
MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Signal_MaterialAlertDialog)
|
||||
.setTitle(R.string.StoriesLandingFragment__hide_story)
|
||||
.setMessage(getString(R.string.StoriesLandingFragment__new_story_updates, model.data.storyRecipient.getShortDisplayName(requireContext())))
|
||||
.setPositiveButton(R.string.StoriesLandingFragment__hide) { _, _ ->
|
||||
viewModel.setHideStory(model.data.storyRecipient, true).subscribe {
|
||||
Snackbar.make(cameraFab, R.string.StoriesLandingFragment__story_hidden, Snackbar.LENGTH_SHORT)
|
||||
.setAnchorView(cameraFab)
|
||||
.setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_FADE)
|
||||
.show()
|
||||
}
|
||||
StoryDialogs.hideStory(requireContext(), model.data.storyRecipient.getShortDisplayName(requireContext())) {
|
||||
viewModel.setHideStory(model.data.storyRecipient, true).subscribe {
|
||||
Snackbar.make(cameraFab, R.string.StoriesLandingFragment__story_hidden, Snackbar.LENGTH_SHORT)
|
||||
.setAnchorView(cameraFab)
|
||||
.setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_FADE)
|
||||
.show()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
|
|
@ -66,6 +66,10 @@ class StoryViewerFragment :
|
|||
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner)
|
||||
lifecycleDisposable += viewModel.state.observeOn(AndroidSchedulers.mainThread()).subscribe { state ->
|
||||
if (state.noPosts) {
|
||||
requireActivity().finish()
|
||||
}
|
||||
|
||||
adapter.setPages(state.pages)
|
||||
if (state.pages.isNotEmpty() && storyPager.currentItem != state.page) {
|
||||
pagerOnPageSelectedLock = true
|
||||
|
@ -96,6 +100,17 @@ class StoryViewerFragment :
|
|||
storyCrossfader.alpha = 0f
|
||||
}
|
||||
}
|
||||
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(HIDDEN)) {
|
||||
val ids: List<RecipientId> = savedInstanceState.getParcelableArrayList(HIDDEN)!!
|
||||
viewModel.addHiddenAndRefresh(ids.toSet())
|
||||
} else {
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putParcelableArrayList(HIDDEN, ArrayList(viewModel.getHidden()))
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -119,7 +134,7 @@ class StoryViewerFragment :
|
|||
}
|
||||
|
||||
override fun onStoryHidden(recipientId: RecipientId) {
|
||||
viewModel.onRecipientHidden()
|
||||
viewModel.addHiddenAndRefresh(setOf(recipientId))
|
||||
}
|
||||
|
||||
override fun onReadyToAnimate() {
|
||||
|
@ -150,6 +165,7 @@ class StoryViewerFragment :
|
|||
|
||||
companion object {
|
||||
private const val ARGS = "args"
|
||||
private const val HIDDEN = "hidden"
|
||||
|
||||
fun create(storyViewerArgs: StoryViewerArgs): Fragment {
|
||||
return StoryViewerFragment().apply {
|
||||
|
|
|
@ -17,11 +17,12 @@ class StoryViewerPagerAdapter(
|
|||
private val isFromInfoContextMenuAction: Boolean
|
||||
) : FragmentStateAdapter(fragment) {
|
||||
|
||||
private var pages: List<RecipientId> = emptyList()
|
||||
private val pages: MutableList<RecipientId> = mutableListOf()
|
||||
|
||||
fun setPages(newPages: List<RecipientId>) {
|
||||
val oldPages = pages
|
||||
pages = newPages
|
||||
val oldPages = ArrayList(pages)
|
||||
pages.clear()
|
||||
pages.addAll(newPages)
|
||||
|
||||
val callback = Callback(oldPages, pages)
|
||||
DiffUtil.calculateDiff(callback).dispatchUpdatesTo(this)
|
||||
|
@ -34,6 +35,10 @@ class StoryViewerPagerAdapter(
|
|||
|
||||
override fun getItemCount(): Int = pages.size
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return pages[position].toLong()
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return StoryViewerPageFragment.create(pages[position], initialStoryId, isFromNotification, groupReplyStartPosition, isUnviewedOnly, isOutgoingOnly, isFromInfoContextMenuAction)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ data class StoryViewerState(
|
|||
val crossfadeSource: CrossfadeSource,
|
||||
val crossfadeTarget: CrossfadeTarget? = null,
|
||||
val loadState: LoadState = LoadState(),
|
||||
val skipCrossfade: Boolean = false
|
||||
val skipCrossfade: Boolean = false,
|
||||
val noPosts: Boolean = false
|
||||
) {
|
||||
sealed class CrossfadeSource {
|
||||
object None : CrossfadeSource()
|
||||
|
|
|
@ -39,6 +39,8 @@ class StoryViewerViewModel(
|
|||
val stateSnapshot: StoryViewerState get() = store.state
|
||||
val state: Flowable<StoryViewerState> = store.stateFlowable
|
||||
|
||||
private val hidden = mutableSetOf<RecipientId>()
|
||||
|
||||
private val scrollStatePublisher: MutableLiveData<Boolean> = MutableLiveData(false)
|
||||
val isScrolling: LiveData<Boolean> = scrollStatePublisher
|
||||
|
||||
|
@ -53,10 +55,13 @@ class StoryViewerViewModel(
|
|||
|
||||
val isChildScrolling: Observable<Boolean> = childScrollStatePublisher.distinctUntilChanged()
|
||||
|
||||
init {
|
||||
fun addHiddenAndRefresh(hidden: Set<RecipientId>) {
|
||||
this.hidden.addAll(hidden)
|
||||
refresh()
|
||||
}
|
||||
|
||||
fun getHidden(): Set<RecipientId> = hidden
|
||||
|
||||
fun setCrossfadeTarget(messageRecord: MmsMessageRecord) {
|
||||
store.update {
|
||||
it.copy(crossfadeTarget = StoryViewerState.CrossfadeTarget.Record(messageRecord))
|
||||
|
@ -85,7 +90,7 @@ class StoryViewerViewModel(
|
|||
|
||||
private fun getStories(): Single<List<RecipientId>> {
|
||||
return if (storyViewerArgs.recipientIds.isNotEmpty()) {
|
||||
Single.just(storyViewerArgs.recipientIds)
|
||||
Single.just(storyViewerArgs.recipientIds - hidden)
|
||||
} else {
|
||||
repository.getStories(
|
||||
hiddenStories = storyViewerArgs.isInHiddenStoryMode,
|
||||
|
@ -95,7 +100,7 @@ class StoryViewerViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
fun refresh() {
|
||||
disposables.clear()
|
||||
disposables += repository.getFirstStory(storyViewerArgs.recipientId, storyViewerArgs.isUnviewedOnly, storyViewerArgs.storyId).subscribe { record ->
|
||||
store.update {
|
||||
|
@ -119,7 +124,7 @@ class StoryViewerViewModel(
|
|||
} else {
|
||||
it.page
|
||||
}
|
||||
updatePages(it.copy(pages = recipientIds), page)
|
||||
updatePages(it.copy(pages = recipientIds), page).copy(noPosts = recipientIds.isEmpty())
|
||||
}
|
||||
}
|
||||
disposables += state
|
||||
|
@ -167,10 +172,6 @@ class StoryViewerViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onRecipientHidden() {
|
||||
refresh()
|
||||
}
|
||||
|
||||
private fun updatePages(state: StoryViewerState, page: Int): StoryViewerState {
|
||||
val newPage = resolvePage(page, state.pages)
|
||||
val prevPage = if (newPage == state.page) {
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.thoughtcrime.securesms.stories.StoryFirstTimeNavigationView
|
|||
import org.thoughtcrime.securesms.stories.StorySlateView
|
||||
import org.thoughtcrime.securesms.stories.StoryVolumeOverlayView
|
||||
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||
import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs
|
||||
import org.thoughtcrime.securesms.stories.viewer.StoryViewerViewModel
|
||||
import org.thoughtcrime.securesms.stories.viewer.StoryVolumeViewModel
|
||||
import org.thoughtcrime.securesms.stories.viewer.info.StoryInfoBottomSheetDialogFragment
|
||||
|
@ -979,8 +980,11 @@ class StoryViewerPageFragment :
|
|||
startActivity(ConversationIntents.createBuilder(requireContext(), storyRecipientId, -1L).build())
|
||||
},
|
||||
onHide = {
|
||||
lifecycleDisposable += viewModel.hideStory().subscribe {
|
||||
callback.onStoryHidden(storyRecipientId)
|
||||
viewModel.setIsDisplayingHideDialog(true)
|
||||
StoryDialogs.hideStory(requireContext(), Recipient.resolved(storyRecipientId).getDisplayName(requireContext()), { viewModel.setIsDisplayingHideDialog(true) }) {
|
||||
lifecycleDisposable += viewModel.hideStory().subscribe {
|
||||
callback.onStoryHidden(storyRecipientId)
|
||||
}
|
||||
}
|
||||
},
|
||||
onShare = {
|
||||
|
|
|
@ -222,6 +222,10 @@ class StoryViewerPageViewModel(
|
|||
storyViewerPlaybackStore.update { it.copy(isDisplayingDeleteDialog = isDisplayingDeleteDialog) }
|
||||
}
|
||||
|
||||
fun setIsDisplayingHideDialog(isDisplayingHideDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingHideDialog = isDisplayingHideDialog) }
|
||||
}
|
||||
|
||||
fun setIsDisplayingViewsAndRepliesDialog(isDisplayingViewsAndRepliesDialog: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingViewsAndRepliesDialog = isDisplayingViewsAndRepliesDialog) }
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ data class StoryViewerPlaybackState(
|
|||
val isUserTouching: Boolean = false,
|
||||
val isDisplayingForwardDialog: Boolean = false,
|
||||
val isDisplayingDeleteDialog: Boolean = false,
|
||||
val isDisplayingHideDialog: Boolean = false,
|
||||
val isDisplayingContextMenu: Boolean = false,
|
||||
val isDisplayingViewsAndRepliesDialog: Boolean = false,
|
||||
val isDisplayingDirectReplyDialog: Boolean = false,
|
||||
|
@ -44,5 +45,6 @@ data class StoryViewerPlaybackState(
|
|||
isRunningSharedElementAnimation ||
|
||||
isDisplayingFirstTimeNavigation ||
|
||||
isDisplayingInfoDialog ||
|
||||
isUserScaling
|
||||
isUserScaling ||
|
||||
isDisplayingHideDialog
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ class StoryViewerViewModelTest {
|
|||
),
|
||||
repository
|
||||
)
|
||||
testSubject.refresh()
|
||||
testScheduler.triggerActions()
|
||||
|
||||
// THEN
|
||||
|
@ -107,6 +108,7 @@ class StoryViewerViewModelTest {
|
|||
),
|
||||
repository
|
||||
)
|
||||
testSubject.refresh()
|
||||
testScheduler.triggerActions()
|
||||
|
||||
// WHEN
|
||||
|
@ -133,6 +135,7 @@ class StoryViewerViewModelTest {
|
|||
),
|
||||
repository
|
||||
)
|
||||
testSubject.refresh()
|
||||
testScheduler.triggerActions()
|
||||
|
||||
// WHEN
|
||||
|
@ -159,6 +162,7 @@ class StoryViewerViewModelTest {
|
|||
),
|
||||
repository
|
||||
)
|
||||
testSubject.refresh()
|
||||
testScheduler.triggerActions()
|
||||
|
||||
// WHEN
|
||||
|
@ -185,6 +189,7 @@ class StoryViewerViewModelTest {
|
|||
),
|
||||
repository
|
||||
)
|
||||
testSubject.refresh()
|
||||
testScheduler.triggerActions()
|
||||
|
||||
// WHEN
|
||||
|
|
Ładowanie…
Reference in New Issue