Add support for stories "seen" state.

fork-5.53.8
Alex Hart 2022-10-19 14:53:31 -03:00 zatwierdzone przez Cody Henthorne
rodzic 995a4ad6ec
commit 94bd3101c9
17 zmienionych plików z 168 dodań i 17 usunięć

Wyświetl plik

@ -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()

Wyświetl plik

@ -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);

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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();

Wyświetl plik

@ -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());

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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)
}
}
}

Wyświetl plik

@ -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")
}

Wyświetl plik

@ -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;
}
}

Wyświetl plik

@ -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());

Wyświetl plik

@ -91,6 +91,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
super.onResume()
viewModel.isTransitioningToAnotherScreen = false
initializeSearchAction()
viewModel.markStoriesRead()
}
override fun onPause() {

Wyświetl plik

@ -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)
}
}
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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(

Wyświetl plik

@ -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();

Wyświetl plik

@ -183,6 +183,7 @@ message AccountRecord {
reserved /* storiesDisabled */ 28;
bool storiesDisabled = 29;
OptionalBool storyViewReceiptsEnabled = 30;
bool hasReadOnboardingStory = 31;
}
message StoryDistributionListRecord {