diff --git a/data/src/main/java/com/moez/QKSMS/util/EmojiReactionUtils.kt b/data/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepositoryImpl.kt
similarity index 90%
rename from data/src/main/java/com/moez/QKSMS/util/EmojiReactionUtils.kt
rename to data/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepositoryImpl.kt
index 251a69bd..fd2eae4a 100644
--- a/data/src/main/java/com/moez/QKSMS/util/EmojiReactionUtils.kt
+++ b/data/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepositoryImpl.kt
@@ -16,65 +16,25 @@
* You should have received a copy of the GNU General Public License
* along with QUIK. If not, see .
*/
-package dev.octoshrimpy.quik.util
+package dev.octoshrimpy.quik.repository
import dev.octoshrimpy.quik.manager.KeyManager
import dev.octoshrimpy.quik.model.EmojiReaction
import dev.octoshrimpy.quik.model.Message
+import dev.octoshrimpy.quik.repository.EmojiReactionUtils.reactionPatterns
+import dev.octoshrimpy.quik.repository.EmojiReactionUtils.removalPatterns
import io.realm.Realm
import io.realm.Sort
import timber.log.Timber
+import javax.inject.Inject
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.iterator
-data class ParsedEmojiReaction(val emoji: String, val originalMessage: String, val isRemoval: Boolean = false)
-
-object EmojiReactionUtils {
-
- private fun tapback(emoji: String, isRemoval: Boolean = false): (MatchResult) -> ParsedEmojiReaction {
- return { match ->
- ParsedEmojiReaction(emoji, match.groupValues[1], isRemoval)
- }
- }
-
- val reactionPatterns: Map ParsedEmojiReaction?> = mapOf(
- // Google Messages - https://github.com/octoshrimpy/quik/issues/152#issuecomment-2330183516
- Regex("^\u200A\u200B(.+?)\u200B to \u201C\u200A(.+?)\u200A\u201D\u200A$") to { match ->
- ParsedEmojiReaction(match.groupValues[1], match.groupValues[2])
- },
- // iOS
- Regex("^Reacted (.+?) to \u201C(.+?)\u201D$") to { match ->
- if (match.groupValues[1] == "with a sticker")
- null
- else
- ParsedEmojiReaction(match.groupValues[1], match.groupValues[2])
- },
- // iOS tapbacks
- Regex("^Loved \u201C(.+?)\u201D$") to tapback("❤️"),
- Regex("^Liked \u201C(.+?)\u201D$") to tapback("👍"),
- Regex("^Disliked \u201C(.+?)\u201D$") to tapback("👎"),
- Regex("^Laughed at \u201C(.+?)\u201D$") to tapback("😂"),
- Regex("^Emphasized \u201C(.+?)\u201D$") to tapback("‼️"),
- Regex("^Questioned \u201C(.+?)\u201D$") to tapback("❓"),
- )
-
- val removalPatterns: Map ParsedEmojiReaction?> = mapOf(
- // Google Messages
- Regex("^\u200ARemoved \u200C(.+?)\u200C from \u201C\u200A(.+?)\u200A\u201D\u200A$") to { match ->
- ParsedEmojiReaction(match.groupValues[1], match.groupValues[2], isRemoval = true)
- },
- // iOS tapbacks
- Regex("^Removed a heart from \u201C(.+?)\u201D$") to tapback("❤️", true),
- Regex("^Removed a like from \u201C(.+?)\u201D$") to tapback("👍", true),
- Regex("^Removed a dislike from \u201C(.+?)\u201D$") to tapback("👎", true),
- Regex("^Removed a laugh from \u201C(.+?)\u201D$") to tapback("😂", true),
- Regex("^Removed an exclamation from \u201C(.+?)\u201D$") to tapback("‼️", true),
- Regex("^Removed a question mark from \u201C(.+?)\u201D$") to tapback("❓", true),
- // iOS emoji - keep this below tapbacks as this regex would otherwise also match the patterns above
- Regex("^Removed (.+?) from \u201C(.+?)\u201D$") to { match ->
- ParsedEmojiReaction(match.groupValues[1], match.groupValues[2], isRemoval = true)
- },
- )
-
- fun parseEmojiReaction(body: String): ParsedEmojiReaction? {
+class EmojiReactionRepositoryImpl @Inject constructor(
+ private val keyManager: KeyManager
+) : EmojiReactionRepository {
+ override fun parseEmojiReaction(body: String): ParsedEmojiReaction? {
val removal = parseRemoval(body)
if (removal != null) return removal
@@ -111,7 +71,7 @@ object EmojiReactionUtils {
* Search for messages in the same thread with matching text content
* We'll search recent messages first (within reasonable time window)
*/
- fun findTargetMessage(threadId: Long, originalMessageText: String, realm: Realm): Message? {
+ override fun findTargetMessage(threadId: Long, originalMessageText: String, realm: Realm): Message? {
val messages = realm.where(Message::class.java)
.equalTo("threadId", threadId)
.sort("date", Sort.DESCENDING)
@@ -158,11 +118,10 @@ object EmojiReactionUtils {
realm.insertOrUpdate(reactionMessage)
}
- fun saveEmojiReaction(
+ override fun saveEmojiReaction(
reactionMessage: Message,
parsedReaction: ParsedEmojiReaction,
targetMessage: Message?,
- keyManager: KeyManager,
realm: Realm,
) {
if (parsedReaction.isRemoval) {
@@ -191,4 +150,52 @@ object EmojiReactionUtils {
Timber.w("Saved emoji reaction without target message: ${reaction.emoji}")
}
}
+
+}
+
+object EmojiReactionUtils {
+ private fun tapback(emoji: String, isRemoval: Boolean = false): (MatchResult) -> ParsedEmojiReaction {
+ return { match ->
+ ParsedEmojiReaction(emoji, match.groupValues[1], isRemoval)
+ }
+ }
+
+ val reactionPatterns: Map ParsedEmojiReaction?> = mapOf(
+ // Google Messages - https://github.com/octoshrimpy/quik/issues/152#issuecomment-2330183516
+ Regex("^\u200A\u200B(.+?)\u200B to \u201C\u200A(.+?)\u200A\u201D\u200A$") to { match ->
+ ParsedEmojiReaction(match.groupValues[1], match.groupValues[2])
+ },
+ // iOS
+ Regex("^Reacted (.+?) to \u201C(.+?)\u201D$") to { match ->
+ if (match.groupValues[1] == "with a sticker")
+ null
+ else
+ ParsedEmojiReaction(match.groupValues[1], match.groupValues[2])
+ },
+ // iOS tapbacks
+ Regex("^Loved \u201C(.+?)\u201D$") to tapback("❤️"),
+ Regex("^Liked \u201C(.+?)\u201D$") to tapback("👍"),
+ Regex("^Disliked \u201C(.+?)\u201D$") to tapback("👎"),
+ Regex("^Laughed at \u201C(.+?)\u201D$") to tapback("😂"),
+ Regex("^Emphasized \u201C(.+?)\u201D$") to tapback("‼️"),
+ Regex("^Questioned \u201C(.+?)\u201D$") to tapback("❓"),
+ )
+
+ val removalPatterns: Map ParsedEmojiReaction?> = mapOf(
+ // Google Messages
+ Regex("^\u200ARemoved \u200C(.+?)\u200C from \u201C\u200A(.+?)\u200A\u201D\u200A$") to { match ->
+ ParsedEmojiReaction(match.groupValues[1], match.groupValues[2], isRemoval = true)
+ },
+ // iOS tapbacks
+ Regex("^Removed a heart from \u201C(.+?)\u201D$") to tapback("❤️", true),
+ Regex("^Removed a like from \u201C(.+?)\u201D$") to tapback("👍", true),
+ Regex("^Removed a dislike from \u201C(.+?)\u201D$") to tapback("👎", true),
+ Regex("^Removed a laugh from \u201C(.+?)\u201D$") to tapback("😂", true),
+ Regex("^Removed an exclamation from \u201C(.+?)\u201D$") to tapback("‼️", true),
+ Regex("^Removed a question mark from \u201C(.+?)\u201D$") to tapback("❓", true),
+ // iOS emoji - keep this below tapbacks as this regex would otherwise also match the patterns above
+ Regex("^Removed (.+?) from \u201C(.+?)\u201D$") to { match ->
+ ParsedEmojiReaction(match.groupValues[1], match.groupValues[2], isRemoval = true)
+ },
+ )
}
diff --git a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt
index 49d386ee..068b579d 100644
--- a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt
+++ b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt
@@ -57,7 +57,6 @@ import dev.octoshrimpy.quik.receiver.SendSmsReceiver
import dev.octoshrimpy.quik.receiver.SmsDeliveredReceiver
import dev.octoshrimpy.quik.receiver.SmsSentReceiver
import dev.octoshrimpy.quik.util.ImageUtils
-import dev.octoshrimpy.quik.util.EmojiReactionUtils
import dev.octoshrimpy.quik.util.PhoneNumberUtils
import dev.octoshrimpy.quik.util.Preferences
import dev.octoshrimpy.quik.util.tryOrNull
@@ -79,6 +78,7 @@ open class MessageRepositoryImpl @Inject constructor(
private val phoneNumberUtils: PhoneNumberUtils,
private val prefs: Preferences,
private val syncRepository: SyncRepository,
+ private val reactions: EmojiReactionRepository,
) : MessageRepository {
companion object {
@@ -765,19 +765,18 @@ open class MessageRepositoryImpl @Inject constructor(
}
managedMessage?.let { savedMessage ->
- val parsedReaction = EmojiReactionUtils.parseEmojiReaction(body)
+ val parsedReaction = reactions.parseEmojiReaction(body)
if (parsedReaction != null) {
- val targetMessage = EmojiReactionUtils.findTargetMessage(
+ val targetMessage = reactions.findTargetMessage(
savedMessage.threadId,
parsedReaction.originalMessage,
realm
)
realm.executeTransaction {
- EmojiReactionUtils.saveEmojiReaction(
+ reactions.saveEmojiReaction(
savedMessage,
parsedReaction,
targetMessage,
- messageIds,
realm,
)
}
diff --git a/data/src/main/java/com/moez/QKSMS/repository/SyncRepositoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/SyncRepositoryImpl.kt
index a7e8fe9f..5241c957 100644
--- a/data/src/main/java/com/moez/QKSMS/repository/SyncRepositoryImpl.kt
+++ b/data/src/main/java/com/moez/QKSMS/repository/SyncRepositoryImpl.kt
@@ -45,7 +45,6 @@ import dev.octoshrimpy.quik.model.MmsPart
import dev.octoshrimpy.quik.model.PhoneNumber
import dev.octoshrimpy.quik.model.Recipient
import dev.octoshrimpy.quik.model.SyncLog
-import dev.octoshrimpy.quik.util.EmojiReactionUtils
import dev.octoshrimpy.quik.util.PhoneNumberUtils
import dev.octoshrimpy.quik.util.tryOrNull
import io.reactivex.subjects.BehaviorSubject
@@ -70,7 +69,8 @@ class SyncRepositoryImpl @Inject constructor(
private val cursorToContactGroupMember: CursorToContactGroupMember,
private val keys: KeyManager,
private val phoneNumberUtils: PhoneNumberUtils,
- private val rxPrefs: RxSharedPreferences
+ private val rxPrefs: RxSharedPreferences,
+ private val reactions: EmojiReactionRepository,
) : SyncRepository {
override val syncProgress: Subject =
@@ -248,18 +248,17 @@ class SyncRepositoryImpl @Inject constructor(
allMessages.forEach { message ->
val text = message.getText(false)
- val parsedReaction = EmojiReactionUtils.parseEmojiReaction(text)
+ val parsedReaction = reactions.parseEmojiReaction(text)
if (parsedReaction != null) {
- val targetMessage = EmojiReactionUtils.findTargetMessage(
+ val targetMessage = reactions.findTargetMessage(
message.threadId,
parsedReaction.originalMessage,
realm
)
- EmojiReactionUtils.saveEmojiReaction(
+ reactions.saveEmojiReaction(
message,
parsedReaction,
targetMessage,
- keys,
realm,
)
}
@@ -326,20 +325,19 @@ class SyncRepositoryImpl @Inject constructor(
insertOrUpdate()
val text = getText(false)
- val parsedReaction = EmojiReactionUtils.parseEmojiReaction(text)
+ val parsedReaction = reactions.parseEmojiReaction(text)
if (parsedReaction != null) {
Realm.getDefaultInstance().use { realm ->
- val targetMessage = EmojiReactionUtils.findTargetMessage(
+ val targetMessage = reactions.findTargetMessage(
threadId,
parsedReaction.originalMessage,
realm
)
realm.executeTransaction {
- EmojiReactionUtils.saveEmojiReaction(
+ reactions.saveEmojiReaction(
this,
parsedReaction,
targetMessage,
- keys,
realm,
)
}
diff --git a/domain/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepository.kt b/domain/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepository.kt
new file mode 100644
index 00000000..d327863c
--- /dev/null
+++ b/domain/src/main/java/com/moez/QKSMS/repository/EmojiReactionRepository.kt
@@ -0,0 +1,19 @@
+package dev.octoshrimpy.quik.repository
+
+import dev.octoshrimpy.quik.model.Message
+import io.realm.Realm
+
+data class ParsedEmojiReaction(val emoji: String, val originalMessage: String, val isRemoval: Boolean = false)
+
+interface EmojiReactionRepository {
+ fun parseEmojiReaction(body: String): ParsedEmojiReaction?
+
+ fun findTargetMessage(threadId: Long, originalMessageText: String, realm: Realm): Message?
+
+ fun saveEmojiReaction(
+ reactionMessage: Message,
+ parsedReaction: ParsedEmojiReaction,
+ targetMessage: Message?,
+ realm: Realm,
+ )
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt b/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt
index 8a1d35b2..8d52fe2f 100644
--- a/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt
+++ b/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt
@@ -81,6 +81,8 @@ import dev.octoshrimpy.quik.repository.ContactRepository
import dev.octoshrimpy.quik.repository.ContactRepositoryImpl
import dev.octoshrimpy.quik.repository.ConversationRepository
import dev.octoshrimpy.quik.repository.ConversationRepositoryImpl
+import dev.octoshrimpy.quik.repository.EmojiReactionRepository
+import dev.octoshrimpy.quik.repository.EmojiReactionRepositoryImpl
import dev.octoshrimpy.quik.repository.MessageContentFilterRepository
import dev.octoshrimpy.quik.repository.MessageContentFilterRepositoryImpl
import dev.octoshrimpy.quik.repository.MessageRepository
@@ -219,6 +221,9 @@ class AppModule(private var application: Application) {
@Provides
fun provideSyncRepository(repository: SyncRepositoryImpl): SyncRepository = repository
+ @Provides
+ fun provideEmojiReactionRepository(repository: EmojiReactionRepositoryImpl): EmojiReactionRepository = repository
+
// worker factory
@Provides
fun provideWorkerFactory(workerFactory: InjectionWorkerFactory): WorkerFactory = workerFactory