That fuck shit the fascists are using
at master 187 lines 5.3 kB view raw
1package org.tm.archive.database 2 3import android.content.Context 4import android.net.Uri 5import androidx.core.content.contentValuesOf 6import org.signal.core.util.SqlUtil 7import org.signal.core.util.delete 8import org.signal.core.util.deleteAll 9import org.signal.core.util.logging.Log 10import org.signal.core.util.readToList 11import org.signal.core.util.requireNonNullString 12import org.signal.core.util.select 13import org.signal.core.util.update 14import org.signal.core.util.withinTransaction 15import org.tm.archive.R 16import java.util.LinkedList 17 18class DraftTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper), ThreadIdDatabaseReference { 19 companion object { 20 private val TAG = Log.tag(DraftTable::class.java) 21 const val TABLE_NAME = "drafts" 22 const val ID = "_id" 23 const val THREAD_ID = "thread_id" 24 const val DRAFT_TYPE = "type" 25 const val DRAFT_VALUE = "value" 26 const val CREATE_TABLE = """ 27 CREATE TABLE $TABLE_NAME ( 28 $ID INTEGER PRIMARY KEY, 29 $THREAD_ID INTEGER, 30 $DRAFT_TYPE TEXT, 31 $DRAFT_VALUE TEXT 32 ) 33 """ 34 35 @JvmField 36 val CREATE_INDEXS = arrayOf("CREATE INDEX IF NOT EXISTS draft_thread_index ON $TABLE_NAME ($THREAD_ID);") 37 } 38 39 fun replaceDrafts(threadId: Long, drafts: List<Draft>) { 40 writableDatabase.withinTransaction { db -> 41 val deletedRowCount = db 42 .delete(TABLE_NAME) 43 .where("$THREAD_ID = ?", threadId) 44 .run() 45 Log.d(TAG, "[replaceDrafts] Deleted $deletedRowCount rows for thread $threadId") 46 47 for (draft in drafts) { 48 val values = contentValuesOf( 49 THREAD_ID to threadId, 50 DRAFT_TYPE to draft.type, 51 DRAFT_VALUE to draft.value 52 ) 53 db.insert(TABLE_NAME, null, values) 54 } 55 } 56 } 57 58 fun clearDrafts(threadId: Long) { 59 val deletedRowCount = writableDatabase 60 .delete(TABLE_NAME) 61 .where("$THREAD_ID = ?", threadId) 62 .run() 63 Log.d(TAG, "[clearDrafts] Deleted $deletedRowCount rows for thread $threadId") 64 } 65 66 fun clearDrafts(threadIds: Set<Long>) { 67 val query = SqlUtil.buildSingleCollectionQuery(THREAD_ID, threadIds) 68 writableDatabase 69 .delete(TABLE_NAME) 70 .where(query.where, *query.whereArgs) 71 .run() 72 } 73 74 fun clearAllDrafts() { 75 writableDatabase.deleteAll(TABLE_NAME) 76 } 77 78 fun getDrafts(threadId: Long): Drafts { 79 return readableDatabase 80 .select() 81 .from(TABLE_NAME) 82 .where("$THREAD_ID = ?", threadId) 83 .run() 84 .readToList { cursor -> 85 Draft( 86 type = cursor.requireNonNullString(DRAFT_TYPE), 87 value = cursor.requireNonNullString(DRAFT_VALUE) 88 ) 89 } 90 .asDrafts() 91 } 92 93 fun getAllVoiceNoteDrafts(): Drafts { 94 return readableDatabase 95 .select() 96 .from(TABLE_NAME) 97 .where("$DRAFT_TYPE = ?", Draft.VOICE_NOTE) 98 .run() 99 .readToList { cursor -> 100 Draft( 101 type = cursor.requireNonNullString(DRAFT_TYPE), 102 value = cursor.requireNonNullString(DRAFT_VALUE) 103 ) 104 } 105 .asDrafts() 106 } 107 108 override fun remapThread(fromId: Long, toId: Long) { 109 writableDatabase 110 .update(TABLE_NAME) 111 .values(THREAD_ID to toId) 112 .where("$THREAD_ID = ?", fromId) 113 .run() 114 } 115 116 private fun List<Draft>.asDrafts(): Drafts { 117 return Drafts(this) 118 } 119 120 class Draft(val type: String, val value: String) { 121 fun getSnippet(context: Context): String { 122 return when (type) { 123 TEXT -> value 124 IMAGE -> context.getString(R.string.DraftDatabase_Draft_image_snippet) 125 VIDEO -> context.getString(R.string.DraftDatabase_Draft_video_snippet) 126 AUDIO -> context.getString(R.string.DraftDatabase_Draft_audio_snippet) 127 LOCATION -> context.getString(R.string.DraftDatabase_Draft_location_snippet) 128 QUOTE -> context.getString(R.string.DraftDatabase_Draft_quote_snippet) 129 VOICE_NOTE -> context.getString(R.string.DraftDatabase_Draft_voice_note) 130 else -> "" 131 } 132 } 133 134 companion object { 135 const val TEXT = "text" 136 const val IMAGE = "image" 137 const val VIDEO = "video" 138 const val AUDIO = "audio" 139 const val LOCATION = "location" 140 const val QUOTE = "quote" 141 const val BODY_RANGES = "mention" 142 const val VOICE_NOTE = "voice_note" 143 const val MESSAGE_EDIT = "message_edit" 144 } 145 } 146 147 class Drafts(list: List<Draft> = emptyList()) : LinkedList<Draft>() { 148 init { 149 addAll(list) 150 } 151 152 fun addIfNotNull(draft: Draft?) { 153 if (draft != null) { 154 add(draft) 155 } 156 } 157 158 fun getDraftOfType(type: String): Draft? { 159 return firstOrNull { it.type == type } 160 } 161 162 fun shouldUpdateSnippet(): Boolean { 163 return none { it.type == Draft.MESSAGE_EDIT } 164 } 165 166 fun getSnippet(context: Context): String { 167 val textDraft = getDraftOfType(Draft.TEXT) 168 return if (textDraft != null) { 169 textDraft.getSnippet(context) 170 } else if (size > 0) { 171 get(0).getSnippet(context) 172 } else { 173 "" 174 } 175 } 176 177 fun getUriSnippet(): Uri? { 178 val imageDraft = getDraftOfType(Draft.IMAGE) 179 180 return if (imageDraft?.value != null) { 181 Uri.parse(imageDraft.value) 182 } else { 183 null 184 } 185 } 186 } 187}