mirror of
https://github.com/quik-sms/quik.git
synced 2026-11-15 10:38:53 +01:00
move emoji reaction code to repo and impl
This commit is contained in:
+61
-54
@@ -16,65 +16,25 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QUIK. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Regex, (MatchResult) -> 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<Regex, (MatchResult) -> 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<Regex, (MatchResult) -> 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<Regex, (MatchResult) -> 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)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<SyncRepository.SyncProgress> =
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user