parent
30b54076ce
commit
0e68da2710
|
@ -187,6 +187,7 @@ class MainActivity : SimpleActivity() {
|
||||||
binding.mainMenu.getToolbar().menu.apply {
|
binding.mainMenu.getToolbar().menu.apply {
|
||||||
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations)
|
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations)
|
||||||
findItem(R.id.show_recycle_bin).isVisible = config.useRecycleBin
|
findItem(R.id.show_recycle_bin).isVisible = config.useRecycleBin
|
||||||
|
findItem(R.id.show_archived).isVisible = config.useThreadsArchive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -249,11 +249,12 @@ class ThreadActivity : SimpleActivity() {
|
||||||
|
|
||||||
private fun refreshMenuItems() {
|
private fun refreshMenuItems() {
|
||||||
val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value
|
val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value
|
||||||
|
val useArchive = config.useThreadsArchive
|
||||||
binding.threadToolbar.menu.apply {
|
binding.threadToolbar.menu.apply {
|
||||||
findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
|
findItem(R.id.delete).isVisible = threadItems.isNotEmpty()
|
||||||
findItem(R.id.restore).isVisible = threadItems.isNotEmpty() && isRecycleBin
|
findItem(R.id.restore).isVisible = threadItems.isNotEmpty() && isRecycleBin
|
||||||
findItem(R.id.archive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == false && !isRecycleBin
|
findItem(R.id.archive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == false && !isRecycleBin && useArchive
|
||||||
findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true && !isRecycleBin
|
findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true && !isRecycleBin && useArchive
|
||||||
findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null && !isRecycleBin
|
findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null && !isRecycleBin
|
||||||
findItem(R.id.conversation_details).isVisible = conversation != null && !isRecycleBin
|
findItem(R.id.conversation_details).isVisible = conversation != null && !isRecycleBin
|
||||||
findItem(R.id.block_number).title = addLockedLabelIfNeeded(com.simplemobiletools.commons.R.string.block_number)
|
findItem(R.id.block_number).title = addLockedLabelIfNeeded(com.simplemobiletools.commons.R.string.block_number)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class ConversationsAdapter(
|
||||||
val isSingleSelection = isOneItemSelected()
|
val isSingleSelection = isOneItemSelected()
|
||||||
val selectedConversation = selectedItems.firstOrNull() ?: return
|
val selectedConversation = selectedItems.firstOrNull() ?: return
|
||||||
val isGroupConversation = selectedConversation.isGroupConversation
|
val isGroupConversation = selectedConversation.isGroupConversation
|
||||||
|
val useArchive = activity.config.useThreadsArchive
|
||||||
|
|
||||||
menu.apply {
|
menu.apply {
|
||||||
findItem(R.id.cab_block_number).title = activity.addLockedLabelIfNeeded(com.simplemobiletools.commons.R.string.block_number)
|
findItem(R.id.cab_block_number).title = activity.addLockedLabelIfNeeded(com.simplemobiletools.commons.R.string.block_number)
|
||||||
|
@ -38,6 +39,7 @@ class ConversationsAdapter(
|
||||||
findItem(R.id.cab_rename_conversation).isVisible = isSingleSelection && isGroupConversation
|
findItem(R.id.cab_rename_conversation).isVisible = isSingleSelection && isGroupConversation
|
||||||
findItem(R.id.cab_mark_as_read).isVisible = selectedItems.any { !it.read }
|
findItem(R.id.cab_mark_as_read).isVisible = selectedItems.any { !it.read }
|
||||||
findItem(R.id.cab_mark_as_unread).isVisible = selectedItems.any { it.read }
|
findItem(R.id.cab_mark_as_unread).isVisible = selectedItems.any { it.read }
|
||||||
|
findItem(R.id.cab_archive).isVisible = useArchive
|
||||||
checkPinBtnVisibility(this)
|
checkPinBtnVisibility(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.content.ContentResolver
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
|
import android.database.sqlite.SQLiteException
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -262,16 +263,21 @@ fun Context.getMMSSender(msgId: Long): String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<SimpleContact> = ArrayList()): ArrayList<Conversation> {
|
fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<SimpleContact> = ArrayList()): ArrayList<Conversation> {
|
||||||
|
val useArchive = config.useThreadsArchive
|
||||||
|
|
||||||
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
||||||
val projection = arrayOf(
|
val projection = mutableListOf(
|
||||||
Threads._ID,
|
Threads._ID,
|
||||||
Threads.SNIPPET,
|
Threads.SNIPPET,
|
||||||
Threads.DATE,
|
Threads.DATE,
|
||||||
Threads.READ,
|
Threads.READ,
|
||||||
Threads.RECIPIENT_IDS,
|
Threads.RECIPIENT_IDS,
|
||||||
Threads.ARCHIVED
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (useArchive) {
|
||||||
|
projection += Threads.ARCHIVED
|
||||||
|
}
|
||||||
|
|
||||||
var selection = "${Threads.MESSAGE_COUNT} > ?"
|
var selection = "${Threads.MESSAGE_COUNT} > ?"
|
||||||
var selectionArgs = arrayOf("0")
|
var selectionArgs = arrayOf("0")
|
||||||
if (threadId != null) {
|
if (threadId != null) {
|
||||||
|
@ -284,39 +290,68 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
|
||||||
val conversations = ArrayList<Conversation>()
|
val conversations = ArrayList<Conversation>()
|
||||||
val simpleContactHelper = SimpleContactsHelper(this)
|
val simpleContactHelper = SimpleContactsHelper(this)
|
||||||
val blockedNumbers = getBlockedNumbers()
|
val blockedNumbers = getBlockedNumbers()
|
||||||
queryCursor(uri, projection, selection, selectionArgs, sortOrder, true) { cursor ->
|
try {
|
||||||
val id = cursor.getLongValue(Threads._ID)
|
queryCursorUnsafe(uri, projection.toTypedArray(), selection, selectionArgs, sortOrder) { cursor ->
|
||||||
var snippet = cursor.getStringValue(Threads.SNIPPET) ?: ""
|
val id = cursor.getLongValue(Threads._ID)
|
||||||
if (snippet.isEmpty()) {
|
var snippet = cursor.getStringValue(Threads.SNIPPET) ?: ""
|
||||||
snippet = getThreadSnippet(id)
|
if (snippet.isEmpty()) {
|
||||||
}
|
snippet = getThreadSnippet(id)
|
||||||
|
}
|
||||||
|
|
||||||
var date = cursor.getLongValue(Threads.DATE)
|
var date = cursor.getLongValue(Threads.DATE)
|
||||||
if (date.toString().length > 10) {
|
if (date.toString().length > 10) {
|
||||||
date /= 1000
|
date /= 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
val rawIds = cursor.getStringValue(Threads.RECIPIENT_IDS)
|
val rawIds = cursor.getStringValue(Threads.RECIPIENT_IDS)
|
||||||
val recipientIds = rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
val recipientIds = rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
||||||
val phoneNumbers = getThreadPhoneNumbers(recipientIds)
|
val phoneNumbers = getThreadPhoneNumbers(recipientIds)
|
||||||
if (phoneNumbers.isEmpty() || phoneNumbers.any { isNumberBlocked(it, blockedNumbers) }) {
|
if (phoneNumbers.isEmpty() || phoneNumbers.any { isNumberBlocked(it, blockedNumbers) }) {
|
||||||
return@queryCursor
|
return@queryCursorUnsafe
|
||||||
}
|
}
|
||||||
|
|
||||||
val names = getThreadContactNames(phoneNumbers, privateContacts)
|
val names = getThreadContactNames(phoneNumbers, privateContacts)
|
||||||
val title = TextUtils.join(", ", names.toTypedArray())
|
val title = TextUtils.join(", ", names.toTypedArray())
|
||||||
val photoUri = if (phoneNumbers.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(phoneNumbers.first()) else ""
|
val photoUri = if (phoneNumbers.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(phoneNumbers.first()) else ""
|
||||||
val isGroupConversation = phoneNumbers.size > 1
|
val isGroupConversation = phoneNumbers.size > 1
|
||||||
val read = cursor.getIntValue(Threads.READ) == 1
|
val read = cursor.getIntValue(Threads.READ) == 1
|
||||||
val archived = cursor.getIntValue(Threads.ARCHIVED) == 1
|
val archived = if (useArchive) cursor.getIntValue(Threads.ARCHIVED) == 1 else false
|
||||||
val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first(), isArchived = archived)
|
val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first(), isArchived = archived)
|
||||||
conversations.add(conversation)
|
conversations.add(conversation)
|
||||||
|
}
|
||||||
|
} catch (sqliteException: SQLiteException) {
|
||||||
|
if (sqliteException.message?.contains("no such column: archived") == true && useArchive) {
|
||||||
|
config.useThreadsArchive = false
|
||||||
|
return getConversations(threadId, privateContacts)
|
||||||
|
} else {
|
||||||
|
showErrorToast(sqliteException)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showErrorToast(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
conversations.sortByDescending { it.date }
|
conversations.sortByDescending { it.date }
|
||||||
return conversations
|
return conversations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Context.queryCursorUnsafe(
|
||||||
|
uri: Uri,
|
||||||
|
projection: Array<String>,
|
||||||
|
selection: String? = null,
|
||||||
|
selectionArgs: Array<String>? = null,
|
||||||
|
sortOrder: String? = null,
|
||||||
|
callback: (cursor: Cursor) -> Unit
|
||||||
|
) {
|
||||||
|
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
||||||
|
cursor?.use {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
callback(cursor)
|
||||||
|
} while (cursor.moveToNext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Context.getConversationIds(): List<Long> {
|
fun Context.getConversationIds(): List<Long> {
|
||||||
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
||||||
val projection = arrayOf(Threads._ID)
|
val projection = arrayOf(Threads._ID)
|
||||||
|
@ -713,7 +748,16 @@ fun Context.updateConversationArchivedStatus(threadId: Long, archived: Boolean)
|
||||||
}
|
}
|
||||||
val selection = "${Threads._ID} = ?"
|
val selection = "${Threads._ID} = ?"
|
||||||
val selectionArgs = arrayOf(threadId.toString())
|
val selectionArgs = arrayOf(threadId.toString())
|
||||||
contentResolver.update(uri, values, selection, selectionArgs)
|
try {
|
||||||
|
contentResolver.update(uri, values, selection, selectionArgs)
|
||||||
|
} catch (sqliteException: SQLiteException) {
|
||||||
|
if (sqliteException.message?.contains("no such column: archived") == true && config.useThreadsArchive) {
|
||||||
|
config.useThreadsArchive = false
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
throw sqliteException
|
||||||
|
}
|
||||||
|
}
|
||||||
if (archived) {
|
if (archived) {
|
||||||
conversationsDB.moveToArchive(threadId)
|
conversationsDB.moveToArchive(threadId)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -111,4 +111,8 @@ class Config(context: Context) : BaseConfig(context) {
|
||||||
var lastRecycleBinCheck: Long
|
var lastRecycleBinCheck: Long
|
||||||
get() = prefs.getLong(LAST_RECYCLE_BIN_CHECK, 0L)
|
get() = prefs.getLong(LAST_RECYCLE_BIN_CHECK, 0L)
|
||||||
set(lastRecycleBinCheck) = prefs.edit().putLong(LAST_RECYCLE_BIN_CHECK, lastRecycleBinCheck).apply()
|
set(lastRecycleBinCheck) = prefs.edit().putLong(LAST_RECYCLE_BIN_CHECK, lastRecycleBinCheck).apply()
|
||||||
|
|
||||||
|
var useThreadsArchive: Boolean
|
||||||
|
get() = prefs.getBoolean(USE_THREADS_ARCHIVE, true)
|
||||||
|
set(useThreadsArchive) = prefs.edit().putBoolean(USE_THREADS_ARCHIVE, useThreadsArchive).apply()
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ 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 IS_RECYCLE_BIN = "is_recycle_bin"
|
const val IS_RECYCLE_BIN = "is_recycle_bin"
|
||||||
|
const val USE_THREADS_ARCHIVE = "use_threads_archive"
|
||||||
|
|
||||||
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"
|
||||||
|
|
|
@ -113,7 +113,9 @@ class SmsReceiver : BroadcastReceiver() {
|
||||||
subscriptionId
|
subscriptionId
|
||||||
)
|
)
|
||||||
context.messagesDB.insertOrUpdate(message)
|
context.messagesDB.insertOrUpdate(message)
|
||||||
context.updateConversationArchivedStatus(threadId, false)
|
if (context.config.useThreadsArchive) {
|
||||||
|
context.updateConversationArchivedStatus(threadId, false)
|
||||||
|
}
|
||||||
refreshMessages()
|
refreshMessages()
|
||||||
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap)
|
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue