forked from upstream-mirrors/quik
0c3fc6c8a7
* Pulled over SIA code from 2.7.3 * Eliminate unnecessary service, fix service binding * Flatten logic in isBlocked * Return single which emits shouldBlock state * Mark conversation as blocked during sync
645 lines
24 KiB
Kotlin
645 lines
24 KiB
Kotlin
/*
|
|
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
|
*
|
|
* This file is part of QKSMS.
|
|
*
|
|
* QKSMS is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* QKSMS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package repository
|
|
|
|
import android.app.PendingIntent
|
|
import android.content.ContentUris
|
|
import android.content.ContentValues
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.net.Uri
|
|
import android.provider.BaseColumns
|
|
import android.provider.Telephony
|
|
import android.telephony.PhoneNumberUtils
|
|
import android.telephony.SmsManager
|
|
import com.klinker.android.send_message.BroadcastUtils
|
|
import com.klinker.android.send_message.StripAccents
|
|
import io.reactivex.Flowable
|
|
import io.reactivex.Maybe
|
|
import io.reactivex.Observable
|
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
import io.reactivex.schedulers.Schedulers
|
|
import io.realm.Realm
|
|
import io.realm.RealmResults
|
|
import io.realm.Sort
|
|
import manager.ExternalBlockingManager
|
|
import manager.KeyManager
|
|
import mapper.CursorToConversation
|
|
import mapper.CursorToRecipient
|
|
import model.Contact
|
|
import model.Conversation
|
|
import model.Message
|
|
import model.MmsPart
|
|
import util.MessageUtils
|
|
import util.Preferences
|
|
import util.extensions.asFlowable
|
|
import util.extensions.asMaybe
|
|
import util.extensions.asObservable
|
|
import util.extensions.insertOrUpdate
|
|
import util.extensions.map
|
|
import javax.inject.Inject
|
|
import javax.inject.Singleton
|
|
|
|
@Singleton
|
|
class MessageRepositoryImpl @Inject constructor(
|
|
private val context: Context,
|
|
private val messageIds: KeyManager,
|
|
private val cursorToConversation: CursorToConversation,
|
|
private val cursorToRecipient: CursorToRecipient,
|
|
private val externalBlockingManager: ExternalBlockingManager,
|
|
private val prefs: Preferences) : MessageRepository {
|
|
|
|
override fun getConversations(archived: Boolean): Flowable<List<Conversation>> {
|
|
val realm = Realm.getDefaultInstance()
|
|
return realm
|
|
.where(Conversation::class.java)
|
|
.notEqualTo("id", 0L)
|
|
.greaterThan("count", 0)
|
|
.equalTo("archived", archived)
|
|
.equalTo("blocked", false)
|
|
.isNotEmpty("recipients")
|
|
.sort("date", Sort.DESCENDING)
|
|
.findAllAsync()
|
|
.asFlowable()
|
|
.filter { it.isLoaded }
|
|
.filter { it.isValid }
|
|
.map { conversations -> realm.copyFromRealm(conversations) }
|
|
}
|
|
|
|
override fun getConversationsSnapshot(): List<Conversation> {
|
|
val realm = Realm.getDefaultInstance()
|
|
return realm.copyFromRealm(realm.where(Conversation::class.java)
|
|
.notEqualTo("id", 0L)
|
|
.greaterThan("count", 0)
|
|
.equalTo("archived", false)
|
|
.equalTo("blocked", false)
|
|
.isNotEmpty("recipients")
|
|
.sort("date", Sort.DESCENDING)
|
|
.findAll())
|
|
}
|
|
|
|
override fun getBlockedConversations(): Flowable<List<Conversation>> {
|
|
return Realm.getDefaultInstance()
|
|
.where(Conversation::class.java)
|
|
.equalTo("blocked", true)
|
|
.findAllAsync()
|
|
.asFlowable()
|
|
.filter { it.isLoaded }
|
|
.map { it.toList() }
|
|
}
|
|
|
|
override fun getConversationAsync(threadId: Long): Conversation {
|
|
return Realm.getDefaultInstance()
|
|
.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirstAsync()
|
|
}
|
|
|
|
override fun getConversation(threadId: Long): Conversation? {
|
|
return Realm.getDefaultInstance()
|
|
.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
}
|
|
|
|
override fun getOrCreateConversation(threadId: Long): Conversation? {
|
|
return getConversation(threadId) ?: getConversationFromCp(threadId)
|
|
}
|
|
|
|
override fun getOrCreateConversation(address: String): Maybe<Conversation> {
|
|
return getOrCreateConversation(listOf(address))
|
|
}
|
|
|
|
override fun getOrCreateConversation(addresses: List<String>): Maybe<Conversation> {
|
|
return Maybe.just(addresses)
|
|
.map { recipients ->
|
|
recipients.map { address ->
|
|
when (MessageUtils.isEmailAddress(address)) {
|
|
true -> MessageUtils.extractAddrSpec(address)
|
|
false -> address
|
|
}
|
|
}
|
|
}
|
|
.map { recipients ->
|
|
Uri.parse("content://mms-sms/threadID").buildUpon().apply {
|
|
recipients.forEach { recipient -> appendQueryParameter("recipient", recipient) }
|
|
}
|
|
}
|
|
.flatMap { uriBuilder ->
|
|
context.contentResolver.query(uriBuilder.build(), arrayOf(BaseColumns._ID), null, null, null).asMaybe()
|
|
}
|
|
.map { cursor -> cursor.getLong(0) }
|
|
.filter { threadId -> threadId != 0L }
|
|
.map { threadId ->
|
|
var conversation = getConversation(threadId)
|
|
if (conversation != null) conversation = Realm.getDefaultInstance().copyFromRealm(conversation)
|
|
|
|
conversation ?: getConversationFromCp(threadId)?.apply { insertOrUpdate() } ?: Conversation()
|
|
}
|
|
.onErrorReturn { Conversation() }
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
}
|
|
|
|
override fun saveDraft(threadId: Long, draft: String) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
val conversation = realm.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
|
|
conversation?.let {
|
|
realm.executeTransaction {
|
|
conversation.draft = draft
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getMessages(threadId: Long): RealmResults<Message> {
|
|
return Realm.getDefaultInstance()
|
|
.where(Message::class.java)
|
|
.equalTo("threadId", threadId)
|
|
.sort("date")
|
|
.findAllAsync()
|
|
}
|
|
|
|
override fun getMessage(id: Long): Message? {
|
|
return Realm.getDefaultInstance()
|
|
.where(Message::class.java)
|
|
.equalTo("id", id)
|
|
.findFirst()
|
|
}
|
|
|
|
override fun getMessageForPart(id: Long): Message? {
|
|
return Realm.getDefaultInstance()
|
|
.where(Message::class.java)
|
|
.equalTo("parts.id", id)
|
|
.findFirst()
|
|
}
|
|
|
|
override fun getUnreadCount(): Long {
|
|
return Realm.getDefaultInstance()
|
|
.where(Conversation::class.java)
|
|
.equalTo("read", false)
|
|
.count()
|
|
}
|
|
|
|
override fun getPart(id: Long): MmsPart? {
|
|
return Realm.getDefaultInstance()
|
|
.where(MmsPart::class.java)
|
|
.equalTo("id", id)
|
|
.findFirst()
|
|
}
|
|
|
|
override fun getPartsForConversation(threadId: Long): Observable<List<MmsPart>> {
|
|
return Realm.getDefaultInstance()
|
|
.where(Message::class.java)
|
|
.equalTo("threadId", threadId)
|
|
.isNotEmpty("parts")
|
|
.sort("date")
|
|
.findAll()
|
|
.asObservable()
|
|
.map { messages -> messages.flatMap { it.parts } }
|
|
}
|
|
|
|
/**
|
|
* Retrieves the list of messages which should be shown in the notification
|
|
* for a given conversation
|
|
*/
|
|
override fun getUnreadUnseenMessages(threadId: Long): RealmResults<Message> {
|
|
return Realm.getDefaultInstance()
|
|
.also { it.refresh() }
|
|
.where(Message::class.java)
|
|
.equalTo("seen", false)
|
|
.equalTo("read", false)
|
|
.equalTo("threadId", threadId)
|
|
.sort("date")
|
|
.findAll()
|
|
}
|
|
|
|
override fun getUnreadMessages(threadId: Long): RealmResults<Message> {
|
|
return Realm.getDefaultInstance()
|
|
.where(Message::class.java)
|
|
.equalTo("read", false)
|
|
.equalTo("threadId", threadId)
|
|
.sort("date")
|
|
.findAll()
|
|
}
|
|
|
|
override fun updateConversation(threadId: Long) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val conversation = realm
|
|
.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst() ?: return
|
|
|
|
val messages = realm
|
|
.where(Message::class.java)
|
|
.equalTo("threadId", threadId)
|
|
.sort("date", Sort.DESCENDING)
|
|
.findAll()
|
|
|
|
val message = messages.firstOrNull()
|
|
|
|
realm.executeTransaction {
|
|
conversation.count = messages.size
|
|
conversation.date = message?.date ?: 0
|
|
conversation.snippet = message?.getSummary() ?: ""
|
|
conversation.read = message?.read ?: true
|
|
conversation.me = message?.isMe() ?: false
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun markArchived(threadId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
val conversation = realm.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
|
|
realm.executeTransaction { conversation?.archived = true }
|
|
realm.close()
|
|
}
|
|
|
|
override fun markUnarchived(threadId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
val conversation = realm.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
|
|
realm.executeTransaction { conversation?.archived = false }
|
|
realm.close()
|
|
}
|
|
|
|
override fun markBlocked(threadId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
val conversation = realm.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
|
|
realm.executeTransaction { conversation?.blocked = true }
|
|
realm.close()
|
|
}
|
|
|
|
override fun markUnblocked(threadId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
val conversation = realm.where(Conversation::class.java)
|
|
.equalTo("id", threadId)
|
|
.findFirst()
|
|
|
|
realm.executeTransaction { conversation?.blocked = false }
|
|
realm.close()
|
|
}
|
|
|
|
override fun markAllSeen() {
|
|
val realm = Realm.getDefaultInstance()
|
|
val messages = realm.where(Message::class.java).equalTo("seen", false).findAll()
|
|
realm.executeTransaction { messages.forEach { message -> message.seen = true } }
|
|
realm.close()
|
|
}
|
|
|
|
override fun markSeen(threadId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
val messages = realm.where(Message::class.java)
|
|
.equalTo("threadId", threadId)
|
|
.equalTo("seen", false)
|
|
.findAll()
|
|
|
|
realm.executeTransaction {
|
|
messages.forEach { message ->
|
|
message.seen = true
|
|
}
|
|
}
|
|
realm.close()
|
|
}
|
|
|
|
override fun markRead(threadId: Long) {
|
|
// TODO also need to mark MMS in ContentProvider as Read
|
|
val projection = arrayOf(BaseColumns._ID)
|
|
val selection = "${Telephony.Sms.THREAD_ID} = $threadId AND (${Telephony.Sms.SEEN} = 0 OR ${Telephony.Sms.READ} = 0)"
|
|
val contentResolver = context.contentResolver
|
|
contentResolver.query(Telephony.Sms.Inbox.CONTENT_URI, projection, selection, null, null)
|
|
.asFlowable()
|
|
.subscribeOn(Schedulers.io())
|
|
.map { cursor -> cursor.getLong(0) }
|
|
.map { id -> Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, id.toString()) }
|
|
.subscribe { uri ->
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.SEEN, true)
|
|
values.put(Telephony.Sms.READ, true)
|
|
contentResolver.update(uri, values, null, null)
|
|
}
|
|
|
|
|
|
val realm = Realm.getDefaultInstance()
|
|
val messages = realm.where(Message::class.java)
|
|
.equalTo("threadId", threadId)
|
|
.beginGroup()
|
|
.equalTo("read", false)
|
|
.or()
|
|
.equalTo("seen", false)
|
|
.endGroup()
|
|
.findAll()
|
|
|
|
realm.executeTransaction {
|
|
messages.forEach { message ->
|
|
message.seen = true
|
|
message.read = true
|
|
}
|
|
}
|
|
realm.close()
|
|
}
|
|
|
|
override fun sendSmsAndPersist(threadId: Long, address: String, body: String) {
|
|
val message = insertSentSms(threadId, address, body)
|
|
sendSms(message)
|
|
}
|
|
|
|
override fun sendSms(message: Message) {
|
|
val smsManager = SmsManager.getDefault()
|
|
|
|
val parts = smsManager.divideMessage(if (prefs.unicode.get()) StripAccents.stripAccents(message.body) else message.body)
|
|
|
|
val sentIntents = parts.map {
|
|
val action = "com.moez.QKSMS.SMS_SENT"
|
|
val intent = Intent(action).putExtra("id", message.id)
|
|
BroadcastUtils.addClassName(context, intent, action)
|
|
PendingIntent.getBroadcast(context, message.id.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
|
}
|
|
|
|
val deliveredIntents = parts.map {
|
|
val action = "com.moez.QKSMS.SMS_DELIVERED"
|
|
val intent = Intent(action).putExtra("id", message.id)
|
|
BroadcastUtils.addClassName(context, intent, action)
|
|
val pendingIntent = PendingIntent.getBroadcast(context, message.id.toInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
|
if (prefs.delivery.get()) pendingIntent else null
|
|
}
|
|
|
|
smsManager.sendMultipartTextMessage(message.address, null, parts, ArrayList(sentIntents), ArrayList(deliveredIntents))
|
|
}
|
|
|
|
override fun insertSentSms(threadId: Long, address: String, body: String): Message {
|
|
|
|
// Insert the message to Realm
|
|
val message = Message().apply {
|
|
this.threadId = threadId
|
|
this.address = address
|
|
this.body = body
|
|
this.date = System.currentTimeMillis()
|
|
|
|
id = messageIds.newId()
|
|
boxId = Telephony.Sms.MESSAGE_TYPE_OUTBOX
|
|
type = "sms"
|
|
read = true
|
|
seen = true
|
|
}
|
|
val realm = Realm.getDefaultInstance()
|
|
var managedMessage: Message? = null
|
|
realm.executeTransaction { managedMessage = realm.copyToRealmOrUpdate(message) }
|
|
|
|
// Insert the message to the native content provider
|
|
val values = ContentValues().apply {
|
|
put(Telephony.Sms.ADDRESS, address)
|
|
put(Telephony.Sms.BODY, body)
|
|
put(Telephony.Sms.DATE, System.currentTimeMillis())
|
|
put(Telephony.Sms.READ, true)
|
|
put(Telephony.Sms.SEEN, true)
|
|
put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_OUTBOX)
|
|
put(Telephony.Sms.THREAD_ID, threadId)
|
|
}
|
|
val uri = context.contentResolver.insert(Telephony.Sms.CONTENT_URI, values)
|
|
|
|
// Update the contentId after the message has been inserted to the content provider
|
|
realm.executeTransaction { managedMessage?.contentId = uri.lastPathSegment.toLong() }
|
|
realm.close()
|
|
|
|
return message
|
|
}
|
|
|
|
override fun insertReceivedSms(address: String, body: String, sentTime: Long): Message {
|
|
|
|
// Insert the message to Realm
|
|
val message = Message().apply {
|
|
this.address = address
|
|
this.body = body
|
|
this.dateSent = sentTime
|
|
this.date = System.currentTimeMillis()
|
|
|
|
id = messageIds.newId()
|
|
threadId = getOrCreateConversation(address).blockingGet().id
|
|
boxId = Telephony.Sms.MESSAGE_TYPE_INBOX
|
|
type = "sms"
|
|
}
|
|
val realm = Realm.getDefaultInstance()
|
|
var managedMessage: Message? = null
|
|
realm.executeTransaction { managedMessage = realm.copyToRealmOrUpdate(message) }
|
|
|
|
// Insert the message to the native content provider
|
|
val values = ContentValues().apply {
|
|
put(Telephony.Sms.ADDRESS, address)
|
|
put(Telephony.Sms.BODY, body)
|
|
put(Telephony.Sms.DATE_SENT, sentTime)
|
|
}
|
|
val uri = context.contentResolver.insert(Telephony.Sms.Inbox.CONTENT_URI, values)
|
|
|
|
// Update the contentId after the message has been inserted to the content provider
|
|
realm.executeTransaction { managedMessage?.contentId = uri.lastPathSegment.toLong() }
|
|
realm.close()
|
|
|
|
return message
|
|
}
|
|
|
|
/**
|
|
* Marks the message as sending, in case we need to retry sending it
|
|
*/
|
|
override fun markSending(id: Long) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val message = realm.where(Message::class.java).equalTo("id", id).findFirst()
|
|
message?.let {
|
|
// Update the message in realm
|
|
realm.executeTransaction {
|
|
message.boxId = Telephony.Sms.MESSAGE_TYPE_OUTBOX
|
|
}
|
|
|
|
// Update the message in the native ContentProvider
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_OUTBOX)
|
|
context.contentResolver.update(message.getUri(), values, null, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun markSent(id: Long) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val message = realm.where(Message::class.java).equalTo("id", id).findFirst()
|
|
message?.let {
|
|
// Update the message in realm
|
|
realm.executeTransaction {
|
|
message.boxId = Telephony.Sms.MESSAGE_TYPE_SENT
|
|
}
|
|
|
|
// Update the message in the native ContentProvider
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_SENT)
|
|
context.contentResolver.update(message.getUri(), values, null, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun markFailed(id: Long, resultCode: Int) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val message = realm.where(Message::class.java).equalTo("id", id).findFirst()
|
|
message?.let {
|
|
// Update the message in realm
|
|
realm.executeTransaction {
|
|
message.boxId = Telephony.Sms.MESSAGE_TYPE_FAILED
|
|
message.errorCode = resultCode
|
|
}
|
|
|
|
// Update the message in the native ContentProvider
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_FAILED)
|
|
values.put(Telephony.Sms.ERROR_CODE, resultCode)
|
|
context.contentResolver.update(message.getUri(), values, null, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun markDelivered(id: Long) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val message = realm.where(Message::class.java).equalTo("id", id).findFirst()
|
|
message?.let {
|
|
// Update the message in realm
|
|
realm.executeTransaction {
|
|
message.deliveryStatus = Telephony.Sms.STATUS_COMPLETE
|
|
message.dateSent = System.currentTimeMillis()
|
|
message.read = true
|
|
}
|
|
|
|
// Update the message in the native ContentProvider
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_COMPLETE)
|
|
values.put(Telephony.Sms.DATE_SENT, System.currentTimeMillis())
|
|
values.put(Telephony.Sms.READ, true)
|
|
context.contentResolver.update(message.getUri(), values, null, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun markDeliveryFailed(id: Long, resultCode: Int) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
realm.refresh()
|
|
|
|
val message = realm.where(Message::class.java).equalTo("id", id).findFirst()
|
|
message?.let {
|
|
// Update the message in realm
|
|
realm.executeTransaction {
|
|
message.deliveryStatus = Telephony.Sms.STATUS_FAILED
|
|
message.dateSent = System.currentTimeMillis()
|
|
message.read = true
|
|
message.errorCode = resultCode
|
|
}
|
|
|
|
// Update the message in the native ContentProvider
|
|
val values = ContentValues()
|
|
values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_FAILED)
|
|
values.put(Telephony.Sms.DATE_SENT, System.currentTimeMillis())
|
|
values.put(Telephony.Sms.READ, true)
|
|
values.put(Telephony.Sms.ERROR_CODE, resultCode)
|
|
context.contentResolver.update(message.getUri(), values, null, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun deleteMessage(messageId: Long) {
|
|
val realm = Realm.getDefaultInstance()
|
|
realm.where(Message::class.java).equalTo("id", messageId).findFirst()?.let { message ->
|
|
val uri = message.getUri()
|
|
realm.executeTransaction { message.deleteFromRealm() }
|
|
context.contentResolver.delete(uri, null, null)
|
|
}
|
|
realm.close()
|
|
}
|
|
|
|
override fun deleteConversation(threadId: Long) {
|
|
Realm.getDefaultInstance().use { realm ->
|
|
val conversation = realm.where(Conversation::class.java).equalTo("id", threadId).findAll()
|
|
val messages = realm.where(Message::class.java).equalTo("threadId", threadId).findAll()
|
|
|
|
realm.executeTransaction {
|
|
conversation.deleteAllFromRealm()
|
|
messages.deleteAllFromRealm()
|
|
}
|
|
}
|
|
|
|
val uri = ContentUris.withAppendedId(Telephony.Threads.CONTENT_URI, threadId)
|
|
context.contentResolver.delete(uri, null, null)
|
|
}
|
|
|
|
private fun getConversationFromCp(threadId: Long): Conversation? {
|
|
var conversation: Conversation? = null
|
|
|
|
val cursor = cursorToConversation.getConversationCursor(threadId)
|
|
|
|
if (cursor.moveToFirst()) {
|
|
conversation = cursorToConversation.map(cursor)
|
|
|
|
val realm = Realm.getDefaultInstance()
|
|
val contacts = realm.copyFromRealm(realm.where(Contact::class.java).findAll())
|
|
|
|
val recipients = conversation.recipients
|
|
.map { recipient -> recipient.id }
|
|
.map { id -> cursorToRecipient.getRecipientCursor(id) }
|
|
.map { recipientCursor -> recipientCursor.map { cursorToRecipient.map(recipientCursor) } }
|
|
.flatten()
|
|
.map { recipient ->
|
|
recipient.apply {
|
|
contact = contacts.firstOrNull {
|
|
it.numbers.any { PhoneNumberUtils.compare(recipient.address, it.address) }
|
|
}
|
|
}
|
|
}
|
|
|
|
// If any of the addresses here should be blocked, then block the conversation
|
|
conversation.blocked = recipients.map { it.address }.any { address ->
|
|
externalBlockingManager.shouldBlock(address).blockingGet()
|
|
}
|
|
|
|
conversation.recipients.clear()
|
|
conversation.recipients.addAll(recipients)
|
|
conversation.insertOrUpdate()
|
|
realm.close()
|
|
}
|
|
|
|
cursor.close()
|
|
|
|
return conversation
|
|
}
|
|
|
|
} |