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