Allow hidden story viewing.

fork-5.53.8
Alex Hart 2022-04-06 14:37:25 -03:00 zatwierdzone przez GitHub
rodzic dc6fd8be7f
commit 7fb5ceeda4
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
12 zmienionych plików z 60 dodań i 33 usunięć

Wyświetl plik

@ -1244,7 +1244,7 @@ public class ConversationParentFragment extends Fragment
} }
private void handleStoryRingClick() { private void handleStoryRingClick() {
startActivity(StoryViewerActivity.createIntent(requireContext(), recipient.getId(), -1L)); startActivity(StoryViewerActivity.createIntent(requireContext(), recipient.getId(), -1L, recipient.get().shouldHideStory()));
} }
private void handleConversationSettings() { private void handleConversationSettings() {

Wyświetl plik

@ -190,7 +190,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
public abstract @NonNull Reader getAllStoriesFor(@NonNull RecipientId recipientId); public abstract @NonNull Reader getAllStoriesFor(@NonNull RecipientId recipientId);
public abstract @NonNull MessageId getStoryId(@NonNull RecipientId authorId, long sentTimestamp) throws NoSuchMessageException; public abstract @NonNull MessageId getStoryId(@NonNull RecipientId authorId, long sentTimestamp) throws NoSuchMessageException;
public abstract int getNumberOfStoryReplies(long parentStoryId); public abstract int getNumberOfStoryReplies(long parentStoryId);
public abstract long getUnreadStoryThreadCount(); public abstract @NonNull List<RecipientId> getUnreadStoryThreadRecipientIds();
public abstract boolean containsStories(long threadId); public abstract boolean containsStories(long threadId);
public abstract boolean hasSelfReplyInStory(long parentStoryId); public abstract boolean hasSelfReplyInStory(long parentStoryId);
public abstract @NonNull Cursor getStoryReplies(long parentStoryId); public abstract @NonNull Cursor getStoryReplies(long parentStoryId);

Wyświetl plik

@ -650,7 +650,7 @@ public class MmsDatabase extends MessageDatabase {
} }
@Override @Override
public long getUnreadStoryThreadCount() { public @NonNull List<RecipientId> getUnreadStoryThreadRecipientIds() {
SQLiteDatabase db = getReadableDatabase(); SQLiteDatabase db = getReadableDatabase();
String query = "SELECT DISTINCT " + ThreadDatabase.RECIPIENT_ID + "\n" String query = "SELECT DISTINCT " + ThreadDatabase.RECIPIENT_ID + "\n"
+ "FROM " + TABLE_NAME + "\n" + "FROM " + TABLE_NAME + "\n"
@ -660,11 +660,16 @@ public class MmsDatabase extends MessageDatabase {
try (Cursor cursor = db.rawQuery(query, null)) { try (Cursor cursor = db.rawQuery(query, null)) {
if (cursor != null) { if (cursor != null) {
return cursor.getCount(); List<RecipientId> recipientIds = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
recipientIds.add(RecipientId.from(cursor.getLong(0)));
}
return recipientIds;
} }
} }
return 0; return Collections.emptyList();
} }
@Override @Override

Wyświetl plik

@ -1427,7 +1427,7 @@ public class SmsDatabase extends MessageDatabase {
} }
@Override @Override
public long getUnreadStoryThreadCount() { public @NonNull List<RecipientId> getUnreadStoryThreadRecipientIds() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

Wyświetl plik

@ -140,7 +140,7 @@ final class RecipientDialogViewModel extends ViewModel {
if (storyViewState.getValue() == null || storyViewState.getValue() == StoryViewState.NONE) { if (storyViewState.getValue() == null || storyViewState.getValue() == StoryViewState.NONE) {
onMessageClicked(activity); onMessageClicked(activity);
} else { } else {
activity.startActivity(StoryViewerActivity.createIntent(activity, recipientDialogRepository.getRecipientId(), -1L)); activity.startActivity(StoryViewerActivity.createIntent(activity, recipientDialogRepository.getRecipientId(), -1L, recipient.getValue().shouldHideStory()));
} }
} }
@ -176,7 +176,7 @@ final class RecipientDialogViewModel extends ViewModel {
if (storyViewState.getValue() == null || storyViewState.getValue() == StoryViewState.NONE) { if (storyViewState.getValue() == null || storyViewState.getValue() == StoryViewState.NONE) {
activity.startActivity(ConversationSettingsActivity.forRecipient(activity, recipientDialogRepository.getRecipientId())); activity.startActivity(ConversationSettingsActivity.forRecipient(activity, recipientDialogRepository.getRecipientId()));
} else { } else {
activity.startActivity(StoryViewerActivity.createIntent(activity, recipientDialogRepository.getRecipientId(), -1L)); activity.startActivity(StoryViewerActivity.createIntent(activity, recipientDialogRepository.getRecipientId(), -1L, recipient.getValue().shouldHideStory()));
} }
} }

Wyświetl plik

