Add support for recycle bin for messages
This adds support for moving messages to recycle bin instead of deleting them right away. The feature is not active by default. This closes #451
This commit is contained in:
parent
53aa4495a0
commit
555b6ebea3
|
@ -64,6 +64,7 @@ class MainActivity : SimpleActivity() {
|
||||||
updateMaterialActivityViews(main_coordinator, conversations_list, useTransparentNavigation = true, useTopSearchMenu = true)
|
updateMaterialActivityViews(main_coordinator, conversations_list, useTransparentNavigation = true, useTopSearchMenu = true)
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
|
checkAndDeleteOldRecycleBinMessages()
|
||||||
handleAppPasswordProtection {
|
handleAppPasswordProtection {
|
||||||
wasProtectionHandled = it
|
wasProtectionHandled = it
|
||||||
if (it) {
|
if (it) {
|
||||||
|
|
|
@ -11,12 +11,15 @@ import com.simplemobiletools.commons.helpers.*
|
||||||
import com.simplemobiletools.commons.models.RadioItem
|
import com.simplemobiletools.commons.models.RadioItem
|
||||||
import com.simplemobiletools.smsmessenger.R
|
import com.simplemobiletools.smsmessenger.R
|
||||||
import com.simplemobiletools.smsmessenger.extensions.config
|
import com.simplemobiletools.smsmessenger.extensions.config
|
||||||
|
import com.simplemobiletools.smsmessenger.extensions.emptyMessagesRecycleBin
|
||||||
|
import com.simplemobiletools.smsmessenger.extensions.messagesDB
|
||||||
import com.simplemobiletools.smsmessenger.helpers.*
|
import com.simplemobiletools.smsmessenger.helpers.*
|
||||||
import kotlinx.android.synthetic.main.activity_settings.*
|
import kotlinx.android.synthetic.main.activity_settings.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SettingsActivity : SimpleActivity() {
|
class SettingsActivity : SimpleActivity() {
|
||||||
private var blockedNumbersAtPause = -1
|
private var blockedNumbersAtPause = -1
|
||||||
|
private var recycleBinMessages = 0
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
isMaterialActivity = true
|
isMaterialActivity = true
|
||||||
|
@ -48,6 +51,8 @@ class SettingsActivity : SimpleActivity() {
|
||||||
setupGroupMessageAsMMS()
|
setupGroupMessageAsMMS()
|
||||||
setupLockScreenVisibility()
|
setupLockScreenVisibility()
|
||||||
setupMMSFileSizeLimit()
|
setupMMSFileSizeLimit()
|
||||||
|
setupUseRecycleBin()
|
||||||
|
setupEmptyRecycleBin()
|
||||||
setupAppPasswordProtection()
|
setupAppPasswordProtection()
|
||||||
updateTextColors(settings_nested_scrollview)
|
updateTextColors(settings_nested_scrollview)
|
||||||
|
|
||||||
|
@ -60,6 +65,7 @@ class SettingsActivity : SimpleActivity() {
|
||||||
settings_general_settings_label,
|
settings_general_settings_label,
|
||||||
settings_outgoing_messages_label,
|
settings_outgoing_messages_label,
|
||||||
settings_notifications_label,
|
settings_notifications_label,
|
||||||
|
settings_recycle_bin_label,
|
||||||
settings_security_label
|
settings_security_label
|
||||||
).forEach {
|
).forEach {
|
||||||
it.setTextColor(getProperPrimaryColor())
|
it.setTextColor(getProperPrimaryColor())
|
||||||
|
@ -259,6 +265,43 @@ class SettingsActivity : SimpleActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupUseRecycleBin() {
|
||||||
|
updateRecycleBinButtons()
|
||||||
|
settings_use_recycle_bin.isChecked = config.useRecycleBin
|
||||||
|
settings_use_recycle_bin_holder.setOnClickListener {
|
||||||
|
settings_use_recycle_bin.toggle()
|
||||||
|
config.useRecycleBin = settings_use_recycle_bin.isChecked
|
||||||
|
updateRecycleBinButtons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateRecycleBinButtons() {
|
||||||
|
settings_empty_recycle_bin_holder.beVisibleIf(config.useRecycleBin)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupEmptyRecycleBin() {
|
||||||
|
ensureBackgroundThread {
|
||||||
|
recycleBinMessages = messagesDB.getArchivedCount()
|
||||||
|
runOnUiThread {
|
||||||
|
settings_empty_recycle_bin_size.text =
|
||||||
|
resources.getQuantityString(R.plurals.delete_messages, recycleBinMessages, recycleBinMessages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings_empty_recycle_bin_holder.setOnClickListener {
|
||||||
|
if (recycleBinMessages == 0) {
|
||||||
|
toast(R.string.recycle_bin_empty)
|
||||||
|
} else {
|
||||||
|
ConfirmationDialog(this, "", R.string.empty_recycle_bin_confirmation, R.string.yes, R.string.no) {
|
||||||
|
emptyMessagesRecycleBin()
|
||||||
|
recycleBinMessages = 0
|
||||||
|
settings_empty_recycle_bin_size.text =
|
||||||
|
resources.getQuantityString(R.plurals.delete_messages, recycleBinMessages, recycleBinMessages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupAppPasswordProtection() {
|
private fun setupAppPasswordProtection() {
|
||||||
settings_app_password_protection.isChecked = config.isAppPasswordProtectionOn
|
settings_app_password_protection.isChecked = config.isAppPasswordProtectionOn
|
||||||
settings_app_password_protection_holder.setOnClickListener {
|
settings_app_password_protection_holder.setOnClickListener {
|
||||||
|
|
|
@ -402,7 +402,7 @@ class ThreadActivity : SimpleActivity() {
|
||||||
activity = this,
|
activity = this,
|
||||||
recyclerView = thread_messages_list,
|
recyclerView = thread_messages_list,
|
||||||
itemClick = { handleItemClick(it) },
|
itemClick = { handleItemClick(it) },
|
||||||
deleteMessages = { deleteMessages(it) }
|
deleteMessages = { messages, toRecycleBin -> deleteMessages(messages, toRecycleBin) }
|
||||||
)
|
)
|
||||||
|
|
||||||
thread_messages_list.adapter = currAdapter
|
thread_messages_list.adapter = currAdapter
|
||||||
|
@ -489,7 +489,7 @@ class ThreadActivity : SimpleActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteMessages(messagesToRemove: List<Message>) {
|
private fun deleteMessages(messagesToRemove: List<Message>, toRecycleBin: Boolean) {
|
||||||
val deletePosition = threadItems.indexOf(messagesToRemove.first())
|
val deletePosition = threadItems.indexOf(messagesToRemove.first())
|
||||||
messages.removeAll(messagesToRemove.toSet())
|
messages.removeAll(messagesToRemove.toSet())
|
||||||
threadItems = getThreadItems()
|
threadItems = getThreadItems()
|
||||||
|
@ -508,10 +508,15 @@ class ThreadActivity : SimpleActivity() {
|
||||||
messagesToRemove.forEach { message ->
|
messagesToRemove.forEach { message ->
|
||||||
val messageId = message.id
|
val messageId = message.id
|
||||||
if (message.isScheduled) {
|
if (message.isScheduled) {
|
||||||
|
// TODO: Moving scheduled messages to recycle bin maybe doesn't make sense
|
||||||
deleteScheduledMessage(messageId)
|
deleteScheduledMessage(messageId)
|
||||||
cancelScheduleSendPendingIntent(messageId)
|
cancelScheduleSendPendingIntent(messageId)
|
||||||
} else {
|
} else {
|
||||||
deleteMessage(messageId, message.isMMS)
|
if (toRecycleBin) {
|
||||||
|
moveMessageToRecycleBin(messageId)
|
||||||
|
} else {
|
||||||
|
deleteMessage(messageId, message.isMMS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateLastConversationMessage(threadId)
|
updateLastConversationMessage(threadId)
|
||||||
|
|
|
@ -23,7 +23,6 @@ import com.bumptech.glide.request.RequestListener
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.bumptech.glide.request.target.Target
|
import com.bumptech.glide.request.target.Target
|
||||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewListAdapter
|
import com.simplemobiletools.commons.adapters.MyRecyclerViewListAdapter
|
||||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
|
||||||
import com.simplemobiletools.commons.extensions.*
|
import com.simplemobiletools.commons.extensions.*
|
||||||
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
|
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
|
||||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||||
|
@ -33,6 +32,7 @@ import com.simplemobiletools.smsmessenger.activities.NewConversationActivity
|
||||||
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
|
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
|
||||||
import com.simplemobiletools.smsmessenger.activities.ThreadActivity
|
import com.simplemobiletools.smsmessenger.activities.ThreadActivity
|
||||||
import com.simplemobiletools.smsmessenger.activities.VCardViewerActivity
|
import com.simplemobiletools.smsmessenger.activities.VCardViewerActivity
|
||||||
|
import com.simplemobiletools.smsmessenger.dialogs.DeleteConfirmationDialog
|
||||||
import com.simplemobiletools.smsmessenger.dialogs.MessageDetailsDialog
|
import com.simplemobiletools.smsmessenger.dialogs.MessageDetailsDialog
|
||||||
import com.simplemobiletools.smsmessenger.dialogs.SelectTextDialog
|
import com.simplemobiletools.smsmessenger.dialogs.SelectTextDialog
|
||||||
import com.simplemobiletools.smsmessenger.extensions.*
|
import com.simplemobiletools.smsmessenger.extensions.*
|
||||||
|
@ -58,7 +58,7 @@ class ThreadAdapter(
|
||||||
activity: SimpleActivity,
|
activity: SimpleActivity,
|
||||||
recyclerView: MyRecyclerView,
|
recyclerView: MyRecyclerView,
|
||||||
itemClick: (Any) -> Unit,
|
itemClick: (Any) -> Unit,
|
||||||
val deleteMessages: (messages: List<Message>) -> Unit
|
val deleteMessages: (messages: List<Message>, toRecycleBin: Boolean) -> Unit
|
||||||
) : MyRecyclerViewListAdapter<ThreadItem>(activity, recyclerView, ThreadItemDiffCallback(), itemClick) {
|
) : MyRecyclerViewListAdapter<ThreadItem>(activity, recyclerView, ThreadItemDiffCallback(), itemClick) {
|
||||||
private var fontSize = activity.getTextSize()
|
private var fontSize = activity.getTextSize()
|
||||||
|
|
||||||
|
@ -206,11 +206,12 @@ class ThreadAdapter(
|
||||||
val baseString = R.string.deletion_confirmation
|
val baseString = R.string.deletion_confirmation
|
||||||
val question = String.format(resources.getString(baseString), items)
|
val question = String.format(resources.getString(baseString), items)
|
||||||
|
|
||||||
ConfirmationDialog(activity, question) {
|
DeleteConfirmationDialog(activity, question, activity.config.useRecycleBin) { skipRecycleBin ->
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
val messagesToRemove = getSelectedItems()
|
val messagesToRemove = getSelectedItems()
|
||||||
if (messagesToRemove.isNotEmpty()) {
|
if (messagesToRemove.isNotEmpty()) {
|
||||||
deleteMessages(messagesToRemove.filterIsInstance<Message>())
|
val toRecycleBin = !skipRecycleBin && activity.config.useRecycleBin
|
||||||
|
deleteMessages(messagesToRemove.filterIsInstance<Message>(), toRecycleBin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,9 @@ import com.simplemobiletools.smsmessenger.interfaces.AttachmentsDao
|
||||||
import com.simplemobiletools.smsmessenger.interfaces.ConversationsDao
|
import com.simplemobiletools.smsmessenger.interfaces.ConversationsDao
|
||||||
import com.simplemobiletools.smsmessenger.interfaces.MessageAttachmentsDao
|
import com.simplemobiletools.smsmessenger.interfaces.MessageAttachmentsDao
|
||||||
import com.simplemobiletools.smsmessenger.interfaces.MessagesDao
|
import com.simplemobiletools.smsmessenger.interfaces.MessagesDao
|
||||||
import com.simplemobiletools.smsmessenger.models.Attachment
|
import com.simplemobiletools.smsmessenger.models.*
|
||||||
import com.simplemobiletools.smsmessenger.models.Conversation
|
|
||||||
import com.simplemobiletools.smsmessenger.models.Message
|
|
||||||
import com.simplemobiletools.smsmessenger.models.MessageAttachment
|
|
||||||
|
|
||||||
@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 7)
|
@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class, RecycleBinMessage::class], version = 8)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
abstract class MessagesDatabase : RoomDatabase() {
|
abstract class MessagesDatabase : RoomDatabase() {
|
||||||
|
|
||||||
|
@ -44,6 +41,7 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
.addMigrations(MIGRATION_4_5)
|
.addMigrations(MIGRATION_4_5)
|
||||||
.addMigrations(MIGRATION_5_6)
|
.addMigrations(MIGRATION_5_6)
|
||||||
.addMigrations(MIGRATION_6_7)
|
.addMigrations(MIGRATION_6_7)
|
||||||
|
.addMigrations(MIGRATION_7_8)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,5 +113,14 @@ abstract class MessagesDatabase : RoomDatabase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATION_7_8 = object : Migration(7, 8) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.apply {
|
||||||
|
execSQL("CREATE TABLE IF NOT EXISTS `recycle_bin_messages` (`id` INTEGER PRIMARY KEY, `deleted_ts` INTEGER NOT NULL)")
|
||||||
|
execSQL("CREATE UNIQUE INDEX `index_recycle_bin_messages_id` ON `recycle_bin_messages` (`id`)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.simplemobiletools.smsmessenger.dialogs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.simplemobiletools.commons.extensions.beGoneIf
|
||||||
|
import com.simplemobiletools.commons.extensions.getAlertDialogBuilder
|
||||||
|
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||||
|
import com.simplemobiletools.smsmessenger.R
|
||||||
|
import kotlinx.android.synthetic.main.dialog_delete_confirmation.view.delete_remember_title
|
||||||
|
import kotlinx.android.synthetic.main.dialog_delete_confirmation.view.skip_the_recycle_bin_checkbox
|
||||||
|
|
||||||
|
class DeleteConfirmationDialog(
|
||||||
|
private val activity: Activity,
|
||||||
|
private val message: String,
|
||||||
|
private val showSkipRecycleBinOption: Boolean,
|
||||||
|
private val callback: (skipRecycleBin: Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
|
private var dialog: AlertDialog? = null
|
||||||
|
val view = activity.layoutInflater.inflate(R.layout.dialog_delete_confirmation, null)!!
|
||||||
|
|
||||||
|
init {
|
||||||
|
view.delete_remember_title.text = message
|
||||||
|
view.skip_the_recycle_bin_checkbox.beGoneIf(!showSkipRecycleBinOption)
|
||||||
|
activity.getAlertDialogBuilder()
|
||||||
|
.setPositiveButton(R.string.yes) { _, _ -> dialogConfirmed() }
|
||||||
|
.setNegativeButton(R.string.no, null)
|
||||||
|
.apply {
|
||||||
|
activity.setupDialogStuff(view, this) { alertDialog ->
|
||||||
|
dialog = alertDialog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dialogConfirmed() {
|
||||||
|
dialog?.dismiss()
|
||||||
|
callback(view.skip_the_recycle_bin_checkbox.isChecked)
|
||||||
|
}
|
||||||
|
}
|
|
@ -641,6 +641,36 @@ fun Context.deleteConversation(threadId: Long) {
|
||||||
messagesDB.deleteThreadMessages(threadId)
|
messagesDB.deleteThreadMessages(threadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.checkAndDeleteOldRecycleBinMessages(callback: (() -> Unit)? = null) {
|
||||||
|
if (config.useRecycleBin && config.lastRecycleBinCheck < System.currentTimeMillis() - DAY_SECONDS * 1000) {
|
||||||
|
config.lastRecycleBinCheck = System.currentTimeMillis()
|
||||||
|
ensureBackgroundThread {
|
||||||
|
try {
|
||||||
|
for (message in messagesDB.getOldRecycleBinMessages(System.currentTimeMillis() - MONTH_SECONDS * 1000L)) {
|
||||||
|
deleteMessage(message.id, message.isMMS)
|
||||||
|
}
|
||||||
|
callback?.invoke()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.emptyMessagesRecycleBin() {
|
||||||
|
val messages = messagesDB.getAllRecycleBinMessages()
|
||||||
|
for (message in messages) {
|
||||||
|
deleteMessage(message.id, message.isMMS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.moveMessageToRecycleBin(id: Long) {
|
||||||
|
try {
|
||||||
|
messagesDB.insertRecycleBinEntry(RecycleBinMessage(id, System.currentTimeMillis()))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showErrorToast(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Context.deleteMessage(id: Long, isMMS: Boolean) {
|
fun Context.deleteMessage(id: Long, isMMS: Boolean) {
|
||||||
val uri = if (isMMS) Mms.CONTENT_URI else Sms.CONTENT_URI
|
val uri = if (isMMS) Mms.CONTENT_URI else Sms.CONTENT_URI
|
||||||
val selection = "${Sms._ID} = ?"
|
val selection = "${Sms._ID} = ?"
|
||||||
|
|
|
@ -103,4 +103,12 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
var keyboardHeight: Int
|
var keyboardHeight: Int
|
||||||
get() = prefs.getInt(SOFT_KEYBOARD_HEIGHT, context.getDefaultKeyboardHeight())
|
get() = prefs.getInt(SOFT_KEYBOARD_HEIGHT, context.getDefaultKeyboardHeight())
|
||||||
set(keyboardHeight) = prefs.edit().putInt(SOFT_KEYBOARD_HEIGHT, keyboardHeight).apply()
|
set(keyboardHeight) = prefs.edit().putInt(SOFT_KEYBOARD_HEIGHT, keyboardHeight).apply()
|
||||||
|
|
||||||
|
var useRecycleBin: Boolean
|
||||||
|
get() = prefs.getBoolean(USE_RECYCLE_BIN, false)
|
||||||
|
set(useRecycleBin) = prefs.edit().putBoolean(USE_RECYCLE_BIN, useRecycleBin).apply()
|
||||||
|
|
||||||
|
var lastRecycleBinCheck: Long
|
||||||
|
get() = prefs.getLong(LAST_RECYCLE_BIN_CHECK, 0L)
|
||||||
|
set(lastRecycleBinCheck) = prefs.edit().putLong(LAST_RECYCLE_BIN_CHECK, lastRecycleBinCheck).apply()
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ const val SCHEDULED_MESSAGE_ID = "scheduled_message_id"
|
||||||
const val SOFT_KEYBOARD_HEIGHT = "soft_keyboard_height"
|
const val SOFT_KEYBOARD_HEIGHT = "soft_keyboard_height"
|
||||||
const val IS_MMS = "is_mms"
|
const val IS_MMS = "is_mms"
|
||||||
const val MESSAGE_ID = "message_id"
|
const val MESSAGE_ID = "message_id"
|
||||||
|
const val USE_RECYCLE_BIN = "use_recycle_bin"
|
||||||
|
const val LAST_RECYCLE_BIN_CHECK = "last_recycle_bin_check"
|
||||||
|
|
||||||
private const val PATH = "com.simplemobiletools.smsmessenger.action."
|
private const val PATH = "com.simplemobiletools.smsmessenger.action."
|
||||||
const val MARK_AS_READ = PATH + "mark_as_read"
|
const val MARK_AS_READ = PATH + "mark_as_read"
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package com.simplemobiletools.smsmessenger.interfaces
|
package com.simplemobiletools.smsmessenger.interfaces
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.*
|
||||||
import androidx.room.Insert
|
import com.simplemobiletools.smsmessenger.models.RecycleBinMessage
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
|
||||||
import com.simplemobiletools.smsmessenger.models.Message
|
import com.simplemobiletools.smsmessenger.models.Message
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
|
@ -11,6 +9,9 @@ interface MessagesDao {
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
fun insertOrUpdate(message: Message)
|
fun insertOrUpdate(message: Message)
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertRecycleBinEntry(recycleBinMessage: RecycleBinMessage)
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
fun insertOrIgnore(message: Message): Long
|
fun insertOrIgnore(message: Message): Long
|
||||||
|
|
||||||
|
@ -20,15 +21,24 @@ interface MessagesDao {
|
||||||
@Query("SELECT * FROM messages")
|
@Query("SELECT * FROM messages")
|
||||||
fun getAll(): List<Message>
|
fun getAll(): List<Message>
|
||||||
|
|
||||||
@Query("SELECT * FROM messages WHERE thread_id = :threadId")
|
@Query("SELECT messages.* FROM messages LEFT OUTER JOIN recycle_bin_messages ON messages.id = recycle_bin_messages.id WHERE recycle_bin_messages.id IS NOT NULL")
|
||||||
|
fun getAllRecycleBinMessages(): List<Message>
|
||||||
|
|
||||||
|
@Query("SELECT messages.* FROM messages LEFT OUTER JOIN recycle_bin_messages ON messages.id = recycle_bin_messages.id WHERE recycle_bin_messages.id IS NOT NULL AND recycle_bin_messages.deleted_ts < :timestamp")
|
||||||
|
fun getOldRecycleBinMessages(timestamp: Long): List<Message>
|
||||||
|
|
||||||
|
@Query("SELECT messages.* FROM messages LEFT OUTER JOIN recycle_bin_messages ON messages.id = recycle_bin_messages.id WHERE recycle_bin_messages.id IS NULL AND thread_id = :threadId")
|
||||||
fun getThreadMessages(threadId: Long): List<Message>
|
fun getThreadMessages(threadId: Long): List<Message>
|
||||||
|
|
||||||
@Query("SELECT * FROM messages WHERE thread_id = :threadId AND is_scheduled = 1")
|
@Query("SELECT messages.* FROM messages LEFT OUTER JOIN recycle_bin_messages ON messages.id = recycle_bin_messages.id WHERE recycle_bin_messages.id IS NULL AND thread_id = :threadId AND is_scheduled = 1")
|
||||||
fun getScheduledThreadMessages(threadId: Long): List<Message>
|
fun getScheduledThreadMessages(threadId: Long): List<Message>
|
||||||
|
|
||||||
@Query("SELECT * FROM messages WHERE thread_id = :threadId AND id = :messageId AND is_scheduled = 1")
|
@Query("SELECT * FROM messages WHERE thread_id = :threadId AND id = :messageId AND is_scheduled = 1")
|
||||||
fun getScheduledMessageWithId(threadId: Long, messageId: Long): Message
|
fun getScheduledMessageWithId(threadId: Long, messageId: Long): Message
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM recycle_bin_messages")
|
||||||
|
fun getArchivedCount(): Int
|
||||||
|
|
||||||
@Query("SELECT * FROM messages WHERE body LIKE :text")
|
@Query("SELECT * FROM messages WHERE body LIKE :text")
|
||||||
fun getMessagesWithText(text: String): List<Message>
|
fun getMessagesWithText(text: String): List<Message>
|
||||||
|
|
||||||
|
@ -44,11 +54,29 @@ interface MessagesDao {
|
||||||
@Query("UPDATE messages SET status = :status WHERE id = :id")
|
@Query("UPDATE messages SET status = :status WHERE id = :id")
|
||||||
fun updateStatus(id: Long, status: Int): Int
|
fun updateStatus(id: Long, status: Int): Int
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
fun delete(id: Long) {
|
||||||
|
deleteFromMessages(id)
|
||||||
|
deleteFromRecycleBin(id)
|
||||||
|
}
|
||||||
|
|
||||||
@Query("DELETE FROM messages WHERE id = :id")
|
@Query("DELETE FROM messages WHERE id = :id")
|
||||||
fun delete(id: Long)
|
fun deleteFromMessages(id: Long)
|
||||||
|
|
||||||
|
@Query("DELETE FROM recycle_bin_messages WHERE id = :id")
|
||||||
|
fun deleteFromRecycleBin(id: Long)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
fun deleteThreadMessages(threadId: Long) {
|
||||||
|
deleteThreadMessagesFromRecycleBin(threadId)
|
||||||
|
deleteAllThreadMessages(threadId)
|
||||||
|
}
|
||||||
|
|
||||||
@Query("DELETE FROM messages WHERE thread_id = :threadId")
|
@Query("DELETE FROM messages WHERE thread_id = :threadId")
|
||||||
fun deleteThreadMessages(threadId: Long)
|
fun deleteAllThreadMessages(threadId: Long)
|
||||||
|
|
||||||
|
@Query("DELETE FROM recycle_bin_messages WHERE id IN (SELECT id FROM messages WHERE thread_id = :threadId)")
|
||||||
|
fun deleteThreadMessagesFromRecycleBin(threadId: Long)
|
||||||
|
|
||||||
@Query("DELETE FROM messages")
|
@Query("DELETE FROM messages")
|
||||||
fun deleteAll()
|
fun deleteAll()
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.simplemobiletools.smsmessenger.models
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "recycle_bin_messages",
|
||||||
|
indices = [(Index(value = ["id"], unique = true))]
|
||||||
|
)
|
||||||
|
data class RecycleBinMessage(
|
||||||
|
@PrimaryKey val id: Long,
|
||||||
|
@ColumnInfo(name = "deleted_ts") var deletedTS: Long
|
||||||
|
)
|
|
@ -361,6 +361,55 @@
|
||||||
android:id="@+id/settings_outgoing_messages_divider"
|
android:id="@+id/settings_outgoing_messages_divider"
|
||||||
layout="@layout/divider" />
|
layout="@layout/divider" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/settings_recycle_bin_label"
|
||||||
|
style="@style/SettingsSectionLabelStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/recycle_bin" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/settings_use_recycle_bin_holder"
|
||||||
|
style="@style/SettingsHolderCheckboxStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||||
|
android:id="@+id/settings_use_recycle_bin"
|
||||||
|
style="@style/SettingsCheckboxStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/move_items_into_recycle_bin" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/settings_empty_recycle_bin_holder"
|
||||||
|
style="@style/SettingsHolderTextViewStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/settings_empty_recycle_bin_label"
|
||||||
|
style="@style/SettingsTextLabelStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/empty_recycle_bin" />
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/settings_empty_recycle_bin_size"
|
||||||
|
style="@style/SettingsTextValueStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/settings_empty_recycle_bin_label"
|
||||||
|
tools:text="0 B" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/settings_recycle_bin_divider"
|
||||||
|
layout="@layout/divider" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/settings_security_label"
|
android:id="@+id/settings_security_label"
|
||||||
style="@style/SettingsSectionLabelStyle"
|
style="@style/SettingsSectionLabelStyle"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/delete_remember_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="@dimen/big_margin"
|
||||||
|
android:paddingTop="@dimen/big_margin"
|
||||||
|
android:paddingRight="@dimen/big_margin">
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyTextView
|
||||||
|
android:id="@+id/delete_remember_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/small_margin"
|
||||||
|
android:paddingBottom="@dimen/activity_margin"
|
||||||
|
android:text="@string/delete_whole_conversation_confirmation"
|
||||||
|
android:textSize="@dimen/bigger_text_size" />
|
||||||
|
|
||||||
|
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||||
|
android:id="@+id/skip_the_recycle_bin_checkbox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/delete_remember_title"
|
||||||
|
android:text="@string/skip_the_recycle_bin" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
Loading…
Reference in New Issue