Implement archive functionality using system API

This commit is contained in:
Ensar Sarajčić 2023-07-17 16:43:31 +02:00
parent 4d13fa1079
commit 857a4f0b93
17 changed files with 127 additions and 218 deletions

View File

@ -64,7 +64,6 @@ class MainActivity : SimpleActivity() {
updateMaterialActivityViews(main_coordinator, conversations_list, useTransparentNavigation = true, useTopSearchMenu = true)
if (savedInstanceState == null) {
checkAndDeleteOldArchivedConversations()
handleAppPasswordProtection {
wasProtectionHandled = it
if (it) {

View File

@ -11,15 +11,12 @@ import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.extensions.config
import com.simplemobiletools.smsmessenger.extensions.conversationsDB
import com.simplemobiletools.smsmessenger.extensions.removeAllArchivedConversations
import com.simplemobiletools.smsmessenger.helpers.*
import kotlinx.android.synthetic.main.activity_settings.*
import java.util.*
class SettingsActivity : SimpleActivity() {
private var blockedNumbersAtPause = -1
private var archiveConversations = 0
override fun onCreate(savedInstanceState: Bundle?) {
isMaterialActivity = true
@ -50,8 +47,6 @@ class SettingsActivity : SimpleActivity() {
setupGroupMessageAsMMS()
setupLockScreenVisibility()
setupMMSFileSizeLimit()
setupUseRecycleBin()
setupEmptyRecycleBin()
setupAppPasswordProtection()
updateTextColors(settings_nested_scrollview)
@ -64,7 +59,6 @@ class SettingsActivity : SimpleActivity() {
settings_general_settings_label,
settings_outgoing_messages_label,
settings_notifications_label,
settings_archive_label,
settings_security_label
).forEach {
it.setTextColor(getProperPrimaryColor())
@ -250,43 +244,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupUseRecycleBin() {
updateRecycleBinButtons()
settings_use_archive.isChecked = config.useArchive
settings_use_archive_holder.setOnClickListener {
settings_use_archive.toggle()
config.useArchive = settings_use_archive.isChecked
updateRecycleBinButtons()
}
}
private fun updateRecycleBinButtons() {
settings_empty_archive_holder.beVisibleIf(config.useArchive)
}
private fun setupEmptyRecycleBin() {
ensureBackgroundThread {
archiveConversations = conversationsDB.getArchivedCount()
runOnUiThread {
settings_empty_archive_size.text =
resources.getQuantityString(R.plurals.delete_conversations, archiveConversations, archiveConversations)
}
}
settings_empty_archive_holder.setOnClickListener {
if (archiveConversations == 0) {
toast(R.string.archive_is_empty)
} else {
ConfirmationDialog(this, "", R.string.empty_archive_confirmation, R.string.yes, R.string.no) {
removeAllArchivedConversations()
archiveConversations = 0
settings_empty_archive_size.text =
resources.getQuantityString(R.plurals.delete_conversations, archiveConversations, archiveConversations)
}
}
}
}
private fun setupAppPasswordProtection() {
settings_app_password_protection.isChecked = config.isAppPasswordProtectionOn
settings_app_password_protection_holder.setOnClickListener {

View File

@ -55,7 +55,6 @@ import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.adapters.AttachmentsAdapter
import com.simplemobiletools.smsmessenger.adapters.AutoCompleteTextViewAdapter
import com.simplemobiletools.smsmessenger.adapters.ThreadAdapter
import com.simplemobiletools.smsmessenger.dialogs.DeleteConfirmationDialog
import com.simplemobiletools.smsmessenger.dialogs.InvalidNumberDialog
import com.simplemobiletools.smsmessenger.dialogs.RenameConversationDialog
import com.simplemobiletools.smsmessenger.dialogs.ScheduleMessageDialog
@ -245,6 +244,8 @@ class ThreadActivity : SimpleActivity() {
val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value
thread_toolbar.menu.apply {
findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
findItem(R.id.archive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == false
findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true
findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null
findItem(R.id.conversation_details).isVisible = conversation != null
findItem(R.id.block_number).title = addLockedLabelIfNeeded(R.string.block_number)
@ -269,6 +270,8 @@ class ThreadActivity : SimpleActivity() {
when (menuItem.itemId) {
R.id.block_number -> tryBlocking()
R.id.delete -> askConfirmDelete()
R.id.archive -> archiveConversation()
R.id.unarchive -> unarchiveConversation()
R.id.rename_conversation -> renameConversation()
R.id.conversation_details -> showConversationDetails()
R.id.add_number_to_contact -> addNumberToContact()
@ -889,18 +892,10 @@ class ThreadActivity : SimpleActivity() {
}
private fun askConfirmDelete() {
val confirmationMessage = if (config.useArchive) {
R.string.archive_whole_conversation_confirmation
} else {
R.string.delete_whole_conversation_confirmation
}
DeleteConfirmationDialog(this, getString(confirmationMessage), config.useArchive) { skipRecycleBin ->
val confirmationMessage = R.string.delete_whole_conversation_confirmation
ConfirmationDialog(this, getString(confirmationMessage)) {
ensureBackgroundThread {
if (skipRecycleBin || config.useArchive.not()) {
deleteConversation(threadId)
} else {
moveConversationToRecycleBin(threadId)
}
runOnUiThread {
refreshMessages()
finish()
@ -909,6 +904,26 @@ class ThreadActivity : SimpleActivity() {
}
}
private fun archiveConversation() {
ensureBackgroundThread {
updateConversationArchivedStatus(threadId, true)
runOnUiThread {
refreshMessages()
finish()
}
}
}
private fun unarchiveConversation() {
ensureBackgroundThread {
updateConversationArchivedStatus(threadId, false)
runOnUiThread {
refreshMessages()
finish()
}
}
}
private fun dialNumber() {
val phoneNumber = participants.first().phoneNumbers.first().normalizedNumber
dialNumber(phoneNumber)
@ -1337,7 +1352,7 @@ class ThreadActivity : SimpleActivity() {
}
}
messagesDB.insertOrUpdate(message)
conversationsDB.deleteThreadFromArchivedConversations(message.threadId)
updateConversationArchivedStatus(message.threadId, false)
}
// show selected contacts, properly split to new lines when appropriate

View File

@ -1,14 +1,14 @@
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.dialogs.DeleteConfirmationDialog
import com.simplemobiletools.smsmessenger.extensions.conversationsDB
import com.simplemobiletools.smsmessenger.extensions.deleteConversation
import com.simplemobiletools.smsmessenger.extensions.updateConversationArchivedStatus
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
import com.simplemobiletools.smsmessenger.models.Conversation
@ -38,7 +38,7 @@ class ArchivedConversationsAdapter(
val baseString = R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items)
DeleteConfirmationDialog(activity, question, showSkipArchiveOption = false) { _ ->
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
deleteConversations()
}
@ -66,7 +66,7 @@ class ArchivedConversationsAdapter(
val conversationsToUnarchive = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
conversationsToUnarchive.forEach {
activity.conversationsDB.deleteThreadFromArchivedConversations(it.threadId)
activity.updateConversationArchivedStatus(it.threadId, false)
}
removeConversationsFromList(conversationsToUnarchive)

View File

@ -12,7 +12,6 @@ import com.simplemobiletools.commons.helpers.isNougatPlus
import com.simplemobiletools.commons.views.MyRecyclerView
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.dialogs.DeleteConfirmationDialog
import com.simplemobiletools.smsmessenger.dialogs.RenameConversationDialog
import com.simplemobiletools.smsmessenger.extensions.*
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
@ -54,6 +53,7 @@ class ConversationsAdapter(
R.id.cab_dial_number -> dialNumber()
R.id.cab_copy_number -> copyNumberToClipboard()
R.id.cab_delete -> askConfirmDelete()
R.id.cab_archive -> ensureBackgroundThread { archiveConversations() }
R.id.cab_rename_conversation -> renameConversation(getSelectedItems().first())
R.id.cab_mark_as_read -> markAsRead()
R.id.cab_mark_as_unread -> markAsUnread()
@ -118,32 +118,54 @@ class ConversationsAdapter(
val itemsCnt = selectedKeys.size
val items = resources.getQuantityString(R.plurals.delete_conversations, itemsCnt, itemsCnt)
val baseString = if (activity.config.useArchive) {
R.string.archive_confirmation
} else {
R.string.deletion_confirmation
}
val baseString = R.string.deletion_confirmation
val question = String.format(resources.getString(baseString), items)
DeleteConfirmationDialog(activity, question, activity.config.useArchive) { skipRecycleBin ->
ConfirmationDialog(activity, question) {
ensureBackgroundThread {
deleteConversations(skipRecycleBin)
deleteConversations()
}
}
}
private fun deleteConversations(skipRecycleBin: Boolean) {
private fun archiveConversations() {
if (selectedKeys.isEmpty()) {
return
}
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
conversationsToRemove.forEach {
if (skipRecycleBin || activity.config.useArchive.not()) {
activity.deleteConversation(it.threadId)
} else {
activity.moveConversationToRecycleBin(it.threadId)
activity.updateConversationArchivedStatus(it.threadId, true)
activity.notificationManager.cancel(it.threadId.hashCode())
}
val newList = try {
currentList.toMutableList().apply { removeAll(conversationsToRemove) }
} catch (ignored: Exception) {
currentList.toMutableList()
}
activity.runOnUiThread {
if (newList.none { selectedKeys.contains(it.hashCode()) }) {
refreshMessages()
finishActMode()
} else {
submitList(newList)
if (newList.isEmpty()) {
refreshMessages()
}
}
}
}
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())
}

View File

@ -14,7 +14,7 @@ import com.simplemobiletools.smsmessenger.interfaces.MessageAttachmentsDao
import com.simplemobiletools.smsmessenger.interfaces.MessagesDao
import com.simplemobiletools.smsmessenger.models.*
@Database(entities = [Conversation::class, ArchivedConversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 8)
@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 8)
@TypeConverters(Converters::class)
abstract class MessagesDatabase : RoomDatabase() {
@ -117,8 +117,7 @@ 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 archived_conversations (`thread_id` INTEGER NOT NULL PRIMARY KEY, `deleted_ts` INTEGER NOT NULL)")
execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_archived_conversations_thread_id` ON `archived_conversations` (`thread_id`)")
execSQL("ALTER TABLE conversations ADD COLUMN archived INTEGER NOT NULL DEFAULT 0")
}
}
}

View File

@ -1,39 +0,0 @@
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_archive_checkbox
class DeleteConfirmationDialog(
private val activity: Activity,
private val message: String,
private val showSkipArchiveOption: 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_archive_checkbox.beGoneIf(!showSkipArchiveOption)
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_archive_checkbox.isChecked)
}
}

View File

@ -238,7 +238,8 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
Threads.SNIPPET,
Threads.DATE,
Threads.READ,
Threads.RECIPIENT_IDS
Threads.RECIPIENT_IDS,
Threads.ARCHIVED
)
var selection = "${Threads.MESSAGE_COUNT} > ?"
@ -277,7 +278,8 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
val photoUri = if (phoneNumbers.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(phoneNumbers.first()) else ""
val isGroupConversation = phoneNumbers.size > 1
val read = cursor.getIntValue(Threads.READ) == 1
val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first())
val archived = cursor.getIntValue(Threads.ARCHIVED) == 1
val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first(), isArchived = archived)
conversations.add(conversation)
}
@ -581,21 +583,6 @@ fun Context.insertNewSMS(address: String, subject: String, body: String, date: L
}
}
fun Context.checkAndDeleteOldArchivedConversations(callback: (() -> Unit)? = null) {
if (config.useArchive && config.lastArchiveCheck < System.currentTimeMillis() - DAY_SECONDS * 1000) {
config.lastArchiveCheck = System.currentTimeMillis()
ensureBackgroundThread {
try {
for (conversation in conversationsDB.getOldArchived(System.currentTimeMillis() - MONTH_SECONDS * 1000L)) {
deleteConversation(conversation.threadId)
}
callback?.invoke()
} catch (e: Exception) {
}
}
}
}
fun Context.removeAllArchivedConversations(callback: (() -> Unit)? = null) {
ensureBackgroundThread {
try {
@ -631,13 +618,19 @@ fun Context.deleteConversation(threadId: Long) {
messagesDB.deleteThreadMessages(threadId)
}
fun Context.moveConversationToRecycleBin(threadId: Long) {
conversationsDB.archiveConversation(
ArchivedConversation(
threadId = threadId,
deletedTs = System.currentTimeMillis()
)
)
fun Context.updateConversationArchivedStatus(threadId: Long, archived: Boolean) {
val uri = Threads.CONTENT_URI
val values = ContentValues().apply {
put(Threads.ARCHIVED, archived)
}
val selection = "${Threads._ID} = ?"
val selectionArgs = arrayOf(threadId.toString())
contentResolver.update(uri, values, selection, selectionArgs)
if (archived) {
conversationsDB.moveToArchive(threadId)
} else {
conversationsDB.unarchive(threadId)
}
}
fun Context.deleteMessage(id: Long, isMMS: Boolean) {
@ -968,7 +961,8 @@ fun Context.createTemporaryThread(message: Message, threadId: Long = generateRan
isGroupConversation = addresses.size > 1,
phoneNumber = addresses.first(),
isScheduled = true,
usesCustomTitle = cachedConv?.usesCustomTitle == true
usesCustomTitle = cachedConv?.usesCustomTitle == true,
isArchived = false
)
try {
conversationsDB.insertOrUpdate(conversation)

View File

@ -1,7 +1,6 @@
package com.simplemobiletools.smsmessenger.interfaces
import androidx.room.*
import com.simplemobiletools.smsmessenger.models.ArchivedConversation
import com.simplemobiletools.smsmessenger.models.Conversation
@Dao
@ -9,21 +8,12 @@ interface ConversationsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdate(conversation: Conversation): Long
@Query("SELECT conversations.* FROM conversations LEFT OUTER JOIN archived_conversations ON conversations.thread_id = archived_conversations.thread_id WHERE archived_conversations.deleted_ts is NULL")
@Query("SELECT * FROM conversations WHERE archived = 0")
fun getNonArchived(): List<Conversation>
@Query("SELECT conversations.* FROM archived_conversations INNER JOIN conversations ON conversations.thread_id = archived_conversations.thread_id")
@Query("SELECT * FROM conversations WHERE archived = 1")
fun getAllArchived(): List<Conversation>
@Query("SELECT COUNT(*) FROM archived_conversations")
fun getArchivedCount(): Int
@Query("SELECT * FROM archived_conversations WHERE deleted_ts < :timestamp")
fun getOldArchived(timestamp: Long): List<ArchivedConversation>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun archiveConversation(archivedConversation: ArchivedConversation)
@Query("SELECT * FROM conversations WHERE thread_id = :threadId")
fun getConversationWithThreadId(threadId: Long): Conversation?
@ -39,15 +29,12 @@ interface ConversationsDao {
@Query("UPDATE conversations SET read = 0 WHERE thread_id = :threadId")
fun markUnread(threadId: Long)
@Query("UPDATE conversations SET archived = 1 WHERE thread_id = :threadId")
fun moveToArchive(threadId: Long)
@Query("UPDATE conversations SET archived = 0 WHERE thread_id = :threadId")
fun unarchive(threadId: Long)
@Query("DELETE FROM conversations WHERE thread_id = :threadId")
fun deleteThreadFromConversations(threadId: Long)
@Query("DELETE FROM archived_conversations WHERE thread_id = :threadId")
fun deleteThreadFromArchivedConversations(threadId: Long)
@Transaction
fun deleteThreadId(threadId: Long) {
deleteThreadFromConversations(threadId)
deleteThreadFromArchivedConversations(threadId)
}
fun deleteThreadId(threadId: Long)
}

View File

@ -16,7 +16,8 @@ data class Conversation(
@ColumnInfo(name = "is_group_conversation") var isGroupConversation: Boolean,
@ColumnInfo(name = "phone_number") var phoneNumber: String,
@ColumnInfo(name = "is_scheduled") var isScheduled: Boolean = false,
@ColumnInfo(name = "uses_custom_title") var usesCustomTitle: Boolean = false
@ColumnInfo(name = "uses_custom_title") var usesCustomTitle: Boolean = false,
@ColumnInfo(name = "archived") var isArchived: Boolean = false
) {
companion object {

View File

@ -100,7 +100,7 @@ class SmsReceiver : BroadcastReceiver() {
subscriptionId
)
context.messagesDB.insertOrUpdate(message)
context.conversationsDB.deleteThreadFromArchivedConversations(threadId)
context.updateConversationArchivedStatus(threadId, false)
refreshMessages()
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap)
}

View File

@ -0,0 +1,3 @@
<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
</vector>

View File

@ -0,0 +1,3 @@
<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20.55,5.22l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6C5.53,3 5.12,3.21 4.85,3.55L3.46,5.22C3.17,5.57 3,6.01 3,6.5V19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5C21,6.01 20.83,5.57 20.55,5.22zM12,9.5l5.5,5.5H14v2h-4v-2H6.5L12,9.5zM5.12,5l0.82,-1h12l0.93,1H5.12z"/>
</vector>

View File

@ -346,55 +346,6 @@
android:id="@+id/settings_outgoing_messages_divider"
layout="@layout/divider" />
<TextView
android:id="@+id/settings_archive_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/archived_conversations" />
<RelativeLayout
android:id="@+id/settings_use_archive_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_use_archive"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/archive_instead_of_delete" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_empty_archive_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_empty_archive_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/empty_archive" />
<com.simplemobiletools.commons.views.MyTextView
android:id="@+id/settings_empty_archive_size"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_empty_archive_label"
tools:text="0 B" />
</RelativeLayout>
<include
android:id="@+id/settings_archive_divider"
layout="@layout/divider" />
<TextView
android:id="@+id/settings_security_label"
style="@style/SettingsSectionLabelStyle"

View File

@ -9,14 +9,15 @@
android:showAsAction="always"
android:title="@string/delete"
app:showAsAction="always" />
<item
android:id="@+id/cab_unarchive"
android:icon="@drawable/ic_unarchive_vector"
android:showAsAction="ifRoom"
android:title="@string/unarchive"
app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_select_all"
android:icon="@drawable/ic_select_all_vector"
android:title="@string/select_all"
app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_unarchive"
android:showAsAction="never"
android:title="@string/unarchive"
app:showAsAction="never" />
</menu>

View File

@ -26,6 +26,12 @@
android:icon="@drawable/ic_minus_circle_vector"
android:title="@string/block_number"
app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_archive"
android:icon="@drawable/ic_archive_vector"
android:showAsAction="ifRoom"
android:title="@string/archive"
app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_copy_number"
android:showAsAction="never"

View File

@ -23,6 +23,16 @@
android:icon="@drawable/ic_edit_vector"
android:title="@string/rename_conversation"
app:showAsAction="always" />
<item
android:id="@+id/archive"
android:icon="@drawable/ic_archive_vector"
android:title="@string/archive"
app:showAsAction="ifRoom" />
<item
android:id="@+id/unarchive"
android:icon="@drawable/ic_unarchive_vector"
android:title="@string/unarchive"
app:showAsAction="ifRoom" />
<item
android:id="@+id/conversation_details"
android:icon="@drawable/ic_info_vector"