Merge pull request #775 from esensar/fix/missing-archive-table

Prevent using `archive` table if it doesn't exist
This commit is contained in:
Tibor Kaputa 2023-10-03 11:42:06 +02:00 committed by GitHub
commit 1d804ebe24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 30 deletions

View File

@ -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.isArchiveAvailable
} }
} }

View File

@ -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 archiveAvailable = config.isArchiveAvailable
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 && archiveAvailable
findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true && !isRecycleBin findItem(R.id.unarchive).isVisible = threadItems.isNotEmpty() && conversation?.isArchived == true && !isRecycleBin && archiveAvailable
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)

View File

@ -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 archiveAvailable = activity.config.isArchiveAvailable
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 = archiveAvailable
checkPinBtnVisibility(this) checkPinBtnVisibility(this)
} }
} }

View File

@ -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 archiveAvailable = config.isArchiveAvailable
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 (archiveAvailable) {
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 (archiveAvailable) 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 && archiveAvailable) {
config.isArchiveAvailable = 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.isArchiveAvailable) {
config.isArchiveAvailable = false
return
} else {
throw sqliteException
}
}
if (archived) { if (archived) {
conversationsDB.moveToArchive(threadId) conversationsDB.moveToArchive(threadId)
} else { } else {

View File

@ -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 isArchiveAvailable: Boolean
get() = prefs.getBoolean(IS_ARCHIVE_AVAILABLE, true)
set(isArchiveAvailable) = prefs.edit().putBoolean(IS_ARCHIVE_AVAILABLE, isArchiveAvailable).apply()
} }

View File

@ -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 IS_ARCHIVE_AVAILABLE = "is_archive_available"
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

@ -113,7 +113,9 @@ class SmsReceiver : BroadcastReceiver() {
subscriptionId subscriptionId
) )
context.messagesDB.insertOrUpdate(message) context.messagesDB.insertOrUpdate(message)
context.updateConversationArchivedStatus(threadId, false) if (context.config.isArchiveAvailable) {
context.updateConversationArchivedStatus(threadId, false)
}
refreshMessages() refreshMessages()
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap) context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap)
} }