mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-06-06 01:49:31 +02:00
Merge branch 'dev' into dev_gh
This commit is contained in:
commit
ba848dfd9d
@ -638,6 +638,10 @@
|
|||||||
"name": "Unlimited Conversation Pinning",
|
"name": "Unlimited Conversation Pinning",
|
||||||
"description": "Allows you to pin an unlimited amount of conversations locally"
|
"description": "Allows you to pin an unlimited amount of conversations locally"
|
||||||
},
|
},
|
||||||
|
"disable_snap_mode_restrictions": {
|
||||||
|
"name": "Disable Snap Mode Restrictions",
|
||||||
|
"description": "Allows you to view self-destructing Snaps without restrictions"
|
||||||
|
},
|
||||||
"prevent_message_sending": {
|
"prevent_message_sending": {
|
||||||
"name": "Prevent Message Sending",
|
"name": "Prevent Message Sending",
|
||||||
"description": "Prevents sending certain types of messages"
|
"description": "Prevents sending certain types of messages"
|
||||||
@ -982,6 +986,10 @@
|
|||||||
"name": "Bypass Camera Roll Limit",
|
"name": "Bypass Camera Roll Limit",
|
||||||
"description": "Increases the maximum amount of media you can send from the camera roll"
|
"description": "Increases the maximum amount of media you can send from the camera roll"
|
||||||
},
|
},
|
||||||
|
"custom_self_destruct_snap_delay": {
|
||||||
|
"name": "Custom Self Destruct Snap Delay",
|
||||||
|
"description": "Gives more options for the self-destruct timer when sending a Snap"
|
||||||
|
},
|
||||||
"composer_console": {
|
"composer_console": {
|
||||||
"name": "Composer Console",
|
"name": "Composer Console",
|
||||||
"description": "Allows you to execute JavaScript code in Composer (arm64 only)"
|
"description": "Allows you to execute JavaScript code in Composer (arm64 only)"
|
||||||
|
@ -27,6 +27,7 @@ class Experimental : ConfigContainer() {
|
|||||||
class ComposerHooksConfig: ConfigContainer(hasGlobalState = true) {
|
class ComposerHooksConfig: ConfigContainer(hasGlobalState = true) {
|
||||||
val showFirstCreatedUsername = boolean("show_first_created_username")
|
val showFirstCreatedUsername = boolean("show_first_created_username")
|
||||||
val bypassCameraRollLimit = boolean("bypass_camera_roll_limit")
|
val bypassCameraRollLimit = boolean("bypass_camera_roll_limit")
|
||||||
|
val customSelfDestructSnapDelay = boolean("custom_self_destruct_snap_delay")
|
||||||
val composerConsole = boolean("composer_console")
|
val composerConsole = boolean("composer_console")
|
||||||
val composerLogs = boolean("composer_logs")
|
val composerLogs = boolean("composer_logs")
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ class MessagingTweaks : ConfigContainer() {
|
|||||||
val halfSwipeNotifier = container("half_swipe_notifier", HalfSwipeNotifierConfig()) { requireRestart()}
|
val halfSwipeNotifier = container("half_swipe_notifier", HalfSwipeNotifierConfig()) { requireRestart()}
|
||||||
val callStartConfirmation = boolean("call_start_confirmation") { requireRestart() }
|
val callStartConfirmation = boolean("call_start_confirmation") { requireRestart() }
|
||||||
val unlimitedConversationPinning = boolean("unlimited_conversation_pinning") { requireRestart() }
|
val unlimitedConversationPinning = boolean("unlimited_conversation_pinning") { requireRestart() }
|
||||||
|
val disableSnapModeRestrictions = boolean("disable_snap_mode_restrictions") { requireRestart() }
|
||||||
val autoSaveMessagesInConversations = multiple("auto_save_messages_in_conversations",
|
val autoSaveMessagesInConversations = multiple("auto_save_messages_in_conversations",
|
||||||
"CHAT",
|
"CHAT",
|
||||||
"SNAP",
|
"SNAP",
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export const jsx = require('composer_core/src/JSX').jsx;
|
import { runtimeName } from "./imports"
|
||||||
export const assetCatalog = require("composer_core/src/AssetCatalog")
|
|
||||||
export const style = require("composer_core/src/Style");
|
export const jsx = require(runtimeName + '_core/src/JSX').jsx;
|
||||||
|
export const assetCatalog = require(runtimeName + "_core/src/AssetCatalog")
|
||||||
|
export const style = require(runtimeName + "_core/src/Style");
|
||||||
export const colors = require("coreui/src/styles/semanticColors");
|
export const colors = require("coreui/src/styles/semanticColors");
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { Config, FriendInfo } from "./types";
|
import { Config, FriendInfo } from "./types";
|
||||||
|
|
||||||
declare var _getImportsFunctionName: string;
|
declare var _getImportsFunctionName: string;
|
||||||
const remoteImports = require('composer_core/src/DeviceBridge')[_getImportsFunctionName]();
|
declare var _runtimeName: boolean;
|
||||||
|
export const runtimeName = _runtimeName;
|
||||||
|
|
||||||
|
const remoteImports = require(_runtimeName + '_core/src/DeviceBridge')[_getImportsFunctionName]();
|
||||||
|
|
||||||
function callRemoteFunction(method: string, ...args: any[]): any | null {
|
function callRemoteFunction(method: string, ...args: any[]): any | null {
|
||||||
return remoteImports[method](...args);
|
return remoteImports[method](...args);
|
||||||
|
@ -4,6 +4,7 @@ import { modules } from "./types";
|
|||||||
import "./modules/operaDownloadButton";
|
import "./modules/operaDownloadButton";
|
||||||
import "./modules/firstCreatedUsername";
|
import "./modules/firstCreatedUsername";
|
||||||
import "./modules/bypassCameraRollSelectionLimit";
|
import "./modules/bypassCameraRollSelectionLimit";
|
||||||
|
import "./modules/selfDestructSnapDelay";
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -21,12 +22,13 @@ try {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
m.init();
|
m.init();
|
||||||
|
console.debug(`module ${m.name} initialized`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`failed to initialize module ${m.name}`, e, e.stack);
|
console.error(`failed to initialize module ${m.name}`, e, e.stack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("modules loaded!");
|
console.debug("modules loaded!");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log("error", "Failed to load composer modules\n" + e + "\n" + e.stack)
|
log("error", "Failed to load composer modules\n" + e + "\n" + e.stack)
|
||||||
}
|
}
|
||||||
|
47
composer/src/main/ts/modules/selfDestructSnapDelay.ts
Normal file
47
composer/src/main/ts/modules/selfDestructSnapDelay.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { defineModule } from "../types";
|
||||||
|
import { interceptComponent } from "../utils";
|
||||||
|
|
||||||
|
export default defineModule({
|
||||||
|
name: "Self Destruct Snap Delay",
|
||||||
|
enabled: config => config.customSelfDestructSnapDelay,
|
||||||
|
init() {
|
||||||
|
interceptComponent(
|
||||||
|
'snap_editor_timer_tool/src/TimerPickerView',
|
||||||
|
'TimerPickerView',
|
||||||
|
{
|
||||||
|
"<init>": (args: any[], superCall: () => void) => {
|
||||||
|
if (args[1].options[0] == 30) {
|
||||||
|
args[1].style = 0; // seconds format
|
||||||
|
|
||||||
|
args[1].options = [
|
||||||
|
5, // 5 seconds
|
||||||
|
10, // 10 seconds
|
||||||
|
20, // 20 seconds
|
||||||
|
30, // 30 seconds
|
||||||
|
60, // 1 minute
|
||||||
|
120, // 2 minutes
|
||||||
|
180, // 3 minutes
|
||||||
|
240, // 4 minutes
|
||||||
|
300, // 5 minutes
|
||||||
|
600, // 10 minutes
|
||||||
|
900, // 15 minutes
|
||||||
|
1200, // 20 minutes
|
||||||
|
1800, // 30 minutes
|
||||||
|
3600, // 1 hour
|
||||||
|
7200, // 2 hours
|
||||||
|
10800, // 3 hours
|
||||||
|
14400, // 4 hours
|
||||||
|
21600, // 6 hours
|
||||||
|
28800, // 8 hours
|
||||||
|
43200, // 12 hours
|
||||||
|
86400, // 1 day
|
||||||
|
172800, // 2 days
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
superCall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
@ -3,6 +3,7 @@ export interface Config {
|
|||||||
readonly bypassCameraRollLimit: boolean
|
readonly bypassCameraRollLimit: boolean
|
||||||
readonly showFirstCreatedUsername: boolean
|
readonly showFirstCreatedUsername: boolean
|
||||||
readonly composerLogs: boolean
|
readonly composerLogs: boolean
|
||||||
|
readonly customSelfDestructSnapDelay: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FriendInfo {
|
export interface FriendInfo {
|
||||||
|
@ -143,6 +143,7 @@ class FeatureManager(
|
|||||||
FriendNotes(),
|
FriendNotes(),
|
||||||
DoubleTapChatAction(),
|
DoubleTapChatAction(),
|
||||||
SnapScoreChanges(),
|
SnapScoreChanges(),
|
||||||
|
DisableSnapModeRestrictions(),
|
||||||
)
|
)
|
||||||
|
|
||||||
features.values.toList().forEach { feature ->
|
features.values.toList().forEach { feature ->
|
||||||
|
@ -104,6 +104,8 @@ class ComposerHooks: Feature("ComposerHooks") {
|
|||||||
override fun init() {
|
override fun init() {
|
||||||
if (config.globalState != true) return
|
if (config.globalState != true) return
|
||||||
|
|
||||||
|
val nativeBridgeClass = runCatching { findClass("com.snapchat.client.valdi.NativeBridge") }.getOrNull() ?: findClass("com.snapchat.client.composer.NativeBridge")
|
||||||
|
|
||||||
val importedFunctions = mutableMapOf<String, Any?>()
|
val importedFunctions = mutableMapOf<String, Any?>()
|
||||||
|
|
||||||
fun composerFunction(name: String, block: ComposerMarshaller.() -> Unit) {
|
fun composerFunction(name: String, block: ComposerMarshaller.() -> Unit) {
|
||||||
@ -118,7 +120,8 @@ class ComposerHooks: Feature("ComposerHooks") {
|
|||||||
"operaDownloadButton" to context.config.downloader.operaDownloadButton.get(),
|
"operaDownloadButton" to context.config.downloader.operaDownloadButton.get(),
|
||||||
"bypassCameraRollLimit" to config.bypassCameraRollLimit.get(),
|
"bypassCameraRollLimit" to config.bypassCameraRollLimit.get(),
|
||||||
"showFirstCreatedUsername" to config.showFirstCreatedUsername.get(),
|
"showFirstCreatedUsername" to config.showFirstCreatedUsername.get(),
|
||||||
"composerLogs" to config.composerLogs.get()
|
"composerLogs" to config.composerLogs.get(),
|
||||||
|
"customSelfDestructSnapDelay" to config.customSelfDestructSnapDelay.get(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +175,8 @@ class ComposerHooks: Feature("ComposerHooks") {
|
|||||||
context.native.setComposerLoader("""
|
context.native.setComposerLoader("""
|
||||||
const i = setInterval(() => {
|
const i = setInterval(() => {
|
||||||
try {
|
try {
|
||||||
require('composer_core/src/DeviceBridge').getDisplayWidth();
|
const _runtimeName = "${if (nativeBridgeClass.name == "com.snapchat.client.valdi.NativeBridge") "valdi" else "composer"}";
|
||||||
|
require(_runtimeName + '_core/src/DeviceBridge').getDisplayWidth();
|
||||||
clearInterval(i);
|
clearInterval(i);
|
||||||
(() => { const _getImportsFunctionName = "$getImportsFunctionName"; $loaderScript })();
|
(() => { const _getImportsFunctionName = "$getImportsFunctionName"; $loaderScript })();
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@ -195,16 +199,14 @@ class ComposerHooks: Feature("ComposerHooks") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findClass("com.snapchat.client.composer.NativeBridge").apply {
|
nativeBridgeClass.hook("registerNativeModuleFactory", HookStage.BEFORE) { param ->
|
||||||
hook("registerNativeModuleFactory", HookStage.BEFORE) { param ->
|
val moduleFactory = param.argNullable<Any>(1) ?: return@hook
|
||||||
val moduleFactory = param.argNullable<Any>(1) ?: return@hook
|
if (moduleFactory.javaClass.getMethod("getModulePath").invoke(moduleFactory)?.toString()?.contains("DeviceBridge") != true) return@hook
|
||||||
if (moduleFactory.javaClass.getMethod("getModulePath").invoke(moduleFactory)?.toString()?.contains("DeviceBridge") != true) return@hook
|
Hooker.ephemeralHookObjectMethod(moduleFactory.javaClass, moduleFactory, "loadModule", HookStage.AFTER) { methodParam ->
|
||||||
Hooker.ephemeralHookObjectMethod(moduleFactory.javaClass, moduleFactory, "loadModule", HookStage.AFTER) { methodParam ->
|
val result = methodParam.getResult() as? MutableMap<String, Any?> ?: return@ephemeralHookObjectMethod
|
||||||
val result = methodParam.getResult() as? MutableMap<String, Any?> ?: return@ephemeralHookObjectMethod
|
result[getImportsFunctionName] = newComposerFunction {
|
||||||
result[getImportsFunctionName] = newComposerFunction {
|
pushUntyped(importedFunctions)
|
||||||
pushUntyped(importedFunctions)
|
true
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package me.rhunk.snapenhance.core.features.impl.tweaks
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
|
import me.rhunk.snapenhance.core.util.dataBuilder
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.hookConstructor
|
||||||
|
|
||||||
|
class DisableSnapModeRestrictions: Feature("Disable Snap Mode Restrictions") {
|
||||||
|
override fun init() {
|
||||||
|
if (!context.config.messaging.disableSnapModeRestrictions.get()) return
|
||||||
|
|
||||||
|
findClass("com.snapchat.client.messaging.SnapModeInfo").hookConstructor(HookStage.AFTER) { param ->
|
||||||
|
param.thisObject<Any>().dataBuilder {
|
||||||
|
set("mSelfDestructSnapDurationMs", null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,12 @@ package me.rhunk.snapenhance.core.features.impl.ui
|
|||||||
import me.rhunk.snapenhance.core.features.Feature
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
|
import me.rhunk.snapenhance.core.util.hook.hookConstructor
|
||||||
import me.rhunk.snapenhance.core.util.ktx.getObjectField
|
import me.rhunk.snapenhance.core.util.ktx.getObjectField
|
||||||
|
import me.rhunk.snapenhance.core.wrapper.impl.SnapUUID
|
||||||
import me.rhunk.snapenhance.mapper.impl.StreaksExpirationMapper
|
import me.rhunk.snapenhance.mapper.impl.StreaksExpirationMapper
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.time.Duration.Companion.hours
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
class CustomStreaksExpirationFormat: Feature("CustomStreaksExpirationFormat") {
|
class CustomStreaksExpirationFormat: Feature("CustomStreaksExpirationFormat") {
|
||||||
@ -12,44 +16,68 @@ class CustomStreaksExpirationFormat: Feature("CustomStreaksExpirationFormat") {
|
|||||||
return this.toString().padStart(2, '0')
|
return this.toString().padStart(2, '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val streakCache = ConcurrentHashMap<String, Pair<Int, Long>>()
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
|
context.classCache.feedEntry.hookConstructor(HookStage.AFTER) { param ->
|
||||||
|
val conversationId = SnapUUID(param.thisObject<Any>().getObjectField("mConversationId")).toString()
|
||||||
|
|
||||||
|
val streakMetadata = param.thisObject<Any>().getObjectField("mStreakMetadata") ?: apply {
|
||||||
|
if (streakCache.containsKey(conversationId)) streakCache.remove(conversationId)
|
||||||
|
return@hookConstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
streakCache.put(conversationId, streakMetadata.getObjectField("mCount") as Int to
|
||||||
|
streakMetadata.getObjectField("mExpirationTimestampMs") as Long)
|
||||||
|
}
|
||||||
|
|
||||||
onNextActivityCreate {
|
onNextActivityCreate {
|
||||||
val expirationFormat by context.config.experimental.customStreaksExpirationFormat
|
val expirationFormat by context.config.experimental.customStreaksExpirationFormat
|
||||||
if (expirationFormat.isNotEmpty() || context.config.userInterface.streakExpirationInfo.get()) {
|
if (expirationFormat.isNotEmpty() || context.config.userInterface.streakExpirationInfo.get()) {
|
||||||
context.mappings.useMapper(StreaksExpirationMapper::class) {
|
context.mappings.useMapper(StreaksExpirationMapper::class) {
|
||||||
runCatching {
|
simpleStreaksFormatterClass.getAsClass()?.hook(
|
||||||
simpleStreaksFormatterClass.getAsClass()?.hook(formatSimpleStreaksTextMethod.get() ?: return@useMapper, HookStage.BEFORE) { param ->
|
formatSimpleStreaksTextMethod.get() ?: return@useMapper,
|
||||||
param.setResult(null)
|
HookStage.AFTER
|
||||||
|
) { param ->
|
||||||
|
val result = param.getResult() as? String ?: return@hook
|
||||||
|
|
||||||
|
streakCache[param.arg<String>(1)]?.also { (streakCount, expirationTime) ->
|
||||||
|
if (expirationTime <= 0L) return@also
|
||||||
|
|
||||||
|
if (expirationFormat.isEmpty()) {
|
||||||
|
val remainingTime = (expirationTime - System.currentTimeMillis()).milliseconds.inWholeHours
|
||||||
|
var emojiIndex = result.indexOfFirst { it.code > 127 }.takeIf { it != -1 }
|
||||||
|
?.let { it + 2 }
|
||||||
|
|
||||||
|
if (emojiIndex == null) {
|
||||||
|
emojiIndex = result.length
|
||||||
|
}
|
||||||
|
|
||||||
|
param.setResult(
|
||||||
|
result.substring(0, emojiIndex) + remainingTime + result.substring(emojiIndex)
|
||||||
|
)
|
||||||
|
return@hook
|
||||||
|
}
|
||||||
|
|
||||||
|
val delta = (expirationTime - System.currentTimeMillis()).milliseconds
|
||||||
|
|
||||||
|
val hourGlassEmoji =
|
||||||
|
if (delta.inWholeMilliseconds in 1..(15.hours.inWholeMilliseconds)) if (expirationTime % 2 == 0L) "\u23F3" else "\u231B" else ""
|
||||||
|
|
||||||
|
param.setResult(
|
||||||
|
expirationFormat
|
||||||
|
.replace("%c", streakCount.toString())
|
||||||
|
.replace("%e", hourGlassEmoji)
|
||||||
|
.replace("%d", delta.inWholeDays.toString())
|
||||||
|
.replace("%h", (delta.inWholeHours % 24).padZero())
|
||||||
|
.replace("%m", (delta.inWholeMinutes % 60).padZero())
|
||||||
|
.replace("%s", (delta.inWholeSeconds % 60).padZero())
|
||||||
|
.replace("%w", delta.toString())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
|
||||||
context.log.warn("Failed to hook simpleStreaksFormatterClass : " + it.message)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expirationFormat.isEmpty()) return@onNextActivityCreate
|
|
||||||
|
|
||||||
context.mappings.useMapper(StreaksExpirationMapper::class) {
|
|
||||||
streaksFormatterClass.getAsClass()?.hook(formatStreaksTextMethod.get() ?: return@useMapper, HookStage.AFTER) { param ->
|
|
||||||
val streaksCount = param.argNullable(2) ?: 0
|
|
||||||
val streaksExpiration = param.argNullable<Any>(3) ?: return@hook
|
|
||||||
|
|
||||||
val hourGlassTimeRemaining = streaksExpiration.getObjectField(hourGlassTimeRemainingField.get() ?: return@hook) as? Long ?: return@hook
|
|
||||||
val expirationTime = streaksExpiration.getObjectField(expirationTimeField.get() ?: return@hook) as? Long ?: return@hook
|
|
||||||
val delta = (expirationTime - System.currentTimeMillis()).milliseconds
|
|
||||||
|
|
||||||
val hourGlassEmoji = if (delta.inWholeMilliseconds in 1..hourGlassTimeRemaining) if (expirationTime % 2 == 0L) "\u23F3" else "\u231B" else ""
|
|
||||||
|
|
||||||
param.setResult(expirationFormat
|
|
||||||
.replace("%c", streaksCount.toString())
|
|
||||||
.replace("%e", hourGlassEmoji)
|
|
||||||
.replace("%d", delta.inWholeDays.toString())
|
|
||||||
.replace("%h", (delta.inWholeHours % 24).padZero())
|
|
||||||
.replace("%m", (delta.inWholeMinutes % 60).padZero())
|
|
||||||
.replace("%s", (delta.inWholeSeconds % 60).padZero())
|
|
||||||
.replace("%w", delta.toString())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -38,8 +38,7 @@ class MenuViewInjector : Feature("MenuViewInjector") {
|
|||||||
onNextActivityCreate(defer = true) {
|
onNextActivityCreate(defer = true) {
|
||||||
menuMap.forEach { it.value.init() }
|
menuMap.forEach { it.value.init() }
|
||||||
|
|
||||||
val chatActionMenu = context.resources.getIdentifier("chat_action_menu", "id")
|
val hasV2ActionMenu = { true }
|
||||||
val hasV2ActionMenu = { context.feature(COFOverride::class).hasActionMenuV2 }
|
|
||||||
|
|
||||||
context.event.subscribe(AddViewEvent::class) { event ->
|
context.event.subscribe(AddViewEvent::class) { event ->
|
||||||
menuMap.forEach { it.value.onViewAdded(event) }
|
menuMap.forEach { it.value.onViewAdded(event) }
|
||||||
|
@ -3,16 +3,9 @@ package me.rhunk.snapenhance.mapper.impl
|
|||||||
import me.rhunk.snapenhance.mapper.AbstractClassMapper
|
import me.rhunk.snapenhance.mapper.AbstractClassMapper
|
||||||
import me.rhunk.snapenhance.mapper.ext.findConstString
|
import me.rhunk.snapenhance.mapper.ext.findConstString
|
||||||
import me.rhunk.snapenhance.mapper.ext.getClassName
|
import me.rhunk.snapenhance.mapper.ext.getClassName
|
||||||
import me.rhunk.snapenhance.mapper.ext.searchNextFieldReference
|
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
class StreaksExpirationMapper: AbstractClassMapper("StreaksExpirationMapper") {
|
class StreaksExpirationMapper: AbstractClassMapper("StreaksExpirationMapper") {
|
||||||
val hourGlassTimeRemainingField = string("hourGlassTimeRemainingField")
|
|
||||||
val expirationTimeField = string("expirationTimeField")
|
|
||||||
|
|
||||||
val streaksFormatterClass = classReference("streaksFormatterClass")
|
|
||||||
val formatStreaksTextMethod = string("formatStreaksTextMethod")
|
|
||||||
|
|
||||||
val simpleStreaksFormatterClass = classReference("simpleStreaksFormatterClass")
|
val simpleStreaksFormatterClass = classReference("simpleStreaksFormatterClass")
|
||||||
val formatSimpleStreaksTextMethod = string("formatSimpleStreaksTextMethod")
|
val formatSimpleStreaksTextMethod = string("formatSimpleStreaksTextMethod")
|
||||||
|
|
||||||
@ -41,35 +34,5 @@ class StreaksExpirationMapper: AbstractClassMapper("StreaksExpirationMapper") {
|
|||||||
return@mapper
|
return@mapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper {
|
|
||||||
var streaksExpirationClassName: String? = null
|
|
||||||
for (clazz in classes) {
|
|
||||||
val toStringMethod = clazz.methods.firstOrNull { it.name == "toString" } ?: continue
|
|
||||||
if (toStringMethod.implementation?.findConstString("StreaksExpiration(", contains = true) != true) continue
|
|
||||||
|
|
||||||
streaksExpirationClassName = clazz.getClassName()
|
|
||||||
toStringMethod.implementation?.apply {
|
|
||||||
hourGlassTimeRemainingField.set(searchNextFieldReference("hourGlassTimeRemaining", contains = true)?.name)
|
|
||||||
expirationTimeField.set(searchNextFieldReference("expirationTime", contains = true)?.name)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streaksExpirationClassName == null) return@mapper
|
|
||||||
|
|
||||||
for (clazz in classes) {
|
|
||||||
val formatStreaksTextDexMethod = clazz.methods.firstOrNull { method ->
|
|
||||||
Modifier.isStatic(method.accessFlags) &&
|
|
||||||
method.returnType == "Ljava/lang/String;" &&
|
|
||||||
method.parameterTypes.let {
|
|
||||||
it.size >= 4 && it[0] == "Ljava/util/Map;" && it[2] == "Ljava/lang/Integer;" && it[3].contains(streaksExpirationClassName)
|
|
||||||
}
|
|
||||||
} ?: continue
|
|
||||||
streaksFormatterClass.set(clazz.getClassName())
|
|
||||||
formatStreaksTextMethod.set(formatStreaksTextDexMethod.name)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
2
native/rust/.cargo/config.toml
Normal file
2
native/rust/.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[build]
|
||||||
|
target = "aarch64-linux-android"
|
Loading…
x
Reference in New Issue
Block a user