mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Implement story ring support.
This commit is contained in:
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.insights.InsightsConstants;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
@@ -193,6 +194,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
public abstract long getUnreadStoryCount();
|
||||
public abstract @Nullable Long getOldestStorySendTimestamp();
|
||||
public abstract int deleteStoriesOlderThan(long timestamp);
|
||||
public abstract @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId);
|
||||
|
||||
final @NonNull String getOutgoingTypeClause() {
|
||||
List<String> segments = new ArrayList<>(Types.OUTGOING_MESSAGE_TYPES.length);
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
@@ -52,6 +53,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.Quote;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
@@ -74,6 +76,7 @@ import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
@@ -591,6 +594,46 @@ public class MmsDatabase extends MessageDatabase {
|
||||
return new Reader(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId) {
|
||||
if (!FeatureFlags.stories() || SignalStore.storyValues().isFeatureDisabled()) {
|
||||
return StoryViewState.NONE;
|
||||
}
|
||||
|
||||
long threadId = SignalDatabase.threads().getThreadIdIfExistsFor(recipientId);
|
||||
|
||||
return getStoryViewState(threadId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@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[] hasStoryArgs = SqlUtil.buildArgs(1, 0, threadId);
|
||||
final boolean hasStories;
|
||||
|
||||
try (Cursor cursor = getReadableDatabase().rawQuery(hasStoryQuery, hasStoryArgs)) {
|
||||
hasStories = cursor != null && cursor.moveToFirst() && !cursor.isNull(0) && cursor.getInt(0) == 1;
|
||||
}
|
||||
|
||||
if (!hasStories) {
|
||||
return StoryViewState.NONE;
|
||||
}
|
||||
|
||||
final String hasUnviewedStoriesQuery = "SELECT EXISTS(SELECT 1 FROM " + TABLE_NAME + " WHERE " + IS_STORY_CLAUSE + " AND " + THREAD_ID_WHERE + " AND " + VIEWED_RECEIPT_COUNT + " = ? " + "AND NOT (" + getOutgoingTypeClause() + ") LIMIT 1)";
|
||||
final String[] hasUnviewedStoriesArgs = SqlUtil.buildArgs(1, 0, threadId, 0);
|
||||
final boolean hasUnviewedStories;
|
||||
|
||||
try (Cursor cursor = getReadableDatabase().rawQuery(hasUnviewedStoriesQuery, hasUnviewedStoriesArgs)) {
|
||||
hasUnviewedStories = cursor != null && cursor.moveToFirst() && !cursor.isNull(0) && cursor.getInt(0) == 1;
|
||||
}
|
||||
|
||||
if (hasUnviewedStories) {
|
||||
return StoryViewState.UNVIEWED;
|
||||
} else {
|
||||
return StoryViewState.VIEWED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MessageId getStoryId(@NonNull RecipientId authorId, long sentTimestamp) throws NoSuchMessageException {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
@@ -1431,6 +1432,11 @@ public class SmsDatabase extends MessageDatabase {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteStoriesOlderThan(long timestamp) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.thoughtcrime.securesms.database.DatabaseObserver
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
||||
/**
|
||||
* Denotes whether a given recipient has stories, and whether those stories are viewed or unviewed.
|
||||
*/
|
||||
enum class StoryViewState {
|
||||
NONE,
|
||||
UNVIEWED,
|
||||
VIEWED;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getForRecipientId(recipientId: RecipientId): Observable<StoryViewState> {
|
||||
return Observable.create<StoryViewState> { emitter ->
|
||||
fun refresh() {
|
||||
emitter.onNext(SignalDatabase.mms.getStoryViewState(recipientId))
|
||||
}
|
||||
|
||||
val storyObserver = DatabaseObserver.Observer {
|
||||
refresh()
|
||||
}
|
||||
|
||||
ApplicationDependencies.getDatabaseObserver().registerStoryObserver(recipientId, storyObserver)
|
||||
emitter.setCancellable {
|
||||
ApplicationDependencies.getDatabaseObserver().unregisterObserver(storyObserver)
|
||||
}
|
||||
|
||||
refresh()
|
||||
}.observeOn(Schedulers.io())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user