mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-13 05:37:48 +02:00
event dispatcher
This commit is contained in:
37
core/src/main/kotlin/me/rhunk/snapenhance/EventDispatcher.kt
Normal file
37
core/src/main/kotlin/me/rhunk/snapenhance/EventDispatcher.kt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package me.rhunk.snapenhance
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.event.impl.OnSnapInteractionEvent
|
||||||
|
import me.rhunk.snapenhance.core.event.impl.SendMessageWithContentEvent
|
||||||
|
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
||||||
|
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
||||||
|
import me.rhunk.snapenhance.hook.HookStage
|
||||||
|
import me.rhunk.snapenhance.hook.hook
|
||||||
|
import me.rhunk.snapenhance.manager.Manager
|
||||||
|
|
||||||
|
class EventDispatcher(
|
||||||
|
private val context: ModContext
|
||||||
|
) : Manager {
|
||||||
|
override fun init() {
|
||||||
|
context.classCache.conversationManager.hook("sendMessageWithContent", HookStage.BEFORE) { param ->
|
||||||
|
val messageContent = MessageContent(param.arg(1))
|
||||||
|
context.event.post(SendMessageWithContentEvent(messageContent))?.let {
|
||||||
|
if (it.canceled) {
|
||||||
|
param.setResult(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.classCache.snapManager.hook("onSnapInteraction", HookStage.BEFORE) { param ->
|
||||||
|
val conversationId = SnapUUID(param.arg(1))
|
||||||
|
val messageId = param.arg<Long>(2)
|
||||||
|
context.event.post(OnSnapInteractionEvent(
|
||||||
|
conversationId = conversationId,
|
||||||
|
messageId = messageId
|
||||||
|
))?.let {
|
||||||
|
if (it.canceled) {
|
||||||
|
param.setResult(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
|
|||||||
import me.rhunk.snapenhance.bridge.BridgeClient
|
import me.rhunk.snapenhance.bridge.BridgeClient
|
||||||
import me.rhunk.snapenhance.bridge.wrapper.TranslationWrapper
|
import me.rhunk.snapenhance.bridge.wrapper.TranslationWrapper
|
||||||
import me.rhunk.snapenhance.core.config.ModConfig
|
import me.rhunk.snapenhance.core.config.ModConfig
|
||||||
|
import me.rhunk.snapenhance.core.event.EventBus
|
||||||
import me.rhunk.snapenhance.data.MessageSender
|
import me.rhunk.snapenhance.data.MessageSender
|
||||||
import me.rhunk.snapenhance.database.DatabaseAccess
|
import me.rhunk.snapenhance.database.DatabaseAccess
|
||||||
import me.rhunk.snapenhance.features.Feature
|
import me.rhunk.snapenhance.features.Feature
|
||||||
@ -41,6 +42,8 @@ class ModContext {
|
|||||||
|
|
||||||
private val modConfig = ModConfig()
|
private val modConfig = ModConfig()
|
||||||
val config by modConfig
|
val config by modConfig
|
||||||
|
val event = EventBus(this)
|
||||||
|
val eventDispatcher = EventDispatcher(this)
|
||||||
|
|
||||||
val translation = TranslationWrapper()
|
val translation = TranslationWrapper()
|
||||||
val features = FeatureManager(this)
|
val features = FeatureManager(this)
|
||||||
|
@ -99,6 +99,7 @@ class SnapEnhance {
|
|||||||
with(appContext) {
|
with(appContext) {
|
||||||
reloadConfig()
|
reloadConfig()
|
||||||
mappings.init()
|
mappings.init()
|
||||||
|
eventDispatcher.init()
|
||||||
//if mappings aren't loaded, we can't initialize features
|
//if mappings aren't loaded, we can't initialize features
|
||||||
if (!mappings.areMappingsLoaded) return
|
if (!mappings.areMappingsLoaded) return
|
||||||
features.init()
|
features.init()
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package me.rhunk.snapenhance.event
|
package me.rhunk.snapenhance.core.event
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.Logger
|
||||||
import me.rhunk.snapenhance.ModContext
|
import me.rhunk.snapenhance.ModContext
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
abstract class Event {
|
abstract class Event {
|
||||||
lateinit var context: ModContext
|
lateinit var context: ModContext
|
||||||
|
var canceled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IListener<T> {
|
interface IListener<T> {
|
||||||
@ -23,12 +25,14 @@ class EventBus(
|
|||||||
subscribers[event]!!.add(listener)
|
subscribers[event]!!.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Event> subscribe(event: KClass<T>, listener: (T) -> Unit) {
|
inline fun <T : Event> subscribe(event: KClass<T>, crossinline listener: (T) -> Unit): () -> Unit {
|
||||||
subscribe(event, object : IListener<T> {
|
val obj = object : IListener<T> {
|
||||||
override fun handle(event: T) {
|
override fun handle(event: T) {
|
||||||
listener(event)
|
listener(event)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
subscribe(event, obj)
|
||||||
|
return { unsubscribe(event, obj) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Event> unsubscribe(event: KClass<T>, listener: IListener<T>) {
|
fun <T : Event> unsubscribe(event: KClass<T>, listener: IListener<T>) {
|
||||||
@ -38,22 +42,22 @@ class EventBus(
|
|||||||
subscribers[event]!!.remove(listener)
|
subscribers[event]!!.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Event> post(event: T) {
|
fun <T : Event> post(event: T): T? {
|
||||||
if (!subscribers.containsKey(event::class)) {
|
if (!subscribers.containsKey(event::class)) {
|
||||||
return
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
event.context = context
|
event.context = context
|
||||||
|
|
||||||
subscribers[event::class]!!.forEach { listener ->
|
subscribers[event::class]?.forEach { listener ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
try {
|
runCatching {
|
||||||
(listener as IListener<T>).handle(event)
|
(listener as IListener<T>).handle(event)
|
||||||
} catch (t: Throwable) {
|
}.onFailure { t ->
|
||||||
println("Error while handling event ${event::class.simpleName} by ${listener::class.simpleName}")
|
Logger.error("Error while handling event ${event::class.simpleName} by ${listener::class.simpleName}", t)
|
||||||
t.printStackTrace()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
@ -0,0 +1,9 @@
|
|||||||
|
package me.rhunk.snapenhance.core.event.impl
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.event.Event
|
||||||
|
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
||||||
|
|
||||||
|
class OnSnapInteractionEvent(
|
||||||
|
val conversationId: SnapUUID,
|
||||||
|
val messageId: Long
|
||||||
|
) : Event()
|
@ -0,0 +1,8 @@
|
|||||||
|
package me.rhunk.snapenhance.core.event.impl
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.event.Event
|
||||||
|
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
||||||
|
|
||||||
|
class SendMessageWithContentEvent(
|
||||||
|
val messageContent: MessageContent
|
||||||
|
) : Event()
|
@ -1,3 +0,0 @@
|
|||||||
package me.rhunk.snapenhance.event
|
|
||||||
|
|
||||||
//TODO: addView event
|
|
@ -1,5 +1,6 @@
|
|||||||
package me.rhunk.snapenhance.features.impl
|
package me.rhunk.snapenhance.features.impl
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.event.impl.OnSnapInteractionEvent
|
||||||
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
||||||
import me.rhunk.snapenhance.features.Feature
|
import me.rhunk.snapenhance.features.Feature
|
||||||
import me.rhunk.snapenhance.features.FeatureLoadParams
|
import me.rhunk.snapenhance.features.FeatureLoadParams
|
||||||
@ -72,9 +73,9 @@ class Messaging : Feature("Messaging", loadParams = FeatureLoadParams.ACTIVITY_C
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get last opened snap for media downloader
|
//get last opened snap for media downloader
|
||||||
Hooker.hook(context.classCache.snapManager, "onSnapInteraction", HookStage.BEFORE) { param ->
|
context.event.subscribe(OnSnapInteractionEvent::class) { event ->
|
||||||
openedConversationUUID = SnapUUID(param.arg(1))
|
openedConversationUUID = event.conversationId
|
||||||
lastFocusedMessageId = param.arg(2)
|
lastFocusedMessageId = event.messageId
|
||||||
}
|
}
|
||||||
|
|
||||||
Hooker.hook(context.classCache.conversationManager, "fetchMessage", HookStage.BEFORE) { param ->
|
Hooker.hook(context.classCache.conversationManager, "fetchMessage", HookStage.BEFORE) { param ->
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.rhunk.snapenhance.features.impl.privacy
|
package me.rhunk.snapenhance.features.impl.privacy
|
||||||
|
|
||||||
import me.rhunk.snapenhance.Logger
|
import me.rhunk.snapenhance.Logger
|
||||||
|
import me.rhunk.snapenhance.core.event.impl.SendMessageWithContentEvent
|
||||||
import me.rhunk.snapenhance.data.NotificationType
|
import me.rhunk.snapenhance.data.NotificationType
|
||||||
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
||||||
import me.rhunk.snapenhance.features.Feature
|
import me.rhunk.snapenhance.features.Feature
|
||||||
@ -23,14 +24,13 @@ class PreventMessageSending : Feature("Prevent message sending", loadParams = Fe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.classCache.conversationManager.hook("sendMessageWithContent", HookStage.BEFORE) { param ->
|
context.event.subscribe(SendMessageWithContentEvent::class) { event ->
|
||||||
val message = MessageContent(param.arg(1))
|
val contentType = event.messageContent.contentType
|
||||||
val contentType = message.contentType
|
val associatedType = NotificationType.fromContentType(contentType) ?: return@subscribe
|
||||||
val associatedType = NotificationType.fromContentType(contentType) ?: return@hook
|
|
||||||
|
|
||||||
if (preventMessageSending.contains(associatedType.key)) {
|
if (preventMessageSending.contains(associatedType.key)) {
|
||||||
Logger.debug("Preventing message sending for $associatedType")
|
Logger.debug("Preventing message sending for $associatedType")
|
||||||
param.setResult(null)
|
event.canceled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package me.rhunk.snapenhance.features.impl.spying
|
package me.rhunk.snapenhance.features.impl.spying
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.event.impl.OnSnapInteractionEvent
|
||||||
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
|
||||||
import me.rhunk.snapenhance.features.Feature
|
import me.rhunk.snapenhance.features.Feature
|
||||||
import me.rhunk.snapenhance.features.FeatureLoadParams
|
import me.rhunk.snapenhance.features.FeatureLoadParams
|
||||||
@ -19,9 +20,10 @@ class PreventReadReceipts : Feature("PreventReadReceipts", loadParams = FeatureL
|
|||||||
it.setResult(null)
|
it.setResult(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Hooker.hook(context.classCache.snapManager, "onSnapInteraction", HookStage.BEFORE) {
|
|
||||||
if (isConversationInStealthMode(SnapUUID(it.arg(1) as Any))) {
|
context.event.subscribe(OnSnapInteractionEvent::class) { event ->
|
||||||
it.setResult(null)
|
if (isConversationInStealthMode(event.conversationId)) {
|
||||||
|
event.canceled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user