mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Add Notification profiles.
This commit is contained in:
@@ -55,3 +55,5 @@ fun Cursor.optionalBlob(column: String): Optional<ByteArray> {
|
||||
fun Cursor.isNull(column: String): Boolean {
|
||||
return CursorUtil.isNull(this, column)
|
||||
}
|
||||
|
||||
fun Boolean.toInt(): Int = if (this) 1 else 0
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
|
||||
@@ -20,7 +21,7 @@ import java.util.concurrent.Executor;
|
||||
*
|
||||
* A replacement for the observer system in {@link Database}. We should move to this over time.
|
||||
*/
|
||||
public final class DatabaseObserver {
|
||||
public class DatabaseObserver {
|
||||
|
||||
private final Application application;
|
||||
private final Executor executor;
|
||||
@@ -36,6 +37,7 @@ public final class DatabaseObserver {
|
||||
private final Set<Observer> attachmentObservers;
|
||||
private final Set<MessageObserver> messageUpdateObservers;
|
||||
private final Map<Long, Set<MessageObserver>> messageInsertObservers;
|
||||
private final Set<Observer> notificationProfileObservers;
|
||||
|
||||
public DatabaseObserver(Application application) {
|
||||
this.application = application;
|
||||
@@ -51,6 +53,7 @@ public final class DatabaseObserver {
|
||||
this.attachmentObservers = new HashSet<>();
|
||||
this.messageUpdateObservers = new HashSet<>();
|
||||
this.messageInsertObservers = new HashMap<>();
|
||||
this.notificationProfileObservers = new HashSet<>();
|
||||
}
|
||||
|
||||
public void registerConversationListObserver(@NonNull Observer listener) {
|
||||
@@ -119,6 +122,12 @@ public final class DatabaseObserver {
|
||||
});
|
||||
}
|
||||
|
||||
public void registerNotificationProfileObserver(@NotNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
notificationProfileObservers.add(listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void unregisterObserver(@NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
conversationListObservers.remove(listener);
|
||||
@@ -129,6 +138,7 @@ public final class DatabaseObserver {
|
||||
stickerObservers.remove(listener);
|
||||
stickerPackObservers.remove(listener);
|
||||
attachmentObservers.remove(listener);
|
||||
notificationProfileObservers.remove(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,6 +241,12 @@ public final class DatabaseObserver {
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyNotificationProfileObservers() {
|
||||
executor.execute(() -> {
|
||||
notifySet(notificationProfileObservers);
|
||||
});
|
||||
}
|
||||
|
||||
private <K, V> void registerMapped(@NonNull Map<K, Set<V>> map, @NonNull K key, @NonNull V listener) {
|
||||
Set<V> listeners = map.get(key);
|
||||
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import net.zetetic.database.sqlcipher.SQLiteConstraintException
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
|
||||
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfileSchedule
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.SqlUtil
|
||||
import java.time.DayOfWeek
|
||||
|
||||
/**
|
||||
* Database for maintaining Notification Profiles, Notification Profile Schedules, and Notification Profile allowed memebers.
|
||||
*/
|
||||
class NotificationProfileDatabase(context: Context, databaseHelper: SignalDatabase) : Database(context, databaseHelper) {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val CREATE_TABLE: Array<String> = arrayOf(NotificationProfileTable.CREATE_TABLE, NotificationProfileScheduleTable.CREATE_TABLE, NotificationProfileAllowedMembersTable.CREATE_TABLE)
|
||||
|
||||
@JvmField
|
||||
val CREATE_INDEXES: Array<String> = arrayOf(NotificationProfileScheduleTable.CREATE_INDEX, NotificationProfileAllowedMembersTable.CREATE_INDEX)
|
||||
}
|
||||
|
||||
private object NotificationProfileTable {
|
||||
const val TABLE_NAME = "notification_profile"
|
||||
|
||||
const val ID = "_id"
|
||||
const val NAME = "name"
|
||||
const val EMOJI = "emoji"
|
||||
const val COLOR = "color"
|
||||
const val CREATED_AT = "created_at"
|
||||
const val ALLOW_ALL_CALLS = "allow_all_calls"
|
||||
const val ALLOW_ALL_MENTIONS = "allow_all_mentions"
|
||||
|
||||
val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$NAME TEXT NOT NULL UNIQUE,
|
||||
$EMOJI TEXT NOT NULL,
|
||||
$COLOR TEXT NOT NULL,
|
||||
$CREATED_AT INTEGER NOT NULL,
|
||||
$ALLOW_ALL_CALLS INTEGER NOT NULL DEFAULT 0,
|
||||
$ALLOW_ALL_MENTIONS INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
private object NotificationProfileScheduleTable {
|
||||
const val TABLE_NAME = "notification_profile_schedule"
|
||||
|
||||
const val ID = "_id"
|
||||
const val NOTIFICATION_PROFILE_ID = "notification_profile_id"
|
||||
const val ENABLED = "enabled"
|
||||
const val START = "start"
|
||||
const val END = "end"
|
||||
const val DAYS_ENABLED = "days_enabled"
|
||||
|
||||
val DEFAULT_DAYS = listOf(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY).serialize()
|
||||
|
||||
val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$NOTIFICATION_PROFILE_ID INTEGER NOT NULL REFERENCES ${NotificationProfileTable.TABLE_NAME} (${NotificationProfileTable.ID}) ON DELETE CASCADE,
|
||||
$ENABLED INTEGER NOT NULL DEFAULT 0,
|
||||
$START INTEGER NOT NULL,
|
||||
$END INTEGER NOT NULL,
|
||||
$DAYS_ENABLED TEXT NOT NULL
|
||||
)
|
||||
""".trimIndent()
|
||||
|
||||
const val CREATE_INDEX = "CREATE INDEX notification_profile_schedule_profile_index ON $TABLE_NAME ($NOTIFICATION_PROFILE_ID)"
|
||||
}
|
||||
|
||||
private object NotificationProfileAllowedMembersTable {
|
||||
const val TABLE_NAME = "notification_profile_allowed_members"
|
||||
|
||||
const val ID = "_id"
|
||||
const val NOTIFICATION_PROFILE_ID = "notification_profile_id"
|
||||
const val RECIPIENT_ID = "recipient_id"
|
||||
|
||||
val CREATE_TABLE = """
|
||||
CREATE TABLE $TABLE_NAME (
|
||||
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
$NOTIFICATION_PROFILE_ID INTEGER NOT NULL REFERENCES ${NotificationProfileTable.TABLE_NAME} (${NotificationProfileTable.ID}) ON DELETE CASCADE,
|
||||
$RECIPIENT_ID INTEGER NOT NULL,
|
||||
UNIQUE($NOTIFICATION_PROFILE_ID, $RECIPIENT_ID) ON CONFLICT REPLACE
|
||||
)
|
||||
""".trimIndent()
|
||||
|
||||
const val CREATE_INDEX = "CREATE INDEX notification_profile_allowed_members_profile_index ON $TABLE_NAME ($NOTIFICATION_PROFILE_ID)"
|
||||
}
|
||||
|
||||
fun createProfile(name: String, emoji: String, color: AvatarColor, createdAt: Long): NotificationProfileChangeResult {
|
||||
val db = writableDatabase
|
||||
|
||||
db.beginTransaction()
|
||||
try {
|
||||
val profileValues = ContentValues().apply {
|
||||
put(NotificationProfileTable.NAME, name)
|
||||
put(NotificationProfileTable.EMOJI, emoji)
|
||||
put(NotificationProfileTable.COLOR, color.serialize())
|
||||
put(NotificationProfileTable.CREATED_AT, createdAt)
|
||||
}
|
||||
|
||||
val profileId = db.insert(NotificationProfileTable.TABLE_NAME, null, profileValues)
|
||||
if (profileId < 0) {
|
||||
return NotificationProfileChangeResult.DuplicateName
|
||||
}
|
||||
|
||||
val scheduleValues = ContentValues().apply {
|
||||
put(NotificationProfileScheduleTable.NOTIFICATION_PROFILE_ID, profileId)
|
||||
put(NotificationProfileScheduleTable.START, 900)
|
||||
put(NotificationProfileScheduleTable.END, 1700)
|
||||
put(NotificationProfileScheduleTable.DAYS_ENABLED, NotificationProfileScheduleTable.DEFAULT_DAYS)
|
||||
}
|
||||
db.insert(NotificationProfileScheduleTable.TABLE_NAME, null, scheduleValues)
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
|
||||
return NotificationProfileChangeResult.Success(
|
||||
NotificationProfile(
|
||||
id = profileId,
|
||||
name = name,
|
||||
emoji = emoji,
|
||||
createdAt = createdAt,
|
||||
schedule = getProfileSchedule(profileId)
|
||||
)
|
||||
)
|
||||
} finally {
|
||||
db.endTransaction()
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateProfile(profileId: Long, name: String, emoji: String): NotificationProfileChangeResult {
|
||||
val profileValues = ContentValues().apply {
|
||||
put(NotificationProfileTable.NAME, name)
|
||||
put(NotificationProfileTable.EMOJI, emoji)
|
||||
}
|
||||
|
||||
val updateQuery = SqlUtil.buildTrueUpdateQuery(ID_WHERE, SqlUtil.buildArgs(profileId), profileValues)
|
||||
|
||||
return try {
|
||||
val count = writableDatabase.update(NotificationProfileTable.TABLE_NAME, profileValues, updateQuery.where, updateQuery.whereArgs)
|
||||
if (count > 0) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
|
||||
NotificationProfileChangeResult.Success(getProfile(profileId)!!)
|
||||
} catch (e: SQLiteConstraintException) {
|
||||
NotificationProfileChangeResult.DuplicateName
|
||||
}
|
||||
}
|
||||
|
||||
fun updateProfile(profile: NotificationProfile): NotificationProfileChangeResult {
|
||||
val db = writableDatabase
|
||||
|
||||
db.beginTransaction()
|
||||
try {
|
||||
val profileValues = ContentValues().apply {
|
||||
put(NotificationProfileTable.NAME, profile.name)
|
||||
put(NotificationProfileTable.EMOJI, profile.emoji)
|
||||
put(NotificationProfileTable.ALLOW_ALL_CALLS, profile.allowAllCalls.toInt())
|
||||
put(NotificationProfileTable.ALLOW_ALL_MENTIONS, profile.allowAllMentions.toInt())
|
||||
}
|
||||
|
||||
val updateQuery = SqlUtil.buildTrueUpdateQuery(ID_WHERE, SqlUtil.buildArgs(profile.id), profileValues)
|
||||
|
||||
try {
|
||||
db.update(NotificationProfileTable.TABLE_NAME, profileValues, updateQuery.where, updateQuery.whereArgs)
|
||||
} catch (e: SQLiteConstraintException) {
|
||||
return NotificationProfileChangeResult.DuplicateName
|
||||
}
|
||||
|
||||
updateSchedule(profile.schedule, true)
|
||||
|
||||
db.delete(NotificationProfileAllowedMembersTable.TABLE_NAME, "${NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID} = ?", SqlUtil.buildArgs(profile.id))
|
||||
|
||||
profile.allowedMembers.forEach { recipientId ->
|
||||
val allowedMembersValues = ContentValues().apply {
|
||||
put(NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID, profile.id)
|
||||
put(NotificationProfileAllowedMembersTable.RECIPIENT_ID, recipientId.serialize())
|
||||
}
|
||||
db.insert(NotificationProfileAllowedMembersTable.TABLE_NAME, null, allowedMembersValues)
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
|
||||
return NotificationProfileChangeResult.Success(getProfile(profile.id)!!)
|
||||
} finally {
|
||||
db.endTransaction()
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSchedule(schedule: NotificationProfileSchedule, silent: Boolean = false) {
|
||||
val scheduleValues = ContentValues().apply {
|
||||
put(NotificationProfileScheduleTable.ENABLED, schedule.enabled.toInt())
|
||||
put(NotificationProfileScheduleTable.START, schedule.start)
|
||||
put(NotificationProfileScheduleTable.END, schedule.end)
|
||||
put(NotificationProfileScheduleTable.DAYS_ENABLED, schedule.daysEnabled.serialize())
|
||||
}
|
||||
|
||||
val updateQuery = SqlUtil.buildTrueUpdateQuery(ID_WHERE, SqlUtil.buildArgs(schedule.id), scheduleValues)
|
||||
writableDatabase.update(NotificationProfileScheduleTable.TABLE_NAME, scheduleValues, updateQuery.where, updateQuery.whereArgs)
|
||||
|
||||
if (!silent) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
}
|
||||
|
||||
fun setAllowedRecipients(profileId: Long, recipients: Set<RecipientId>): NotificationProfile {
|
||||
val db = writableDatabase
|
||||
|
||||
db.beginTransaction()
|
||||
try {
|
||||
db.delete(NotificationProfileAllowedMembersTable.TABLE_NAME, "${NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID} = ?", SqlUtil.buildArgs(profileId))
|
||||
|
||||
recipients.forEach { recipientId ->
|
||||
val allowedMembersValues = ContentValues().apply {
|
||||
put(NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID, profileId)
|
||||
put(NotificationProfileAllowedMembersTable.RECIPIENT_ID, recipientId.serialize())
|
||||
}
|
||||
db.insert(NotificationProfileAllowedMembersTable.TABLE_NAME, null, allowedMembersValues)
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
|
||||
return getProfile(profileId)!!
|
||||
} finally {
|
||||
db.endTransaction()
|
||||
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
}
|
||||
|
||||
fun addAllowedRecipient(profileId: Long, recipientId: RecipientId): NotificationProfile {
|
||||
val allowedValues = ContentValues().apply {
|
||||
put(NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID, profileId)
|
||||
put(NotificationProfileAllowedMembersTable.RECIPIENT_ID, recipientId.serialize())
|
||||
}
|
||||
writableDatabase.insert(NotificationProfileAllowedMembersTable.TABLE_NAME, null, allowedValues)
|
||||
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
return getProfile(profileId)!!
|
||||
}
|
||||
|
||||
fun removeAllowedRecipient(profileId: Long, recipientId: RecipientId): NotificationProfile {
|
||||
writableDatabase.delete(
|
||||
NotificationProfileAllowedMembersTable.TABLE_NAME,
|
||||
"${NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID} = ? AND ${NotificationProfileAllowedMembersTable.RECIPIENT_ID} = ?",
|
||||
SqlUtil.buildArgs(profileId, recipientId)
|
||||
)
|
||||
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
return getProfile(profileId)!!
|
||||
}
|
||||
|
||||
fun getProfiles(): List<NotificationProfile> {
|
||||
val profiles: MutableList<NotificationProfile> = mutableListOf()
|
||||
|
||||
readableDatabase.query(NotificationProfileTable.TABLE_NAME, null, null, null, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
profiles += getProfile(cursor)
|
||||
}
|
||||
}
|
||||
|
||||
return profiles
|
||||
}
|
||||
|
||||
fun getProfile(profileId: Long): NotificationProfile? {
|
||||
return readableDatabase.query(NotificationProfileTable.TABLE_NAME, null, ID_WHERE, SqlUtil.buildArgs(profileId), null, null, null).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
getProfile(cursor)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteProfile(profileId: Long) {
|
||||
writableDatabase.delete(NotificationProfileTable.TABLE_NAME, ID_WHERE, SqlUtil.buildArgs(profileId))
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
|
||||
fun remapRecipient(oldId: RecipientId, newId: RecipientId) {
|
||||
val query = "${NotificationProfileAllowedMembersTable.RECIPIENT_ID} = ?"
|
||||
val args = SqlUtil.buildArgs(oldId)
|
||||
val values = ContentValues().apply {
|
||||
put(NotificationProfileAllowedMembersTable.RECIPIENT_ID, newId.serialize())
|
||||
}
|
||||
|
||||
databaseHelper.signalWritableDatabase.update(NotificationProfileAllowedMembersTable.TABLE_NAME, values, query, args)
|
||||
|
||||
ApplicationDependencies.getDatabaseObserver().notifyNotificationProfileObservers()
|
||||
}
|
||||
|
||||
private fun getProfile(cursor: Cursor): NotificationProfile {
|
||||
val profileId: Long = cursor.requireLong(NotificationProfileTable.ID)
|
||||
|
||||
return NotificationProfile(
|
||||
id = profileId,
|
||||
name = cursor.requireString(NotificationProfileTable.NAME)!!,
|
||||
emoji = cursor.requireString(NotificationProfileTable.EMOJI)!!,
|
||||
color = AvatarColor.deserialize(cursor.requireString(NotificationProfileTable.COLOR)),
|
||||
createdAt = cursor.requireLong(NotificationProfileTable.CREATED_AT),
|
||||
allowAllCalls = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_CALLS),
|
||||
allowAllMentions = cursor.requireBoolean(NotificationProfileTable.ALLOW_ALL_MENTIONS),
|
||||
schedule = getProfileSchedule(profileId),
|
||||
allowedMembers = getProfileAllowedMembers(profileId)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getProfileSchedule(profileId: Long): NotificationProfileSchedule {
|
||||
val query = SqlUtil.buildQuery("${NotificationProfileScheduleTable.NOTIFICATION_PROFILE_ID} = ?", profileId)
|
||||
|
||||
return readableDatabase.query(NotificationProfileScheduleTable.TABLE_NAME, null, query.where, query.whereArgs, null, null, null).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
val daysEnabledString = cursor.requireString(NotificationProfileScheduleTable.DAYS_ENABLED) ?: ""
|
||||
val daysEnabled: Set<DayOfWeek> = daysEnabledString.split(",")
|
||||
.filter { it.isNotBlank() }
|
||||
.map { it.toDayOfWeek() }
|
||||
.toSet()
|
||||
|
||||
NotificationProfileSchedule(
|
||||
id = cursor.requireLong(NotificationProfileScheduleTable.ID),
|
||||
enabled = cursor.requireBoolean(NotificationProfileScheduleTable.ENABLED),
|
||||
start = cursor.requireInt(NotificationProfileScheduleTable.START),
|
||||
end = cursor.requireInt(NotificationProfileScheduleTable.END),
|
||||
daysEnabled = daysEnabled
|
||||
)
|
||||
} else {
|
||||
throw AssertionError("No schedule for $profileId")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProfileAllowedMembers(profileId: Long): Set<RecipientId> {
|
||||
val allowed = mutableSetOf<RecipientId>()
|
||||
val query = SqlUtil.buildQuery("${NotificationProfileAllowedMembersTable.NOTIFICATION_PROFILE_ID} = ?", profileId)
|
||||
|
||||
readableDatabase.query(NotificationProfileAllowedMembersTable.TABLE_NAME, null, query.where, query.whereArgs, null, null, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
allowed += RecipientId.from(cursor.requireLong(NotificationProfileAllowedMembersTable.RECIPIENT_ID))
|
||||
}
|
||||
}
|
||||
|
||||
return allowed
|
||||
}
|
||||
|
||||
sealed class NotificationProfileChangeResult {
|
||||
data class Success(val notificationProfile: NotificationProfile) : NotificationProfileChangeResult()
|
||||
object DuplicateName : NotificationProfileChangeResult()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Iterable<DayOfWeek>.serialize(): String {
|
||||
return joinToString(separator = ",", transform = { it.serialize() })
|
||||
}
|
||||
|
||||
private fun String.toDayOfWeek(): DayOfWeek {
|
||||
return when (this) {
|
||||
"1" -> DayOfWeek.MONDAY
|
||||
"2" -> DayOfWeek.TUESDAY
|
||||
"3" -> DayOfWeek.WEDNESDAY
|
||||
"4" -> DayOfWeek.THURSDAY
|
||||
"5" -> DayOfWeek.FRIDAY
|
||||
"6" -> DayOfWeek.SATURDAY
|
||||
"7" -> DayOfWeek.SUNDAY
|
||||
else -> throw AssertionError("Value ($this) does not map to a day")
|
||||
}
|
||||
}
|
||||
|
||||
private fun DayOfWeek.serialize(): String {
|
||||
return when (this) {
|
||||
DayOfWeek.MONDAY -> "1"
|
||||
DayOfWeek.TUESDAY -> "2"
|
||||
DayOfWeek.WEDNESDAY -> "3"
|
||||
DayOfWeek.THURSDAY -> "4"
|
||||
DayOfWeek.FRIDAY -> "5"
|
||||
DayOfWeek.SATURDAY -> "6"
|
||||
DayOfWeek.SUNDAY -> "7"
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.groups
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.identities
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messageLog
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.notificationProfiles
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.reactions
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.sessions
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase.Companion.threads
|
||||
@@ -2592,6 +2593,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||
// Reactions
|
||||
reactions.remapRecipient(byE164, byAci)
|
||||
|
||||
// Notification Profiles
|
||||
notificationProfiles.remapRecipient(byE164, byAci)
|
||||
|
||||
// Recipient
|
||||
Log.w(TAG, "Deleting recipient $byE164", true)
|
||||
db.delete(TABLE_NAME, ID_WHERE, SqlUtil.buildArgs(byE164))
|
||||
|
||||
@@ -70,6 +70,7 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
val avatarPickerDatabase: AvatarPickerDatabase = AvatarPickerDatabase(context, this)
|
||||
val groupCallRingDatabase: GroupCallRingDatabase = GroupCallRingDatabase(context, this)
|
||||
val reactionDatabase: ReactionDatabase = ReactionDatabase(context, this)
|
||||
val notificationProfileDatabase: NotificationProfileDatabase = NotificationProfileDatabase(context, this)
|
||||
|
||||
override fun onOpen(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
|
||||
db.enableWriteAheadLogging()
|
||||
@@ -105,6 +106,8 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
executeStatements(db, SearchDatabase.CREATE_TABLE)
|
||||
executeStatements(db, RemappedRecordsDatabase.CREATE_TABLE)
|
||||
executeStatements(db, MessageSendLogDatabase.CREATE_TABLE)
|
||||
executeStatements(db, NotificationProfileDatabase.CREATE_TABLE)
|
||||
|
||||
executeStatements(db, RecipientDatabase.CREATE_INDEXS)
|
||||
executeStatements(db, SmsDatabase.CREATE_INDEXS)
|
||||
executeStatements(db, MmsDatabase.CREATE_INDEXS)
|
||||
@@ -119,8 +122,11 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
executeStatements(db, PaymentDatabase.CREATE_INDEXES)
|
||||
executeStatements(db, MessageSendLogDatabase.CREATE_INDEXES)
|
||||
executeStatements(db, GroupCallRingDatabase.CREATE_INDEXES)
|
||||
executeStatements(db, NotificationProfileDatabase.CREATE_INDEXES)
|
||||
|
||||
executeStatements(db, MessageSendLogDatabase.CREATE_TRIGGERS)
|
||||
executeStatements(db, ReactionDatabase.CREATE_TRIGGERS)
|
||||
|
||||
if (context.getDatabasePath(ClassicOpenHelper.NAME).exists()) {
|
||||
val legacyHelper = ClassicOpenHelper(context)
|
||||
val legacyDb = legacyHelper.writableDatabase
|
||||
@@ -438,5 +444,10 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
|
||||
@get:JvmName("unknownStorageIds")
|
||||
val unknownStorageIds: UnknownStorageIdDatabase
|
||||
get() = instance!!.storageIdDatabase
|
||||
|
||||
@get:JvmStatic
|
||||
@get:JvmName("notificationProfiles")
|
||||
val notificationProfiles: NotificationProfileDatabase
|
||||
get() = instance!!.notificationProfileDatabase
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,8 +179,9 @@ object SignalDatabaseMigrations {
|
||||
private const val SENDER_KEY_SHARED_TIMESTAMP = 120
|
||||
private const val REACTION_REFACTOR = 121
|
||||
private const val PNI = 122
|
||||
private const val NOTIFICATION_PROFILES = 123
|
||||
|
||||
const val DATABASE_VERSION = 122
|
||||
const val DATABASE_VERSION = 123
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Context, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -2176,6 +2177,51 @@ object SignalDatabaseMigrations {
|
||||
db.execSQL("ALTER TABLE recipient ADD COLUMN pni TEXT DEFAULT NULL")
|
||||
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS recipient_pni_index ON recipient (pni)")
|
||||
}
|
||||
|
||||
if (oldVersion < NOTIFICATION_PROFILES) {
|
||||
db.execSQL(
|
||||
// language=sql
|
||||
"""
|
||||
CREATE TABLE notification_profile (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
emoji TEXT NOT NULL,
|
||||
color TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
allow_all_calls INTEGER NOT NULL DEFAULT 0,
|
||||
allow_all_mentions INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
// language=sql
|
||||
"""
|
||||
CREATE TABLE notification_profile_schedule (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
notification_profile_id INTEGER NOT NULL REFERENCES notification_profile (_id) ON DELETE CASCADE,
|
||||
enabled INTEGER NOT NULL DEFAULT 0,
|
||||
start INTEGER NOT NULL,
|
||||
end INTEGER NOT NULL,
|
||||
days_enabled TEXT NOT NULL
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL(
|
||||
// language=sql
|
||||
"""
|
||||
CREATE TABLE notification_profile_allowed_members (
|
||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
notification_profile_id INTEGER NOT NULL REFERENCES notification_profile (_id) ON DELETE CASCADE,
|
||||
recipient_id INTEGER NOT NULL,
|
||||
UNIQUE(notification_profile_id, recipient_id) ON CONFLICT REPLACE)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
db.execSQL("CREATE INDEX notification_profile_schedule_profile_index ON notification_profile_schedule (notification_profile_id)")
|
||||
db.execSQL("CREATE INDEX notification_profile_allowed_members_profile_index ON notification_profile_allowed_members (notification_profile_id)")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
Reference in New Issue
Block a user