@ -165,7 +165,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show()
} else { } else {
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), preview, ViewCompat.getTransitionName(preview) ?: "") val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), preview, ViewCompat.getTransitionName(preview) ?: "")
startActivity(StoryViewerActivity.createIntent(requireContext(), model.data.storyRecipient.id), options.toBundle()) startActivity(StoryViewerActivity.createIntent(requireContext(), model.data.storyRecipient.id, -1L, model.data.isHidden), options.toBundle())
} }
}, },
onForwardStory = { onForwardStory = {

Wyświetl plik

@ -5,6 +5,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.DatabaseObserver import org.thoughtcrime.securesms.database.DatabaseObserver
import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
class ConversationListTabRepository { class ConversationListTabRepository {
@ -21,14 +22,18 @@ class ConversationListTabRepository {
} }
fun getNumberOfUnseenStories(): Observable<Long> { fun getNumberOfUnseenStories(): Observable<Long> {
return Observable.create<Long> { return Observable.create<Long> { emitter ->
fun refresh() {
emitter.onNext(SignalDatabase.mms.unreadStoryThreadRecipientIds.map { Recipient.resolved(it) }.filterNot { it.shouldHideStory() }.size.toLong())
}
val listener = DatabaseObserver.Observer { val listener = DatabaseObserver.Observer {
it.onNext(SignalDatabase.mms.unreadStoryThreadCount) refresh()
} }
ApplicationDependencies.getDatabaseObserver().registerConversationListObserver(listener) ApplicationDependencies.getDatabaseObserver().registerConversationListObserver(listener)
it.setCancellable { ApplicationDependencies.getDatabaseObserver().unregisterObserver(listener) } emitter.setCancellable { ApplicationDependencies.getDatabaseObserver().unregisterObserver(listener) }
it.onNext(SignalDatabase.mms.unreadStoryThreadCount) refresh()
}.subscribeOn(Schedulers.io()) }.subscribeOn(Schedulers.io())
} }
} }

Wyświetl plik

@ -27,7 +27,8 @@ class StoryViewerActivity : PassphraseRequiredActivity() {
R.id.fragment_container, R.id.fragment_container,
StoryViewerFragment.create( StoryViewerFragment.create(
intent.getParcelableExtra(ARG_START_RECIPIENT_ID)!!, intent.getParcelableExtra(ARG_START_RECIPIENT_ID)!!,
intent.getLongExtra(ARG_START_STORY_ID, -1L) intent.getLongExtra(ARG_START_STORY_ID, -1L),
intent.getBooleanExtra(ARG_HIDDEN_STORIES, false)
) )
) )
.commit() .commit()
@ -37,12 +38,14 @@ class StoryViewerActivity : PassphraseRequiredActivity() {
companion object { companion object {
private const val ARG_START_RECIPIENT_ID = "start.recipient.id" private const val ARG_START_RECIPIENT_ID = "start.recipient.id"
private const val ARG_START_STORY_ID = "start.story.id" private const val ARG_START_STORY_ID = "start.story.id"
private const val ARG_HIDDEN_STORIES = "hidden_stories"
@JvmStatic @JvmStatic
fun createIntent(context: Context, recipientId: RecipientId, storyId: Long = -1L): Intent { fun createIntent(context: Context, recipientId: RecipientId, storyId: Long = -1L, onlyIncludeHiddenStories: Boolean = false): Intent {
return Intent(context, StoryViewerActivity::class.java) return Intent(context, StoryViewerActivity::class.java)
.putExtra(ARG_START_RECIPIENT_ID, recipientId) .putExtra(ARG_START_RECIPIENT_ID, recipientId)
.putExtra(ARG_START_STORY_ID, storyId) .putExtra(ARG_START_STORY_ID, storyId)
.putExtra(ARG_HIDDEN_STORIES, onlyIncludeHiddenStories)
} }
} }
} }

Wyświetl plik

@ -21,7 +21,7 @@ class StoryViewerFragment : Fragment(R.layout.stories_viewer_fragment), StoryVie
private val viewModel: StoryViewerViewModel by viewModels( private val viewModel: StoryViewerViewModel by viewModels(
factoryProducer = { factoryProducer = {
StoryViewerViewModel.Factory(storyRecipientId, StoryViewerRepository()) StoryViewerViewModel.Factory(storyRecipientId, onlyIncludeHiddenStories, StoryViewerRepository())
} }
) )
@ -31,6 +31,9 @@ class StoryViewerFragment : Fragment(R.layout.stories_viewer_fragment), StoryVie
private val storyId: Long private val storyId: Long
get() = requireArguments().getLong(ARG_START_STORY_ID, -1L) get() = requireArguments().getLong(ARG_START_STORY_ID, -1L)
private val onlyIncludeHiddenStories: Boolean
get() = requireArguments().getBoolean(ARG_HIDDEN_STORIES)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
storyPager = view.findViewById(R.id.story_item_pager) storyPager = view.findViewById(R.id.story_item_pager)
@ -90,12 +93,14 @@ class StoryViewerFragment : Fragment(R.layout.stories_viewer_fragment), StoryVie
companion object { companion object {
private const val ARG_START_RECIPIENT_ID = "start.recipient.id" private const val ARG_START_RECIPIENT_ID = "start.recipient.id"
private const val ARG_START_STORY_ID = "start.story.id" private const val ARG_START_STORY_ID = "start.story.id"
private const val ARG_HIDDEN_STORIES = "hidden_stories"
fun create(storyRecipientId: RecipientId, storyId: Long): Fragment { fun create(storyRecipientId: RecipientId, storyId: Long, onlyIncludeHiddenStories: Boolean): Fragment {
return StoryViewerFragment().apply { return StoryViewerFragment().apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putParcelable(ARG_START_RECIPIENT_ID, storyRecipientId) putParcelable(ARG_START_RECIPIENT_ID, storyRecipientId)
putLong(ARG_START_STORY_ID, storyId) putLong(ARG_START_STORY_ID, storyId)
putBoolean(ARG_HIDDEN_STORIES, onlyIncludeHiddenStories)
} }
} }
} }

