kopia lustrzana https://github.com/ryukoposting/Signal-Android
Allow hidden story viewing.
rodzic
dc6fd8be7f
commit
7fb5ceeda4
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Ładowanie…
Reference in New Issue