Merge pull request #353 from FossifyOrg/remove_storage_permissions
Removed storage permission requirement
This commit is contained in:
commit
9d45c9d81f
11 changed files with 168 additions and 153 deletions
|
|
@ -15,10 +15,6 @@
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||||
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
|
||||||
android:maxSdkVersion="28" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.USE_BIOMETRIC"
|
android:name="android.permission.USE_BIOMETRIC"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package org.fossify.messages.activities
|
package org.fossify.messages.activities
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
|
||||||
import android.app.role.RoleManager
|
import android.app.role.RoleManager
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ShortcutInfo
|
import android.content.pm.ShortcutInfo
|
||||||
|
|
@ -208,7 +207,7 @@ class MainActivity : SimpleActivity() {
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, resultData)
|
super.onActivityResult(requestCode, resultCode, resultData)
|
||||||
if (requestCode == MAKE_DEFAULT_APP_REQUEST) {
|
if (requestCode == MAKE_DEFAULT_APP_REQUEST) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
askPermissions()
|
askPermissions()
|
||||||
} else {
|
} else {
|
||||||
finish()
|
finish()
|
||||||
|
|
@ -251,7 +250,8 @@ class MainActivity : SimpleActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// while SEND_SMS and READ_SMS permissions are mandatory, READ_CONTACTS is optional. If we don't have it, we just won't be able to show the contact name in some cases
|
// while SEND_SMS and READ_SMS permissions are mandatory, READ_CONTACTS is optional.
|
||||||
|
// If we don't have it, we just won't be able to show the contact name in some cases
|
||||||
private fun askPermissions() {
|
private fun askPermissions() {
|
||||||
handlePermission(PERMISSION_READ_SMS) {
|
handlePermission(PERMISSION_READ_SMS) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
|
@ -271,7 +271,7 @@ class MainActivity : SimpleActivity() {
|
||||||
bus = EventBus.getDefault()
|
bus = EventBus.getDefault()
|
||||||
try {
|
try {
|
||||||
bus!!.register(this)
|
bus!!.register(this)
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -302,20 +302,22 @@ class MainActivity : SimpleActivity() {
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
val conversations = try {
|
val conversations = try {
|
||||||
conversationsDB.getNonArchived().toMutableList() as ArrayList<Conversation>
|
conversationsDB.getNonArchived().toMutableList() as ArrayList<Conversation>
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
ArrayList()
|
ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val archived = try {
|
val archived = try {
|
||||||
conversationsDB.getAllArchived()
|
conversationsDB.getAllArchived()
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
listOf()
|
listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUnreadCountBadge(conversations)
|
updateUnreadCountBadge(conversations)
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
setupConversations(conversations, cached = true)
|
setupConversations(conversations, cached = true)
|
||||||
getNewConversations((conversations + archived).toMutableList() as ArrayList<Conversation>)
|
getNewConversations(
|
||||||
|
(conversations + archived).toMutableList() as ArrayList<Conversation>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
conversations.forEach {
|
conversations.forEach {
|
||||||
clearExpiredScheduledMessages(it.threadId)
|
clearExpiredScheduledMessages(it.threadId)
|
||||||
|
|
@ -349,11 +351,14 @@ class MainActivity : SimpleActivity() {
|
||||||
val newConversation =
|
val newConversation =
|
||||||
conversations.find { it.phoneNumber == cachedConversation.phoneNumber }
|
conversations.find { it.phoneNumber == cachedConversation.phoneNumber }
|
||||||
if (isTemporaryThread && newConversation != null) {
|
if (isTemporaryThread && newConversation != null) {
|
||||||
// delete the original temporary thread and move any scheduled messages to the new thread
|
// delete the original temporary thread and move any scheduled messages
|
||||||
|
// to the new thread
|
||||||
conversationsDB.deleteThreadId(threadId)
|
conversationsDB.deleteThreadId(threadId)
|
||||||
messagesDB.getScheduledThreadMessages(threadId)
|
messagesDB.getScheduledThreadMessages(threadId)
|
||||||
.forEach { message ->
|
.forEach { message ->
|
||||||
messagesDB.insertOrUpdate(message.copy(threadId = newConversation.threadId))
|
messagesDB.insertOrUpdate(
|
||||||
|
message.copy(threadId = newConversation.threadId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
insertOrUpdateConversation(newConversation, cachedConversation)
|
insertOrUpdateConversation(newConversation, cachedConversation)
|
||||||
}
|
}
|
||||||
|
|
@ -366,7 +371,8 @@ class MainActivity : SimpleActivity() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (conv != null) {
|
if (conv != null) {
|
||||||
// FIXME: Scheduled message date is being reset here. Conversations with scheduled messages will have their original date.
|
// FIXME: Scheduled message date is being reset here. Conversations with
|
||||||
|
// scheduled messages will have their original date.
|
||||||
insertOrUpdateConversation(conv)
|
insertOrUpdateConversation(conv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -412,15 +418,18 @@ class MainActivity : SimpleActivity() {
|
||||||
|
|
||||||
private fun setupConversations(
|
private fun setupConversations(
|
||||||
conversations: ArrayList<Conversation>,
|
conversations: ArrayList<Conversation>,
|
||||||
cached: Boolean = false
|
cached: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val sortedConversations = conversations.sortedWith(
|
val sortedConversations = conversations
|
||||||
compareByDescending<Conversation> { config.pinnedConversations.contains(it.threadId.toString()) }
|
.sortedWith(
|
||||||
.thenByDescending { it.date }
|
compareByDescending<Conversation> {
|
||||||
).toMutableList() as ArrayList<Conversation>
|
config.pinnedConversations.contains(it.threadId.toString())
|
||||||
|
}.thenByDescending { it.date }
|
||||||
|
).toMutableList() as ArrayList<Conversation>
|
||||||
|
|
||||||
if (cached && config.appRunCount == 1) {
|
if (cached && config.appRunCount == 1) {
|
||||||
// there are no cached conversations on the first run so we show the loading placeholder and progress until we are done loading from telephony
|
// there are no cached conversations on the first run so we show the
|
||||||
|
// loading placeholder and progress until we are done loading from telephony
|
||||||
showOrHideProgress(conversations.isEmpty())
|
showOrHideProgress(conversations.isEmpty())
|
||||||
} else {
|
} else {
|
||||||
showOrHideProgress(false)
|
showOrHideProgress(false)
|
||||||
|
|
@ -435,7 +444,7 @@ class MainActivity : SimpleActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -498,7 +507,7 @@ class MainActivity : SimpleActivity() {
|
||||||
try {
|
try {
|
||||||
manager.dynamicShortcuts = listOf(newConversation)
|
manager.dynamicShortcuts = listOf(newConversation)
|
||||||
config.lastHandledShortcutColor = appIconColor
|
config.lastHandledShortcutColor = appIconColor
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,17 @@ import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import org.fossify.commons.dialogs.ExportBlockedNumbersDialog
|
|
||||||
import org.fossify.commons.dialogs.FilePickerDialog
|
|
||||||
import org.fossify.commons.extensions.beVisibleIf
|
import org.fossify.commons.extensions.beVisibleIf
|
||||||
import org.fossify.commons.extensions.getFileOutputStream
|
|
||||||
import org.fossify.commons.extensions.getProperPrimaryColor
|
import org.fossify.commons.extensions.getProperPrimaryColor
|
||||||
import org.fossify.commons.extensions.getTempFile
|
import org.fossify.commons.extensions.getTempFile
|
||||||
import org.fossify.commons.extensions.showErrorToast
|
import org.fossify.commons.extensions.showErrorToast
|
||||||
import org.fossify.commons.extensions.toFileDirItem
|
|
||||||
import org.fossify.commons.extensions.toast
|
import org.fossify.commons.extensions.toast
|
||||||
import org.fossify.commons.extensions.underlineText
|
import org.fossify.commons.extensions.underlineText
|
||||||
import org.fossify.commons.extensions.updateTextColors
|
import org.fossify.commons.extensions.updateTextColors
|
||||||
import org.fossify.commons.extensions.viewBinding
|
import org.fossify.commons.extensions.viewBinding
|
||||||
import org.fossify.commons.helpers.ExportResult
|
import org.fossify.commons.helpers.ExportResult
|
||||||
import org.fossify.commons.helpers.NavigationIcon
|
import org.fossify.commons.helpers.NavigationIcon
|
||||||
import org.fossify.commons.helpers.PERMISSION_READ_STORAGE
|
|
||||||
import org.fossify.commons.helpers.PERMISSION_WRITE_STORAGE
|
|
||||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||||
import org.fossify.commons.helpers.isQPlus
|
|
||||||
import org.fossify.commons.interfaces.RefreshRecyclerViewListener
|
import org.fossify.commons.interfaces.RefreshRecyclerViewListener
|
||||||
import org.fossify.messages.R
|
import org.fossify.messages.R
|
||||||
import org.fossify.messages.databinding.ActivityManageBlockedKeywordsBinding
|
import org.fossify.messages.databinding.ActivityManageBlockedKeywordsBinding
|
||||||
|
|
@ -96,7 +89,7 @@ class ManageBlockedKeywordsActivity : SimpleActivity(), RefreshRecyclerViewListe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val exportActivityResultLauncher =
|
private val createDocument =
|
||||||
registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
|
registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
|
||||||
try {
|
try {
|
||||||
val outputStream = uri?.let { contentResolver.openOutputStream(it) }
|
val outputStream = uri?.let { contentResolver.openOutputStream(it) }
|
||||||
|
|
@ -108,7 +101,7 @@ class ManageBlockedKeywordsActivity : SimpleActivity(), RefreshRecyclerViewListe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val importActivityResultLauncher =
|
private val getContent =
|
||||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||||
try {
|
try {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
|
@ -120,27 +113,13 @@ class ManageBlockedKeywordsActivity : SimpleActivity(), RefreshRecyclerViewListe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryImportBlockedKeywords() {
|
private fun tryImportBlockedKeywords() {
|
||||||
if (isQPlus()) {
|
val mimeType = "text/plain"
|
||||||
val mimeType = "text/plain"
|
try {
|
||||||
try {
|
getContent.launch(mimeType)
|
||||||
importActivityResultLauncher.launch(mimeType)
|
} catch (_: ActivityNotFoundException) {
|
||||||
} catch (e: ActivityNotFoundException) {
|
toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG)
|
||||||
toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG)
|
} catch (e: Exception) {
|
||||||
} catch (e: Exception) {
|
showErrorToast(e)
|
||||||
showErrorToast(e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handlePermission(PERMISSION_READ_STORAGE) { isAllowed ->
|
|
||||||
if (isAllowed) {
|
|
||||||
pickFileToImportBlockedKeywords()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pickFileToImportBlockedKeywords() {
|
|
||||||
FilePickerDialog(this) {
|
|
||||||
importBlockedKeywords(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,32 +179,20 @@ class ManageBlockedKeywordsActivity : SimpleActivity(), RefreshRecyclerViewListe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryExportBlockedNumbers() {
|
private fun tryExportBlockedNumbers() {
|
||||||
if (isQPlus()) {
|
ExportBlockedKeywordsDialog(
|
||||||
ExportBlockedKeywordsDialog(this, config.lastBlockedKeywordExportPath, true) { file ->
|
activity = this,
|
||||||
try {
|
path = config.lastBlockedKeywordExportPath,
|
||||||
exportActivityResultLauncher.launch(file.name)
|
hidePath = true
|
||||||
} catch (e: ActivityNotFoundException) {
|
) { file ->
|
||||||
toast(
|
try {
|
||||||
org.fossify.commons.R.string.system_service_disabled,
|
createDocument.launch(file.name)
|
||||||
Toast.LENGTH_LONG
|
} catch (_: ActivityNotFoundException) {
|
||||||
)
|
toast(
|
||||||
} catch (e: Exception) {
|
org.fossify.commons.R.string.system_service_disabled,
|
||||||
showErrorToast(e)
|
Toast.LENGTH_LONG
|
||||||
}
|
)
|
||||||
}
|
} catch (e: Exception) {
|
||||||
} else {
|
showErrorToast(e)
|
||||||
handlePermission(PERMISSION_WRITE_STORAGE) { isAllowed ->
|
|
||||||
if (isAllowed) {
|
|
||||||
ExportBlockedNumbersDialog(
|
|
||||||
this,
|
|
||||||
config.lastBlockedKeywordExportPath,
|
|
||||||
false
|
|
||||||
) { file ->
|
|
||||||
getFileOutputStream(file.toFileDirItem(this), true) { out ->
|
|
||||||
exportBlockedKeywordsTo(out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,9 @@ abstract class BaseConversationsAdapter(
|
||||||
|
|
||||||
override fun getSelectableItemCount() = itemCount
|
override fun getSelectableItemCount() = itemCount
|
||||||
|
|
||||||
protected fun getSelectedItems() =
|
protected fun getSelectedItems() = currentList.filter {
|
||||||
currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
selectedKeys.contains(it.hashCode())
|
||||||
|
} as ArrayList<Conversation>
|
||||||
|
|
||||||
override fun getIsItemSelectable(position: Int) = true
|
override fun getIsItemSelectable(position: Int) = true
|
||||||
|
|
||||||
|
|
@ -143,7 +144,9 @@ abstract class BaseConversationsAdapter(
|
||||||
draftIndicator.beVisibleIf(!smsDraft.isNullOrEmpty())
|
draftIndicator.beVisibleIf(!smsDraft.isNullOrEmpty())
|
||||||
draftIndicator.setTextColor(properPrimaryColor)
|
draftIndicator.setTextColor(properPrimaryColor)
|
||||||
|
|
||||||
pinIndicator.beVisibleIf(activity.config.pinnedConversations.contains(conversation.threadId.toString()))
|
pinIndicator.beVisibleIf(
|
||||||
|
activity.config.pinnedConversations.contains(conversation.threadId.toString())
|
||||||
|
)
|
||||||
pinIndicator.applyColorFilter(textColor)
|
pinIndicator.applyColorFilter(textColor)
|
||||||
|
|
||||||
conversationFrame.isSelected = selectedKeys.contains(conversation.hashCode())
|
conversationFrame.isSelected = selectedKeys.contains(conversation.hashCode())
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import org.fossify.commons.extensions.setupDialogStuff
|
||||||
import org.fossify.commons.extensions.showErrorToast
|
import org.fossify.commons.extensions.showErrorToast
|
||||||
import org.fossify.commons.extensions.toast
|
import org.fossify.commons.extensions.toast
|
||||||
import org.fossify.commons.extensions.value
|
import org.fossify.commons.extensions.value
|
||||||
|
import org.fossify.commons.helpers.MEDIUM_ALPHA
|
||||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||||
import org.fossify.messages.R
|
import org.fossify.messages.R
|
||||||
import org.fossify.messages.activities.SimpleActivity
|
import org.fossify.messages.activities.SimpleActivity
|
||||||
|
|
@ -72,7 +73,7 @@ class ExportMessagesDialog(
|
||||||
getButton(AlertDialog.BUTTON_NEGATIVE)
|
getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||||
).forEach {
|
).forEach {
|
||||||
it.isEnabled = false
|
it.isEnabled = false
|
||||||
it.alpha = 0.6f
|
it.alpha = MEDIUM_ALPHA
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.exportProgress.setIndicatorColor(activity.getProperPrimaryColor())
|
binding.exportProgress.setIndicatorColor(activity.getProperPrimaryColor())
|
||||||
|
|
@ -112,7 +113,7 @@ class ExportMessagesDialog(
|
||||||
// delete the file to avoid leaving behind an empty/corrupt file
|
// delete the file to avoid leaving behind an empty/corrupt file
|
||||||
try {
|
try {
|
||||||
DocumentsContract.deleteDocument(activity.contentResolver, uri)
|
DocumentsContract.deleteDocument(activity.contentResolver, uri)
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
// ignored because we don't want to show two error messages
|
// ignored because we don't want to show two error messages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import org.fossify.commons.extensions.getAlertDialogBuilder
|
||||||
import org.fossify.commons.extensions.getProperPrimaryColor
|
import org.fossify.commons.extensions.getProperPrimaryColor
|
||||||
import org.fossify.commons.extensions.setupDialogStuff
|
import org.fossify.commons.extensions.setupDialogStuff
|
||||||
import org.fossify.commons.extensions.toast
|
import org.fossify.commons.extensions.toast
|
||||||
|
import org.fossify.commons.helpers.MEDIUM_ALPHA
|
||||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||||
import org.fossify.messages.R
|
import org.fossify.messages.R
|
||||||
import org.fossify.messages.activities.SimpleActivity
|
import org.fossify.messages.activities.SimpleActivity
|
||||||
|
|
@ -65,7 +66,7 @@ class ImportMessagesDialog(
|
||||||
negativeButton
|
negativeButton
|
||||||
).forEach {
|
).forEach {
|
||||||
it.isEnabled = false
|
it.isEnabled = false
|
||||||
it.alpha = 0.6f
|
it.alpha = MEDIUM_ALPHA
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ fun Activity.dialNumber(phoneNumber: String, callback: (() -> Unit)? = null) {
|
||||||
try {
|
try {
|
||||||
startActivity(this)
|
startActivity(this)
|
||||||
callback?.invoke()
|
callback?.invoke()
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (_: ActivityNotFoundException) {
|
||||||
toast(org.fossify.commons.R.string.no_app_found)
|
toast(org.fossify.commons.R.string.no_app_found)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showErrorToast(e)
|
showErrorToast(e)
|
||||||
|
|
@ -46,7 +46,7 @@ fun Activity.launchViewIntent(uri: Uri, mimetype: String, filename: String) {
|
||||||
try {
|
try {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
startActivity(this)
|
startActivity(this)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (_: ActivityNotFoundException) {
|
||||||
val newMimetype = filename.getMimeType()
|
val newMimetype = filename.getMimeType()
|
||||||
if (newMimetype.isNotEmpty() && mimetype != newMimetype) {
|
if (newMimetype.isNotEmpty() && mimetype != newMimetype) {
|
||||||
launchViewIntent(uri, newMimetype, filename)
|
launchViewIntent(uri, newMimetype, filename)
|
||||||
|
|
|
||||||
|
|
@ -78,32 +78,41 @@ import org.fossify.messages.models.RecycleBinMessage
|
||||||
import org.xmlpull.v1.XmlPullParserException
|
import org.xmlpull.v1.XmlPullParserException
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
val Context.config: Config get() = Config.newInstance(applicationContext)
|
val Context.config: Config
|
||||||
|
get() = Config.newInstance(applicationContext)
|
||||||
|
|
||||||
fun Context.getMessagesDB() = MessagesDatabase.getInstance(this)
|
fun Context.getMessagesDB() = MessagesDatabase.getInstance(this)
|
||||||
|
|
||||||
val Context.conversationsDB: ConversationsDao get() = getMessagesDB().ConversationsDao()
|
val Context.conversationsDB: ConversationsDao
|
||||||
|
get() = getMessagesDB().ConversationsDao()
|
||||||
|
|
||||||
val Context.attachmentsDB: AttachmentsDao get() = getMessagesDB().AttachmentsDao()
|
val Context.attachmentsDB: AttachmentsDao
|
||||||
|
get() = getMessagesDB().AttachmentsDao()
|
||||||
|
|
||||||
val Context.messageAttachmentsDB: MessageAttachmentsDao get() = getMessagesDB().MessageAttachmentsDao()
|
val Context.messageAttachmentsDB: MessageAttachmentsDao
|
||||||
|
get() = getMessagesDB().MessageAttachmentsDao()
|
||||||
|
|
||||||
val Context.messagesDB: MessagesDao get() = getMessagesDB().MessagesDao()
|
val Context.messagesDB: MessagesDao
|
||||||
|
get() = getMessagesDB().MessagesDao()
|
||||||
|
|
||||||
val Context.draftsDB: DraftsDao get() = getMessagesDB().DraftsDao()
|
val Context.draftsDB: DraftsDao
|
||||||
|
get() = getMessagesDB().DraftsDao()
|
||||||
|
|
||||||
val Context.notificationHelper get() = NotificationHelper(this)
|
val Context.notificationHelper
|
||||||
|
get() = NotificationHelper(this)
|
||||||
|
|
||||||
val Context.messagingUtils get() = MessagingUtils(this)
|
val Context.messagingUtils
|
||||||
|
get() = MessagingUtils(this)
|
||||||
|
|
||||||
val Context.smsSender get() = SmsSender.getInstance(applicationContext as Application)
|
val Context.smsSender
|
||||||
|
get() = SmsSender.getInstance(applicationContext as Application)
|
||||||
|
|
||||||
fun Context.getMessages(
|
fun Context.getMessages(
|
||||||
threadId: Long,
|
threadId: Long,
|
||||||
getImageResolutions: Boolean,
|
getImageResolutions: Boolean,
|
||||||
dateFrom: Int = -1,
|
dateFrom: Int = -1,
|
||||||
includeScheduledMessages: Boolean = true,
|
includeScheduledMessages: Boolean = true,
|
||||||
limit: Int = MESSAGES_LIMIT
|
limit: Int = MESSAGES_LIMIT,
|
||||||
): ArrayList<Message> {
|
): ArrayList<Message> {
|
||||||
val uri = Sms.CONTENT_URI
|
val uri = Sms.CONTENT_URI
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
|
|
@ -212,7 +221,7 @@ fun Context.getMMS(
|
||||||
threadId: Long? = null,
|
threadId: Long? = null,
|
||||||
getImageResolutions: Boolean = false,
|
getImageResolutions: Boolean = false,
|
||||||
sortOrder: String? = null,
|
sortOrder: String? = null,
|
||||||
dateFrom: Int = -1
|
dateFrom: Int = -1,
|
||||||
): ArrayList<Message> {
|
): ArrayList<Message> {
|
||||||
val uri = Mms.CONTENT_URI
|
val uri = Mms.CONTENT_URI
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
|
|
@ -229,8 +238,8 @@ fun Context.getMMS(
|
||||||
var selectionArgs: Array<String>? = null
|
var selectionArgs: Array<String>? = null
|
||||||
|
|
||||||
if (threadId == null && dateFrom != -1) {
|
if (threadId == null && dateFrom != -1) {
|
||||||
selection =
|
// Should not multiply 1000 here, because date in mms's database is different from sms's.
|
||||||
"${Sms.DATE} < ${dateFrom.toLong()}" //Should not multiply 1000 here, because date in mms's database is different from sms's.
|
selection = "${Sms.DATE} < ${dateFrom.toLong()}"
|
||||||
} else if (threadId != null && dateFrom == -1) {
|
} else if (threadId != null && dateFrom == -1) {
|
||||||
selection = "${Sms.THREAD_ID} = ?"
|
selection = "${Sms.THREAD_ID} = ?"
|
||||||
selectionArgs = arrayOf(threadId.toString())
|
selectionArgs = arrayOf(threadId.toString())
|
||||||
|
|
@ -315,18 +324,18 @@ fun Context.getMMSSender(msgId: Long): String {
|
||||||
return it.getStringValue(Mms.Addr.ADDRESS)
|
return it.getStringValue(Mms.Addr.ADDRESS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getConversations(
|
fun Context.getConversations(
|
||||||
threadId: Long? = null,
|
threadId: Long? = null,
|
||||||
privateContacts: ArrayList<SimpleContact> = ArrayList()
|
privateContacts: ArrayList<SimpleContact> = ArrayList(),
|
||||||
): ArrayList<Conversation> {
|
): ArrayList<Conversation> {
|
||||||
val archiveAvailable = config.isArchiveAvailable
|
val archiveAvailable = config.isArchiveAvailable
|
||||||
|
|
||||||
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
val uri = "${Threads.CONTENT_URI}?simple=true".toUri()
|
||||||
val projection = mutableListOf(
|
val projection = mutableListOf(
|
||||||
Threads._ID,
|
Threads._ID,
|
||||||
Threads.SNIPPET,
|
Threads.SNIPPET,
|
||||||
|
|
@ -413,7 +422,10 @@ fun Context.getConversations(
|
||||||
conversations.add(conversation)
|
conversations.add(conversation)
|
||||||
}
|
}
|
||||||
} catch (sqliteException: SQLiteException) {
|
} catch (sqliteException: SQLiteException) {
|
||||||
if (sqliteException.message?.contains("no such column: archived") == true && archiveAvailable) {
|
if (
|
||||||
|
sqliteException.message?.contains("no such column: archived") == true
|
||||||
|
&& archiveAvailable
|
||||||
|
) {
|
||||||
config.isArchiveAvailable = false
|
config.isArchiveAvailable = false
|
||||||
return getConversations(threadId, privateContacts)
|
return getConversations(threadId, privateContacts)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -433,7 +445,7 @@ private fun Context.queryCursorUnsafe(
|
||||||
selection: String? = null,
|
selection: String? = null,
|
||||||
selectionArgs: Array<String>? = null,
|
selectionArgs: Array<String>? = null,
|
||||||
sortOrder: String? = null,
|
sortOrder: String? = null,
|
||||||
callback: (cursor: Cursor) -> Unit
|
callback: (cursor: Cursor) -> Unit,
|
||||||
) {
|
) {
|
||||||
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
||||||
cursor?.use {
|
cursor?.use {
|
||||||
|
|
@ -446,7 +458,7 @@ private fun Context.queryCursorUnsafe(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getConversationIds(): List<Long> {
|
fun Context.getConversationIds(): List<Long> {
|
||||||
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
val uri = "${Threads.CONTENT_URI}?simple=true".toUri()
|
||||||
val projection = arrayOf(Threads._ID)
|
val projection = arrayOf(Threads._ID)
|
||||||
val selection = "${Threads.MESSAGE_COUNT} > 0"
|
val selection = "${Threads.MESSAGE_COUNT} > 0"
|
||||||
val sortOrder = "${Threads.DATE} ASC"
|
val sortOrder = "${Threads.DATE} ASC"
|
||||||
|
|
@ -464,7 +476,7 @@ fun Context.getMmsAttachment(id: Long, getImageResolutions: Boolean): MessageAtt
|
||||||
val uri = if (isQPlus()) {
|
val uri = if (isQPlus()) {
|
||||||
Mms.Part.CONTENT_URI
|
Mms.Part.CONTENT_URI
|
||||||
} else {
|
} else {
|
||||||
Uri.parse("content://mms/part")
|
"content://mms/part".toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
|
|
@ -502,12 +514,21 @@ fun Context.getMmsAttachment(id: Long, getImageResolutions: Boolean): MessageAtt
|
||||||
)
|
)
|
||||||
width = options.outWidth
|
width = options.outWidth
|
||||||
height = options.outHeight
|
height = options.outHeight
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val attachment = Attachment(partId, id, fileUri.toString(), mimetype, width, height, "")
|
messageAttachment.attachments.add(
|
||||||
messageAttachment.attachments.add(attachment)
|
Attachment(
|
||||||
|
id = partId,
|
||||||
|
messageId = id,
|
||||||
|
uriString = fileUri.toString(),
|
||||||
|
mimetype = mimetype,
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
filename = ""
|
||||||
|
)
|
||||||
|
)
|
||||||
} else if (mimetype != "application/smil") {
|
} else if (mimetype != "application/smil") {
|
||||||
val attachmentName = attachmentNames?.getOrNull(attachmentCount) ?: ""
|
val attachmentName = attachmentNames?.getOrNull(attachmentCount) ?: ""
|
||||||
val attachment = Attachment(
|
val attachment = Attachment(
|
||||||
|
|
@ -562,7 +583,7 @@ fun Context.getThreadSnippet(threadId: Long): String {
|
||||||
snippet = cursor.getStringValue(Sms.BODY)
|
snippet = cursor.getStringValue(Sms.BODY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
return snippet
|
return snippet
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +604,7 @@ fun Context.getMessageRecipientAddress(messageId: Long): String {
|
||||||
return cursor.getStringValue(Sms.ADDRESS)
|
return cursor.getStringValue(Sms.ADDRESS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -591,9 +612,9 @@ fun Context.getMessageRecipientAddress(messageId: Long): String {
|
||||||
|
|
||||||
fun Context.getThreadParticipants(
|
fun Context.getThreadParticipants(
|
||||||
threadId: Long,
|
threadId: Long,
|
||||||
contactsMap: HashMap<Int, SimpleContact>?
|
contactsMap: HashMap<Int, SimpleContact>?,
|
||||||
): ArrayList<SimpleContact> {
|
): ArrayList<SimpleContact> {
|
||||||
val uri = Uri.parse("${MmsSms.CONTENT_CONVERSATIONS_URI}?simple=true")
|
val uri = "${MmsSms.CONTENT_CONVERSATIONS_URI}?simple=true".toUri()
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
ThreadsColumns.RECIPIENT_IDS
|
ThreadsColumns.RECIPIENT_IDS
|
||||||
)
|
)
|
||||||
|
|
@ -646,7 +667,7 @@ fun Context.getThreadPhoneNumbers(recipientIds: List<Int>): ArrayList<String> {
|
||||||
|
|
||||||
fun Context.getThreadContactNames(
|
fun Context.getThreadContactNames(
|
||||||
phoneNumbers: List<String>,
|
phoneNumbers: List<String>,
|
||||||
privateContacts: ArrayList<SimpleContact>
|
privateContacts: ArrayList<SimpleContact>,
|
||||||
): ArrayList<String> {
|
): ArrayList<String> {
|
||||||
val names = ArrayList<String>()
|
val names = ArrayList<String>()
|
||||||
phoneNumbers.forEach { number ->
|
phoneNumbers.forEach { number ->
|
||||||
|
|
@ -686,7 +707,9 @@ fun Context.getPhoneNumberFromAddressId(canonicalAddressId: Int): String {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getSuggestedContacts(privateContacts: ArrayList<SimpleContact>): ArrayList<SimpleContact> {
|
fun Context.getSuggestedContacts(
|
||||||
|
privateContacts: ArrayList<SimpleContact>,
|
||||||
|
): ArrayList<SimpleContact> {
|
||||||
val contacts = ArrayList<SimpleContact>()
|
val contacts = ArrayList<SimpleContact>()
|
||||||
val uri = Sms.CONTENT_URI
|
val uri = Sms.CONTENT_URI
|
||||||
val projection = arrayOf(
|
val projection = arrayOf(
|
||||||
|
|
@ -705,8 +728,9 @@ fun Context.getSuggestedContacts(privateContacts: ArrayList<SimpleContact>): Arr
|
||||||
return@queryCursor
|
return@queryCursor
|
||||||
} else if (namePhoto.name == senderNumber) {
|
} else if (namePhoto.name == senderNumber) {
|
||||||
if (privateContacts.isNotEmpty()) {
|
if (privateContacts.isNotEmpty()) {
|
||||||
val privateContact =
|
val privateContact = privateContacts.firstOrNull {
|
||||||
privateContacts.firstOrNull { it.phoneNumbers.first().normalizedNumber == senderNumber }
|
it.phoneNumbers.first().normalizedNumber == senderNumber
|
||||||
|
}
|
||||||
if (privateContact != null) {
|
if (privateContact != null) {
|
||||||
senderName = privateContact.name
|
senderName = privateContact.name
|
||||||
photoUri = privateContact.photoUri
|
photoUri = privateContact.photoUri
|
||||||
|
|
@ -757,7 +781,7 @@ fun Context.getNameAndPhotoFromPhoneNumber(number: String): NamePhoto {
|
||||||
return NamePhoto(name, photoUri)
|
return NamePhoto(name, photoUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return NamePhoto(number, null)
|
return NamePhoto(number, null)
|
||||||
|
|
@ -771,7 +795,7 @@ fun Context.insertNewSMS(
|
||||||
read: Int,
|
read: Int,
|
||||||
threadId: Long,
|
threadId: Long,
|
||||||
type: Int,
|
type: Int,
|
||||||
subscriptionId: Int
|
subscriptionId: Int,
|
||||||
): Long {
|
): Long {
|
||||||
val uri = Sms.CONTENT_URI
|
val uri = Sms.CONTENT_URI
|
||||||
val contentValues = ContentValues().apply {
|
val contentValues = ContentValues().apply {
|
||||||
|
|
@ -788,7 +812,7 @@ fun Context.insertNewSMS(
|
||||||
return try {
|
return try {
|
||||||
val newUri = contentResolver.insert(uri, contentValues)
|
val newUri = contentResolver.insert(uri, contentValues)
|
||||||
newUri?.lastPathSegment?.toLong() ?: 0L
|
newUri?.lastPathSegment?.toLong() ?: 0L
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
0L
|
0L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -801,7 +825,7 @@ fun Context.removeAllArchivedConversations(callback: (() -> Unit)? = null) {
|
||||||
}
|
}
|
||||||
toast(R.string.archive_emptied_successfully)
|
toast(R.string.archive_emptied_successfully)
|
||||||
callback?.invoke()
|
callback?.invoke()
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
toast(org.fossify.commons.R.string.unknown_error_occurred)
|
toast(org.fossify.commons.R.string.unknown_error_occurred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -834,15 +858,20 @@ fun Context.deleteConversation(threadId: Long) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.checkAndDeleteOldRecycleBinMessages(callback: (() -> Unit)? = null) {
|
fun Context.checkAndDeleteOldRecycleBinMessages(callback: (() -> Unit)? = null) {
|
||||||
if (config.useRecycleBin && config.lastRecycleBinCheck < System.currentTimeMillis() - DAY_SECONDS * 1000) {
|
if (
|
||||||
|
config.useRecycleBin
|
||||||
|
&& config.lastRecycleBinCheck < System.currentTimeMillis() - DAY_SECONDS * 1000
|
||||||
|
) {
|
||||||
config.lastRecycleBinCheck = System.currentTimeMillis()
|
config.lastRecycleBinCheck = System.currentTimeMillis()
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
try {
|
try {
|
||||||
for (message in messagesDB.getOldRecycleBinMessages(System.currentTimeMillis() - MONTH_SECONDS * 1000L)) {
|
messagesDB.getOldRecycleBinMessages(
|
||||||
|
timestamp = System.currentTimeMillis() - MONTH_SECONDS * 1000L
|
||||||
|
).forEach { message ->
|
||||||
deleteMessage(message.id, message.isMMS)
|
deleteMessage(message.id, message.isMMS)
|
||||||
}
|
}
|
||||||
callback?.invoke()
|
callback?.invoke()
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -892,7 +921,10 @@ fun Context.updateConversationArchivedStatus(threadId: Long, archived: Boolean)
|
||||||
try {
|
try {
|
||||||
contentResolver.update(uri, values, selection, selectionArgs)
|
contentResolver.update(uri, values, selection, selectionArgs)
|
||||||
} catch (sqliteException: SQLiteException) {
|
} catch (sqliteException: SQLiteException) {
|
||||||
if (sqliteException.message?.contains("no such column: archived") == true && config.isArchiveAvailable) {
|
if (
|
||||||
|
sqliteException.message?.contains("no such column: archived") == true
|
||||||
|
&& config.isArchiveAvailable
|
||||||
|
) {
|
||||||
config.isArchiveAvailable = false
|
config.isArchiveAvailable = false
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -976,7 +1008,7 @@ fun Context.updateUnreadCountBadge(conversations: List<Conversation>) {
|
||||||
fun Context.getThreadId(address: String): Long {
|
fun Context.getThreadId(address: String): Long {
|
||||||
return try {
|
return try {
|
||||||
Threads.getOrCreateThreadId(this, address)
|
Threads.getOrCreateThreadId(this, address)
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
0L
|
0L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -985,7 +1017,7 @@ fun Context.getThreadId(address: String): Long {
|
||||||
fun Context.getThreadId(addresses: Set<String>): Long {
|
fun Context.getThreadId(addresses: Set<String>): Long {
|
||||||
return try {
|
return try {
|
||||||
Threads.getOrCreateThreadId(this, addresses)
|
Threads.getOrCreateThreadId(this, addresses)
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
0L
|
0L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -995,7 +1027,7 @@ fun Context.showReceivedMessageNotification(
|
||||||
address: String,
|
address: String,
|
||||||
body: String,
|
body: String,
|
||||||
threadId: Long,
|
threadId: Long,
|
||||||
bitmap: Bitmap?
|
bitmap: Bitmap?,
|
||||||
) {
|
) {
|
||||||
val privateCursor = getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
|
val privateCursor = getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
|
|
@ -1055,7 +1087,7 @@ fun Context.getNotificationBitmap(photoUri: String): Bitmap? {
|
||||||
.apply(RequestOptions.circleCropTransform())
|
.apply(RequestOptions.circleCropTransform())
|
||||||
.into(size, size)
|
.into(size, size)
|
||||||
.get()
|
.get()
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1067,7 +1099,7 @@ fun Context.removeDiacriticsIfNeeded(text: String): String {
|
||||||
fun Context.getSmsDraft(threadId: Long): String {
|
fun Context.getSmsDraft(threadId: Long): String {
|
||||||
val draft = try {
|
val draft = try {
|
||||||
draftsDB.getDraftById(threadId)
|
draftsDB.getDraftById(threadId)
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1145,14 +1177,14 @@ fun Context.updateLastConversationMessage(threadIds: Iterable<Long>) {
|
||||||
val newConversation = getConversations(threadId)[0]
|
val newConversation = getConversations(threadId)[0]
|
||||||
insertOrUpdateConversation(newConversation)
|
insertOrUpdateConversation(newConversation)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getFileSizeFromUri(uri: Uri): Long {
|
fun Context.getFileSizeFromUri(uri: Uri): Long {
|
||||||
val assetFileDescriptor = try {
|
val assetFileDescriptor = try {
|
||||||
contentResolver.openAssetFileDescriptor(uri, "r")
|
contentResolver.openAssetFileDescriptor(uri, "r")
|
||||||
} catch (e: FileNotFoundException) {
|
} catch (_: FileNotFoundException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1205,12 +1237,14 @@ fun Context.subscriptionManagerCompat(): SubscriptionManager {
|
||||||
|
|
||||||
fun Context.insertOrUpdateConversation(
|
fun Context.insertOrUpdateConversation(
|
||||||
conversation: Conversation,
|
conversation: Conversation,
|
||||||
cachedConv: Conversation? = conversationsDB.getConversationWithThreadId(conversation.threadId)
|
cachedConv: Conversation? = conversationsDB.getConversationWithThreadId(conversation.threadId),
|
||||||
) {
|
) {
|
||||||
var updatedConv = conversation
|
var updatedConv = conversation
|
||||||
if (cachedConv != null && cachedConv.usesCustomTitle) {
|
if (cachedConv != null && cachedConv.usesCustomTitle) {
|
||||||
updatedConv =
|
updatedConv = updatedConv.copy(
|
||||||
updatedConv.copy(title = cachedConv.title, usesCustomTitle = cachedConv.usesCustomTitle)
|
title = cachedConv.title,
|
||||||
|
usesCustomTitle = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
conversationsDB.insertOrUpdate(updatedConv)
|
conversationsDB.insertOrUpdate(updatedConv)
|
||||||
}
|
}
|
||||||
|
|
@ -1228,12 +1262,16 @@ fun Context.renameConversation(conversation: Conversation, newTitle: String): Co
|
||||||
fun Context.createTemporaryThread(
|
fun Context.createTemporaryThread(
|
||||||
message: Message,
|
message: Message,
|
||||||
threadId: Long = generateRandomId(),
|
threadId: Long = generateRandomId(),
|
||||||
cachedConv: Conversation?
|
cachedConv: Conversation?,
|
||||||
) {
|
) {
|
||||||
val simpleContactHelper = SimpleContactsHelper(this)
|
val simpleContactHelper = SimpleContactsHelper(this)
|
||||||
val addresses = message.participants.getAddresses()
|
val addresses = message.participants.getAddresses()
|
||||||
val photoUri =
|
val photoUri = if (addresses.size == 1) {
|
||||||
if (addresses.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(addresses.first()) else ""
|
simpleContactHelper.getPhotoUriFromPhoneNumber(addresses.first())
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
val title = if (cachedConv != null && cachedConv.usesCustomTitle) {
|
val title = if (cachedConv != null && cachedConv.usesCustomTitle) {
|
||||||
cachedConv.title
|
cachedConv.title
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1286,5 +1324,6 @@ fun Context.clearExpiredScheduledMessages(threadId: Long, messagesToDelete: List
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getDefaultKeyboardHeight() =
|
fun Context.getDefaultKeyboardHeight(): Int {
|
||||||
resources.getDimensionPixelSize(R.dimen.default_keyboard_height)
|
return resources.getDimensionPixelSize(R.dimen.default_keyboard_height)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ class MessagesImporter(private val activity: SimpleActivity) {
|
||||||
|
|
||||||
val messages = if (isUpsideDownCakePlus()) {
|
val messages = if (isUpsideDownCakePlus()) {
|
||||||
deserializedList.map { message ->
|
deserializedList.map { message ->
|
||||||
// workaround for messages not being imported on Android 14 when the device has a different subscriptionId (see #191)
|
// workaround for messages not being imported on Android 14 when the device
|
||||||
|
// has a different subscriptionId (see #191)
|
||||||
when (message) {
|
when (message) {
|
||||||
is SmsBackup -> message.copy(subscriptionId = -1)
|
is SmsBackup -> message.copy(subscriptionId = -1)
|
||||||
is MmsBackup -> message.copy(subscriptionId = -1)
|
is MmsBackup -> message.copy(subscriptionId = -1)
|
||||||
|
|
@ -70,9 +71,9 @@ class MessagesImporter(private val activity: SimpleActivity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportMessagesDialog(activity, messages)
|
ImportMessagesDialog(activity, messages)
|
||||||
} catch (e: SerializationException) {
|
} catch (_: SerializationException) {
|
||||||
activity.toast(org.fossify.commons.R.string.invalid_file_format)
|
activity.toast(org.fossify.commons.R.string.invalid_file_format)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
activity.toast(org.fossify.commons.R.string.invalid_file_format)
|
activity.toast(org.fossify.commons.R.string.invalid_file_format)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
activity.showErrorToast(e)
|
activity.showErrorToast(e)
|
||||||
|
|
@ -201,7 +202,7 @@ class MessagesImporter(private val activity: SimpleActivity) {
|
||||||
private fun getInputStreamFromUri(uri: Uri): InputStream? {
|
private fun getInputStreamFromUri(uri: Uri): InputStream? {
|
||||||
return try {
|
return try {
|
||||||
activity.contentResolver.openInputStream(uri)
|
activity.contentResolver.openInputStream(uri)
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -209,14 +210,12 @@ class MessagesImporter(private val activity: SimpleActivity) {
|
||||||
private fun isFileXml(uri: Uri): Boolean {
|
private fun isFileXml(uri: Uri): Boolean {
|
||||||
val inputStream = getInputStreamFromUri(uri)
|
val inputStream = getInputStreamFromUri(uri)
|
||||||
return inputStream?.bufferedReader()?.use { reader ->
|
return inputStream?.bufferedReader()?.use { reader ->
|
||||||
reader.readLine()?.startsWith("<?xml") ?: false
|
reader.readLine()?.startsWith("<?xml") == true
|
||||||
} ?: false
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isXmlMimeType(mimeType: String): Boolean {
|
private fun isXmlMimeType(mimeType: String): Boolean {
|
||||||
return mimeType.equals("application/xml", ignoreCase = true) || mimeType.equals(
|
return mimeType.equals("application/xml", ignoreCase = true)
|
||||||
other = "text/xml",
|
|| mimeType.equals(other = "text/xml", ignoreCase = true)
|
||||||
ignoreCase = true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ eventbus = "3.3.1"
|
||||||
#Room
|
#Room
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
#Fossify
|
#Fossify
|
||||||
commons = "29e9b0d13e"
|
commons = "79b1077e39"
|
||||||
android-smsmms = "c3e678befd"
|
android-smsmms = "c3e678befd"
|
||||||
indicator-fast-scroll = "4524cd0b61"
|
indicator-fast-scroll = "4524cd0b61"
|
||||||
#Gradle
|
#Gradle
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue