Use in-app db for drafts
Closes https://github.com/FossifyOrg/Messages/issues/274 Closes https://github.com/FossifyOrg/Messages/issues/225
This commit is contained in:
parent
55c4e84ddc
commit
f661e126df
6 changed files with 118 additions and 49 deletions
|
|
@ -365,9 +365,8 @@ class MainActivity : SimpleActivity() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (conv != null) {
|
if (conv != null) {
|
||||||
val lastModified = maxOf(cachedConv.date, conv.date)
|
// FIXME: Scheduled message date is being reset here.
|
||||||
val conversation = conv.copy(date = lastModified)
|
insertOrUpdateConversation(conv)
|
||||||
insertOrUpdateConversation(conversation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ import org.fossify.messages.extensions.createTemporaryThread
|
||||||
import org.fossify.messages.extensions.deleteConversation
|
import org.fossify.messages.extensions.deleteConversation
|
||||||
import org.fossify.messages.extensions.deleteMessage
|
import org.fossify.messages.extensions.deleteMessage
|
||||||
import org.fossify.messages.extensions.deleteScheduledMessage
|
import org.fossify.messages.extensions.deleteScheduledMessage
|
||||||
|
import org.fossify.messages.extensions.deleteSmsDraft
|
||||||
import org.fossify.messages.extensions.dialNumber
|
import org.fossify.messages.extensions.dialNumber
|
||||||
import org.fossify.messages.extensions.emptyMessagesRecycleBinForConversation
|
import org.fossify.messages.extensions.emptyMessagesRecycleBinForConversation
|
||||||
import org.fossify.messages.extensions.getAddresses
|
import org.fossify.messages.extensions.getAddresses
|
||||||
|
|
@ -280,10 +281,6 @@ class ThreadActivity : SimpleActivity() {
|
||||||
statusBarColor = getProperBackgroundColor()
|
statusBarColor = getProperBackgroundColor()
|
||||||
)
|
)
|
||||||
|
|
||||||
val smsDraft = getSmsDraft(threadId)
|
|
||||||
if (!smsDraft.isNullOrEmpty()) {
|
|
||||||
binding.messageHolder.threadTypeMessage.setText(smsDraft)
|
|
||||||
}
|
|
||||||
isActivityVisible = true
|
isActivityVisible = true
|
||||||
|
|
||||||
notificationManager.cancel(threadId.hashCode())
|
notificationManager.cancel(threadId.hashCode())
|
||||||
|
|
@ -296,6 +293,13 @@ class ThreadActivity : SimpleActivity() {
|
||||||
setupThreadTitle()
|
setupThreadTitle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val smsDraft = getSmsDraft(threadId)
|
||||||
|
if (smsDraft.isNotEmpty()) {
|
||||||
|
runOnUiThread {
|
||||||
|
binding.messageHolder.threadTypeMessage.setText(smsDraft)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val bottomBarColor = getBottomBarColor()
|
val bottomBarColor = getBottomBarColor()
|
||||||
|
|
@ -332,10 +336,12 @@ class ThreadActivity : SimpleActivity() {
|
||||||
|
|
||||||
private fun saveDraftMessage() {
|
private fun saveDraftMessage() {
|
||||||
val draftMessage = binding.messageHolder.threadTypeMessage.value
|
val draftMessage = binding.messageHolder.threadTypeMessage.value
|
||||||
if (getAttachmentSelections().isEmpty()) {
|
ensureBackgroundThread {
|
||||||
saveSmsDraft(draftMessage, threadId)
|
if (draftMessage.isNotEmpty() && getAttachmentSelections().isEmpty()) {
|
||||||
} else {
|
saveSmsDraft(draftMessage, threadId)
|
||||||
saveSmsDraft("", threadId)
|
} else {
|
||||||
|
deleteSmsDraft(threadId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,27 @@ import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import org.fossify.messages.helpers.Converters
|
import org.fossify.messages.helpers.Converters
|
||||||
import org.fossify.messages.interfaces.AttachmentsDao
|
import org.fossify.messages.interfaces.AttachmentsDao
|
||||||
import org.fossify.messages.interfaces.ConversationsDao
|
import org.fossify.messages.interfaces.ConversationsDao
|
||||||
|
import org.fossify.messages.interfaces.DraftsDao
|
||||||
import org.fossify.messages.interfaces.MessageAttachmentsDao
|
import org.fossify.messages.interfaces.MessageAttachmentsDao
|
||||||
import org.fossify.messages.interfaces.MessagesDao
|
import org.fossify.messages.interfaces.MessagesDao
|
||||||
import org.fossify.messages.models.*
|
import org.fossify.messages.models.Attachment
|
||||||
|
import org.fossify.messages.models.Conversation
|
||||||
|
import org.fossify.messages.models.Draft
|
||||||
|
import org.fossify.messages.models.Message
|
||||||
|
import org.fossify.messages.models.MessageAttachment
|
||||||
|
import org.fossify.messages.models.RecycleBinMessage
|
||||||
|
|
||||||
@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class, RecycleBinMessage::class], version = 8)
|
@Database(
|
||||||
|
entities = [
|
||||||
|
Conversation::class,
|
||||||
|
Attachment::class,
|
||||||
|
MessageAttachment::class,
|
||||||
|
Message::class,
|
||||||
|
RecycleBinMessage::class,
|
||||||
|
Draft::class
|
||||||
|
],
|
||||||
|
version = 9
|
||||||
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
abstract class MessagesDatabase : RoomDatabase() {
|
abstract class MessagesDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
|
@ -26,6 +42,8 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun MessagesDao(): MessagesDao
|
abstract fun MessagesDao(): MessagesDao
|
||||||
|
|
||||||
|
abstract fun DraftsDao(): DraftsDao
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var db: MessagesDatabase? = null
|
private var db: MessagesDatabase? = null
|
||||||
|
|
||||||
|
|
@ -33,7 +51,11 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
if (db == null) {
|
if (db == null) {
|
||||||
synchronized(MessagesDatabase::class) {
|
synchronized(MessagesDatabase::class) {
|
||||||
if (db == null) {
|
if (db == null) {
|
||||||
db = Room.databaseBuilder(context.applicationContext, MessagesDatabase::class.java, "conversations.db")
|
db = Room.databaseBuilder(
|
||||||
|
context = context.applicationContext,
|
||||||
|
klass = MessagesDatabase::class.java,
|
||||||
|
name = "conversations.db"
|
||||||
|
)
|
||||||
.fallbackToDestructiveMigration()
|
.fallbackToDestructiveMigration()
|
||||||
.addMigrations(MIGRATION_1_2)
|
.addMigrations(MIGRATION_1_2)
|
||||||
.addMigrations(MIGRATION_2_3)
|
.addMigrations(MIGRATION_2_3)
|
||||||
|
|
@ -42,6 +64,7 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
.addMigrations(MIGRATION_5_6)
|
.addMigrations(MIGRATION_5_6)
|
||||||
.addMigrations(MIGRATION_6_7)
|
.addMigrations(MIGRATION_6_7)
|
||||||
.addMigrations(MIGRATION_7_8)
|
.addMigrations(MIGRATION_7_8)
|
||||||
|
.addMigrations(MIGRATION_8_9)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +92,7 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
|
|
||||||
execSQL(
|
execSQL(
|
||||||
"INSERT OR IGNORE INTO conversations_new (thread_id, snippet, date, read, title, photo_uri, is_group_conversation, phone_number) " +
|
"INSERT OR IGNORE INTO conversations_new (thread_id, snippet, date, read, title, photo_uri, is_group_conversation, phone_number) " +
|
||||||
"SELECT thread_id, snippet, date, read, title, photo_uri, is_group_conversation, phone_number FROM conversations"
|
"SELECT thread_id, snippet, date, read, title, photo_uri, is_group_conversation, phone_number FROM conversations"
|
||||||
)
|
)
|
||||||
|
|
||||||
execSQL("DROP TABLE conversations")
|
execSQL("DROP TABLE conversations")
|
||||||
|
|
@ -123,5 +146,13 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATION_8_9 = object : Migration(8, 9) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.apply {
|
||||||
|
execSQL("CREATE TABLE IF NOT EXISTS `drafts` (`thread_id` INTEGER NOT NULL PRIMARY KEY, `body` TEXT NOT NULL, `date` INTEGER NOT NULL)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ import org.fossify.messages.helpers.NotificationHelper
|
||||||
import org.fossify.messages.helpers.generateRandomId
|
import org.fossify.messages.helpers.generateRandomId
|
||||||
import org.fossify.messages.interfaces.AttachmentsDao
|
import org.fossify.messages.interfaces.AttachmentsDao
|
||||||
import org.fossify.messages.interfaces.ConversationsDao
|
import org.fossify.messages.interfaces.ConversationsDao
|
||||||
|
import org.fossify.messages.interfaces.DraftsDao
|
||||||
import org.fossify.messages.interfaces.MessageAttachmentsDao
|
import org.fossify.messages.interfaces.MessageAttachmentsDao
|
||||||
import org.fossify.messages.interfaces.MessagesDao
|
import org.fossify.messages.interfaces.MessagesDao
|
||||||
import org.fossify.messages.messaging.MessagingUtils
|
import org.fossify.messages.messaging.MessagingUtils
|
||||||
|
|
@ -66,6 +67,7 @@ import org.fossify.messages.messaging.MessagingUtils.Companion.ADDRESS_SEPARATOR
|
||||||
import org.fossify.messages.messaging.SmsSender
|
import org.fossify.messages.messaging.SmsSender
|
||||||
import org.fossify.messages.models.Attachment
|
import org.fossify.messages.models.Attachment
|
||||||
import org.fossify.messages.models.Conversation
|
import org.fossify.messages.models.Conversation
|
||||||
|
import org.fossify.messages.models.Draft
|
||||||
import org.fossify.messages.models.Message
|
import org.fossify.messages.models.Message
|
||||||
import org.fossify.messages.models.MessageAttachment
|
import org.fossify.messages.models.MessageAttachment
|
||||||
import org.fossify.messages.models.NamePhoto
|
import org.fossify.messages.models.NamePhoto
|
||||||
|
|
@ -85,6 +87,8 @@ val Context.messageAttachmentsDB: MessageAttachmentsDao get() = getMessagesDB().
|
||||||
|
|
||||||
val Context.messagesDB: MessagesDao get() = getMessagesDB().MessagesDao()
|
val Context.messagesDB: MessagesDao get() = getMessagesDB().MessagesDao()
|
||||||
|
|
||||||
|
val Context.draftsDB: DraftsDao get() = getMessagesDB().DraftsDao()
|
||||||
|
|
||||||
val Context.notificationHelper get() = NotificationHelper(this)
|
val Context.notificationHelper get() = NotificationHelper(this)
|
||||||
|
|
||||||
val Context.messagingUtils get() = MessagingUtils(this)
|
val Context.messagingUtils get() = MessagingUtils(this)
|
||||||
|
|
@ -360,6 +364,12 @@ fun Context.getConversations(
|
||||||
date /= 1000
|
date /= 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drafts are stored locally they take priority over the original date
|
||||||
|
val draft = draftsDB.getDraftById(id)
|
||||||
|
if (draft != null) {
|
||||||
|
date = draft.date / 1000
|
||||||
|
}
|
||||||
|
|
||||||
val rawIds = cursor.getStringValue(Threads.RECIPIENT_IDS)
|
val rawIds = cursor.getStringValue(Threads.RECIPIENT_IDS)
|
||||||
val recipientIds =
|
val recipientIds =
|
||||||
rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
||||||
|
|
@ -1045,40 +1055,21 @@ fun Context.removeDiacriticsIfNeeded(text: String): String {
|
||||||
return if (config.useSimpleCharacters) text.normalizeString() else text
|
return if (config.useSimpleCharacters) text.normalizeString() else text
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getSmsDraft(threadId: Long): String? {
|
fun Context.getSmsDraft(threadId: Long): String {
|
||||||
val uri = Sms.Draft.CONTENT_URI
|
val draft = try {
|
||||||
val projection = arrayOf(Sms.BODY)
|
draftsDB.getDraftById(threadId)
|
||||||
val selection = "${Sms.THREAD_ID} = ?"
|
|
||||||
val selectionArgs = arrayOf(threadId.toString())
|
|
||||||
|
|
||||||
try {
|
|
||||||
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null)
|
|
||||||
cursor.use {
|
|
||||||
if (cursor?.moveToFirst() == true) {
|
|
||||||
return cursor.getString(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return draft?.body.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getAllDrafts(): HashMap<Long, String> {
|
fun Context.getAllDrafts(): HashMap<Long, String> {
|
||||||
val drafts = HashMap<Long, String>()
|
val drafts = HashMap<Long, String>()
|
||||||
val uri = Sms.Draft.CONTENT_URI
|
|
||||||
val projection = arrayOf(Sms.BODY, Sms.THREAD_ID)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val cursor = contentResolver.query(uri, projection, null, null, null)
|
draftsDB.getAll().forEach {
|
||||||
cursor?.use {
|
drafts[it.threadId] = it.body
|
||||||
while (it.moveToNext()) {
|
|
||||||
val threadId = it.getLongValue(Sms.THREAD_ID)
|
|
||||||
val draft = it.getStringValue(Sms.BODY)
|
|
||||||
if (!draft.isNullOrEmpty()) {
|
|
||||||
drafts[threadId] = draft
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
|
@ -1088,17 +1079,25 @@ fun Context.getAllDrafts(): HashMap<Long, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.saveSmsDraft(body: String, threadId: Long) {
|
fun Context.saveSmsDraft(body: String, threadId: Long) {
|
||||||
val uri = Sms.Draft.CONTENT_URI
|
val draft = Draft(
|
||||||
val contentValues = ContentValues().apply {
|
threadId = threadId,
|
||||||
put(Sms.BODY, body)
|
body = body,
|
||||||
put(Sms.DATE, System.currentTimeMillis().toString())
|
date = System.currentTimeMillis()
|
||||||
put(Sms.TYPE, Sms.MESSAGE_TYPE_DRAFT)
|
)
|
||||||
put(Sms.THREAD_ID, threadId)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contentResolver.insert(uri, contentValues)
|
draftsDB.insertOrUpdate(draft)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
showErrorToast(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.deleteSmsDraft(threadId: Long) {
|
||||||
|
try {
|
||||||
|
draftsDB.delete(threadId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
showErrorToast(e)
|
showErrorToast(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.fossify.messages.interfaces
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import org.fossify.messages.models.Draft
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface DraftsDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertOrUpdate(draft: Draft): Long
|
||||||
|
|
||||||
|
@Query("SELECT * FROM drafts")
|
||||||
|
fun getAll(): List<Draft>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM drafts WHERE thread_id = :threadId")
|
||||||
|
fun getDraftById(threadId: Long): Draft?
|
||||||
|
|
||||||
|
@Query("DELETE FROM drafts WHERE thread_id = :threadId")
|
||||||
|
fun delete(threadId: Long): Int
|
||||||
|
}
|
||||||
12
app/src/main/kotlin/org/fossify/messages/models/Draft.kt
Normal file
12
app/src/main/kotlin/org/fossify/messages/models/Draft.kt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.fossify.messages.models
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "drafts")
|
||||||
|
data class Draft(
|
||||||
|
@ColumnInfo(name = "thread_id") @PrimaryKey val threadId: Long,
|
||||||
|
@ColumnInfo(name = "body") val body: String,
|
||||||
|
@ColumnInfo(name = "date") val date: Long,
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue