Add separate screen for recycle bin messages

This commit is contained in:
Ensar Sarajčić 2023-07-20 16:04:51 +02:00
parent 31be5d3d95
commit 3f06b521bf
11 changed files with 239 additions and 27 deletions

View File

@ -191,6 +191,7 @@ class MainActivity : SimpleActivity() {
private fun refreshMenuItems() { private fun refreshMenuItems() {
main_menu.getToolbar().menu.apply { main_menu.getToolbar().menu.apply {
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(R.bool.hide_google_relations) findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(R.bool.hide_google_relations)
findItem(R.id.show_recycle_bin).isVisible = config.useRecycleBin
} }
} }

View File

@ -8,6 +8,7 @@ import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.adapters.ConversationsAdapter import com.simplemobiletools.smsmessenger.adapters.ConversationsAdapter
import com.simplemobiletools.smsmessenger.adapters.RecycleBinConversationsAdapter
import com.simplemobiletools.smsmessenger.extensions.* import com.simplemobiletools.smsmessenger.extensions.*
import com.simplemobiletools.smsmessenger.helpers.* import com.simplemobiletools.smsmessenger.helpers.*
import com.simplemobiletools.smsmessenger.models.Conversation import com.simplemobiletools.smsmessenger.models.Conversation
@ -97,11 +98,11 @@ class RecycleBinConversationsActivity : SimpleActivity() {
} }
} }
private fun getOrCreateConversationsAdapter(): ConversationsAdapter { private fun getOrCreateConversationsAdapter(): RecycleBinConversationsAdapter {
var currAdapter = conversations_list.adapter var currAdapter = conversations_list.adapter
if (currAdapter == null) { if (currAdapter == null) {
hideKeyboard() hideKeyboard()
currAdapter = ConversationsAdapter( currAdapter = RecycleBinConversationsAdapter(
activity = this, activity = this,
recyclerView = conversations_list, recyclerView = conversations_list,
onRefresh = { notifyDatasetChanged() }, onRefresh = { notifyDatasetChanged() },
@ -113,7 +114,7 @@ class RecycleBinConversationsActivity : SimpleActivity() {
conversations_list.scheduleLayoutAnimation() conversations_list.scheduleLayoutAnimation()
} }
} }
return currAdapter as ConversationsAdapter return currAdapter as RecycleBinConversationsAdapter
} }
private fun setupConversations(conversations: ArrayList<Conversation>) { private fun setupConversations(conversations: ArrayList<Conversation>) {
@ -150,6 +151,7 @@ class RecycleBinConversationsActivity : SimpleActivity() {
putExtra(THREAD_ID, conversation.threadId) putExtra(THREAD_ID, conversation.threadId)
putExtra(THREAD_TITLE, conversation.title) putExtra(THREAD_TITLE, conversation.title)
putExtra(WAS_PROTECTION_HANDLED, true) putExtra(WAS_PROTECTION_HANDLED, true)
putExtra(IS_RECYCLE_BIN, true)
startActivity(this) startActivity(this)
} }
} }

View File

@ -105,6 +105,7 @@ class ThreadActivity : SimpleActivity() {
private var allMessagesFetched = false private var allMessagesFetched = false
private var oldestMessageDate = -1 private var oldestMessageDate = -1
private var wasProtectionHandled = false private var wasProtectionHandled = false
private var isRecycleBin = false
private var isScheduledMessage: Boolean = false private var isScheduledMessage: Boolean = false
private var scheduledMessage: Message? = null private var scheduledMessage: Message? = null
@ -140,6 +141,7 @@ class ThreadActivity : SimpleActivity() {
intent.getStringExtra(THREAD_TITLE)?.let { intent.getStringExtra(THREAD_TITLE)?.let {
thread_toolbar.title = it thread_toolbar.title = it
} }
isRecycleBin = intent.getBooleanExtra(IS_RECYCLE_BIN, false)
wasProtectionHandled = intent.getBooleanExtra(WAS_PROTECTION_HANDLED, false) wasProtectionHandled = intent.getBooleanExtra(WAS_PROTECTION_HANDLED, false)
bus = EventBus.getDefault() bus = EventBus.getDefault()
@ -163,6 +165,7 @@ class ThreadActivity : SimpleActivity() {
setupAttachmentPickerView() setupAttachmentPickerView()
setupKeyboardListener() setupKeyboardListener()
hideAttachmentPicker() hideAttachmentPicker()
maybeSetupRecycleBinView()
} }
override fun onResume() { override fun onResume() {
@ -247,20 +250,21 @@ class ThreadActivity : SimpleActivity() {
val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value
thread_toolbar.menu.apply { thread_toolbar.menu.apply {
findItem(R.id.delete).isVisible = threadItems.isNotEmpty() findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
findItem(R.id.archive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == false findItem(R.id.restore).isVisible = threadItems.isNotEmpty() && isRecycleBin
findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true findItem(R.id.archive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == false && !isRecycleBin
findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true && !isRecycleBin
findItem(R.id.conversation_details).isVisible = conversation != null findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null && !isRecycleBin
findItem(R.id.conversation_details).isVisible = conversation != null && !isRecycleBin
findItem(R.id.block_number).title = addLockedLabelIfNeeded(R.string.block_number) findItem(R.id.block_number).title = addLockedLabelIfNeeded(R.string.block_number)
findItem(R.id.block_number).isVisible = isNougatPlus() findItem(R.id.block_number).isVisible = isNougatPlus() && !isRecycleBin
findItem(R.id.dial_number).isVisible = participants.size == 1 && !isSpecialNumber() findItem(R.id.dial_number).isVisible = participants.size == 1 && !isSpecialNumber() && !isRecycleBin
findItem(R.id.manage_people).isVisible = !isSpecialNumber() findItem(R.id.manage_people).isVisible = !isSpecialNumber() && !isRecycleBin
findItem(R.id.mark_as_unread).isVisible = threadItems.isNotEmpty() findItem(R.id.mark_as_unread).isVisible = threadItems.isNotEmpty() && !isRecycleBin
// allow saving number in cases when we dont have it stored yet and it is a casual readable number // allow saving number in cases when we dont have it stored yet and it is a casual readable number
findItem(R.id.add_number_to_contact).isVisible = participants.size == 1 && participants.first().name == firstPhoneNumber && firstPhoneNumber.any { findItem(R.id.add_number_to_contact).isVisible = participants.size == 1 && participants.first().name == firstPhoneNumber && firstPhoneNumber.any {
it.isDigit() it.isDigit()
} } && !isRecycleBin
} }
} }
@ -273,6 +277,7 @@ class ThreadActivity : SimpleActivity() {
when (menuItem.itemId) { when (menuItem.itemId) {
R.id.block_number -> tryBlocking() R.id.block_number -> tryBlocking()
R.id.delete -> askConfirmDelete() R.id.delete -> askConfirmDelete()
R.id.restore -> askConfirmRestoreAll()
R.id.archive -> archiveConversation() R.id.archive -> archiveConversation()
R.id.unarchive -> unarchiveConversation() R.id.unarchive -> unarchiveConversation()
R.id.rename_conversation -> renameConversation() R.id.rename_conversation -> renameConversation()
@ -306,7 +311,11 @@ class ThreadActivity : SimpleActivity() {
private fun setupCachedMessages(callback: () -> Unit) { private fun setupCachedMessages(callback: () -> Unit) {
ensureBackgroundThread { ensureBackgroundThread {
messages = try { messages = try {
messagesDB.getThreadMessages(threadId).toMutableList() as ArrayList<Message> if (isRecycleBin) {
messagesDB.getThreadMessagesFromRecycleBin(threadId).toMutableList() as ArrayList<Message>
} else {
messagesDB.getThreadMessages(threadId).toMutableList() as ArrayList<Message>
}
} catch (e: Exception) { } catch (e: Exception) {
ArrayList() ArrayList()
} }
@ -341,7 +350,10 @@ class ThreadActivity : SimpleActivity() {
privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor) privateContacts = MyContactsContentProvider.getSimpleContacts(this, privateCursor)
val cachedMessagesCode = messages.clone().hashCode() val cachedMessagesCode = messages.clone().hashCode()
messages = getMessages(threadId, true) if (!isRecycleBin) {
val recycledMessages = messagesDB.getThreadMessagesFromRecycleBin(threadId).map { it.id }
messages = getMessages(threadId, true).filter { !recycledMessages.contains(it.id) }.toMutableList() as ArrayList<Message>
}
val hasParticipantWithoutName = participants.any { contact -> val hasParticipantWithoutName = participants.any { contact ->
contact.phoneNumbers.map { it.normalizedNumber }.contains(contact.name) contact.phoneNumbers.map { it.normalizedNumber }.contains(contact.name)
@ -389,8 +401,10 @@ class ThreadActivity : SimpleActivity() {
participants.add(contact) participants.add(contact)
} }
messages.chunked(30).forEach { currentMessages -> if (!isRecycleBin) {
messagesDB.insertMessages(*currentMessages.toTypedArray()) messages.chunked(30).forEach { currentMessages ->
messagesDB.insertMessages(*currentMessages.toTypedArray())
}
} }
setupAttachmentSizes() setupAttachmentSizes()
@ -409,7 +423,8 @@ class ThreadActivity : SimpleActivity() {
activity = this, activity = this,
recyclerView = thread_messages_list, recyclerView = thread_messages_list,
itemClick = { handleItemClick(it) }, itemClick = { handleItemClick(it) },
deleteMessages = { messages, toRecycleBin -> deleteMessages(messages, toRecycleBin) } isRecycleBin = isRecycleBin,
deleteMessages = { messages, toRecycleBin, fromRecycleBin -> deleteMessages(messages, toRecycleBin, fromRecycleBin) }
) )
thread_messages_list.adapter = currAdapter thread_messages_list.adapter = currAdapter
@ -496,7 +511,7 @@ class ThreadActivity : SimpleActivity() {
} }
} }
private fun deleteMessages(messagesToRemove: List<Message>, toRecycleBin: Boolean) { private fun deleteMessages(messagesToRemove: List<Message>, toRecycleBin: Boolean, fromRecycleBin: 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()
@ -515,12 +530,13 @@ 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 {
if (toRecycleBin) { if (toRecycleBin) {
moveMessageToRecycleBin(messageId) moveMessageToRecycleBin(messageId)
} else if (fromRecycleBin) {
restoreMessageFromRecycleBin(messageId)
} else { } else {
deleteMessage(messageId, message.isMMS) deleteMessage(messageId, message.isMMS)
} }
@ -792,7 +808,7 @@ class ThreadActivity : SimpleActivity() {
} }
private fun maybeDisableShortCodeReply() { private fun maybeDisableShortCodeReply() {
if (isSpecialNumber()) { if (isSpecialNumber() && !isRecycleBin) {
thread_send_message_holder.beGone() thread_send_message_holder.beGone()
reply_disabled_info_holder.beVisible() reply_disabled_info_holder.beVisible()
val textColor = getProperTextColor() val textColor = getProperTextColor()
@ -922,7 +938,23 @@ class ThreadActivity : SimpleActivity() {
val confirmationMessage = R.string.delete_whole_conversation_confirmation val confirmationMessage = R.string.delete_whole_conversation_confirmation
ConfirmationDialog(this, getString(confirmationMessage)) { ConfirmationDialog(this, getString(confirmationMessage)) {
ensureBackgroundThread { ensureBackgroundThread {
deleteConversation(threadId) if (isRecycleBin) {
emptyMessagesRecycleBinForConversation(threadId)
} else {
deleteConversation(threadId)
}
runOnUiThread {
refreshMessages()
finish()
}
}
}
}
private fun askConfirmRestoreAll() {
ConfirmationDialog(this, "Restore all messages from this conversation?") {
ensureBackgroundThread {
restoreAllMessagesFromRecycleBinForConversation(threadId)
runOnUiThread { runOnUiThread {
refreshMessages() refreshMessages()
finish() finish()
@ -1485,6 +1517,10 @@ class ThreadActivity : SimpleActivity() {
@Subscribe(threadMode = ThreadMode.ASYNC) @Subscribe(threadMode = ThreadMode.ASYNC)
fun refreshMessages(event: Events.RefreshMessages) { fun refreshMessages(event: Events.RefreshMessages) {
if (isRecycleBin) {
return
}
refreshedSinceSent = true refreshedSinceSent = true
allMessagesFetched = false allMessagesFetched = false
oldestMessageDate = -1 oldestMessageDate = -1
@ -1747,6 +1783,12 @@ class ThreadActivity : SimpleActivity() {
animateAttachmentButton(rotation = -135f) animateAttachmentButton(rotation = -135f)
} }
private fun maybeSetupRecycleBinView() {
if (isRecycleBin) {
thread_send_message_holder.beGone()
}
}
private fun hideAttachmentPicker() { private fun hideAttachmentPicker() {
attachment_picker_divider.beGone() attachment_picker_divider.beGone()
attachment_picker_holder.apply { attachment_picker_holder.apply {

View File

@ -0,0 +1,107 @@
package com.simplemobiletools.smsmessenger.adapters
import android.view.Menu
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.notificationManager
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.extensions.deleteConversation
import com.simplemobiletools.smsmessenger.extensions.restoreAllMessagesFromRecycleBinForConversation
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
import com.simplemobiletools.smsmessenger.models.Conversation
class RecycleBinConversationsAdapter(
activity: SimpleActivity, recyclerView: MyRecyclerView, onRefresh: () -> Unit, itemClick: (Any) -> Unit
) : BaseConversationsAdapter(activity, recyclerView, onRefresh, itemClick) {
override fun getActionMenuId() = R.menu.cab_recycle_bin_conversations
override fun prepareActionMode(menu: Menu) {}
override fun actionItemPressed(id: Int) {
if (selectedKeys.isEmpty()) {
return
}
when (id) {
R.id.cab_delete -> askConfirmDelete()
R.id.cab_restore -> askConfirmRestore()
R.id.cab_select_all -> selectAll()
}
}
private fun askConfirmDelete() {
val itemsCnt = selectedKeys.size
val items = resources.getQuantityString(R.plurals.delete_conversations, itemsCnt, itemsCnt)
val baseString = R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items)
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
deleteConversations()
}
}
}
private fun deleteConversations() {
if (selectedKeys.isEmpty()) {
return
}
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
conversationsToRemove.forEach {
activity.deleteConversation(it.threadId)
activity.notificationManager.cancel(it.threadId.hashCode())
}
removeConversationsFromList(conversationsToRemove)
}
private fun askConfirmRestore() {
val itemsCnt = selectedKeys.size
val items = resources.getQuantityString(R.plurals.delete_conversations, itemsCnt, itemsCnt)
val question = String.format("Are you sure you want to restore %s?", items)
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
restoreConversations()
}
}
}
private fun restoreConversations() {
if (selectedKeys.isEmpty()) {
return
}
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
conversationsToRemove.forEach {
activity.restoreAllMessagesFromRecycleBinForConversation(it.threadId)
}
removeConversationsFromList(conversationsToRemove)
}
private fun removeConversationsFromList(removedConversations: List<Conversation>) {
val newList = try {
currentList.toMutableList().apply { removeAll(removedConversations) }
} catch (ignored: Exception) {
currentList.toMutableList()
}
activity.runOnUiThread {
if (newList.none { selectedKeys.contains(it.hashCode()) }) {
refreshMessages()
finishActMode()
} else {
submitList(newList)
if (newList.isEmpty()) {
refreshMessages()
}
}
}
}
}

View File

@ -23,6 +23,7 @@ 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
@ -58,7 +59,8 @@ class ThreadAdapter(
activity: SimpleActivity, activity: SimpleActivity,
recyclerView: MyRecyclerView, recyclerView: MyRecyclerView,
itemClick: (Any) -> Unit, itemClick: (Any) -> Unit,
val deleteMessages: (messages: List<Message>, toRecycleBin: Boolean) -> Unit val isRecycleBin: Boolean,
val deleteMessages: (messages: List<Message>, toRecycleBin: Boolean, fromRecycleBin: Boolean) -> Unit
) : MyRecyclerViewListAdapter<ThreadItem>(activity, recyclerView, ThreadItemDiffCallback(), itemClick) { ) : MyRecyclerViewListAdapter<ThreadItem>(activity, recyclerView, ThreadItemDiffCallback(), itemClick) {
private var fontSize = activity.getTextSize() private var fontSize = activity.getTextSize()
@ -84,6 +86,7 @@ class ThreadAdapter(
findItem(R.id.cab_forward_message).isVisible = isOneItemSelected findItem(R.id.cab_forward_message).isVisible = isOneItemSelected
findItem(R.id.cab_select_text).isVisible = isOneItemSelected && hasText findItem(R.id.cab_select_text).isVisible = isOneItemSelected && hasText
findItem(R.id.cab_properties).isVisible = isOneItemSelected findItem(R.id.cab_properties).isVisible = isOneItemSelected
findItem(R.id.cab_restore).isVisible = isRecycleBin
} }
} }
@ -99,6 +102,7 @@ class ThreadAdapter(
R.id.cab_forward_message -> forwardMessage() R.id.cab_forward_message -> forwardMessage()
R.id.cab_select_text -> selectText() R.id.cab_select_text -> selectText()
R.id.cab_delete -> askConfirmDelete() R.id.cab_delete -> askConfirmDelete()
R.id.cab_restore -> askConfirmRestore()
R.id.cab_select_all -> selectAll() R.id.cab_select_all -> selectAll()
R.id.cab_properties -> showMessageDetails() R.id.cab_properties -> showMessageDetails()
} }
@ -206,12 +210,36 @@ 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)
DeleteConfirmationDialog(activity, question, activity.config.useRecycleBin) { skipRecycleBin -> DeleteConfirmationDialog(activity, question, activity.config.useRecycleBin && !isRecycleBin) { skipRecycleBin ->
ensureBackgroundThread { ensureBackgroundThread {
val messagesToRemove = getSelectedItems() val messagesToRemove = getSelectedItems()
if (messagesToRemove.isNotEmpty()) { if (messagesToRemove.isNotEmpty()) {
val toRecycleBin = !skipRecycleBin && activity.config.useRecycleBin val toRecycleBin = !skipRecycleBin && activity.config.useRecycleBin && !isRecycleBin
deleteMessages(messagesToRemove.filterIsInstance<Message>(), toRecycleBin) deleteMessages(messagesToRemove.filterIsInstance<Message>(), toRecycleBin, false)
}
}
}
}
private fun askConfirmRestore() {
val itemsCnt = selectedKeys.size
// not sure how we can get UnknownFormatConversionException here, so show the error and hope that someone reports it
val items = try {
resources.getQuantityString(R.plurals.delete_messages, itemsCnt, itemsCnt)
} catch (e: Exception) {
activity.showErrorToast(e)
return
}
val baseString = R.string.deletion_confirmation
val question = String.format("Are you sure you want to restore %s?", items)
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
val messagesToRestore = getSelectedItems()
if (messagesToRestore.isNotEmpty()) {
deleteMessages(messagesToRestore.filterIsInstance<Message>(), false, true)
} }
} }
} }

View File

@ -679,6 +679,17 @@ fun Context.emptyMessagesRecycleBin() {
} }
} }
fun Context.emptyMessagesRecycleBinForConversation(threadId: Long) {
val messages = messagesDB.getThreadMessagesFromRecycleBin(threadId)
for (message in messages) {
deleteMessage(message.id, message.isMMS)
}
}
fun Context.restoreAllMessagesFromRecycleBinForConversation(threadId: Long) {
messagesDB.deleteThreadMessagesFromRecycleBin(threadId)
}
fun Context.moveMessageToRecycleBin(id: Long) { fun Context.moveMessageToRecycleBin(id: Long) {
try { try {
messagesDB.insertRecycleBinEntry(RecycleBinMessage(id, System.currentTimeMillis())) messagesDB.insertRecycleBinEntry(RecycleBinMessage(id, System.currentTimeMillis()))
@ -687,6 +698,14 @@ fun Context.moveMessageToRecycleBin(id: Long) {
} }
} }
fun Context.restoreMessageFromRecycleBin(id: Long) {
try {
messagesDB.deleteFromRecycleBin(id)
} catch (e: Exception) {
showErrorToast(e)
}
}
fun Context.updateConversationArchivedStatus(threadId: Long, archived: Boolean) { fun Context.updateConversationArchivedStatus(threadId: Long, archived: Boolean) {
val uri = Threads.CONTENT_URI val uri = Threads.CONTENT_URI
val values = ContentValues().apply { val values = ContentValues().apply {

View File

@ -42,7 +42,7 @@ 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 USE_RECYCLE_BIN = "use_recycle_bin"
const val LAST_RECYCLE_BIN_CHECK = "last_recycle_bin_check" const val LAST_RECYCLE_BIN_CHECK = "last_recycle_bin_check"
const val USE_ARCHIVE = "use_archive" const val IS_RECYCLE_BIN = "is_recycle_bin"
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"

View File

@ -30,6 +30,9 @@ interface MessagesDao {
@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") @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 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 thread_id = :threadId")
fun getThreadMessagesFromRecycleBin(threadId: 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 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>

View File

@ -12,7 +12,7 @@
<item <item
android:id="@+id/cab_restore" android:id="@+id/cab_restore"
android:showAsAction="never" android:showAsAction="never"
android:title="Restore this message" android:title="Restore all messages from this conversation"
app:showAsAction="never" /> app:showAsAction="never" />
<item <item
android:id="@+id/cab_select_all" android:id="@+id/cab_select_all"

View File

@ -31,6 +31,11 @@
android:icon="@drawable/ic_info_vector" android:icon="@drawable/ic_info_vector"
android:title="@string/properties" android:title="@string/properties"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_restore"
android:showAsAction="never"
android:title="Restore this message"
app:showAsAction="never" />
<item <item
android:id="@+id/cab_forward_message" android:id="@+id/cab_forward_message"
android:showAsAction="never" android:showAsAction="never"

View File

@ -47,6 +47,11 @@
android:showAsAction="never" android:showAsAction="never"
android:title="@string/block_number" android:title="@string/block_number"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/restore"
android:showAsAction="never"
android:title="Restore all messages from this conversation"
app:showAsAction="never" />
<item <item
android:id="@+id/mark_as_unread" android:id="@+id/mark_as_unread"
android:showAsAction="never" android:showAsAction="never"