Add support for stories "seen" state.
This commit is contained in:
parent
995a4ad6ec
commit
94bd3101c9
17 changed files with 168 additions and 17 deletions
|
@ -129,7 +129,7 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
|
|||
|
||||
fun onClearOnboardingState() {
|
||||
SignalStore.storyValues().hasDownloadedOnboardingStory = false
|
||||
SignalStore.storyValues().userHasSeenOnboardingStory = false
|
||||
SignalStore.storyValues().userHasViewedOnboardingStory = false
|
||||
Stories.onStorySettingsChanged(Recipient.self().id)
|
||||
refresh()
|
||||
StoryOnboardingDownloadJob.enqueueIfNeeded()
|
||||
|
|
|
@ -203,7 +203,11 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
|
|||
public abstract @NonNull Reader getOutgoingStoriesTo(@NonNull RecipientId recipientId);
|
||||
public abstract @NonNull Reader getAllOutgoingStories(boolean reverse, int limit);
|
||||
public abstract @NonNull Reader getAllOutgoingStoriesAt(long sentTimestamp);
|
||||
public abstract @NonNull List<MarkedMessageInfo> markAllIncomingStoriesRead();
|
||||
public abstract @NonNull List<StoryResult> getOrderedStoryRecipientsAndIds(boolean isOutgoingOnly);
|
||||
|
||||
public abstract void markOnboardingStoryRead();
|
||||
|
||||
public abstract @NonNull Reader getAllStoriesFor(@NonNull RecipientId recipientId, int limit);
|
||||
public abstract @NonNull MessageId getStoryId(@NonNull RecipientId authorId, long sentTimestamp) throws NoSuchMessageException;
|
||||
public abstract int getNumberOfStoryReplies(long parentStoryId);
|
||||
|
|
|
@ -655,6 +655,31 @@ public class MmsDatabase extends MessageDatabase {
|
|||
return new Reader(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<MarkedMessageInfo> markAllIncomingStoriesRead() {
|
||||
String where = IS_STORY_CLAUSE + " AND NOT (" + getOutgoingTypeClause() + ") AND " + READ + " = 0";
|
||||
|
||||
List<MarkedMessageInfo> markedMessageInfos = setMessagesRead(where, null);
|
||||
notifyConversationListListeners();
|
||||
|
||||
return markedMessageInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markOnboardingStoryRead() {
|
||||
RecipientId recipientId = SignalStore.releaseChannelValues().getReleaseChannelRecipientId();
|
||||
if (recipientId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String where = IS_STORY_CLAUSE + " AND NOT (" + getOutgoingTypeClause() + ") AND " + READ + " = 0 AND " + RECIPIENT_ID + " = ?";
|
||||
|
||||
List<MarkedMessageInfo> markedMessageInfos = setMessagesRead(where, SqlUtil.buildArgs(recipientId));
|
||||
if (!markedMessageInfos.isEmpty()) {
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MessageDatabase.Reader getAllStoriesFor(@NonNull RecipientId recipientId, int limit) {
|
||||
long threadId = SignalDatabase.threads().getThreadIdIfExistsFor(recipientId);
|
||||
|
@ -801,7 +826,7 @@ public class MmsDatabase extends MessageDatabase {
|
|||
+ "FROM " + TABLE_NAME + "\n"
|
||||
+ "JOIN " + ThreadDatabase.TABLE_NAME + "\n"
|
||||
+ "ON " + TABLE_NAME + "." + THREAD_ID + " = " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.ID + "\n"
|
||||
+ "WHERE " + IS_STORY_CLAUSE + " AND (" + getOutgoingTypeClause() + ") = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0";
|
||||
+ "WHERE " + IS_STORY_CLAUSE + " AND (" + getOutgoingTypeClause() + ") = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0 AND " + TABLE_NAME + "." + READ + " = 0";
|
||||
|
||||
try (Cursor cursor = db.rawQuery(query, null)) {
|
||||
if (cursor != null) {
|
||||
|
|
|
@ -1488,11 +1488,21 @@ public class SmsDatabase extends MessageDatabase {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<MarkedMessageInfo> markAllIncomingStoriesRead() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<StoryResult> getOrderedStoryRecipientsAndIds(boolean isOutgoingOnly) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markOnboardingStoryRead() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MessageDatabase.Reader getAllStoriesFor(@NonNull RecipientId recipientId, int limit) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -62,6 +62,7 @@ import org.thoughtcrime.securesms.migrations.StickerMyDailyLifeMigrationJob;
|
|||
import org.thoughtcrime.securesms.migrations.StorageCapabilityMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.StorageServiceMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.StorageServiceSystemNameMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.StoryReadStateMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.StoryViewedReceiptsStateMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.SyncDistributionListsMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.TrimByLengthSettingsMigrationJob;
|
||||
|
@ -226,6 +227,7 @@ public final class JobManagerFactories {
|
|||
put(StorageCapabilityMigrationJob.KEY, new StorageCapabilityMigrationJob.Factory());
|
||||
put(StorageServiceMigrationJob.KEY, new StorageServiceMigrationJob.Factory());
|
||||
put(StorageServiceSystemNameMigrationJob.KEY, new StorageServiceSystemNameMigrationJob.Factory());
|
||||
put(StoryReadStateMigrationJob.KEY, new StoryReadStateMigrationJob.Factory());
|
||||
put(StoryViewedReceiptsStateMigrationJob.KEY, new StoryViewedReceiptsStateMigrationJob.Factory());
|
||||
put(TrimByLengthSettingsMigrationJob.KEY, new TrimByLengthSettingsMigrationJob.Factory());
|
||||
put(UserNotificationMigrationJob.KEY, new UserNotificationMigrationJob.Factory());
|
||||
|
|
|
@ -36,9 +36,14 @@ internal class StoryValues(store: KeyValueStore) : SignalStoreValues(store) {
|
|||
private const val HAS_DOWNLOADED_ONBOARDING_STORY = "stories.has.downloaded.onboarding"
|
||||
|
||||
/**
|
||||
* Marks whether the user has seen the onboarding story
|
||||
* Marks whether the user has opened and viewed the onboarding story
|
||||
*/
|
||||
private const val USER_HAS_SEEN_ONBOARDING_STORY = "stories.user.has.seen.onboarding"
|
||||
private const val USER_HAS_VIEWED_ONBOARDING_STORY = "stories.user.has.seen.onboarding"
|
||||
|
||||
/**
|
||||
* Marks whether the user has seen the onboarding story in the stories landing page
|
||||
*/
|
||||
private const val USER_HAS_READ_ONBOARDING_STORY = "stories.user.has.read.onboarding"
|
||||
|
||||
/**
|
||||
* Marks whether the user has seen the beta dialog
|
||||
|
@ -61,7 +66,8 @@ internal class StoryValues(store: KeyValueStore) : SignalStoreValues(store) {
|
|||
USER_HAS_SEEN_FIRST_NAV_VIEW,
|
||||
HAS_DOWNLOADED_ONBOARDING_STORY,
|
||||
USER_HAS_SEEN_BETA_DIALOG,
|
||||
STORY_VIEWED_RECEIPTS
|
||||
STORY_VIEWED_RECEIPTS,
|
||||
USER_HAS_READ_ONBOARDING_STORY
|
||||
)
|
||||
|
||||
var isFeatureDisabled: Boolean by booleanValue(MANUAL_FEATURE_DISABLE, false)
|
||||
|
@ -74,7 +80,9 @@ internal class StoryValues(store: KeyValueStore) : SignalStoreValues(store) {
|
|||
|
||||
var hasDownloadedOnboardingStory: Boolean by booleanValue(HAS_DOWNLOADED_ONBOARDING_STORY, false)
|
||||
|
||||
var userHasSeenOnboardingStory: Boolean by booleanValue(USER_HAS_SEEN_ONBOARDING_STORY, false)
|
||||
var userHasViewedOnboardingStory: Boolean by booleanValue(USER_HAS_VIEWED_ONBOARDING_STORY, false)
|
||||
|
||||
var userHasReadOnboardingStory: Boolean by booleanValue(USER_HAS_READ_ONBOARDING_STORY, false)
|
||||
|
||||
var userHasSeenBetaDialog: Boolean by booleanValue(USER_HAS_SEEN_BETA_DIALOG, false)
|
||||
|
||||
|
@ -84,6 +92,10 @@ internal class StoryValues(store: KeyValueStore) : SignalStoreValues(store) {
|
|||
return store.containsKey(STORY_VIEWED_RECEIPTS)
|
||||
}
|
||||
|
||||
fun hasUserOnboardingStoryReadBeenSet(): Boolean {
|
||||
return store.containsKey(USER_HAS_READ_ONBOARDING_STORY)
|
||||
}
|
||||
|
||||
fun setLatestStorySend(storySend: StorySend) {
|
||||
synchronized(this) {
|
||||
val storySends: List<StorySend> = getList(LATEST_STORY_SENDS, StorySendSerializer)
|
||||
|
|
|
@ -110,9 +110,10 @@ public class ApplicationMigrations {
|
|||
static final int PNI_2 = 66;
|
||||
static final int SYSTEM_NAME_SYNC = 67;
|
||||
static final int STORY_VIEWED_STATE = 68;
|
||||
static final int STORY_READ_STATE = 69;
|
||||
}
|
||||
|
||||
public static final int CURRENT_VERSION = 68;
|
||||
public static final int CURRENT_VERSION = 69;
|
||||
|
||||
/**
|
||||
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
|
||||
|
@ -486,6 +487,10 @@ public class ApplicationMigrations {
|
|||
jobs.put(Version.STORY_VIEWED_STATE, new StoryViewedReceiptsStateMigrationJob());
|
||||
}
|
||||
|
||||
if (lastSeenVersion < Version.STORY_READ_STATE) {
|
||||
jobs.put(Version.STORY_READ_STATE, new StoryReadStateMigrationJob());
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package org.thoughtcrime.securesms.migrations
|
||||
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.mms
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.recipients
|
||||
import org.thoughtcrime.securesms.jobmanager.Data
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
|
||||
/**
|
||||
* Added to initialize whether the user has seen the onboarding story
|
||||
*/
|
||||
internal class StoryReadStateMigrationJob(
|
||||
parameters: Parameters = Parameters.Builder().build()
|
||||
) : MigrationJob(parameters) {
|
||||
|
||||
companion object {
|
||||
const val KEY = "StoryReadStateMigrationJob"
|
||||
}
|
||||
|
||||
override fun getFactoryKey(): String = KEY
|
||||
|
||||
override fun isUiBlocking(): Boolean = false
|
||||
|
||||
override fun performMigration() {
|
||||
if (!SignalStore.storyValues().hasUserOnboardingStoryReadBeenSet()) {
|
||||
SignalStore.storyValues().userHasReadOnboardingStory = SignalStore.storyValues().userHasReadOnboardingStory
|
||||
mms.markOnboardingStoryRead()
|
||||
|
||||
if (SignalStore.account().isRegistered) {
|
||||
recipients.markNeedsSync(Recipient.self().id)
|
||||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRetry(e: Exception): Boolean = false
|
||||
|
||||
class Factory : Job.Factory<StoryReadStateMigrationJob> {
|
||||
override fun create(parameters: Parameters, data: Data): StoryReadStateMigrationJob {
|
||||
return StoryReadStateMigrationJob(parameters)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ class ExpiringStoriesManager(
|
|||
|
||||
@WorkerThread
|
||||
override fun getNextClosestEvent(): Event? {
|
||||
val oldestTimestamp = mmsDatabase.getOldestStorySendTimestamp(SignalStore.storyValues().userHasSeenOnboardingStory) ?: return null
|
||||
val oldestTimestamp = mmsDatabase.getOldestStorySendTimestamp(SignalStore.storyValues().userHasViewedOnboardingStory) ?: return null
|
||||
|
||||
val timeSinceSend = System.currentTimeMillis() - oldestTimestamp
|
||||
val delay = (STORY_LIFESPAN - timeSinceSend).coerceAtLeast(0)
|
||||
|
@ -44,7 +44,7 @@ class ExpiringStoriesManager(
|
|||
@WorkerThread
|
||||
override fun executeEvent(event: Event) {
|
||||
val threshold = System.currentTimeMillis() - STORY_LIFESPAN
|
||||
val deletes = mmsDatabase.deleteStoriesOlderThan(threshold, SignalStore.storyValues().userHasSeenOnboardingStory)
|
||||
val deletes = mmsDatabase.deleteStoriesOlderThan(threshold, SignalStore.storyValues().userHasViewedOnboardingStory)
|
||||
Log.i(TAG, "Deleted $deletes stories before $threshold")
|
||||
}
|
||||
|
||||
|
|
|
@ -123,8 +123,9 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
|||
boolean hasSetMyStoriesPrivacy = remote.hasSetMyStoriesPrivacy();
|
||||
boolean hasViewedOnboardingStory = remote.hasViewedOnboardingStory();
|
||||
boolean storiesDisabled = remote.isStoriesDisabled();
|
||||
boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile, subscriptionManuallyCancelled, keepMutedChatsArchived, hasSetMyStoriesPrivacy, hasViewedOnboardingStory, storiesDisabled, storyViewReceiptsState);
|
||||
boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile, subscriptionManuallyCancelled, keepMutedChatsArchived, hasSetMyStoriesPrivacy, hasViewedOnboardingStory, storiesDisabled, storyViewReceiptsState);
|
||||
boolean hasReadOnboardingStory = remote.hasReadOnboardingStory() || remote.hasViewedOnboardingStory() || local.hasReadOnboardingStory() || local.hasViewedOnboardingStory() ;
|
||||
boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile, subscriptionManuallyCancelled, keepMutedChatsArchived, hasSetMyStoriesPrivacy, hasViewedOnboardingStory, storiesDisabled, storyViewReceiptsState, hasReadOnboardingStory);
|
||||
boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars, payments, universalExpireTimer, primarySendsSms, e164, defaultReactions, subscriber, displayBadgesOnProfile, subscriptionManuallyCancelled, keepMutedChatsArchived, hasSetMyStoriesPrivacy, hasViewedOnboardingStory, storiesDisabled, storyViewReceiptsState, hasReadOnboardingStory);
|
||||
|
||||
if (matchesRemote) {
|
||||
return remote;
|
||||
|
@ -159,6 +160,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
|||
.setHasSetMyStoriesPrivacy(hasSetMyStoriesPrivacy)
|
||||
.setHasViewedOnboardingStory(hasViewedOnboardingStory)
|
||||
.setStoriesDisabled(storiesDisabled)
|
||||
.setHasReadOnboardingStory(hasReadOnboardingStory)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +208,8 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
|||
boolean hasSetMyStoriesPrivacy,
|
||||
boolean hasViewedOnboardingStory,
|
||||
boolean storiesDisabled,
|
||||
@NonNull OptionalBool storyViewReceiptsState)
|
||||
@NonNull OptionalBool storyViewReceiptsState,
|
||||
boolean hasReadOnboardingStory)
|
||||
{
|
||||
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
|
||||
Objects.equals(contact.getGivenName().orElse(""), givenName) &&
|
||||
|
@ -235,6 +238,7 @@ public class AccountRecordProcessor extends DefaultStorageRecordProcessor<Signal
|
|||
contact.hasSetMyStoriesPrivacy() == hasSetMyStoriesPrivacy &&
|
||||
contact.hasViewedOnboardingStory() == hasViewedOnboardingStory &&
|
||||
contact.isStoriesDisabled() == storiesDisabled &&
|
||||
contact.getStoryViewReceiptsState().equals(storyViewReceiptsState);
|
||||
contact.getStoryViewReceiptsState().equals(storyViewReceiptsState) &&
|
||||
contact.hasReadOnboardingStory() == hasReadOnboardingStory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
|
|||
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
||||
import org.whispersystems.signalservice.api.storage.StorageId;
|
||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.OptionalBool;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -122,6 +121,8 @@ public final class StorageSyncHelper {
|
|||
record = recipientDatabase.getRecordForSync(self.getId());
|
||||
}
|
||||
|
||||
final boolean hasReadOnboardingStory = SignalStore.storyValues().getUserHasViewedOnboardingStory() || SignalStore.storyValues().getUserHasReadOnboardingStory();
|
||||
|
||||
SignalAccountRecord account = new SignalAccountRecord.Builder(self.getStorageServiceId(), record != null ? record.getSyncExtras().getStorageProto() : null)
|
||||
.setProfileKey(self.getProfileKey())
|
||||
.setGivenName(self.getProfileName().getGivenName())
|
||||
|
@ -147,9 +148,10 @@ public final class StorageSyncHelper {
|
|||
.setSubscriptionManuallyCancelled(SignalStore.donationsValues().isUserManuallyCancelled())
|
||||
.setKeepMutedChatsArchived(SignalStore.settings().shouldKeepMutedChatsArchived())
|
||||
.setHasSetMyStoriesPrivacy(SignalStore.storyValues().getUserHasBeenNotifiedAboutStories())
|
||||
.setHasViewedOnboardingStory(SignalStore.storyValues().getUserHasSeenOnboardingStory())
|
||||
.setHasViewedOnboardingStory(SignalStore.storyValues().getUserHasViewedOnboardingStory())
|
||||
.setStoriesDisabled(SignalStore.storyValues().isFeatureDisabled())
|
||||
.setStoryViewReceiptsState(storyViewReceiptsState)
|
||||
.setHasReadOnboardingStory(hasReadOnboardingStory)
|
||||
.build();
|
||||
|
||||
return SignalStorageRecord.forAccount(account);
|
||||
|
@ -176,8 +178,9 @@ public final class StorageSyncHelper {
|
|||
SignalStore.donationsValues().setDisplayBadgesOnProfile(update.getNew().isDisplayBadgesOnProfile());
|
||||
SignalStore.settings().setKeepMutedChatsArchived(update.getNew().isKeepMutedChatsArchived());
|
||||
SignalStore.storyValues().setUserHasBeenNotifiedAboutStories(update.getNew().hasSetMyStoriesPrivacy());
|
||||
SignalStore.storyValues().setUserHasSeenOnboardingStory(update.getNew().hasViewedOnboardingStory());
|
||||
SignalStore.storyValues().setUserHasViewedOnboardingStory(update.getNew().hasViewedOnboardingStory());
|
||||
SignalStore.storyValues().setFeatureDisabled(update.getNew().isStoriesDisabled());
|
||||
SignalStore.storyValues().setUserHasReadOnboardingStory(update.getNew().hasReadOnboardingStory());
|
||||
|
||||
if (update.getNew().getStoryViewReceiptsState() == OptionalBool.UNSET) {
|
||||
SignalStore.storyValues().setViewedReceiptsEnabled(update.getNew().isReadReceiptsEnabled());
|
||||
|
|
|
@ -91,6 +91,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
|||
super.onResume()
|
||||
viewModel.isTransitioningToAnotherScreen = false
|
||||
initializeSearchAction()
|
||||
viewModel.markStoriesRead()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
|
|
@ -4,18 +4,23 @@ import android.content.Context
|
|||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage
|
||||
import org.thoughtcrime.securesms.database.DatabaseObserver
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListId
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.StoryResult
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.sms.MessageSender
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
|
||||
class StoriesLandingRepository(context: Context) {
|
||||
|
||||
|
@ -159,4 +164,21 @@ class StoriesLandingRepository(context: Context) {
|
|||
SignalDatabase.recipients.setHideStory(recipientId, hideStory)
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all stories as "seen" by the user (marking them as read in the database)
|
||||
*/
|
||||
fun markStoriesRead() {
|
||||
SignalExecutors.BOUNDED_IO.execute {
|
||||
val messageInfos: List<MessageDatabase.MarkedMessageInfo> = SignalDatabase.mms.markAllIncomingStoriesRead()
|
||||
val releaseThread: Long? = SignalStore.releaseChannelValues().releaseChannelRecipientId?.let { SignalDatabase.threads.getThreadIdIfExistsFor(it) }
|
||||
|
||||
MultiDeviceReadUpdateJob.enqueue(messageInfos.filter { it.threadId == releaseThread }.map { it.syncMessageId })
|
||||
|
||||
if (messageInfos.any { it.threadId == releaseThread }) {
|
||||
SignalStore.storyValues().userHasReadOnboardingStory = true
|
||||
Stories.onStorySettingsChanged(Recipient.self().id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,10 @@ class StoriesLandingViewModel(private val storiesLandingRepository: StoriesLandi
|
|||
store.update { it.copy(searchQuery = query) }
|
||||
}
|
||||
|
||||
fun markStoriesRead() {
|
||||
storiesLandingRepository.markStoriesRead()
|
||||
}
|
||||
|
||||
class Factory(private val storiesLandingRepository: StoriesLandingRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.cast(StoriesLandingViewModel(storiesLandingRepository)) as T
|
||||
|
|
|
@ -173,7 +173,7 @@ open class StoryViewerPageRepository(context: Context) {
|
|||
ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners()
|
||||
|
||||
if (storyPost.sender.isReleaseNotes) {
|
||||
SignalStore.storyValues().userHasSeenOnboardingStory = true
|
||||
SignalStore.storyValues().userHasViewedOnboardingStory = true
|
||||
Stories.onStorySettingsChanged(Recipient.self().id)
|
||||
} else {
|
||||
ApplicationDependencies.getJobManager().add(
|
||||
|
|
|
@ -187,6 +187,10 @@ public final class SignalAccountRecord implements SignalRecord {
|
|||
diff.add("StoryViewedReceipts");
|
||||
}
|
||||
|
||||
if (hasReadOnboardingStory() != that.hasReadOnboardingStory()) {
|
||||
diff.add("HasReadOnboardingStory");
|
||||
}
|
||||
|
||||
return diff.toString();
|
||||
} else {
|
||||
return "Different class. " + getClass().getSimpleName() + " | " + other.getClass().getSimpleName();
|
||||
|
@ -309,6 +313,10 @@ public final class SignalAccountRecord implements SignalRecord {
|
|||
return proto.getStoryViewReceiptsEnabled();
|
||||
}
|
||||
|
||||
public boolean hasReadOnboardingStory() {
|
||||
return proto.getHasReadOnboardingStory();
|
||||
}
|
||||
|
||||
public AccountRecord toProto() {
|
||||
return proto;
|
||||
}
|
||||
|
@ -671,6 +679,11 @@ public final class SignalAccountRecord implements SignalRecord {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setHasReadOnboardingStory(boolean hasReadOnboardingStory) {
|
||||
builder.setHasReadOnboardingStory(hasReadOnboardingStory);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static AccountRecord.Builder parseUnknowns(byte[] serializedUnknowns) {
|
||||
try {
|
||||
return AccountRecord.parseFrom(serializedUnknowns).toBuilder();
|
||||
|
|
|
@ -183,6 +183,7 @@ message AccountRecord {
|
|||
reserved /* storiesDisabled */ 28;
|
||||
bool storiesDisabled = 29;
|
||||
OptionalBool storyViewReceiptsEnabled = 30;
|
||||
bool hasReadOnboardingStory = 31;
|
||||
}
|
||||
|
||||
message StoryDistributionListRecord {
|
||||
|
|
Loading…
Add table
Reference in a new issue