mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 21:10:20 +02:00
feat(composer_hooks): opera download button
This commit is contained in:
parent
69e5ca74ee
commit
f830ce13c6
@ -9,51 +9,130 @@ if (config.composerLogs) {
|
|||||||
console.info("loader.js loaded");
|
console.info("loader.js loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.bypassCameraRollLimit) {
|
// Composer imports
|
||||||
(module => {
|
|
||||||
module.MultiSelectClickHandler = new Proxy(module.MultiSelectClickHandler, {
|
const jsx = require('composer_core/src/JSX').jsx;
|
||||||
construct: function(target, args, newTarget) {
|
const assetCatalog = require("composer_core/src/AssetCatalog")
|
||||||
args[1].selectionLimit = 9999999;
|
const style = require("composer_core/src/Style");
|
||||||
return Reflect.construct(target, args, newTarget);
|
const colors = require("coreui/src/styles/semanticColors");
|
||||||
},
|
|
||||||
});
|
function dumpObject(obj, indent = 0) {
|
||||||
})(require('memories_ui/src/clickhandlers/MultiSelectClickHandler'))
|
if (typeof obj !== "object") return console.log(obj);
|
||||||
|
let prefix = ""
|
||||||
|
for (let i = 0; i < indent; i++) {
|
||||||
|
prefix += " ";
|
||||||
|
}
|
||||||
|
for (let key of Object.keys(obj)) {
|
||||||
|
try {
|
||||||
|
console.log(prefix, key, typeof obj[key], obj[key]);
|
||||||
|
if (key == "renderer") continue
|
||||||
|
if (typeof obj[key] === "object" && indent < 10) dumpObject(obj[key], indent + 1);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(module => {
|
function proxyProperty(module, functionName, handler) {
|
||||||
function onComponentPreRender(component, viewModel) {
|
if (!module || !module[functionName]) {
|
||||||
const componentName = component.constructor.name;
|
console.warn("Function not found", functionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
module[functionName] = new Proxy(module[functionName], {
|
||||||
|
apply: (a, b, c) => handler(a, b, c),
|
||||||
|
construct: (a, b, c) => handler(a, b, c)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (componentName == "ProfileIdentityView" && config.showFirstCreatedUsername) {
|
function interceptComponent(moduleName, className, functions) {
|
||||||
let userInfo = callExport("getFriendInfoByUsername", viewModel.username);
|
proxyProperty(require(moduleName), className, (target, args, newTarget) => {
|
||||||
|
let initProxy = functions["<init>"]
|
||||||
|
let component;
|
||||||
|
|
||||||
if (userInfo) {
|
if (initProxy) {
|
||||||
let userInfoJson = JSON.parse(userInfo);
|
initProxy(args, (newArgs) => {
|
||||||
let firstCreatedUsername = userInfoJson.username.split("|")[0];
|
component = Reflect.construct(target, newArgs || args, newTarget);
|
||||||
if (firstCreatedUsername != viewModel.username) {
|
});
|
||||||
viewModel.username += " (" + firstCreatedUsername + ")";
|
} else {
|
||||||
|
component = Reflect.construct(target, args, newTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let funcName of Object.keys(functions)) {
|
||||||
|
if (funcName == "<init>" || !component[funcName]) continue
|
||||||
|
proxyProperty(component, funcName, (target, thisArg, argumentsList) => {
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
functions[funcName](component, argumentsList, (newArgs) => {
|
||||||
|
result = Reflect.apply(target, thisArg, newArgs || argumentsList);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error in", funcName, e);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.bypassCameraRollLimit) {
|
||||||
|
interceptComponent(
|
||||||
|
'memories_ui/src/clickhandlers/MultiSelectClickHandler',
|
||||||
|
'MultiSelectClickHandler',
|
||||||
|
{
|
||||||
|
"<init>": (args, superCall) => {
|
||||||
|
args[1].selectionLimit = 9999999;
|
||||||
|
superCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
if (config.operaDownloadButton) {
|
||||||
}
|
const downloadIcon = assetCatalog.loadCatalog("share_sheet/res").downloadIcon
|
||||||
|
|
||||||
function onComponentPostRender(component, viewModel) {
|
|
||||||
}
|
|
||||||
|
|
||||||
module.Component = new Proxy(module.Component, {
|
interceptComponent(
|
||||||
construct: function(target, args, newTarget) {
|
'context_chrome_header/src/ChromeHeaderRenderer',
|
||||||
let component = Reflect.construct(target, args, newTarget);
|
'ChromeHeaderRenderer',
|
||||||
component.onRender = new Proxy(component.onRender, {
|
{
|
||||||
apply: function(target, thisArg, argumentsList) {
|
onRenderBaseHeader: (component, args, render) => {
|
||||||
if (onComponentPreRender(component, thisArg.viewModel || {})) return;
|
render()
|
||||||
let result = Reflect.apply(target, thisArg, argumentsList);
|
jsx.beginRender(jsx.makeNodePrototype("image"))
|
||||||
onComponentPostRender(component, thisArg.viewModel || {});
|
jsx.setAttributeStyle("style", new style.Style({
|
||||||
return result;
|
height: 32,
|
||||||
}
|
marginTop: 4,
|
||||||
});
|
marginLeft: 8,
|
||||||
return component;
|
marginRight: 12,
|
||||||
|
objectFit: "contain",
|
||||||
|
tint: colors.SemanticColor.Icon.PRIMARY
|
||||||
|
}))
|
||||||
|
jsx.setAttribute("src", downloadIcon)
|
||||||
|
jsx.setAttributeFunction("onTap", () => callExport("downloadLastOperaMedia", false))
|
||||||
|
jsx.setAttributeFunction("onLongPress", () => callExport("downloadLastOperaMedia", true))
|
||||||
|
jsx.endRender()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
})(require('composer_core/src/Component'))
|
}
|
||||||
|
|
||||||
|
if (config.showFirstCreatedUsername) {
|
||||||
|
interceptComponent(
|
||||||
|
'common_profile/src/identity/ProfileIdentityView',
|
||||||
|
'ProfileIdentityView',
|
||||||
|
{
|
||||||
|
onRender: (component, _, render) => {
|
||||||
|
if (component.viewModel) {
|
||||||
|
let userInfo = callExport("getFriendInfoByUsername", component.viewModel.username);
|
||||||
|
if (userInfo) {
|
||||||
|
let userInfoJson = JSON.parse(userInfo);
|
||||||
|
let firstCreatedUsername = userInfoJson.username.split("|")[0];
|
||||||
|
if (firstCreatedUsername != component.viewModel.username) {
|
||||||
|
component.viewModel.username += " (" + firstCreatedUsername + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -30,6 +30,7 @@ import me.rhunk.snapenhance.common.ui.createComposeAlertDialog
|
|||||||
import me.rhunk.snapenhance.common.ui.createComposeView
|
import me.rhunk.snapenhance.common.ui.createComposeView
|
||||||
import me.rhunk.snapenhance.core.features.Feature
|
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.impl.downloader.MediaDownloader
|
||||||
import me.rhunk.snapenhance.core.util.hook.HookStage
|
import me.rhunk.snapenhance.core.util.hook.HookStage
|
||||||
import me.rhunk.snapenhance.core.util.hook.Hooker
|
import me.rhunk.snapenhance.core.util.hook.Hooker
|
||||||
import me.rhunk.snapenhance.core.util.hook.hook
|
import me.rhunk.snapenhance.core.util.hook.hook
|
||||||
@ -131,12 +132,13 @@ class ComposerHooks: Feature("ComposerHooks", loadParams = FeatureLoadParams.ACT
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getConfig(): Map<String, Any> {
|
private fun getConfig(): Map<String, Any> {
|
||||||
return HashMap<String, Any>().apply {
|
return mapOf<String, Any>(
|
||||||
put("bypassCameraRollLimit", config.bypassCameraRollLimit.get())
|
"operaDownloadButton" to context.config.downloader.operaDownloadButton.get(),
|
||||||
put("showFirstCreatedUsername", config.showFirstCreatedUsername.get())
|
"bypassCameraRollLimit" to config.bypassCameraRollLimit.get(),
|
||||||
put("composerConsole", config.composerConsole.get())
|
"showFirstCreatedUsername" to config.showFirstCreatedUsername.get(),
|
||||||
put("composerLogs", config.composerLogs.get())
|
"composerConsole" to config.composerConsole.get(),
|
||||||
}
|
"composerLogs" to config.composerLogs.get()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExportCall(composerMarshaller: ComposerMarshaller): Boolean {
|
private fun handleExportCall(composerMarshaller: ComposerMarshaller): Boolean {
|
||||||
@ -150,6 +152,7 @@ class ComposerHooks: Feature("ComposerHooks", loadParams = FeatureLoadParams.ACT
|
|||||||
if (argc < 2) return false
|
if (argc < 2) return false
|
||||||
context.shortToast(composerMarshaller.getUntyped(1) as? String ?: return false)
|
context.shortToast(composerMarshaller.getUntyped(1) as? String ?: return false)
|
||||||
}
|
}
|
||||||
|
"downloadLastOperaMedia" -> context.feature(MediaDownloader::class).downloadLastOperaMediaAsync(composerMarshaller.getUntyped(1) == true)
|
||||||
"getFriendInfoByUsername" -> {
|
"getFriendInfoByUsername" -> {
|
||||||
if (argc < 2) return false
|
if (argc < 2) return false
|
||||||
val username = composerMarshaller.getUntyped(1) as? String ?: return false
|
val username = composerMarshaller.getUntyped(1) as? String ?: return false
|
||||||
@ -176,16 +179,6 @@ class ComposerHooks: Feature("ComposerHooks", loadParams = FeatureLoadParams.ACT
|
|||||||
"error" -> context.log.error(message, tag)
|
"error" -> context.log.error(message, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"eval" -> {
|
|
||||||
if (argc < 2) return false
|
|
||||||
runCatching {
|
|
||||||
composerMarshaller.pushUntyped(context.native.composerEval(
|
|
||||||
composerMarshaller.getUntyped(1) as? String ?: return false
|
|
||||||
))
|
|
||||||
}.onFailure {
|
|
||||||
composerMarshaller.pushUntyped(it.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> context.log.warn("Unknown action: $action", "Composer")
|
else -> context.log.warn("Unknown action: $action", "Composer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user