diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index f7312752f9..8a4ead88e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -475,6 +475,8 @@ public class ConversationListFragment extends MainFragment implements LoaderMana megaphone.getOnVisibleListener().onVisible(megaphone, this); } } + + viewModel.onMegaphoneVisible(megaphone); } private void updateReminders() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.java index 6f32230627..864688483c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListViewModel.java @@ -14,7 +14,6 @@ import android.text.TextUtils; import org.thoughtcrime.securesms.conversationlist.model.SearchResult; import org.thoughtcrime.securesms.database.DatabaseContentProviders; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.megaphone.Megaphone; import org.thoughtcrime.securesms.megaphone.MegaphoneRepository; import org.thoughtcrime.securesms.megaphone.Megaphones; @@ -75,6 +74,10 @@ class ConversationListViewModel extends ViewModel { megaphone.postValue(null); } + void onMegaphoneVisible(@NonNull Megaphone visible) { + megaphoneRepository.markVisible(visible.getEvent()); + } + void updateQuery(String query) { lastQuery = query; debouncer.publish(() -> searchRepository.query(query, result -> { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MegaphoneDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MegaphoneDatabase.java index 24c30c4dce..947fe6a03e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MegaphoneDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MegaphoneDatabase.java @@ -23,17 +23,19 @@ public class MegaphoneDatabase extends Database { private static final String TABLE_NAME = "megaphone"; - private static final String ID = "_id"; - private static final String EVENT = "event"; - private static final String SEEN_COUNT = "seen_count"; - private static final String LAST_SEEN = "last_seen"; - private static final String FINISHED = "finished"; + private static final String ID = "_id"; + private static final String EVENT = "event"; + private static final String SEEN_COUNT = "seen_count"; + private static final String LAST_SEEN = "last_seen"; + private static final String FIRST_VISIBLE = "first_visible"; + private static final String FINISHED = "finished"; - public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + - EVENT + " TEXT UNIQUE, " + - SEEN_COUNT + " INTEGER, " + - LAST_SEEN + " INTEGER, " + - FINISHED + " INTEGER)"; + public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + EVENT + " TEXT UNIQUE, " + + SEEN_COUNT + " INTEGER, " + + LAST_SEEN + " INTEGER, " + + FIRST_VISIBLE + " INTEGER, " + + FINISHED + " INTEGER)"; MegaphoneDatabase(Context context, SQLCipherOpenHelper databaseHelper) { super(context, databaseHelper); @@ -62,18 +64,29 @@ public class MegaphoneDatabase extends Database { try (Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, null, null, null, null, null, null)) { while (cursor != null && cursor.moveToNext()) { - String event = cursor.getString(cursor.getColumnIndexOrThrow(EVENT)); - int seenCount = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_COUNT)); - long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(LAST_SEEN)); - boolean finished = cursor.getInt(cursor.getColumnIndexOrThrow(FINISHED)) == 1; + String event = cursor.getString(cursor.getColumnIndexOrThrow(EVENT)); + int seenCount = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_COUNT)); + long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(LAST_SEEN)); + long firstVisible = cursor.getLong(cursor.getColumnIndexOrThrow(FIRST_VISIBLE)); + boolean finished = cursor.getInt(cursor.getColumnIndexOrThrow(FINISHED)) == 1; - records.add(new MegaphoneRecord(Event.fromKey(event), seenCount, lastSeen, finished)); + records.add(new MegaphoneRecord(Event.fromKey(event), seenCount, lastSeen, firstVisible, finished)); } } return records; } + public void markFirstVisible(@NonNull Event event, long time) { + String query = EVENT + " = ?"; + String[] args = new String[]{event.getKey()}; + + ContentValues values = new ContentValues(); + values.put(FIRST_VISIBLE, time); + + databaseHelper.getWritableDatabase().update(TABLE_NAME, values, query, args); + } + public void markSeen(@NonNull Event event, int seenCount, long lastSeen) { String query = EVENT + " = ?"; String[] args = new String[]{event.getKey()}; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index e469550628..44055c11f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -104,8 +104,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int SPLIT_PROFILE_NAMES = 43; private static final int STICKER_PACK_ORDER = 44; private static final int MEGAPHONES = 45; + private static final int MEGAPHONE_FIRST_APPEARANCE = 46; - private static final int DATABASE_VERSION = 45; + private static final int DATABASE_VERSION = 46; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -719,6 +720,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { "finished INTEGER)"); } + if (oldVersion < MEGAPHONE_FIRST_APPEARANCE) { + db.execSQL("ALTER TABLE megaphone ADD COLUMN first_visible INTEGER DEFAULT 0"); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MegaphoneRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MegaphoneRecord.java index 28f476001c..4ba070cf20 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MegaphoneRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MegaphoneRecord.java @@ -9,13 +9,15 @@ public class MegaphoneRecord { private final Megaphones.Event event; private final int seenCount; private final long lastSeen; + private final long firstVisible; private final boolean finished; - public MegaphoneRecord(@NonNull Megaphones.Event event, int seenCount, long lastSeen, boolean finished) { - this.event = event; - this.seenCount = seenCount; - this.lastSeen = lastSeen; - this.finished = finished; + public MegaphoneRecord(@NonNull Megaphones.Event event, int seenCount, long lastSeen, long firstVisible, boolean finished) { + this.event = event; + this.seenCount = seenCount; + this.lastSeen = lastSeen; + this.firstVisible = firstVisible; + this.finished = finished; } public @NonNull Megaphones.Event getEvent() { @@ -30,6 +32,10 @@ public class MegaphoneRecord { return lastSeen; } + public long getFirstVisible() { + return firstVisible; + } + public boolean isFinished() { return finished; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/ForeverSchedule.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/ForeverSchedule.java index 4a0c624516..d1f08a4d46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/ForeverSchedule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/ForeverSchedule.java @@ -9,7 +9,7 @@ final class ForeverSchedule implements MegaphoneSchedule { } @Override - public boolean shouldDisplay(int seenCount, long lastSeen, long currentTime) { + public boolean shouldDisplay(int seenCount, long lastSeen, long firstVisible, long currentTime) { return enabled; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java index 82b0aa5927..6a7a15edc9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneRepository.java @@ -69,6 +69,18 @@ public class MegaphoneRepository { }); } + @MainThread + public void markVisible(@NonNull Megaphones.Event event) { + long time = System.currentTimeMillis(); + + executor.execute(() -> { + if (getRecord(event).getFirstVisible() == 0) { + database.markFirstVisible(event, time); + resetDatabaseCache(); + } + }); + } + @MainThread public void markSeen(@NonNull Megaphone megaphone) { long lastSeen = System.currentTimeMillis(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneSchedule.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneSchedule.java index 2ca93f76a4..09e7ecfa07 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneSchedule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/MegaphoneSchedule.java @@ -1,5 +1,5 @@ package org.thoughtcrime.securesms.megaphone; public interface MegaphoneSchedule { - boolean shouldDisplay(int seenCount, long lastSeen, long currentTime); + boolean shouldDisplay(int seenCount, long lastSeen, long firstVisible, long currentTime); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java index 7c83a9130a..7b8033f41a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java @@ -45,7 +45,7 @@ public final class Megaphones { MegaphoneRecord record = Objects.requireNonNull(records.get(e.getKey())); MegaphoneSchedule schedule = e.getValue(); - return !record.isFinished() && schedule.shouldDisplay(record.getSeenCount(), record.getLastSeen(), currentTime); + return !record.isFinished() && schedule.shouldDisplay(record.getSeenCount(), record.getLastSeen(), record.getFirstVisible(), currentTime); }) .map(Map.Entry::getKey) .map(records::get) diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/RecurringSchedule.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/RecurringSchedule.java index 43862a657d..90fe17dd5f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/RecurringSchedule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/RecurringSchedule.java @@ -9,7 +9,7 @@ class RecurringSchedule implements MegaphoneSchedule { } @Override - public boolean shouldDisplay(int seenCount, long lastSeen, long currentTime) { + public boolean shouldDisplay(int seenCount, long lastSeen, long firstVisible, long currentTime) { if (seenCount == 0) { return true; }