mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-06 09:24:30 +02:00
feat(social): auto sync scope
This commit is contained in:
parent
8bdd7a16b4
commit
f2e49e93fb
@ -13,6 +13,7 @@ import me.rhunk.snapenhance.core.database.objects.FriendInfo
|
|||||||
import me.rhunk.snapenhance.core.logger.LogLevel
|
import me.rhunk.snapenhance.core.logger.LogLevel
|
||||||
import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo
|
import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
|
import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
|
||||||
|
import me.rhunk.snapenhance.core.messaging.SocialScope
|
||||||
import me.rhunk.snapenhance.core.util.SerializableDataObject
|
import me.rhunk.snapenhance.core.util.SerializableDataObject
|
||||||
import me.rhunk.snapenhance.download.DownloadProcessor
|
import me.rhunk.snapenhance.download.DownloadProcessor
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
@ -33,25 +34,36 @@ class BridgeService : Service() {
|
|||||||
return BridgeBinder()
|
return BridgeBinder()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun triggerFriendSync(friendId: String) {
|
fun triggerScopeSync(scope: SocialScope, id: String, updateOnly: Boolean = false) {
|
||||||
val syncedFriend = syncCallback.syncFriend(friendId)
|
val modDatabase = remoteSideContext.modDatabase
|
||||||
if (syncedFriend == null) {
|
val syncedObject = when (scope) {
|
||||||
remoteSideContext.log.error("Failed to sync friend $friendId")
|
SocialScope.FRIEND -> {
|
||||||
return
|
if (updateOnly && modDatabase.getFriendInfo(id) == null) return
|
||||||
|
syncCallback.syncFriend(id)
|
||||||
}
|
}
|
||||||
SerializableDataObject.fromJson<FriendInfo>(syncedFriend).let {
|
SocialScope.GROUP -> {
|
||||||
remoteSideContext.modDatabase.syncFriend(it)
|
if (updateOnly && modDatabase.getGroupInfo(id) == null) return
|
||||||
|
syncCallback.syncGroup(id)
|
||||||
}
|
}
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun triggerGroupSync(groupId: String) {
|
if (syncedObject == null) {
|
||||||
val syncedGroup = syncCallback.syncGroup(groupId)
|
remoteSideContext.log.error("Failed to sync $scope $id")
|
||||||
if (syncedGroup == null) {
|
|
||||||
remoteSideContext.log.error("Failed to sync group $groupId")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SerializableDataObject.fromJson<MessagingGroupInfo>(syncedGroup).let {
|
|
||||||
remoteSideContext.modDatabase.syncGroupInfo(it)
|
when (scope) {
|
||||||
|
SocialScope.FRIEND -> {
|
||||||
|
SerializableDataObject.fromJson<FriendInfo>(syncedObject).let {
|
||||||
|
modDatabase.syncFriend(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SocialScope.GROUP -> {
|
||||||
|
SerializableDataObject.fromJson<MessagingGroupInfo>(syncedObject).let {
|
||||||
|
modDatabase.syncGroupInfo(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,14 +153,14 @@ class BridgeService : Service() {
|
|||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
remoteSideContext.modDatabase.getFriends().map { it.userId } .forEach { friendId ->
|
remoteSideContext.modDatabase.getFriends().map { it.userId } .forEach { friendId ->
|
||||||
runCatching {
|
runCatching {
|
||||||
triggerFriendSync(friendId)
|
triggerScopeSync(SocialScope.FRIEND, friendId, true)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
remoteSideContext.log.error("Failed to sync friend $friendId", it)
|
remoteSideContext.log.error("Failed to sync friend $friendId", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remoteSideContext.modDatabase.getGroups().map { it.conversationId }.forEach { groupId ->
|
remoteSideContext.modDatabase.getGroups().map { it.conversationId }.forEach { groupId ->
|
||||||
runCatching {
|
runCatching {
|
||||||
triggerGroupSync(groupId)
|
triggerScopeSync(SocialScope.GROUP, groupId, true)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
remoteSideContext.log.error("Failed to sync group $groupId", it)
|
remoteSideContext.log.error("Failed to sync group $groupId", it)
|
||||||
}
|
}
|
||||||
@ -158,6 +170,11 @@ class BridgeService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun triggerSync(scope: String, id: String) {
|
||||||
|
remoteSideContext.log.verbose("trigger sync for $scope $id")
|
||||||
|
triggerScopeSync(SocialScope.getByName(scope), id, true)
|
||||||
|
}
|
||||||
|
|
||||||
override fun passGroupsAndFriends(
|
override fun passGroupsAndFriends(
|
||||||
groups: List<String>,
|
groups: List<String>,
|
||||||
friends: List<String>
|
friends: List<String>
|
||||||
|
@ -47,6 +47,7 @@ import me.rhunk.snapenhance.RemoteSideContext
|
|||||||
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
||||||
import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo
|
import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
|
import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
|
||||||
|
import me.rhunk.snapenhance.core.messaging.SocialScope
|
||||||
import me.rhunk.snapenhance.core.util.snap.SnapWidgetBroadcastReceiverHelper
|
import me.rhunk.snapenhance.core.util.snap.SnapWidgetBroadcastReceiverHelper
|
||||||
|
|
||||||
class AddFriendDialog(
|
class AddFriendDialog(
|
||||||
@ -239,7 +240,7 @@ class AddFriendDialog(
|
|||||||
getCurrentState = { context.modDatabase.getGroupInfo(group.conversationId) != null }
|
getCurrentState = { context.modDatabase.getGroupInfo(group.conversationId) != null }
|
||||||
) { state ->
|
) { state ->
|
||||||
if (state) {
|
if (state) {
|
||||||
context.bridgeService.triggerGroupSync(group.conversationId)
|
context.bridgeService.triggerScopeSync(SocialScope.GROUP, group.conversationId)
|
||||||
} else {
|
} else {
|
||||||
context.modDatabase.deleteGroup(group.conversationId)
|
context.modDatabase.deleteGroup(group.conversationId)
|
||||||
}
|
}
|
||||||
@ -266,7 +267,7 @@ class AddFriendDialog(
|
|||||||
getCurrentState = { context.modDatabase.getFriendInfo(friend.userId) != null }
|
getCurrentState = { context.modDatabase.getFriendInfo(friend.userId) != null }
|
||||||
) { state ->
|
) { state ->
|
||||||
if (state) {
|
if (state) {
|
||||||
context.bridgeService.triggerFriendSync(friend.userId)
|
context.bridgeService.triggerScopeSync(SocialScope.FRIEND, friend.userId)
|
||||||
} else {
|
} else {
|
||||||
context.modDatabase.deleteFriend(friend.userId)
|
context.modDatabase.deleteFriend(friend.userId)
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,11 @@ interface BridgeInterface {
|
|||||||
*/
|
*/
|
||||||
oneway void sync(SyncCallback callback);
|
oneway void sync(SyncCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger sync for an id
|
||||||
|
*/
|
||||||
|
void triggerSync(String scope, String id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass all groups and friends to be able to add them to the database
|
* Pass all groups and friends to be able to add them to the database
|
||||||
* @param groups list of groups (MessagingGroupInfo as json string)
|
* @param groups list of groups (MessagingGroupInfo as json string)
|
||||||
|
@ -26,7 +26,8 @@ class EventDispatcher(
|
|||||||
context.classCache.conversationManager.hook("sendMessageWithContent", HookStage.BEFORE) { param ->
|
context.classCache.conversationManager.hook("sendMessageWithContent", HookStage.BEFORE) { param ->
|
||||||
context.event.post(SendMessageWithContentEvent(
|
context.event.post(SendMessageWithContentEvent(
|
||||||
destinations = MessageDestinations(param.arg(0)),
|
destinations = MessageDestinations(param.arg(0)),
|
||||||
messageContent = MessageContent(param.arg(1))
|
messageContent = MessageContent(param.arg(1)),
|
||||||
|
callback = param.arg(2)
|
||||||
).apply { adapter = param })?.also {
|
).apply { adapter = param })?.also {
|
||||||
if (it.canceled) {
|
if (it.canceled) {
|
||||||
param.setResult(null)
|
param.setResult(null)
|
||||||
|
@ -14,10 +14,12 @@ import me.rhunk.snapenhance.ModContext
|
|||||||
import me.rhunk.snapenhance.bridge.BridgeInterface
|
import me.rhunk.snapenhance.bridge.BridgeInterface
|
||||||
import me.rhunk.snapenhance.bridge.DownloadCallback
|
import me.rhunk.snapenhance.bridge.DownloadCallback
|
||||||
import me.rhunk.snapenhance.bridge.SyncCallback
|
import me.rhunk.snapenhance.bridge.SyncCallback
|
||||||
|
import me.rhunk.snapenhance.bridge.scripting.IScripting
|
||||||
import me.rhunk.snapenhance.core.BuildConfig
|
import me.rhunk.snapenhance.core.BuildConfig
|
||||||
import me.rhunk.snapenhance.core.bridge.types.BridgeFileType
|
import me.rhunk.snapenhance.core.bridge.types.BridgeFileType
|
||||||
import me.rhunk.snapenhance.core.bridge.types.FileActionType
|
import me.rhunk.snapenhance.core.bridge.types.FileActionType
|
||||||
import me.rhunk.snapenhance.core.messaging.MessagingRuleType
|
import me.rhunk.snapenhance.core.messaging.MessagingRuleType
|
||||||
|
import me.rhunk.snapenhance.core.messaging.SocialScope
|
||||||
import me.rhunk.snapenhance.data.LocalePair
|
import me.rhunk.snapenhance.data.LocalePair
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@ -118,24 +120,12 @@ class BridgeClient(
|
|||||||
|
|
||||||
fun getApplicationApkPath() = service.getApplicationApkPath()
|
fun getApplicationApkPath() = service.getApplicationApkPath()
|
||||||
|
|
||||||
fun getAutoUpdaterTime(): Long {
|
|
||||||
createAndReadFile(BridgeFileType.AUTO_UPDATER_TIMESTAMP, "0".toByteArray()).run {
|
|
||||||
return if (isEmpty()) {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
String(this).toLong()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setAutoUpdaterTime(time: Long) {
|
|
||||||
writeFile(BridgeFileType.AUTO_UPDATER_TIMESTAMP, time.toString().toByteArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enqueueDownload(intent: Intent, callback: DownloadCallback) = service.enqueueDownload(intent, callback)
|
fun enqueueDownload(intent: Intent, callback: DownloadCallback) = service.enqueueDownload(intent, callback)
|
||||||
|
|
||||||
fun sync(callback: SyncCallback) = service.sync(callback)
|
fun sync(callback: SyncCallback) = service.sync(callback)
|
||||||
|
|
||||||
|
fun triggerSync(scope: SocialScope, id: String) = service.triggerSync(scope.key, id)
|
||||||
|
|
||||||
fun passGroupsAndFriends(groups: List<String>, friends: List<String>) = service.passGroupsAndFriends(groups, friends)
|
fun passGroupsAndFriends(groups: List<String>, friends: List<String>) = service.passGroupsAndFriends(groups, friends)
|
||||||
|
|
||||||
fun getRules(targetUuid: String): List<MessagingRuleType> {
|
fun getRules(targetUuid: String): List<MessagingRuleType> {
|
||||||
@ -149,5 +139,5 @@ class BridgeClient(
|
|||||||
fun setRule(targetUuid: String, type: MessagingRuleType, state: Boolean)
|
fun setRule(targetUuid: String, type: MessagingRuleType, state: Boolean)
|
||||||
= service.setRule(targetUuid, type.key, state)
|
= service.setRule(targetUuid, type.key, state)
|
||||||
|
|
||||||
fun getScriptingInterface() = service.getScriptingInterface()
|
fun getScriptingInterface(): IScripting = service.getScriptingInterface()
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,7 @@ enum class BridgeFileType(val value: Int, val fileName: String, val displayName:
|
|||||||
CONFIG(0, "config.json", "Config"),
|
CONFIG(0, "config.json", "Config"),
|
||||||
MAPPINGS(1, "mappings.json", "Mappings"),
|
MAPPINGS(1, "mappings.json", "Mappings"),
|
||||||
MESSAGE_LOGGER_DATABASE(2, "message_logger.db", "Message Logger",true),
|
MESSAGE_LOGGER_DATABASE(2, "message_logger.db", "Message Logger",true),
|
||||||
AUTO_UPDATER_TIMESTAMP(3, "auto_updater_timestamp.txt", "Auto Updater Timestamp"),
|
PINNED_CONVERSATIONS(3, "pinned_conversations.txt", "Pinned Conversations");
|
||||||
PINNED_CONVERSATIONS(4, "pinned_conversations.txt", "Pinned Conversations");
|
|
||||||
|
|
||||||
fun resolve(context: Context): File = if (isDatabase) {
|
fun resolve(context: Context): File = if (isDatabase) {
|
||||||
context.getDatabasePath(fileName)
|
context.getDatabasePath(fileName)
|
||||||
|
@ -3,8 +3,21 @@ package me.rhunk.snapenhance.core.eventbus.events.impl
|
|||||||
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent
|
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent
|
||||||
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
|
||||||
import me.rhunk.snapenhance.data.wrapper.impl.MessageDestinations
|
import me.rhunk.snapenhance.data.wrapper.impl.MessageDestinations
|
||||||
|
import me.rhunk.snapenhance.hook.HookStage
|
||||||
|
import me.rhunk.snapenhance.hook.Hooker
|
||||||
|
|
||||||
class SendMessageWithContentEvent(
|
class SendMessageWithContentEvent(
|
||||||
val destinations: MessageDestinations,
|
val destinations: MessageDestinations,
|
||||||
val messageContent: MessageContent
|
val messageContent: MessageContent,
|
||||||
) : AbstractHookEvent()
|
private val callback: Any
|
||||||
|
) : AbstractHookEvent() {
|
||||||
|
|
||||||
|
fun addCallbackResult(methodName: String, block: (args: Array<Any?>) -> Unit) {
|
||||||
|
Hooker.ephemeralHookObjectMethod(
|
||||||
|
callback::class.java,
|
||||||
|
callback,
|
||||||
|
methodName,
|
||||||
|
HookStage.BEFORE
|
||||||
|
) { block(it.args()) }
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,11 @@ enum class SocialScope(
|
|||||||
val tabRoute: String,
|
val tabRoute: String,
|
||||||
) {
|
) {
|
||||||
FRIEND("friend", "friend_info/{id}"),
|
FRIEND("friend", "friend_info/{id}"),
|
||||||
GROUP("group", "group_info/{id}"),
|
GROUP("group", "group_info/{id}");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getByName(name: String) = values().first { it.key == name }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MessagingRuleType(
|
enum class MessagingRuleType(
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package me.rhunk.snapenhance.features.impl
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent
|
||||||
|
import me.rhunk.snapenhance.core.messaging.SocialScope
|
||||||
|
import me.rhunk.snapenhance.data.ContentType
|
||||||
|
import me.rhunk.snapenhance.features.Feature
|
||||||
|
import me.rhunk.snapenhance.features.FeatureLoadParams
|
||||||
|
|
||||||
|
class ScopeSync : Feature("Scope Sync", loadParams = FeatureLoadParams.INIT_SYNC) {
|
||||||
|
companion object {
|
||||||
|
private const val DELAY_BEFORE_SYNC = 2000L
|
||||||
|
}
|
||||||
|
|
||||||
|
private val updateJobs = mutableMapOf<String, Job>()
|
||||||
|
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||||
|
|
||||||
|
private fun sync(conversationId: String) {
|
||||||
|
context.database.getDMOtherParticipant(conversationId)?.also { participant ->
|
||||||
|
context.bridgeClient.triggerSync(SocialScope.FRIEND, participant)
|
||||||
|
} ?: run {
|
||||||
|
context.bridgeClient.triggerSync(SocialScope.GROUP, conversationId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
context.event.subscribe(SendMessageWithContentEvent::class) { event ->
|
||||||
|
if (event.messageContent.contentType != ContentType.SNAP) return@subscribe
|
||||||
|
|
||||||
|
event.addCallbackResult("onSuccess") {
|
||||||
|
event.destinations.conversations.map { it.toString() }.forEach { conversationId ->
|
||||||
|
updateJobs[conversationId]?.also { it.cancel() }
|
||||||
|
|
||||||
|
updateJobs[conversationId] = (coroutineScope.launch {
|
||||||
|
delay(DELAY_BEFORE_SYNC)
|
||||||
|
sync(conversationId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ class SnapchatPlus: Feature("SnapchatPlus", loadParams = FeatureLoadParams.INIT_
|
|||||||
it.parameterTypes[0].name != "java.lang.Boolean"
|
it.parameterTypes[0].name != "java.lang.Boolean"
|
||||||
}.hook(HookStage.BEFORE) { param ->
|
}.hook(HookStage.BEFORE) { param ->
|
||||||
val instance = param.thisObject<Any>()
|
val instance = param.thisObject<Any>()
|
||||||
val firstArg = param.args()[0]
|
val firstArg = param.arg<Any>(0)
|
||||||
|
|
||||||
instance::class.java.declaredFields.filter { it.type == firstArg::class.java }.forEach {
|
instance::class.java.declaredFields.filter { it.type == firstArg::class.java }.forEach {
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
|
@ -26,7 +26,7 @@ class HookAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> argNullable(index: Int): T? {
|
fun <T : Any> argNullable(index: Int): T? {
|
||||||
return methodHookParam.args[index] as T?
|
return methodHookParam.args.getOrNull(index) as T?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setArg(index: Int, value: Any?) {
|
fun setArg(index: Int, value: Any?) {
|
||||||
@ -34,7 +34,7 @@ class HookAdapter(
|
|||||||
methodHookParam.args[index] = value
|
methodHookParam.args[index] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun args(): Array<Any> {
|
fun args(): Array<Any?> {
|
||||||
return methodHookParam.args
|
return methodHookParam.args
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class HookAdapter(
|
|||||||
invokeOriginalSafe(args(), errorCallback)
|
invokeOriginalSafe(args(), errorCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invokeOriginalSafe(args: Array<Any>, errorCallback: Consumer<Throwable>) {
|
fun invokeOriginalSafe(args: Array<Any?>, errorCallback: Consumer<Throwable>) {
|
||||||
runCatching {
|
runCatching {
|
||||||
setResult(XposedBridge.invokeOriginalMethod(method(), thisObject(), args))
|
setResult(XposedBridge.invokeOriginalMethod(method(), thisObject(), args))
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
@ -6,34 +6,17 @@ import me.rhunk.snapenhance.features.Feature
|
|||||||
import me.rhunk.snapenhance.features.FeatureLoadParams
|
import me.rhunk.snapenhance.features.FeatureLoadParams
|
||||||
import me.rhunk.snapenhance.features.impl.ConfigurationOverride
|
import me.rhunk.snapenhance.features.impl.ConfigurationOverride
|
||||||
import me.rhunk.snapenhance.features.impl.Messaging
|
import me.rhunk.snapenhance.features.impl.Messaging
|
||||||
|
import me.rhunk.snapenhance.features.impl.ScopeSync
|
||||||
import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
|
import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
|
||||||
import me.rhunk.snapenhance.features.impl.downloader.ProfilePictureDownloader
|
import me.rhunk.snapenhance.features.impl.downloader.ProfilePictureDownloader
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.AddFriendSourceSpoof
|
import me.rhunk.snapenhance.features.impl.experiments.*
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.AmoledDarkMode
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.AppPasscode
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.DeviceSpooferHook
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.InfiniteStoryBoost
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.MeoPasscodeBypass
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.NoFriendScoreDelay
|
|
||||||
import me.rhunk.snapenhance.features.impl.experiments.UnlimitedMultiSnap
|
|
||||||
import me.rhunk.snapenhance.features.impl.privacy.DisableMetrics
|
import me.rhunk.snapenhance.features.impl.privacy.DisableMetrics
|
||||||
import me.rhunk.snapenhance.features.impl.privacy.PreventMessageSending
|
import me.rhunk.snapenhance.features.impl.privacy.PreventMessageSending
|
||||||
import me.rhunk.snapenhance.features.impl.spying.AnonymousStoryViewing
|
import me.rhunk.snapenhance.features.impl.spying.AnonymousStoryViewing
|
||||||
import me.rhunk.snapenhance.features.impl.spying.MessageLogger
|
import me.rhunk.snapenhance.features.impl.spying.MessageLogger
|
||||||
import me.rhunk.snapenhance.features.impl.spying.PreventReadReceipts
|
import me.rhunk.snapenhance.features.impl.spying.PreventReadReceipts
|
||||||
import me.rhunk.snapenhance.features.impl.spying.StealthMode
|
import me.rhunk.snapenhance.features.impl.spying.StealthMode
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.AutoSave
|
import me.rhunk.snapenhance.features.impl.tweaks.*
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.CameraTweaks
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.DisableReplayInFF
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.DisableVideoLengthRestriction
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.GooglePlayServicesDialogs
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.LocationSpoofer
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.MediaQualityLevelOverride
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.Notifications
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.OldBitmojiSelfie
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.SendOverride
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.SnapchatPlus
|
|
||||||
import me.rhunk.snapenhance.features.impl.tweaks.UnlimitedSnapViewTime
|
|
||||||
import me.rhunk.snapenhance.features.impl.ui.ClientBootstrapOverride
|
import me.rhunk.snapenhance.features.impl.ui.ClientBootstrapOverride
|
||||||
import me.rhunk.snapenhance.features.impl.ui.PinConversations
|
import me.rhunk.snapenhance.features.impl.ui.PinConversations
|
||||||
import me.rhunk.snapenhance.features.impl.ui.UITweaks
|
import me.rhunk.snapenhance.features.impl.ui.UITweaks
|
||||||
@ -46,14 +29,16 @@ class FeatureManager(private val context: ModContext) : Manager {
|
|||||||
private val asyncLoadExecutorService = Executors.newFixedThreadPool(5)
|
private val asyncLoadExecutorService = Executors.newFixedThreadPool(5)
|
||||||
private val features = mutableListOf<Feature>()
|
private val features = mutableListOf<Feature>()
|
||||||
|
|
||||||
private fun register(featureClass: KClass<out Feature>) {
|
private fun register(vararg featureClasses: KClass<out Feature>) {
|
||||||
|
featureClasses.forEach { clazz ->
|
||||||
runCatching {
|
runCatching {
|
||||||
with(featureClass.java.newInstance()) {
|
clazz.constructors.first().call().also { feature ->
|
||||||
context = this@FeatureManager.context
|
feature.context = context
|
||||||
features.add(this)
|
features.add(feature)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Logger.xposedLog("Failed to register feature ${featureClass.simpleName}", it)
|
Logger.xposedLog("Failed to register feature ${clazz.simpleName}", it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,40 +48,43 @@ class FeatureManager(private val context: ModContext) : Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
register(Messaging::class)
|
register(
|
||||||
register(MediaDownloader::class)
|
ScopeSync::class,
|
||||||
register(StealthMode::class)
|
Messaging::class,
|
||||||
register(MenuViewInjector::class)
|
MediaDownloader::class,
|
||||||
register(PreventReadReceipts::class)
|
StealthMode::class,
|
||||||
register(AnonymousStoryViewing::class)
|
MenuViewInjector::class,
|
||||||
register(MessageLogger::class)
|
PreventReadReceipts::class,
|
||||||
register(SnapchatPlus::class)
|
AnonymousStoryViewing::class,
|
||||||
register(DisableMetrics::class)
|
MessageLogger::class,
|
||||||
register(PreventMessageSending::class)
|
SnapchatPlus::class,
|
||||||
register(Notifications::class)
|
DisableMetrics::class,
|
||||||
register(AutoSave::class)
|
PreventMessageSending::class,
|
||||||
register(UITweaks::class)
|
Notifications::class,
|
||||||
register(ConfigurationOverride::class)
|
AutoSave::class,
|
||||||
register(SendOverride::class)
|
UITweaks::class,
|
||||||
register(UnlimitedSnapViewTime::class)
|
ConfigurationOverride::class,
|
||||||
register(DisableVideoLengthRestriction::class)
|
SendOverride::class,
|
||||||
register(MediaQualityLevelOverride::class)
|
UnlimitedSnapViewTime::class,
|
||||||
register(MeoPasscodeBypass::class)
|
DisableVideoLengthRestriction::class,
|
||||||
register(AppPasscode::class)
|
MediaQualityLevelOverride::class,
|
||||||
register(LocationSpoofer::class)
|
MeoPasscodeBypass::class,
|
||||||
register(CameraTweaks::class)
|
AppPasscode::class,
|
||||||
register(InfiniteStoryBoost::class)
|
LocationSpoofer::class,
|
||||||
register(AmoledDarkMode::class)
|
CameraTweaks::class,
|
||||||
register(PinConversations::class)
|
InfiniteStoryBoost::class,
|
||||||
register(UnlimitedMultiSnap::class)
|
AmoledDarkMode::class,
|
||||||
register(DeviceSpooferHook::class)
|
PinConversations::class,
|
||||||
register(ClientBootstrapOverride::class)
|
UnlimitedMultiSnap::class,
|
||||||
register(GooglePlayServicesDialogs::class)
|
DeviceSpooferHook::class,
|
||||||
register(NoFriendScoreDelay::class)
|
ClientBootstrapOverride::class,
|
||||||
register(ProfilePictureDownloader::class)
|
GooglePlayServicesDialogs::class,
|
||||||
register(AddFriendSourceSpoof::class)
|
NoFriendScoreDelay::class,
|
||||||
register(DisableReplayInFF::class)
|
ProfilePictureDownloader::class,
|
||||||
register(OldBitmojiSelfie::class)
|
AddFriendSourceSpoof::class,
|
||||||
|
DisableReplayInFF::class,
|
||||||
|
OldBitmojiSelfie::class,
|
||||||
|
)
|
||||||
|
|
||||||
initializeFeatures()
|
initializeFeatures()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user