Wyświetl plik

@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId
* Open for testing * Open for testing
*/ */
open class StoryViewerRepository { open class StoryViewerRepository {
fun getStories(): Single<List<RecipientId>> { fun getStories(hiddenStories: Boolean): Single<List<RecipientId>> {
return Single.create { emitter -> return Single.create { emitter ->
val myStoriesId = SignalDatabase.recipients.getOrInsertFromDistributionListId(DistributionListId.MY_STORY) val myStoriesId = SignalDatabase.recipients.getOrInsertFromDistributionListId(DistributionListId.MY_STORY)
val myStories = Recipient.resolved(myStoriesId) val myStories = Recipient.resolved(myStoriesId)
@ -21,7 +21,13 @@ open class StoryViewerRepository {
} else { } else {
recipient recipient
} }
}.keys.filterNot { it.shouldHideStory() }.map { it.id } }.keys.filter {
if (hiddenStories) {
it.shouldHideStory()
} else {
!it.shouldHideStory()
}
}.map { it.id }
emitter.onSuccess( emitter.onSuccess(
if (recipientIds.contains(myStoriesId)) { if (recipientIds.contains(myStoriesId)) {

Wyświetl plik

@ -13,6 +13,7 @@ import kotlin.math.max
class StoryViewerViewModel( class StoryViewerViewModel(
private val startRecipientId: RecipientId, private val startRecipientId: RecipientId,
private val onlyIncludeHiddenStories: Boolean,
private val repository: StoryViewerRepository private val repository: StoryViewerRepository
) : ViewModel() { ) : ViewModel() {
@ -38,7 +39,7 @@ class StoryViewerViewModel(
private fun refresh() { private fun refresh() {
disposables.clear() disposables.clear()
disposables += repository.getStories().subscribe { recipientIds -> disposables += repository.getStories(onlyIncludeHiddenStories).subscribe { recipientIds ->
store.update { store.update {
val page: Int = if (it.pages.isNotEmpty()) { val page: Int = if (it.pages.isNotEmpty()) {
val oldPage = it.page val oldPage = it.page
@ -125,10 +126,11 @@ class StoryViewerViewModel(
class Factory( class Factory(
private val startRecipientId: RecipientId, private val startRecipientId: RecipientId,
private val onlyIncludeHiddenStories: Boolean,
private val repository: StoryViewerRepository private val repository: StoryViewerRepository
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T { override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.cast(StoryViewerViewModel(startRecipientId, repository)) as T return modelClass.cast(StoryViewerViewModel(startRecipientId, onlyIncludeHiddenStories, repository)) as T
} }
} }
} }

Wyświetl plik

@ -7,6 +7,7 @@ import org.junit.After
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
@ -32,10 +33,10 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = RecipientId.from(2L) val startStory = RecipientId.from(2L)
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
// WHEN // WHEN
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// THEN // THEN
@ -50,8 +51,8 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = RecipientId.from(1L) val startStory = RecipientId.from(1L)
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// WHEN // WHEN
@ -70,8 +71,8 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = stories.last() val startStory = stories.last()
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// WHEN // WHEN
@ -90,8 +91,8 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = stories.last() val startStory = stories.last()
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// WHEN // WHEN
@ -110,8 +111,8 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = stories.first() val startStory = stories.first()
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// WHEN // WHEN
@ -130,8 +131,8 @@ class StoryViewerViewModelTest {
// GIVEN // GIVEN
val stories: List<RecipientId> = (1L..5L).map(RecipientId::from) val stories: List<RecipientId> = (1L..5L).map(RecipientId::from)
val startStory = stories.first() val startStory = stories.first()
whenever(repository.getStories()).doReturn(Single.just(stories)) whenever(repository.getStories(any())).doReturn(Single.just(stories))
val testSubject = StoryViewerViewModel(startStory, repository) val testSubject = StoryViewerViewModel(startStory, false, repository)
testScheduler.triggerActions() testScheduler.triggerActions()
// WHEN // WHEN