mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 21:10:20 +02:00
perf: bridge objects
- bridge oneway methods - scope sync
This commit is contained in:
parent
0994b8f36d
commit
8c71e4af27
@ -8,6 +8,7 @@ import java.io.ByteArrayOutputStream
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.androidApplication)
|
alias(libs.plugins.androidApplication)
|
||||||
alias(libs.plugins.kotlinAndroid)
|
alias(libs.plugins.kotlinAndroid)
|
||||||
|
id("kotlin-parcelize")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -12,9 +12,8 @@ import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper
|
|||||||
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||||
import me.rhunk.snapenhance.common.data.SocialScope
|
import me.rhunk.snapenhance.common.data.SocialScope
|
||||||
import me.rhunk.snapenhance.common.database.impl.FriendInfo
|
|
||||||
import me.rhunk.snapenhance.common.logger.LogLevel
|
import me.rhunk.snapenhance.common.logger.LogLevel
|
||||||
import me.rhunk.snapenhance.common.util.SerializableDataObject
|
import me.rhunk.snapenhance.common.util.toParcelable
|
||||||
import me.rhunk.snapenhance.download.DownloadProcessor
|
import me.rhunk.snapenhance.download.DownloadProcessor
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@ -61,12 +60,12 @@ class BridgeService : Service() {
|
|||||||
|
|
||||||
when (scope) {
|
when (scope) {
|
||||||
SocialScope.FRIEND -> {
|
SocialScope.FRIEND -> {
|
||||||
SerializableDataObject.fromJson<FriendInfo>(syncedObject).let {
|
toParcelable<MessagingFriendInfo>(syncedObject)?.let {
|
||||||
modDatabase.syncFriend(it)
|
modDatabase.syncFriend(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocialScope.GROUP -> {
|
SocialScope.GROUP -> {
|
||||||
SerializableDataObject.fromJson<MessagingGroupInfo>(syncedObject).let {
|
toParcelable<MessagingGroupInfo>(syncedObject)?.let {
|
||||||
modDatabase.syncGroupInfo(it)
|
modDatabase.syncGroupInfo(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,8 +168,8 @@ class BridgeService : Service() {
|
|||||||
) {
|
) {
|
||||||
remoteSideContext.log.verbose("Received ${groups.size} groups and ${friends.size} friends")
|
remoteSideContext.log.verbose("Received ${groups.size} groups and ${friends.size} friends")
|
||||||
remoteSideContext.modDatabase.receiveMessagingDataCallback(
|
remoteSideContext.modDatabase.receiveMessagingDataCallback(
|
||||||
friends.map { SerializableDataObject.fromJson<MessagingFriendInfo>(it) },
|
friends.mapNotNull { toParcelable<MessagingFriendInfo>(it) },
|
||||||
groups.map { SerializableDataObject.fromJson<MessagingGroupInfo>(it) }
|
groups.mapNotNull { toParcelable<MessagingGroupInfo>(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import me.rhunk.snapenhance.common.data.FriendStreaks
|
|||||||
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
||||||
import me.rhunk.snapenhance.common.database.impl.FriendInfo
|
|
||||||
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
|
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
|
||||||
import me.rhunk.snapenhance.common.util.SQLiteDatabaseHelper
|
import me.rhunk.snapenhance.common.util.SQLiteDatabaseHelper
|
||||||
import me.rhunk.snapenhance.common.util.ktx.getInteger
|
import me.rhunk.snapenhance.common.util.ktx.getInteger
|
||||||
@ -56,7 +55,7 @@ class ModDatabase(
|
|||||||
"targetUuid VARCHAR"
|
"targetUuid VARCHAR"
|
||||||
),
|
),
|
||||||
"streaks" to listOf(
|
"streaks" to listOf(
|
||||||
"userId VARCHAR PRIMARY KEY",
|
"id VARCHAR PRIMARY KEY",
|
||||||
"notify BOOLEAN",
|
"notify BOOLEAN",
|
||||||
"expirationTimestamp BIGINT",
|
"expirationTimestamp BIGINT",
|
||||||
"length INTEGER"
|
"length INTEGER"
|
||||||
@ -78,10 +77,10 @@ class ModDatabase(
|
|||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
groups.add(
|
groups.add(
|
||||||
MessagingGroupInfo(
|
MessagingGroupInfo(
|
||||||
conversationId = cursor.getStringOrNull("conversationId")!!,
|
conversationId = cursor.getStringOrNull("conversationId")!!,
|
||||||
name = cursor.getStringOrNull("name")!!,
|
name = cursor.getStringOrNull("name")!!,
|
||||||
participantsCount = cursor.getInteger("participantsCount")
|
participantsCount = cursor.getInteger("participantsCount")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
groups
|
groups
|
||||||
@ -89,18 +88,25 @@ class ModDatabase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFriends(descOrder: Boolean = false): List<MessagingFriendInfo> {
|
fun getFriends(descOrder: Boolean = false): List<MessagingFriendInfo> {
|
||||||
return database.rawQuery("SELECT * FROM friends ORDER BY id ${if (descOrder) "DESC" else "ASC"}", null).use { cursor ->
|
return database.rawQuery("SELECT * FROM friends LEFT OUTER JOIN streaks ON friends.userId = streaks.id ORDER BY id ${if (descOrder) "DESC" else "ASC"}", null).use { cursor ->
|
||||||
val friends = mutableListOf<MessagingFriendInfo>()
|
val friends = mutableListOf<MessagingFriendInfo>()
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
runCatching {
|
runCatching {
|
||||||
friends.add(
|
friends.add(
|
||||||
MessagingFriendInfo(
|
MessagingFriendInfo(
|
||||||
userId = cursor.getStringOrNull("userId")!!,
|
userId = cursor.getStringOrNull("userId")!!,
|
||||||
displayName = cursor.getStringOrNull("displayName"),
|
displayName = cursor.getStringOrNull("displayName"),
|
||||||
mutableUsername = cursor.getStringOrNull("mutableUsername")!!,
|
mutableUsername = cursor.getStringOrNull("mutableUsername")!!,
|
||||||
bitmojiId = cursor.getStringOrNull("bitmojiId"),
|
bitmojiId = cursor.getStringOrNull("bitmojiId"),
|
||||||
selfieId = cursor.getStringOrNull("selfieId")
|
selfieId = cursor.getStringOrNull("selfieId"),
|
||||||
)
|
streaks = cursor.getLongOrNull("expirationTimestamp")?.let {
|
||||||
|
FriendStreaks(
|
||||||
|
notify = cursor.getInteger("notify") == 1,
|
||||||
|
expirationTimestamp = it,
|
||||||
|
length = cursor.getInteger("length")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
context.log.error("Failed to parse friend", it)
|
context.log.error("Failed to parse friend", it)
|
||||||
@ -125,7 +131,7 @@ class ModDatabase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun syncFriend(friend: FriendInfo) {
|
fun syncFriend(friend: MessagingFriendInfo) {
|
||||||
executeAsync {
|
executeAsync {
|
||||||
try {
|
try {
|
||||||
database.execSQL(
|
database.execSQL(
|
||||||
@ -133,24 +139,22 @@ class ModDatabase(
|
|||||||
arrayOf(
|
arrayOf(
|
||||||
friend.userId,
|
friend.userId,
|
||||||
friend.displayName,
|
friend.displayName,
|
||||||
friend.usernameForSorting!!,
|
friend.mutableUsername,
|
||||||
friend.bitmojiAvatarId,
|
friend.bitmojiId,
|
||||||
friend.bitmojiSelfieId
|
friend.selfieId
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
//sync streaks
|
//sync streaks
|
||||||
if (friend.streakLength > 0) {
|
friend.streaks?.takeIf { it.length > 0 }?.let {
|
||||||
val streaks = getFriendStreaks(friend.userId!!)
|
val streaks = getFriendStreaks(friend.userId)
|
||||||
|
|
||||||
database.execSQL("INSERT OR REPLACE INTO streaks (userId, notify, expirationTimestamp, length) VALUES (?, ?, ?, ?)", arrayOf(
|
database.execSQL("INSERT OR REPLACE INTO streaks (id, notify, expirationTimestamp, length) VALUES (?, ?, ?, ?)", arrayOf(
|
||||||
friend.userId,
|
friend.userId,
|
||||||
streaks?.notify ?: true,
|
streaks?.notify ?: true,
|
||||||
friend.streakExpirationTimestamp,
|
it.expirationTimestamp,
|
||||||
friend.streakLength
|
it.length
|
||||||
))
|
))
|
||||||
} else {
|
} ?: database.execSQL("DELETE FROM streaks WHERE id = ?", arrayOf(friend.userId))
|
||||||
database.execSQL("DELETE FROM streaks WHERE userId = ?", arrayOf(friend.userId))
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
@ -190,14 +194,21 @@ class ModDatabase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFriendInfo(userId: String): MessagingFriendInfo? {
|
fun getFriendInfo(userId: String): MessagingFriendInfo? {
|
||||||
return database.rawQuery("SELECT * FROM friends WHERE userId = ?", arrayOf(userId)).use { cursor ->
|
return database.rawQuery("SELECT * FROM friends LEFT OUTER JOIN streaks ON friends.userId = streaks.id WHERE userId = ?", arrayOf(userId)).use { cursor ->
|
||||||
if (!cursor.moveToFirst()) return@use null
|
if (!cursor.moveToFirst()) return@use null
|
||||||
MessagingFriendInfo(
|
MessagingFriendInfo(
|
||||||
userId = cursor.getStringOrNull("userId")!!,
|
userId = cursor.getStringOrNull("userId")!!,
|
||||||
displayName = cursor.getStringOrNull("displayName"),
|
displayName = cursor.getStringOrNull("displayName"),
|
||||||
mutableUsername = cursor.getStringOrNull("mutableUsername")!!,
|
mutableUsername = cursor.getStringOrNull("mutableUsername")!!,
|
||||||
bitmojiId = cursor.getStringOrNull("bitmojiId"),
|
bitmojiId = cursor.getStringOrNull("bitmojiId"),
|
||||||
selfieId = cursor.getStringOrNull("selfieId")
|
selfieId = cursor.getStringOrNull("selfieId"),
|
||||||
|
streaks = cursor.getLongOrNull("expirationTimestamp")?.let {
|
||||||
|
FriendStreaks(
|
||||||
|
notify = cursor.getInteger("notify") == 1,
|
||||||
|
expirationTimestamp = it,
|
||||||
|
length = cursor.getInteger("length")
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +216,7 @@ class ModDatabase(
|
|||||||
fun deleteFriend(userId: String) {
|
fun deleteFriend(userId: String) {
|
||||||
executeAsync {
|
executeAsync {
|
||||||
database.execSQL("DELETE FROM friends WHERE userId = ?", arrayOf(userId))
|
database.execSQL("DELETE FROM friends WHERE userId = ?", arrayOf(userId))
|
||||||
database.execSQL("DELETE FROM streaks WHERE userId = ?", arrayOf(userId))
|
database.execSQL("DELETE FROM streaks WHERE id = ?", arrayOf(userId))
|
||||||
database.execSQL("DELETE FROM rules WHERE targetUuid = ?", arrayOf(userId))
|
database.execSQL("DELETE FROM rules WHERE targetUuid = ?", arrayOf(userId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,10 +240,9 @@ class ModDatabase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFriendStreaks(userId: String): FriendStreaks? {
|
fun getFriendStreaks(userId: String): FriendStreaks? {
|
||||||
return database.rawQuery("SELECT * FROM streaks WHERE userId = ?", arrayOf(userId)).use { cursor ->
|
return database.rawQuery("SELECT * FROM streaks WHERE id = ?", arrayOf(userId)).use { cursor ->
|
||||||
if (!cursor.moveToFirst()) return@use null
|
if (!cursor.moveToFirst()) return@use null
|
||||||
FriendStreaks(
|
FriendStreaks(
|
||||||
userId = cursor.getStringOrNull("userId")!!,
|
|
||||||
notify = cursor.getInteger("notify") == 1,
|
notify = cursor.getInteger("notify") == 1,
|
||||||
expirationTimestamp = cursor.getLongOrNull("expirationTimestamp") ?: 0L,
|
expirationTimestamp = cursor.getLongOrNull("expirationTimestamp") ?: 0L,
|
||||||
length = cursor.getInteger("length")
|
length = cursor.getInteger("length")
|
||||||
@ -242,7 +252,7 @@ class ModDatabase(
|
|||||||
|
|
||||||
fun setFriendStreaksNotify(userId: String, notify: Boolean) {
|
fun setFriendStreaksNotify(userId: String, notify: Boolean) {
|
||||||
executeAsync {
|
executeAsync {
|
||||||
database.execSQL("UPDATE streaks SET notify = ? WHERE userId = ?", arrayOf(
|
database.execSQL("UPDATE streaks SET notify = ? WHERE id = ?", arrayOf(
|
||||||
if (notify) 1 else 0,
|
if (notify) 1 else 0,
|
||||||
userId
|
userId
|
||||||
))
|
))
|
||||||
|
@ -26,7 +26,9 @@ import androidx.compose.ui.window.Dialog
|
|||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import me.rhunk.snapenhance.R
|
import me.rhunk.snapenhance.R
|
||||||
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||||
@ -214,8 +216,13 @@ class SocialSection : Section() {
|
|||||||
|
|
||||||
SocialScope.FRIEND -> {
|
SocialScope.FRIEND -> {
|
||||||
val friend = friendList[index]
|
val friend = friendList[index]
|
||||||
val streaks =
|
var streaks by remember { mutableStateOf(friend.streaks) }
|
||||||
remember { context.modDatabase.getFriendStreaks(friend.userId) }
|
|
||||||
|
LaunchedEffect(friend.userId) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
streaks = context.modDatabase.getFriendStreaks(friend.userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BitmojiImage(
|
BitmojiImage(
|
||||||
context = context,
|
context = context,
|
||||||
@ -244,7 +251,7 @@ class SocialSection : Section() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (streaks != null && streaks.notify) {
|
streaks?.takeIf { it.notify }?.let { streaks ->
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.streak_icon),
|
imageVector = ImageVector.vectorResource(id = R.drawable.streak_icon),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@ -256,7 +263,7 @@ class SocialSection : Section() {
|
|||||||
Text(
|
Text(
|
||||||
text = context.translation.format(
|
text = context.translation.format(
|
||||||
"manager.sections.social.streaks_expiration_short",
|
"manager.sections.social.streaks_expiration_short",
|
||||||
"hours" to ((streaks.expirationTimestamp - System.currentTimeMillis()) / 3600000).toInt()
|
"hours" to (((streaks.expirationTimestamp - System.currentTimeMillis()) / 3600000).toInt().takeIf { it > 0 } ?: 0)
|
||||||
.toString()
|
.toString()
|
||||||
),
|
),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.androidLibrary)
|
alias(libs.plugins.androidLibrary)
|
||||||
alias(libs.plugins.kotlinAndroid)
|
alias(libs.plugins.kotlinAndroid)
|
||||||
|
id("kotlin-parcelize")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -13,7 +13,7 @@ interface BridgeInterface {
|
|||||||
/**
|
/**
|
||||||
* broadcast a log message
|
* broadcast a log message
|
||||||
*/
|
*/
|
||||||
void broadcastLog(String tag, String level, String message);
|
oneway void broadcastLog(String tag, String level, String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a file operation
|
* Execute a file operation
|
||||||
@ -36,7 +36,7 @@ interface BridgeInterface {
|
|||||||
/**
|
/**
|
||||||
* Enqueue a download
|
* Enqueue a download
|
||||||
*/
|
*/
|
||||||
void enqueueDownload(in Intent intent, DownloadCallback callback);
|
oneway void enqueueDownload(in Intent intent, DownloadCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get rules for a given user or conversation
|
* Get rules for a given user or conversation
|
||||||
@ -56,7 +56,7 @@ interface BridgeInterface {
|
|||||||
*
|
*
|
||||||
* @param type rule type (MessagingRuleType)
|
* @param type rule type (MessagingRuleType)
|
||||||
*/
|
*/
|
||||||
void setRule(String uuid, String type, boolean state);
|
oneway void setRule(String uuid, String type, boolean state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync groups and friends
|
* Sync groups and friends
|
||||||
@ -66,12 +66,12 @@ interface BridgeInterface {
|
|||||||
/**
|
/**
|
||||||
* Trigger sync for an id
|
* Trigger sync for an id
|
||||||
*/
|
*/
|
||||||
void triggerSync(String scope, String id);
|
oneway 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 parcelable)
|
||||||
* @param friends list of friends (MessagingFriendInfo as json string)
|
* @param friends list of friends (MessagingFriendInfo as parcelable)
|
||||||
*/
|
*/
|
||||||
oneway void passGroupsAndFriends(in List<String> groups, in List<String> friends);
|
oneway void passGroupsAndFriends(in List<String> groups, in List<String> friends);
|
||||||
|
|
||||||
@ -81,11 +81,11 @@ interface BridgeInterface {
|
|||||||
|
|
||||||
MessageLoggerInterface getMessageLogger();
|
MessageLoggerInterface getMessageLogger();
|
||||||
|
|
||||||
void registerMessagingBridge(MessagingBridge bridge);
|
oneway void registerMessagingBridge(MessagingBridge bridge);
|
||||||
|
|
||||||
void openSettingsOverlay();
|
oneway void openSettingsOverlay();
|
||||||
|
|
||||||
void closeSettingsOverlay();
|
oneway void closeSettingsOverlay();
|
||||||
|
|
||||||
void registerConfigStateListener(in ConfigStateListener listener);
|
oneway void registerConfigStateListener(in ConfigStateListener listener);
|
||||||
}
|
}
|
@ -8,11 +8,11 @@ interface IScripting {
|
|||||||
|
|
||||||
@nullable String getScriptContent(String path);
|
@nullable String getScriptContent(String path);
|
||||||
|
|
||||||
void registerIPCListener(String channel, String eventName, IPCListener listener);
|
oneway void registerIPCListener(String channel, String eventName, IPCListener listener);
|
||||||
|
|
||||||
void sendIPCMessage(String channel, String eventName, in String[] args);
|
oneway void sendIPCMessage(String channel, String eventName, in String[] args);
|
||||||
|
|
||||||
@nullable String configTransaction(String module, String action, @nullable String key, @nullable String value, boolean save);
|
@nullable String configTransaction(String module, String action, @nullable String key, @nullable String value, boolean save);
|
||||||
|
|
||||||
void registerAutoReloadListener(in AutoReloadListener listener);
|
oneway void registerAutoReloadListener(in AutoReloadListener listener);
|
||||||
}
|
}
|
@ -33,7 +33,7 @@ class ModConfig(
|
|||||||
private fun load() {
|
private fun load() {
|
||||||
root = createRootConfig()
|
root = createRootConfig()
|
||||||
wasPresent = file.isFileExists()
|
wasPresent = file.isFileExists()
|
||||||
if (!file.isFileExists()) {
|
if (!wasPresent) {
|
||||||
writeConfig()
|
writeConfig()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package me.rhunk.snapenhance.common.data
|
package me.rhunk.snapenhance.common.data
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
import me.rhunk.snapenhance.common.config.FeatureNotice
|
import me.rhunk.snapenhance.common.config.FeatureNotice
|
||||||
import me.rhunk.snapenhance.common.util.SerializableDataObject
|
|
||||||
import kotlin.time.Duration.Companion.hours
|
import kotlin.time.Duration.Companion.hours
|
||||||
|
|
||||||
|
|
||||||
@ -52,12 +53,12 @@ enum class MessagingRuleType(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class FriendStreaks(
|
data class FriendStreaks(
|
||||||
val userId: String,
|
val notify: Boolean = true,
|
||||||
val notify: Boolean,
|
|
||||||
val expirationTimestamp: Long,
|
val expirationTimestamp: Long,
|
||||||
val length: Int
|
val length: Int
|
||||||
) : SerializableDataObject() {
|
): Parcelable {
|
||||||
fun hoursLeft() = (expirationTimestamp - System.currentTimeMillis()) / 1000 / 60 / 60
|
fun hoursLeft() = (expirationTimestamp - System.currentTimeMillis()) / 1000 / 60 / 60
|
||||||
|
|
||||||
fun isAboutToExpire(expireHours: Int) = (expirationTimestamp - System.currentTimeMillis()).let {
|
fun isAboutToExpire(expireHours: Int) = (expirationTimestamp - System.currentTimeMillis()).let {
|
||||||
@ -65,20 +66,22 @@ data class FriendStreaks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class MessagingGroupInfo(
|
data class MessagingGroupInfo(
|
||||||
val conversationId: String,
|
val conversationId: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val participantsCount: Int
|
val participantsCount: Int
|
||||||
) : SerializableDataObject()
|
): Parcelable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class MessagingFriendInfo(
|
data class MessagingFriendInfo(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val displayName: String?,
|
val displayName: String?,
|
||||||
val mutableUsername: String,
|
val mutableUsername: String,
|
||||||
val bitmojiId: String?,
|
val bitmojiId: String?,
|
||||||
val selfieId: String?
|
val selfieId: String?,
|
||||||
) : SerializableDataObject()
|
var streaks: FriendStreaks?,
|
||||||
|
): Parcelable
|
||||||
|
|
||||||
class StoryData(
|
class StoryData(
|
||||||
val url: String,
|
val url: String,
|
||||||
@ -86,4 +89,4 @@ class StoryData(
|
|||||||
val createdAt: Long,
|
val createdAt: Long,
|
||||||
val key: ByteArray?,
|
val key: ByteArray?,
|
||||||
val iv: ByteArray?
|
val iv: ByteArray?
|
||||||
) : SerializableDataObject()
|
)
|
@ -3,7 +3,6 @@ package me.rhunk.snapenhance.common.database.impl
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import me.rhunk.snapenhance.common.database.DatabaseObject
|
import me.rhunk.snapenhance.common.database.DatabaseObject
|
||||||
import me.rhunk.snapenhance.common.util.SerializableDataObject
|
|
||||||
import me.rhunk.snapenhance.common.util.ktx.getInteger
|
import me.rhunk.snapenhance.common.util.ktx.getInteger
|
||||||
import me.rhunk.snapenhance.common.util.ktx.getLong
|
import me.rhunk.snapenhance.common.util.ktx.getLong
|
||||||
import me.rhunk.snapenhance.common.util.ktx.getStringOrNull
|
import me.rhunk.snapenhance.common.util.ktx.getStringOrNull
|
||||||
@ -33,7 +32,7 @@ data class FriendInfo(
|
|||||||
var usernameForSorting: String? = null,
|
var usernameForSorting: String? = null,
|
||||||
var friendLinkType: Int = 0,
|
var friendLinkType: Int = 0,
|
||||||
var postViewEmoji: String? = null,
|
var postViewEmoji: String? = null,
|
||||||
) : DatabaseObject, SerializableDataObject() {
|
) : DatabaseObject {
|
||||||
val mutableUsername get() = username?.split("|")?.last()
|
val mutableUsername get() = username?.split("|")?.last()
|
||||||
val firstCreatedUsername get() = username?.split("|")?.first()
|
val firstCreatedUsername get() = username?.split("|")?.first()
|
||||||
|
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package me.rhunk.snapenhance.common.util
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.parcelableCreator
|
||||||
|
import kotlin.io.encoding.Base64
|
||||||
|
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||||
|
|
||||||
|
@OptIn(ExperimentalEncodingApi::class)
|
||||||
|
fun Parcelable.toSerialized(): String? {
|
||||||
|
val parcel = android.os.Parcel.obtain()
|
||||||
|
return try {
|
||||||
|
writeToParcel(parcel, 0)
|
||||||
|
parcel.marshall()?.let {
|
||||||
|
Base64.encode(it)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
parcel.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalEncodingApi::class)
|
||||||
|
inline fun <reified T : Parcelable> toParcelable(serialized: String): T? {
|
||||||
|
val parcel = android.os.Parcel.obtain()
|
||||||
|
return try {
|
||||||
|
Base64.decode(serialized).let {
|
||||||
|
parcel.unmarshall(it, 0, it.size)
|
||||||
|
}
|
||||||
|
parcel.setDataPosition(0)
|
||||||
|
parcelableCreator<T>().createFromParcel(parcel)
|
||||||
|
} finally {
|
||||||
|
parcel.recycle()
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
package me.rhunk.snapenhance.common.util
|
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
|
|
||||||
open class SerializableDataObject {
|
|
||||||
companion object {
|
|
||||||
val gson: Gson = GsonBuilder().create()
|
|
||||||
|
|
||||||
inline fun <reified T : SerializableDataObject> fromJson(json: String): T {
|
|
||||||
return gson.fromJson(json, T::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T : SerializableDataObject> fromJson(json: String, type: Class<T>): T {
|
|
||||||
return gson.fromJson(json, type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toJson(): String {
|
|
||||||
return gson.toJson(this)
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,8 +13,10 @@ import me.rhunk.snapenhance.bridge.SyncCallback
|
|||||||
import me.rhunk.snapenhance.common.Constants
|
import me.rhunk.snapenhance.common.Constants
|
||||||
import me.rhunk.snapenhance.common.ReceiversConfig
|
import me.rhunk.snapenhance.common.ReceiversConfig
|
||||||
import me.rhunk.snapenhance.common.action.EnumAction
|
import me.rhunk.snapenhance.common.action.EnumAction
|
||||||
|
import me.rhunk.snapenhance.common.data.FriendStreaks
|
||||||
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||||
|
import me.rhunk.snapenhance.common.util.toSerialized
|
||||||
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
||||||
import me.rhunk.snapenhance.core.bridge.loadFromBridge
|
import me.rhunk.snapenhance.core.bridge.loadFromBridge
|
||||||
import me.rhunk.snapenhance.core.data.SnapClassCache
|
import me.rhunk.snapenhance.core.data.SnapClassCache
|
||||||
@ -151,7 +153,6 @@ class SnapEnhance {
|
|||||||
features.init()
|
features.init()
|
||||||
scriptRuntime.connect(bridgeClient.getScriptingInterface())
|
scriptRuntime.connect(bridgeClient.getScriptingInterface())
|
||||||
scriptRuntime.eachModule { callFunction("module.onSnapApplicationLoad", androidContext) }
|
scriptRuntime.eachModule { callFunction("module.onSnapApplicationLoad", androidContext) }
|
||||||
syncRemote()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ class SnapEnhance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appContext.apply {
|
appContext.executeAsync {
|
||||||
bridgeClient.registerConfigStateListener(object: ConfigStateListener.Stub() {
|
bridgeClient.registerConfigStateListener(object: ConfigStateListener.Stub() {
|
||||||
override fun onConfigChanged() {
|
override fun onConfigChanged() {
|
||||||
log.verbose("onConfigChanged")
|
log.verbose("onConfigChanged")
|
||||||
@ -227,7 +228,21 @@ class SnapEnhance {
|
|||||||
appContext.executeAsync {
|
appContext.executeAsync {
|
||||||
bridgeClient.sync(object : SyncCallback.Stub() {
|
bridgeClient.sync(object : SyncCallback.Stub() {
|
||||||
override fun syncFriend(uuid: String): String? {
|
override fun syncFriend(uuid: String): String? {
|
||||||
return database.getFriendInfo(uuid)?.toJson()
|
return database.getFriendInfo(uuid)?.let {
|
||||||
|
MessagingFriendInfo(
|
||||||
|
userId = it.userId!!,
|
||||||
|
displayName = it.displayName,
|
||||||
|
mutableUsername = it.mutableUsername!!,
|
||||||
|
bitmojiId = it.bitmojiAvatarId,
|
||||||
|
selfieId = it.bitmojiSelfieId,
|
||||||
|
streaks = if (it.streakLength > 0) {
|
||||||
|
FriendStreaks(
|
||||||
|
expirationTimestamp = it.streakExpirationTimestamp,
|
||||||
|
length = it.streakLength
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
).toSerialized()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun syncGroup(uuid: String): String? {
|
override fun syncGroup(uuid: String): String? {
|
||||||
@ -236,7 +251,7 @@ class SnapEnhance {
|
|||||||
it.key!!,
|
it.key!!,
|
||||||
it.feedDisplayName!!,
|
it.feedDisplayName!!,
|
||||||
it.participantsSize
|
it.participantsSize
|
||||||
).toJson()
|
).toSerialized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -260,14 +275,12 @@ class SnapEnhance {
|
|||||||
it.friendDisplayName,
|
it.friendDisplayName,
|
||||||
it.friendDisplayUsername!!.split("|")[1],
|
it.friendDisplayUsername!!.split("|")[1],
|
||||||
it.bitmojiAvatarId,
|
it.bitmojiAvatarId,
|
||||||
it.bitmojiSelfieId
|
it.bitmojiSelfieId,
|
||||||
|
streaks = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeClient.passGroupsAndFriends(
|
bridgeClient.passGroupsAndFriends(groups, friends)
|
||||||
groups.map { it.toJson() },
|
|
||||||
friends.map { it.toJson() }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,11 @@ import me.rhunk.snapenhance.common.bridge.FileLoaderWrapper
|
|||||||
import me.rhunk.snapenhance.common.bridge.types.BridgeFileType
|
import me.rhunk.snapenhance.common.bridge.types.BridgeFileType
|
||||||
import me.rhunk.snapenhance.common.bridge.types.FileActionType
|
import me.rhunk.snapenhance.common.bridge.types.FileActionType
|
||||||
import me.rhunk.snapenhance.common.bridge.types.LocalePair
|
import me.rhunk.snapenhance.common.bridge.types.LocalePair
|
||||||
|
import me.rhunk.snapenhance.common.data.MessagingFriendInfo
|
||||||
|
import me.rhunk.snapenhance.common.data.MessagingGroupInfo
|
||||||
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
import me.rhunk.snapenhance.common.data.MessagingRuleType
|
||||||
import me.rhunk.snapenhance.common.data.SocialScope
|
import me.rhunk.snapenhance.common.data.SocialScope
|
||||||
|
import me.rhunk.snapenhance.common.util.toSerialized
|
||||||
import me.rhunk.snapenhance.core.ModContext
|
import me.rhunk.snapenhance.core.ModContext
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@ -136,7 +139,10 @@ class BridgeClient(
|
|||||||
|
|
||||||
fun triggerSync(scope: SocialScope, id: String) = service.triggerSync(scope.key, id)
|
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<MessagingGroupInfo>, friends: List<MessagingFriendInfo>) = service.passGroupsAndFriends(
|
||||||
|
groups.mapNotNull { it.toSerialized() },
|
||||||
|
friends.mapNotNull { it.toSerialized() }
|
||||||
|
)
|
||||||
|
|
||||||
fun getRules(targetUuid: String): List<MessagingRuleType> {
|
fun getRules(targetUuid: String): List<MessagingRuleType> {
|
||||||
return service.getRules(targetUuid).mapNotNull { MessagingRuleType.getByName(it) }
|
return service.getRules(targetUuid).mapNotNull { MessagingRuleType.getByName(it) }
|
||||||
|
@ -15,12 +15,12 @@ class ActionManager(
|
|||||||
|
|
||||||
private val actions by lazy {
|
private val actions by lazy {
|
||||||
mapOf(
|
mapOf(
|
||||||
EnumAction.CLEAN_CACHE to CleanCache::class,
|
EnumAction.CLEAN_CACHE to CleanCache(),
|
||||||
EnumAction.EXPORT_CHAT_MESSAGES to ExportChatMessages::class,
|
EnumAction.EXPORT_CHAT_MESSAGES to ExportChatMessages(),
|
||||||
EnumAction.BULK_MESSAGING_ACTION to BulkMessagingAction::class,
|
EnumAction.BULK_MESSAGING_ACTION to BulkMessagingAction(),
|
||||||
EnumAction.EXPORT_MEMORIES to ExportMemories::class,
|
EnumAction.EXPORT_MEMORIES to ExportMemories(),
|
||||||
).map {
|
).map {
|
||||||
it.key to it.value.java.getConstructor().newInstance().apply {
|
it.key to it.value.apply {
|
||||||
this.context = modContext
|
this.context = modContext
|
||||||
}
|
}
|
||||||
}.toMap().toMutableMap()
|
}.toMap().toMutableMap()
|
||||||
|
@ -8,17 +8,15 @@ import me.rhunk.snapenhance.core.features.Feature
|
|||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
import me.rhunk.snapenhance.core.features.MessagingRuleFeature
|
import me.rhunk.snapenhance.core.features.MessagingRuleFeature
|
||||||
import me.rhunk.snapenhance.core.features.impl.ConfigurationOverride
|
import me.rhunk.snapenhance.core.features.impl.ConfigurationOverride
|
||||||
|
import me.rhunk.snapenhance.core.features.impl.MixerStories
|
||||||
import me.rhunk.snapenhance.core.features.impl.OperaViewerParamsOverride
|
import me.rhunk.snapenhance.core.features.impl.OperaViewerParamsOverride
|
||||||
import me.rhunk.snapenhance.core.features.impl.ScopeSync
|
import me.rhunk.snapenhance.core.features.impl.ScopeSync
|
||||||
import me.rhunk.snapenhance.core.features.impl.MixerStories
|
|
||||||
import me.rhunk.snapenhance.core.features.impl.downloader.MediaDownloader
|
import me.rhunk.snapenhance.core.features.impl.downloader.MediaDownloader
|
||||||
import me.rhunk.snapenhance.core.features.impl.downloader.ProfilePictureDownloader
|
import me.rhunk.snapenhance.core.features.impl.downloader.ProfilePictureDownloader
|
||||||
import me.rhunk.snapenhance.core.features.impl.experiments.*
|
import me.rhunk.snapenhance.core.features.impl.experiments.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.global.*
|
import me.rhunk.snapenhance.core.features.impl.global.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.messaging.*
|
import me.rhunk.snapenhance.core.features.impl.messaging.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.HalfSwipeNotifier
|
import me.rhunk.snapenhance.core.features.impl.spying.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.StealthMode
|
|
||||||
import me.rhunk.snapenhance.core.features.impl.tweaks.BypassScreenshotDetection
|
import me.rhunk.snapenhance.core.features.impl.tweaks.BypassScreenshotDetection
|
||||||
import me.rhunk.snapenhance.core.features.impl.tweaks.CameraTweaks
|
import me.rhunk.snapenhance.core.features.impl.tweaks.CameraTweaks
|
||||||
import me.rhunk.snapenhance.core.features.impl.tweaks.PreventMessageListAutoScroll
|
import me.rhunk.snapenhance.core.features.impl.tweaks.PreventMessageListAutoScroll
|
||||||
@ -33,23 +31,19 @@ import kotlin.system.measureTimeMillis
|
|||||||
class FeatureManager(
|
class FeatureManager(
|
||||||
private val context: ModContext
|
private val context: ModContext
|
||||||
) : Manager {
|
) : Manager {
|
||||||
private val features = mutableListOf<Feature>()
|
private val features = mutableMapOf<KClass<out Feature>, Feature>()
|
||||||
|
|
||||||
private fun register(vararg featureClasses: KClass<out Feature>) {
|
private fun register(vararg featureList: Feature) {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
featureClasses.forEach { clazz ->
|
featureList.forEach { feature ->
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
clazz.java.constructors.first().newInstance()
|
feature.context = context
|
||||||
.let { it as Feature }
|
synchronized(features) {
|
||||||
.also {
|
features[feature::class] = feature
|
||||||
it.context = context
|
}
|
||||||
synchronized(features) {
|
|
||||||
features.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
CoreLogger.xposedLog("Failed to register feature ${clazz.simpleName}", it)
|
CoreLogger.xposedLog("Failed to register feature ${feature.featureKey}", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,91 +52,92 @@ class FeatureManager(
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T : Feature> get(featureClass: KClass<T>): T? {
|
fun <T : Feature> get(featureClass: KClass<T>): T? {
|
||||||
return features.find { it::class == featureClass } as? T
|
return features[featureClass] as? T
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRuleFeatures() = features.filterIsInstance<MessagingRuleFeature>().sortedBy { it.ruleType.ordinal }
|
fun getRuleFeatures() = features.values.filterIsInstance<MessagingRuleFeature>().sortedBy { it.ruleType.ordinal }
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
register(
|
register(
|
||||||
EndToEndEncryption::class,
|
EndToEndEncryption(),
|
||||||
ScopeSync::class,
|
ScopeSync(),
|
||||||
PreventMessageListAutoScroll::class,
|
PreventMessageListAutoScroll(),
|
||||||
Messaging::class,
|
Messaging(),
|
||||||
MediaDownloader::class,
|
MediaDownloader(),
|
||||||
StealthMode::class,
|
StealthMode(),
|
||||||
MenuViewInjector::class,
|
MenuViewInjector(),
|
||||||
PreventReadReceipts::class,
|
PreventReadReceipts(),
|
||||||
MessageLogger::class,
|
MessageLogger(),
|
||||||
ConvertMessageLocally::class,
|
ConvertMessageLocally(),
|
||||||
SnapchatPlus::class,
|
SnapchatPlus(),
|
||||||
DisableMetrics::class,
|
DisableMetrics(),
|
||||||
PreventMessageSending::class,
|
PreventMessageSending(),
|
||||||
Notifications::class,
|
Notifications(),
|
||||||
AutoSave::class,
|
AutoSave(),
|
||||||
UITweaks::class,
|
UITweaks(),
|
||||||
ConfigurationOverride::class,
|
ConfigurationOverride(),
|
||||||
UnsaveableMessages::class,
|
UnsaveableMessages(),
|
||||||
SendOverride::class,
|
SendOverride(),
|
||||||
UnlimitedSnapViewTime::class,
|
UnlimitedSnapViewTime(),
|
||||||
BypassVideoLengthRestriction::class,
|
BypassVideoLengthRestriction(),
|
||||||
MediaQualityLevelOverride::class,
|
MediaQualityLevelOverride(),
|
||||||
MeoPasscodeBypass::class,
|
MeoPasscodeBypass(),
|
||||||
AppPasscode::class,
|
AppPasscode(),
|
||||||
LocationSpoofer::class,
|
LocationSpoofer(),
|
||||||
CameraTweaks::class,
|
CameraTweaks(),
|
||||||
InfiniteStoryBoost::class,
|
InfiniteStoryBoost(),
|
||||||
AmoledDarkMode::class,
|
AmoledDarkMode(),
|
||||||
PinConversations::class,
|
PinConversations(),
|
||||||
UnlimitedMultiSnap::class,
|
UnlimitedMultiSnap(),
|
||||||
DeviceSpooferHook::class,
|
DeviceSpooferHook(),
|
||||||
ClientBootstrapOverride::class,
|
ClientBootstrapOverride(),
|
||||||
GooglePlayServicesDialogs::class,
|
GooglePlayServicesDialogs(),
|
||||||
NoFriendScoreDelay::class,
|
NoFriendScoreDelay(),
|
||||||
ProfilePictureDownloader::class,
|
ProfilePictureDownloader(),
|
||||||
AddFriendSourceSpoof::class,
|
AddFriendSourceSpoof(),
|
||||||
DisableReplayInFF::class,
|
DisableReplayInFF(),
|
||||||
OldBitmojiSelfie::class,
|
OldBitmojiSelfie(),
|
||||||
FriendFeedMessagePreview::class,
|
FriendFeedMessagePreview(),
|
||||||
HideStreakRestore::class,
|
HideStreakRestore(),
|
||||||
HideFriendFeedEntry::class,
|
HideFriendFeedEntry(),
|
||||||
HideQuickAddFriendFeed::class,
|
HideQuickAddFriendFeed(),
|
||||||
CallStartConfirmation::class,
|
CallStartConfirmation(),
|
||||||
SnapPreview::class,
|
SnapPreview(),
|
||||||
InstantDelete::class,
|
InstantDelete(),
|
||||||
BypassScreenshotDetection::class,
|
BypassScreenshotDetection(),
|
||||||
HalfSwipeNotifier::class,
|
HalfSwipeNotifier(),
|
||||||
DisableConfirmationDialogs::class,
|
DisableConfirmationDialogs(),
|
||||||
MixerStories::class,
|
MixerStories(),
|
||||||
DisableComposerModules::class,
|
DisableComposerModules(),
|
||||||
FideliusIndicator::class,
|
FideliusIndicator(),
|
||||||
EditTextOverride::class,
|
EditTextOverride(),
|
||||||
PreventForcedLogout::class,
|
PreventForcedLogout(),
|
||||||
SuspendLocationUpdates::class,
|
SuspendLocationUpdates(),
|
||||||
ConversationToolbox::class,
|
ConversationToolbox(),
|
||||||
SpotlightCommentsUsername::class,
|
SpotlightCommentsUsername(),
|
||||||
OperaViewerParamsOverride::class,
|
OperaViewerParamsOverride(),
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeFeatures()
|
initializeFeatures()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun tryInit(feature: Feature, crossinline block: () -> Unit) {
|
||||||
|
runCatching {
|
||||||
|
block()
|
||||||
|
}.onFailure {
|
||||||
|
context.log.error("Failed to init feature ${feature.featureKey}", it)
|
||||||
|
context.longToast("Failed to init feature ${feature.featureKey}! Check logcat for more details.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun initFeatures(
|
private fun initFeatures(
|
||||||
syncParam: Int,
|
syncParam: Int,
|
||||||
asyncParam: Int,
|
asyncParam: Int,
|
||||||
syncAction: (Feature) -> Unit,
|
syncAction: (Feature) -> Unit,
|
||||||
asyncAction: (Feature) -> Unit
|
asyncAction: (Feature) -> Unit
|
||||||
) {
|
) {
|
||||||
fun tryInit(feature: Feature, block: () -> Unit) {
|
|
||||||
runCatching {
|
|
||||||
block()
|
|
||||||
}.onFailure {
|
|
||||||
context.log.error("Failed to init feature ${feature.featureKey}", it)
|
|
||||||
context.longToast("Failed to init feature ${feature.featureKey}! Check logcat for more details.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
features.toList().forEach { feature ->
|
features.values.toList().forEach { feature ->
|
||||||
if (feature.loadParams and syncParam != 0) {
|
if (feature.loadParams and syncParam != 0) {
|
||||||
tryInit(feature) {
|
tryInit(feature) {
|
||||||
syncAction(feature)
|
syncAction(feature)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user