Add support for smarter story downloads.
This commit is contained in:
parent
c4bc2162f2
commit
17111abc72
13 changed files with 125 additions and 15 deletions
|
@ -195,7 +195,10 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||||
public abstract @NonNull Cursor getStoryReplies(long parentStoryId);
|
public abstract @NonNull Cursor getStoryReplies(long parentStoryId);
|
||||||
public abstract @Nullable Long getOldestStorySendTimestamp();
|
public abstract @Nullable Long getOldestStorySendTimestamp();
|
||||||
public abstract int deleteStoriesOlderThan(long timestamp);
|
public abstract int deleteStoriesOlderThan(long timestamp);
|
||||||
|
public abstract @NonNull MessageDatabase.Reader getUnreadStories(@NonNull RecipientId recipientId, int limit);
|
||||||
|
|
||||||
public abstract @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId);
|
public abstract @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId);
|
||||||
|
public abstract void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds);
|
||||||
|
|
||||||
final @NonNull String getOutgoingTypeClause() {
|
final @NonNull String getOutgoingTypeClause() {
|
||||||
List<String> segments = new ArrayList<>(Types.OUTGOING_MESSAGE_TYPES.length);
|
List<String> segments = new ArrayList<>(Types.OUTGOING_MESSAGE_TYPES.length);
|
||||||
|
|
|
@ -590,6 +590,17 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
return new Reader(cursor);
|
return new Reader(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull MessageDatabase.Reader getUnreadStories(@NonNull RecipientId recipientId, int limit) {
|
||||||
|
final String query = IS_STORY_CLAUSE +
|
||||||
|
" AND NOT (" + getOutgoingTypeClause() + ") " +
|
||||||
|
" AND " + RECIPIENT_ID + " = ?" +
|
||||||
|
" AND " + VIEWED_RECEIPT_COUNT + " = ?";
|
||||||
|
final String[] args = SqlUtil.buildArgs(recipientId, 0);
|
||||||
|
|
||||||
|
return new Reader(rawQuery(query, args, false, limit));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId) {
|
public @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId) {
|
||||||
if (!Stories.isFeatureEnabled()) {
|
if (!Stories.isFeatureEnabled()) {
|
||||||
|
@ -601,6 +612,28 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
return getStoryViewState(threadId);
|
return getStoryViewState(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronizes whether we've viewed a recipient's story based on incoming sync messages.
|
||||||
|
*/
|
||||||
|
public void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds) {
|
||||||
|
final String timestamps = Util.join(syncMessageIds.stream().map(SyncMessageId::getTimetamp).collect(java.util.stream.Collectors.toList()), ",");
|
||||||
|
final String[] projection = SqlUtil.buildArgs(RECIPIENT_ID);
|
||||||
|
final String where = IS_STORY_CLAUSE + " AND " + NORMALIZED_DATE_SENT + " IN (" + timestamps + ") AND NOT (" + getOutgoingTypeClause() + ") AND " + VIEWED_RECEIPT_COUNT + " > 0";
|
||||||
|
|
||||||
|
try {
|
||||||
|
getWritableDatabase().beginTransaction();
|
||||||
|
try (Cursor cursor = getWritableDatabase().query(TABLE_NAME, projection, where, null, null, null, null)) {
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
Recipient recipient = Recipient.resolved(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)));
|
||||||
|
SignalDatabase.recipients().updateLastStoryViewTimestamp(recipient.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getWritableDatabase().setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
getWritableDatabase().endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@NonNull StoryViewState getStoryViewState(long threadId) {
|
@NonNull StoryViewState getStoryViewState(long threadId) {
|
||||||
final String hasStoryQuery = "SELECT EXISTS(SELECT 1 FROM " + TABLE_NAME + " WHERE " + IS_STORY_CLAUSE + " AND " + THREAD_ID_WHERE + " LIMIT 1)";
|
final String hasStoryQuery = "SELECT EXISTS(SELECT 1 FROM " + TABLE_NAME + " WHERE " + IS_STORY_CLAUSE + " AND " + THREAD_ID_WHERE + " LIMIT 1)";
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.signal.libsignal.protocol.util.Pair;
|
||||||
import org.thoughtcrime.securesms.database.MessageDatabase.MessageUpdate;
|
import org.thoughtcrime.securesms.database.MessageDatabase.MessageUpdate;
|
||||||
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.notifications.v2.MessageNotifierV2;
|
import org.thoughtcrime.securesms.notifications.v2.MessageNotifierV2;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
@ -529,6 +530,9 @@ public class MmsSmsDatabase extends Database {
|
||||||
return SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType, true);
|
return SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds) {
|
||||||
|
SignalDatabase.mms().updateViewedStories(syncMessageIds);
|
||||||
|
}
|
||||||
|
|
||||||
public void setTimestampRead(@NonNull Recipient senderRecipient, @NonNull List<ReadMessage> readMessages, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
public void setTimestampRead(@NonNull Recipient senderRecipient, @NonNull List<ReadMessage> readMessages, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
|
|
|
@ -1964,6 +1964,10 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
StorageSyncHelper.scheduleSyncForDataChange()
|
StorageSyncHelper.scheduleSyncForDataChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateLastStoryViewTimestamp(id: RecipientId) {
|
||||||
|
updateExtras(id) { it.setLastStoryView(System.currentTimeMillis()) }
|
||||||
|
}
|
||||||
|
|
||||||
fun clearUsernameIfExists(username: String) {
|
fun clearUsernameIfExists(username: String) {
|
||||||
val existingUsername = getByUsername(username)
|
val existingUsername = getByUsername(username)
|
||||||
if (existingUsername.isPresent) {
|
if (existingUsername.isPresent) {
|
||||||
|
|
|
@ -1451,11 +1451,21 @@ public class SmsDatabase extends MessageDatabase {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int deleteStoriesOlderThan(long timestamp) {
|
public int deleteStoriesOlderThan(long timestamp) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull MessageDatabase.Reader getUnreadStories(@NonNull RecipientId recipientId, int limit) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MessageRecord getMessageRecord(long messageId) throws NoSuchMessageException {
|
public MessageRecord getMessageRecord(long messageId) throws NoSuchMessageException {
|
||||||
return getSmsMessage(messageId);
|
return getSmsMessage(messageId);
|
||||||
|
|
|
@ -177,12 +177,14 @@ import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -1407,13 +1409,7 @@ public final class MessageContentProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
List<DatabaseAttachment> allAttachments = SignalDatabase.attachments().getAttachmentsForMessage(insertResult.get().getMessageId());
|
Stories.enqueueNextStoriesForDownload(threadRecipient.getId(), false);
|
||||||
List<DatabaseAttachment> attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList();
|
|
||||||
|
|
||||||
for (DatabaseAttachment attachment : attachments) {
|
|
||||||
ApplicationDependencies.getJobManager().add(new AttachmentDownloadJob(insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary();
|
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2164,6 +2160,11 @@ public final class MessageContentProcessor {
|
||||||
Collection<SyncMessageId> unhandled = shouldOnlyProcessStories ? SignalDatabase.mmsSms().incrementViewedStoryReceiptCounts(ids, content.getTimestamp())
|
Collection<SyncMessageId> unhandled = shouldOnlyProcessStories ? SignalDatabase.mmsSms().incrementViewedStoryReceiptCounts(ids, content.getTimestamp())
|
||||||
: SignalDatabase.mmsSms().incrementViewedReceiptCounts(ids, content.getTimestamp());
|
: SignalDatabase.mmsSms().incrementViewedReceiptCounts(ids, content.getTimestamp());
|
||||||
|
|
||||||
|
Set<SyncMessageId> handled = new HashSet<>(ids);
|
||||||
|
handled.removeAll(unhandled);
|
||||||
|
|
||||||
|
SignalDatabase.mmsSms().updateViewedStories(handled);
|
||||||
|
|
||||||
for (SyncMessageId id : unhandled) {
|
for (SyncMessageId id : unhandled) {
|
||||||
warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId());
|
warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + senderRecipient.getId());
|
||||||
if (!processingEarlyContent) {
|
if (!processingEarlyContent) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
|
import org.signal.core.util.StringUtil;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
|
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
@ -44,7 +45,6 @@ import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.thoughtcrime.securesms.util.AvatarUtil;
|
import org.thoughtcrime.securesms.util.AvatarUtil;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.signal.core.util.StringUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||||
import org.whispersystems.signalservice.api.push.PNI;
|
import org.whispersystems.signalservice.api.push.PNI;
|
||||||
|
@ -725,6 +725,10 @@ public class Recipient {
|
||||||
return extras.map(Extras::hideStory).orElse(false);
|
return extras.map(Extras::hideStory).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasViewedStory() {
|
||||||
|
return extras.map(Extras::hasViewedStory).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
public @NonNull GroupId requireGroupId() {
|
public @NonNull GroupId requireGroupId() {
|
||||||
GroupId resolved = resolving ? resolve().groupId : groupId;
|
GroupId resolved = resolving ? resolve().groupId : groupId;
|
||||||
|
|
||||||
|
@ -1218,17 +1222,21 @@ public class Recipient {
|
||||||
return recipientExtras.getHideStory();
|
return recipientExtras.getHideStory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasViewedStory() {
|
||||||
|
return recipientExtras.getLastStoryView() > 0L;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
final Extras that = (Extras) o;
|
final Extras that = (Extras) o;
|
||||||
return manuallyShownAvatar() == that.manuallyShownAvatar() && hideStory() == that.hideStory();
|
return manuallyShownAvatar() == that.manuallyShownAvatar() && hideStory() == that.hideStory() && hasViewedStory() == that.hasViewedStory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(manuallyShownAvatar(), hideStory());
|
return Objects.hash(manuallyShownAvatar(), hideStory(), hasViewedStory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,12 @@ import androidx.fragment.app.FragmentManager
|
||||||
import io.reactivex.rxjava3.core.Completable
|
import io.reactivex.rxjava3.core.Completable
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.contacts.HeaderAction
|
import org.thoughtcrime.securesms.contacts.HeaderAction
|
||||||
|
import org.thoughtcrime.securesms.database.AttachmentDatabase
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListId
|
import org.thoughtcrime.securesms.database.model.DistributionListId
|
||||||
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
|
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
|
||||||
|
@ -72,4 +75,24 @@ object Stories {
|
||||||
SignalDatabase.recipients.markNeedsSync(storyRecipientId)
|
SignalDatabase.recipients.markNeedsSync(storyRecipientId)
|
||||||
StorageSyncHelper.scheduleSyncForDataChange()
|
StorageSyncHelper.scheduleSyncForDataChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@WorkerThread
|
||||||
|
fun enqueueNextStoriesForDownload(recipientId: RecipientId, ignoreAutoDownloadConstraints: Boolean = false) {
|
||||||
|
val recipient = Recipient.resolved(recipientId)
|
||||||
|
if (!recipient.isSelf && (recipient.shouldHideStory() || !recipient.hasViewedStory())) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val unreadStoriesReader = SignalDatabase.mms.getUnreadStories(recipientId, FeatureFlags.storiesAutoDownloadMaximum())
|
||||||
|
while (unreadStoriesReader.next != null) {
|
||||||
|
val record = unreadStoriesReader.current as MmsMessageRecord
|
||||||
|
SignalDatabase.attachments.getAttachmentsForMessage(record.id).filterNot { it.isSticker }.forEach {
|
||||||
|
if (it.transferState == AttachmentDatabase.TRANSFER_PROGRESS_PENDING) {
|
||||||
|
val job = AttachmentDownloadJob(record.id, it.attachmentId, ignoreAutoDownloadConstraints)
|
||||||
|
ApplicationDependencies.getJobManager().add(job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,6 +547,10 @@ class StoryViewerPageFragment :
|
||||||
AttachmentDatabase.TRANSFER_PROGRESS_DONE -> {
|
AttachmentDatabase.TRANSFER_PROGRESS_DONE -> {
|
||||||
storySlate.moveToState(StorySlateView.State.HIDDEN, post.id)
|
storySlate.moveToState(StorySlateView.State.HIDDEN, post.id)
|
||||||
viewModel.setIsDisplayingSlate(false)
|
viewModel.setIsDisplayingSlate(false)
|
||||||
|
|
||||||
|
if (post.content.transferState == AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||||
|
viewModel.markViewed(post)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AttachmentDatabase.TRANSFER_PROGRESS_PENDING -> {
|
AttachmentDatabase.TRANSFER_PROGRESS_PENDING -> {
|
||||||
storySlate.moveToState(StorySlateView.State.LOADING, post.id)
|
storySlate.moveToState(StorySlateView.State.LOADING, post.id)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceViewedUpdateJob
|
||||||
import org.thoughtcrime.securesms.jobs.SendViewedReceiptJob
|
import org.thoughtcrime.securesms.jobs.SendViewedReceiptJob
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
|
import org.thoughtcrime.securesms.stories.Stories
|
||||||
import org.thoughtcrime.securesms.util.Base64
|
import org.thoughtcrime.securesms.util.Base64
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,6 +174,10 @@ open class StoryViewerPageRepository(context: Context) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
MultiDeviceViewedUpdateJob.enqueue(listOf(markedMessageInfo.syncMessageId))
|
MultiDeviceViewedUpdateJob.enqueue(listOf(markedMessageInfo.syncMessageId))
|
||||||
|
|
||||||
|
val recipientId = storyPost.group?.id ?: storyPost.sender.id
|
||||||
|
SignalDatabase.recipients.updateLastStoryViewTimestamp(recipientId)
|
||||||
|
Stories.enqueueNextStoriesForDownload(recipientId, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
import io.reactivex.rxjava3.subjects.Subject
|
import io.reactivex.rxjava3.subjects.Subject
|
||||||
|
import org.thoughtcrime.securesms.database.AttachmentDatabase
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import org.thoughtcrime.securesms.util.livedata.Store
|
import org.thoughtcrime.securesms.util.livedata.Store
|
||||||
import org.thoughtcrime.securesms.util.rx.RxStore
|
import org.thoughtcrime.securesms.util.rx.RxStore
|
||||||
|
@ -76,11 +77,15 @@ class StoryViewerPageViewModel(
|
||||||
return repository.hideStory(recipientId)
|
return repository.hideStory(recipientId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markViewed(storyPost: StoryPost) {
|
||||||
|
repository.markViewed(storyPost)
|
||||||
|
}
|
||||||
|
|
||||||
fun setSelectedPostIndex(index: Int) {
|
fun setSelectedPostIndex(index: Int) {
|
||||||
val selectedPost = getPostAt(index)
|
val selectedPost = getPostAt(index)
|
||||||
|
|
||||||
if (selectedPost != null) {
|
if (selectedPost != null && selectedPost.content.transferState != AttachmentDatabase.TRANSFER_PROGRESS_DONE) {
|
||||||
repository.markViewed(selectedPost)
|
repository.forceDownload(selectedPost)
|
||||||
}
|
}
|
||||||
|
|
||||||
store.update {
|
store.update {
|
||||||
|
|
|
@ -97,6 +97,7 @@ public final class FeatureFlags {
|
||||||
private static final String PAYMENTS_COUNTRY_BLOCKLIST = "android.payments.blocklist";
|
private static final String PAYMENTS_COUNTRY_BLOCKLIST = "android.payments.blocklist";
|
||||||
private static final String PNP_CDS = "android.pnp.cds";
|
private static final String PNP_CDS = "android.pnp.cds";
|
||||||
private static final String USE_FCM_FOREGROUND_SERVICE = "android.useFcmForegroundService";
|
private static final String USE_FCM_FOREGROUND_SERVICE = "android.useFcmForegroundService";
|
||||||
|
private static final String STORIES_AUTO_DOWNLOAD_MAXIMUM = "android.stories.autoDownloadMaximum";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We will only store remote values for flags in this set. If you want a flag to be controllable
|
* We will only store remote values for flags in this set. If you want a flag to be controllable
|
||||||
|
@ -145,7 +146,8 @@ public final class FeatureFlags {
|
||||||
USE_HARDWARE_AEC_IF_OLD,
|
USE_HARDWARE_AEC_IF_OLD,
|
||||||
USE_AEC3,
|
USE_AEC3,
|
||||||
PAYMENTS_COUNTRY_BLOCKLIST,
|
PAYMENTS_COUNTRY_BLOCKLIST,
|
||||||
USE_FCM_FOREGROUND_SERVICE
|
USE_FCM_FOREGROUND_SERVICE,
|
||||||
|
STORIES_AUTO_DOWNLOAD_MAXIMUM
|
||||||
);
|
);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -512,6 +514,13 @@ public final class FeatureFlags {
|
||||||
return getBoolean(USE_FCM_FOREGROUND_SERVICE, false);
|
return getBoolean(USE_FCM_FOREGROUND_SERVICE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefetch count for stories from a given user.
|
||||||
|
*/
|
||||||
|
public static int storiesAutoDownloadMaximum() {
|
||||||
|
return getInteger(STORIES_AUTO_DOWNLOAD_MAXIMUM, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/** Only for rendering debug info. */
|
/** Only for rendering debug info. */
|
||||||
public static synchronized @NonNull Map<String, Object> getMemoryValues() {
|
public static synchronized @NonNull Map<String, Object> getMemoryValues() {
|
||||||
return new TreeMap<>(REMOTE_VALUES);
|
return new TreeMap<>(REMOTE_VALUES);
|
||||||
|
|
|
@ -178,8 +178,9 @@ message ChatColor {
|
||||||
}
|
}
|
||||||
|
|
||||||
message RecipientExtras {
|
message RecipientExtras {
|
||||||
bool manuallyShownAvatar = 1;
|
bool manuallyShownAvatar = 1;
|
||||||
bool hideStory = 2;
|
bool hideStory = 2;
|
||||||
|
int64 lastStoryView = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CustomAvatar {
|
message CustomAvatar {
|
||||||
|
|
Loading…
Add table
Reference in a new issue