From fc8cf2957ff419fa556186911823e1e5f4d85949 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 6 Dec 2022 17:28:59 -0500 Subject: [PATCH] Convert DraftTable to kotlin. --- .../conversation/drafts/DraftRepository.kt | 2 +- .../conversation/drafts/DraftViewModel.kt | 2 +- .../securesms/database/DraftTable.java | 210 ------------------ .../securesms/database/DraftTable.kt | 183 +++++++++++++++ 4 files changed, 185 insertions(+), 212 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt index eab2be6e44..5804305cce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftRepository.kt @@ -46,7 +46,7 @@ class DraftRepository( } draftTable.replaceDrafts(actualThreadId, drafts) - threadTable.updateSnippet(actualThreadId, drafts.getSnippet(context), drafts.uriSnippet, System.currentTimeMillis(), MmsSmsColumns.Types.BASE_DRAFT_TYPE, true) + threadTable.updateSnippet(actualThreadId, drafts.getSnippet(context), drafts.getUriSnippet(), System.currentTimeMillis(), MmsSmsColumns.Types.BASE_DRAFT_TYPE, true) } else if (threadId > 0) { draftTable.clearDrafts(threadId) threadTable.update(threadId, unarchive = false, allowDeletion = false) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt index a85948ebe9..a7e6e35897 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/drafts/DraftViewModel.kt @@ -74,7 +74,7 @@ class DraftViewModel @JvmOverloads constructor( fun setLocationDraft(place: SignalPlace) { store.update { - saveDrafts(it.copy(locationDraft = Draft(Draft.LOCATION, place.serialize()))) + saveDrafts(it.copy(locationDraft = Draft(Draft.LOCATION, place.serialize() ?: ""))) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.java deleted file mode 100644 index 2d35364c81..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.java +++ /dev/null @@ -1,210 +0,0 @@ -package org.thoughtcrime.securesms.database; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.R; -import org.signal.core.util.CursorUtil; -import org.signal.core.util.SqlUtil; - -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -public class DraftTable extends DatabaseTable implements ThreadIdDatabaseReference { - - private static final String TAG = Log.tag(DraftTable.class); - - static final String TABLE_NAME = "drafts"; - public static final String ID = "_id"; - public static final String THREAD_ID = "thread_id"; - public static final String DRAFT_TYPE = "type"; - public static final String DRAFT_VALUE = "value"; - - public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + - THREAD_ID + " INTEGER, " + DRAFT_TYPE + " TEXT, " + DRAFT_VALUE + " TEXT);"; - - public static final String[] CREATE_INDEXS = { - "CREATE INDEX IF NOT EXISTS draft_thread_index ON " + TABLE_NAME + " (" + THREAD_ID + ");", - }; - - public DraftTable(Context context, SignalDatabase databaseHelper) { - super(context, databaseHelper); - } - - public void replaceDrafts(long threadId, List drafts) { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - - try { - db.beginTransaction(); - - int deletedRowCount = db.delete(TABLE_NAME, THREAD_ID + " = ?", SqlUtil.buildArgs(threadId)); - Log.d(TAG, "[replaceDrafts] Deleted " + deletedRowCount + " rows for thread " + threadId); - - for (Draft draft : drafts) { - ContentValues values = new ContentValues(3); - values.put(THREAD_ID, threadId); - values.put(DRAFT_TYPE, draft.getType()); - values.put(DRAFT_VALUE, draft.getValue()); - - db.insert(TABLE_NAME, null, values); - } - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - - public void clearDrafts(long threadId) { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - int deletedRowCount = db.delete(TABLE_NAME, THREAD_ID + " = ?", SqlUtil.buildArgs(threadId)); - Log.d(TAG, "[clearDrafts] Deleted " + deletedRowCount + " rows for thread " + threadId); - } - - void clearDrafts(Set threadIds) { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - StringBuilder where = new StringBuilder(); - List arguments = new LinkedList<>(); - - for (long threadId : threadIds) { - where.append(" OR ") - .append(THREAD_ID) - .append(" = ?"); - - arguments.add(String.valueOf(threadId)); - } - - db.delete(TABLE_NAME, where.toString().substring(4), arguments.toArray(new String[0])); - } - - void clearAllDrafts() { - SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); - db.delete(TABLE_NAME, null, null); - } - - public Drafts getDrafts(long threadId) { - SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); - Drafts results = new Drafts(); - - try (Cursor cursor = db.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] {threadId+""}, null, null, null)) { - while (cursor != null && cursor.moveToNext()) { - String type = cursor.getString(cursor.getColumnIndexOrThrow(DRAFT_TYPE)); - String value = cursor.getString(cursor.getColumnIndexOrThrow(DRAFT_VALUE)); - - results.add(new Draft(type, value)); - } - - return results; - } - } - - public @NonNull Drafts getAllVoiceNoteDrafts() { - SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); - Drafts results = new Drafts(); - String where = DRAFT_TYPE + " = ?"; - String[] args = SqlUtil.buildArgs(Draft.VOICE_NOTE); - - try (Cursor cursor = db.query(TABLE_NAME, null, where, args, null, null, null)) { - while (cursor != null && cursor.moveToNext()) { - String type = CursorUtil.requireString(cursor, DRAFT_TYPE); - String value = CursorUtil.requireString(cursor, DRAFT_VALUE); - - results.add(new Draft(type, value)); - } - - return results; - } - } - - @Override - public void remapThread(long fromId, long toId) { - ContentValues values = new ContentValues(); - values.put(THREAD_ID, toId); - getWritableDatabase().update(TABLE_NAME, values, THREAD_ID + " = ?", SqlUtil.buildArgs(fromId)); - } - - public static class Draft { - public static final String TEXT = "text"; - public static final String IMAGE = "image"; - public static final String VIDEO = "video"; - public static final String AUDIO = "audio"; - public static final String LOCATION = "location"; - public static final String QUOTE = "quote"; - public static final String MENTION = "mention"; - public static final String VOICE_NOTE = "voice_note"; - - private final String type; - private final String value; - - public Draft(String type, String value) { - this.type = type; - this.value = value; - } - - public String getType() { - return type; - } - - public String getValue() { - return value; - } - - String getSnippet(Context context) { - switch (type) { - case TEXT: return value; - case IMAGE: return context.getString(R.string.DraftDatabase_Draft_image_snippet); - case VIDEO: return context.getString(R.string.DraftDatabase_Draft_video_snippet); - case AUDIO: return context.getString(R.string.DraftDatabase_Draft_audio_snippet); - case LOCATION: return context.getString(R.string.DraftDatabase_Draft_location_snippet); - case QUOTE: return context.getString(R.string.DraftDatabase_Draft_quote_snippet); - case VOICE_NOTE: return context.getString(R.string.DraftDatabase_Draft_voice_note); - default: return null; - } - } - } - - public static class Drafts extends LinkedList { - public void addIfNotNull(@Nullable Draft draft) { - if (draft != null) { - add(draft); - } - } - - public @Nullable Draft getDraftOfType(String type) { - for (Draft draft : this) { - if (type.equals(draft.getType())) { - return draft; - } - } - return null; - } - - public @NonNull String getSnippet(Context context) { - Draft textDraft = getDraftOfType(Draft.TEXT); - if (textDraft != null) { - return textDraft.getSnippet(context); - } else if (size() > 0) { - return get(0).getSnippet(context); - } else { - return ""; - } - } - - public @Nullable Uri getUriSnippet() { - Draft imageDraft = getDraftOfType(Draft.IMAGE); - - if (imageDraft != null && imageDraft.getValue() != null) { - return Uri.parse(imageDraft.getValue()); - } - - return null; - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.kt new file mode 100644 index 0000000000..a5fd4d5325 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DraftTable.kt @@ -0,0 +1,183 @@ +package org.thoughtcrime.securesms.database + +import android.content.Context +import android.net.Uri +import androidx.core.content.contentValuesOf +import org.signal.core.util.SqlUtil +import org.signal.core.util.delete +import org.signal.core.util.logging.Log +import org.signal.core.util.readToList +import org.signal.core.util.requireNonNullString +import org.signal.core.util.select +import org.signal.core.util.update +import org.signal.core.util.withinTransaction +import org.thoughtcrime.securesms.R +import java.util.LinkedList + +class DraftTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper), ThreadIdDatabaseReference { + companion object { + private val TAG = Log.tag(DraftTable::class.java) + const val TABLE_NAME = "drafts" + const val ID = "_id" + const val THREAD_ID = "thread_id" + const val DRAFT_TYPE = "type" + const val DRAFT_VALUE = "value" + const val CREATE_TABLE = """ + CREATE TABLE $TABLE_NAME ( + $ID INTEGER PRIMARY KEY, + $THREAD_ID INTEGER, + $DRAFT_TYPE TEXT, + $DRAFT_VALUE TEXT + ) + """ + + @JvmField + val CREATE_INDEXS = arrayOf("CREATE INDEX IF NOT EXISTS draft_thread_index ON $TABLE_NAME ($THREAD_ID);") + } + + fun replaceDrafts(threadId: Long, drafts: List) { + writableDatabase.withinTransaction { db -> + val deletedRowCount = db + .delete(TABLE_NAME) + .where("$THREAD_ID = ?", threadId) + .run() + Log.d(TAG, "[replaceDrafts] Deleted $deletedRowCount rows for thread $threadId") + + for (draft in drafts) { + val values = contentValuesOf( + THREAD_ID to threadId, + DRAFT_TYPE to draft.type, + DRAFT_VALUE to draft.value + ) + db.insert(TABLE_NAME, null, values) + } + } + } + + fun clearDrafts(threadId: Long) { + val deletedRowCount = writableDatabase + .delete(TABLE_NAME) + .where("$THREAD_ID = ?", threadId) + .run() + Log.d(TAG, "[clearDrafts] Deleted $deletedRowCount rows for thread $threadId") + } + + fun clearDrafts(threadIds: Set) { + val query = SqlUtil.buildSingleCollectionQuery(THREAD_ID, threadIds) + writableDatabase + .delete(TABLE_NAME) + .where(query.where, *query.whereArgs) + .run() + } + + fun clearAllDrafts() { + writableDatabase + .delete(TABLE_NAME) + .run() + } + + fun getDrafts(threadId: Long): Drafts { + return readableDatabase + .select() + .from(TABLE_NAME) + .where("$THREAD_ID = ?", threadId) + .run() + .readToList { cursor -> + Draft( + type = cursor.requireNonNullString(DRAFT_TYPE), + value = cursor.requireNonNullString(DRAFT_VALUE) + ) + } + .asDrafts() + } + + fun getAllVoiceNoteDrafts(): Drafts { + return readableDatabase + .select() + .from(TABLE_NAME) + .where("$DRAFT_TYPE = ?", Draft.VOICE_NOTE) + .run() + .readToList { cursor -> + Draft( + type = cursor.requireNonNullString(DRAFT_TYPE), + value = cursor.requireNonNullString(DRAFT_VALUE) + ) + } + .asDrafts() + } + + override fun remapThread(fromId: Long, toId: Long) { + writableDatabase + .update(TABLE_NAME) + .values(THREAD_ID to toId) + .where("$THREAD_ID = ?", fromId) + .run() + } + + private fun List.asDrafts(): Drafts { + return Drafts(this) + } + + class Draft(val type: String, val value: String) { + fun getSnippet(context: Context): String { + return when (type) { + TEXT -> value + IMAGE -> context.getString(R.string.DraftDatabase_Draft_image_snippet) + VIDEO -> context.getString(R.string.DraftDatabase_Draft_video_snippet) + AUDIO -> context.getString(R.string.DraftDatabase_Draft_audio_snippet) + LOCATION -> context.getString(R.string.DraftDatabase_Draft_location_snippet) + QUOTE -> context.getString(R.string.DraftDatabase_Draft_quote_snippet) + VOICE_NOTE -> context.getString(R.string.DraftDatabase_Draft_voice_note) + else -> "" + } + } + + companion object { + const val TEXT = "text" + const val IMAGE = "image" + const val VIDEO = "video" + const val AUDIO = "audio" + const val LOCATION = "location" + const val QUOTE = "quote" + const val MENTION = "mention" + const val VOICE_NOTE = "voice_note" + } + } + + class Drafts(list: List = emptyList()) : LinkedList() { + init { + addAll(list) + } + + fun addIfNotNull(draft: Draft?) { + if (draft != null) { + add(draft) + } + } + + fun getDraftOfType(type: String): Draft? { + return firstOrNull { it.type == type } + } + + fun getSnippet(context: Context): String { + val textDraft = getDraftOfType(Draft.TEXT) + return if (textDraft != null) { + textDraft.getSnippet(context) + } else if (size > 0) { + get(0).getSnippet(context) + } else { + "" + } + } + + fun getUriSnippet(): Uri? { + val imageDraft = getDraftOfType(Draft.IMAGE) + + return if (imageDraft?.value != null) { + Uri.parse(imageDraft.value) + } else { + null + } + } + } +}