Skip to content

Commit

Permalink
Merge branch 'Dev4Mod:master' into theme
Browse files Browse the repository at this point in the history
Strange-IPmart authored Nov 25, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents e4cf5a8 + 8c0934a commit 47dec3d
Showing 44 changed files with 975 additions and 651 deletions.
2 changes: 1 addition & 1 deletion .idea/other.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ dependencies {
implementation(libs.filepicker)
implementation(libs.betterypermissionhelper)
implementation(libs.bcpkix.jdk18on)
implementation("com.assemblyai:assemblyai-java:3.0.0")
implementation(libs.assemblyai.java)
}

configurations.all {
6 changes: 6 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -20,11 +20,17 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn *

-keepclasseswithmembers class com.wmods.** {
*;
}

-keepclasseswithmembernames class com.wmods.**

-keepclasseswithmembers class cz.vutbr.** {
*;
}

-keepclasseswithmembers class com.assemblyai.api.** {
*;
}
Original file line number Diff line number Diff line change
@@ -147,7 +147,7 @@ public void setInfo(Object item) {
}
var statusInfo = XposedHelpers.getObjectField(item, "A01");
var field = ReflectionUtils.getFieldByType(statusInfo.getClass(), XposedHelpers.findClass("com.whatsapp.jid.UserJid", statusInfoClazz.getClassLoader()));
var userJid = ReflectionUtils.getField(field, statusInfo);
var userJid = ReflectionUtils.getObjectField(field, statusInfo);
var contactName = WppCore.getContactName(userJid);
jid = WppCore.getRawString(userJid);
igStatusContactName.setText(contactName);
56 changes: 18 additions & 38 deletions app/src/main/java/com/wmods/wppenhacer/utils/DrawableColors.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.wmods.wppenhacer.utils;

import static com.wmods.wppenhacer.utils.IColors.parseColor;
import static com.wmods.wppenhacer.xposed.features.customization.CustomTheme.loader1;

import android.content.res.ColorStateList;
@@ -27,12 +26,15 @@

public class DrawableColors {

private static final HashMap<Bitmap,Integer> ninePatchs = new HashMap<>();
private static final HashMap<Bitmap, Integer> ninePatchs = new HashMap<>();

public static void replaceColor(Drawable drawable, HashMap<String, String> colors) {
if (DesignUtils.isNightMode()){
if (drawable == null) return;

if (DesignUtils.isNightMode()) {
colors.remove("#ffffffff");
}

if (drawable instanceof StateListDrawable stateListDrawable) {
var count = StateListDrawableCompact.getStateCount(stateListDrawable);
for (int i = 0; i < count; i++) {
@@ -59,49 +61,28 @@ public static void replaceColor(Drawable drawable, HashMap<String, String> color
var gradientColors = gradientDrawable.getColors();
if (gradientColors != null) {
for (var i = 0; i < gradientColors.length; i++) {
var gradientColor = IColors.toString(gradientColors[i]);
var newColor = colors.get(gradientColor);
// XposedBridge.log(gradientColor + " / " + newColor);
if (newColor != null) {
gradientColors[i] = IColors.parseColor(newColor);
} else {
if (!gradientColor.startsWith("#ff") && !gradientColor.startsWith("#0")) {
var sColorSub = gradientColor.substring(0, 3);
newColor = colors.get(gradientColor.substring(3));
if (newColor != null)
gradientColors[i] = IColors.parseColor(sColorSub + newColor);
}
}
var color = gradientColors[i];
var newColor = IColors.getFromIntColor(color, colors);
if (color == newColor) continue;
gradientColors[i] = newColor;
}
gradientDrawable.setColors(gradientColors);
}
} else if (drawable instanceof InsetDrawable insetDrawable) {
replaceColor(insetDrawable.getDrawable(), colors);
} else if (drawable instanceof NinePatchDrawable ninePatchDrawable) {
var color = getNinePatchDrawableColor(ninePatchDrawable);
var sColor = IColors.toString(color);
var newColor = colors.get(sColor);
// XposedBridge.log(sColor + " / " + newColor);
if (newColor != null) {
ninePatchDrawable.setTintList(ColorStateList.valueOf(parseColor(newColor)));
}
var newColor = IColors.getFromIntColor(color, colors);
if (color == newColor) return;
ninePatchDrawable.setTintList(ColorStateList.valueOf(newColor));
} else if (drawable instanceof ColorDrawable colorDrawable) {
var color = getColorDrawableColor(colorDrawable);
colorDrawable.setColor(IColors.getFromIntColor(color, colors));
} else {
if (drawable == null) return;
var color = getColor(drawable);
var sColor = IColors.toString(color);
var newColor = colors.get(sColor);
// XposedBridge.log(sColor + " / " + newColor);
if (newColor != null) {
drawable.setColorFilter(new PorterDuffColorFilter(parseColor(newColor), PorterDuff.Mode.SRC_IN));
} else {
if (!sColor.startsWith("#ff") && !sColor.startsWith("#0")) {
var sColorSub = sColor.substring(0, 3);
newColor = colors.get(sColor.substring(3));
if (newColor != null) {
drawable.setColorFilter(new PorterDuffColorFilter(parseColor(sColorSub + newColor), PorterDuff.Mode.SRC_IN));
}
}
}
var newColor = IColors.getFromIntColor(color, colors);
if (color == newColor) return;
drawable.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_IN));
}

}
@@ -140,7 +121,6 @@ public static int getNinePatchDrawableColor(NinePatchDrawable ninePatchDrawable)
var corSalva = ninePatchs.get(bitmap);
if (corSalva != null) return corSalva;

// return bitmap.getPixel(width / 2, Math.min(5, height));
HashMap<Integer, Integer> contagemCores = new HashMap<>();
int corMaisFrequente = 0;
int contagemMaxima = 0;
35 changes: 34 additions & 1 deletion app/src/main/java/com/wmods/wppenhacer/utils/IColors.java
Original file line number Diff line number Diff line change
@@ -23,14 +23,27 @@ public class IColors {
colors.put("#ff25d366", "#ff25d366"); // status indicator
colors.put("#ffd9fdd3", "#ffd9fdd3"); // nav bar color in light theme
colors.put("#ff15603e", "#ff15603e"); // nav bar color in light theme
colors.put("#fff1f2f4", "#fff1f2f4"); // nav bar color in light theme
colors.put("#ff008069", "#ff008069"); // header and buttons in light theme

colors.put("15603e", "15603e");
// colors.put("#0b141a", "#ff0b141a");

// background
colors.put("0a1014", "0a1014"); // background green color (above version 22)
colors.put("#ff0a1014", "#ff0a1014"); // background green color (above version 22)
colors.put("#ff10161a", "#ff10161a"); // background header green color (above version 22)
colors.put("#ff12181c", "#ff12181c"); // background header green color (above version 22)
colors.put("#ff20272b", "#ff20272b"); // background footer (above version 22)
colors.put("#ff3a484f", "#ff3a484f"); // background of Dialogs

colors.put("#ffffffff", "#ffffffff"); // background color in light theme
colors.put("#ff1b8755", "#ff1b8755"); // background toolbar color in light theme


// Secondary
colors.put("#ff202c33", "#ff202c33");
colors.put("#ff2a2f33", "#ff2a2f33");

// New theme color
colors.put("0b141a", "0b141a");
@@ -46,8 +59,28 @@ public static int parseColor(String str) {
}

public static String toString(int i) {
return "#" + Integer.toHexString(i);
var color = Integer.toHexString(i);
if (color.length() == 7) {
color = "0" + color;
}
return "#" + color;
}


public static int getFromIntColor(int color, HashMap<String, String> colors) {
var sColor = IColors.toString(color);
var newColor = colors.get(sColor);
if (newColor != null && newColor.length() == 9) {
return IColors.parseColor(newColor);
} else {
if (!sColor.equals("#0") && !sColor.startsWith("#ff")) {
var sColorSub = sColor.substring(0, 3);
newColor = colors.get(sColor.substring(3));
if (newColor != null) {
return IColors.parseColor(sColorSub + newColor);
}
}
}
return color;
}
}
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ public IGStatusView(@NonNull Context context) {

private void init(Context context) {
mStatusListView = new HorizontalListView(context);
var layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
var layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
// layoutParams.setMargins(Utils.dipToPixels(4), Utils.dipToPixels(10), 0, 0);
mStatusListView.setLayoutParams(layoutParams);
addView(mStatusListView);
Original file line number Diff line number Diff line change
@@ -268,6 +268,7 @@ private static void plugins(@NonNull ClassLoader loader, @NonNull XSharedPrefere
BubbleColors.class,
CallPrivacy.class,
CustomTheme.class,
// CustomThemeV2.class,
ChatLimit.class,
SeparateGroup.class,
ShowOnline.class,
Original file line number Diff line number Diff line change
@@ -303,7 +303,9 @@ public static String getCurrentRawJID() {
var conversation = getCurrentConversation();
if (conversation == null) return null;
var chatField = XposedHelpers.getObjectField(conversation, convChatField.getName());
if (chatField == null) return null;
var chatJidObj = XposedHelpers.getObjectField(chatField, chatJidField.getName());
if (chatJidObj == null) return null;
return getRawString(chatJidObj);
}

Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ public class FMessageWpp {
private static Method userJidMethod;
private static Field keyMessage;
private static Field getFieldIdMessage;
private static Method deviceJidMethod;
private static Field deviceJidField;
private static Method messageMethod;
private static Method messageWithMediaMethod;
private static Field mediaTypeField;
@@ -46,7 +46,8 @@ public static void init(ClassLoader classLoader) throws Exception {
messageMethod = Unobfuscator.loadNewMessageMethod(classLoader);
messageWithMediaMethod = Unobfuscator.loadNewMessageWithMediaMethod(classLoader);
getFieldIdMessage = Unobfuscator.loadSetEditMessageField(classLoader);
deviceJidMethod = ReflectionUtils.findMethodUsingFilter(TYPE, method -> method.getReturnType().equals(XposedHelpers.findClass("com.whatsapp.jid.DeviceJid", classLoader)));
var deviceJidClass = XposedHelpers.findClass("com.whatsapp.jid.DeviceJid", classLoader);
deviceJidField = ReflectionUtils.findFieldUsingFilter(TYPE, field -> field.getType() == deviceJidClass);
mediaTypeField = Unobfuscator.loadMediaTypeField(classLoader);
getOriginalMessageKey = Unobfuscator.loadOriginalMessageKey(classLoader);
abstractMediaMessageClass = Unobfuscator.loadAbstractMediaMessageClass(classLoader);
@@ -63,7 +64,7 @@ public Object getUserJid() {

public Object getDeviceJid() {
try {
return deviceJidMethod.invoke(fmessage);
return deviceJidField.get(fmessage);
} catch (Exception e) {
XposedBridge.log(e);
}
@@ -128,7 +129,7 @@ public File getMediaFile() {
if (field.getType().isPrimitive()) continue;
var fileField = ReflectionUtils.getFieldByType(field.getType(), File.class);
if (fileField != null) {
var mediaFile = ReflectionUtils.getField(field, fmessage);
var mediaFile = ReflectionUtils.getObjectField(field, fmessage);
return (File) fileField.get(mediaFile);
}
}
Original file line number Diff line number Diff line change
@@ -324,12 +324,38 @@ public synchronized static Method loadIconTabMethod(ClassLoader classLoader) thr
});
}

public synchronized static Field loadPreIconTabField(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
Class<?> cls = loadIconTabMethod(classLoader).getDeclaringClass();
Class<?> clsType = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "Tried to set badge");
if (clsType == null) throw new Exception("PreIconTabField not found");
Field result = null;
for (var field1 : cls.getFields()) {
Object checkResult = Arrays.stream(field1.getType().getFields()).filter(f -> f.getType().equals(clsType)).findFirst().orElse(null);
if (checkResult != null) {
result = field1;
break;
}
}
if (result == null) throw new Exception("PreIconTabField not found 2");
return result;
});
}

public synchronized static Field loadIconTabField(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getField(classLoader, () -> {
Class<?> cls = loadIconTabMethod(classLoader).getDeclaringClass();
Class<?> clsType = findFirstClassUsingStringsFilter(classLoader, "X.", StringMatchType.Contains, "Tried to set badge");
if (clsType == null) throw new Exception("IconTabField not found");
var result = Arrays.stream(cls.getFields()).filter(f -> f.getType().equals(clsType)).findFirst().orElse(null);
if (result == null) throw new Exception("IconTabField not found");
// for 23.xx, the result is null
if (result == null) {
for (var field1 : cls.getFields()) {
result = Arrays.stream(field1.getType().getFields()).filter(f -> f.getType().equals(clsType)).findFirst().orElse(null);
if (result != null) break;
}
}
if (result == null) throw new Exception("IconTabField not found 2");
return result;
});
}
@@ -426,28 +452,6 @@ private static Class<?> loadMediaQualityClass(ClassLoader classLoader) throws Ex
});
}

public synchronized static Method loadMediaQualityResolutionMethod(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
var clazz = loadMediaQualityClass(classLoader);
return Arrays.stream(clazz.getDeclaredMethods()).filter(
m -> m.getParameterTypes().length == 3 &&
m.getParameterTypes()[0].equals(int.class) &&
m.getParameterTypes()[1].equals(int.class) &&
m.getParameterTypes()[2].equals(int.class)
).findFirst().orElse(null);
});
}

public synchronized static Method loadMediaQualityBitrateMethod(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
var clazz = loadMediaQualityClass(classLoader);
return Arrays.stream(clazz.getDeclaredMethods()).filter(
m -> m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(int.class) &&
m.getReturnType().equals(int.class)
).findFirst().orElse(null);
});
}

public synchronized static Method loadMediaQualityVideoMethod2(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
@@ -472,12 +476,19 @@ public synchronized static HashMap<String, Field> loadMediaQualityVideoFields(Cl
return result;
}

public synchronized static Class loadMediaQualityVideoLimitClass(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(classLoader, () -> {
var clazz = findFirstClassUsingStrings(classLoader, StringMatchType.Contains, "videoLimitMb=");
if (clazz == null) throw new Exception("MediaQualityVideoLimit method not found");
return clazz;
});
public synchronized static HashMap<String, Field> loadMediaQualityOriginalVideoFields(ClassLoader classLoader) throws Exception {
var method = loadMediaQualityVideoMethod2(classLoader);
var methodString = method.getParameterTypes()[0].getDeclaredMethod("toString");
var methodData = dexkit.getMethodData(methodString);
var usingFields = Objects.requireNonNull(methodData).getUsingFields();
var usingStrings = Objects.requireNonNull(methodData).getUsingStrings();
var result = new HashMap<String, Field>();
for (int i = 0; i < usingStrings.size(); i++) {
if (i == usingFields.size()) break;
var field = usingFields.get(i).getField().getFieldInstance(classLoader);
result.put(usingStrings.get(i), field);
}
return result;
}

// TODO: Classes and methods to ShareLimit
@@ -841,11 +852,11 @@ public synchronized static Method loadSendPresenceMethod(ClassLoader loader) thr
var methodData = dexkit.getMethodData(method);
var groupJidClass = XposedHelpers.findClass("com.whatsapp.jid.GroupJid", loader);
var classCheckMethod = dexkit.findMethod(FindMethod.create()
.searchInClass(Collections.singletonList(methodData.getDeclaredClass()))
.matcher(MethodMatcher.create().returnType(groupJidClass)))
.searchInClass(Collections.singletonList(methodData.getDeclaredClass()))
.matcher(MethodMatcher.create().returnType(groupJidClass)))
.singleOrNull();
if (classCheckMethod == null) {
var newMethod = methodData.getCallers().firstOrNull();
var newMethod = methodData.getCallers().singleOrNull(method1 -> method1.getParamCount() == 4);
if (newMethod == null) throw new Exception("SendPresence method not found 2");
return newMethod.getMethodInstance(loader);
}
@@ -1328,13 +1339,6 @@ public synchronized static Class loadImageVewContainerClass(ClassLoader loader)
});
}

public synchronized static Class loadMediaQualityProcessor(ClassLoader loader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(loader, () -> {
var clazz = findFirstClassUsingStrings(loader, StringMatchType.Contains, "{maxKb=");
if (clazz == null) throw new RuntimeException("MediaQualityProcessor class not found");
return clazz;
});
}

public synchronized static Method getFilterInitMethod(ClassLoader loader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(loader, () -> {
@@ -1493,17 +1497,12 @@ public synchronized static Method loadPlaybackSpeed(ClassLoader classLoader) thr
// });
// }

public synchronized static Constructor loadListUpdateItemsConstructor(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getConstructor(classLoader, () -> {
var method = dexkit.findMethod(new FindMethod().matcher(new MethodMatcher().paramCount(1).returnType(void.class).addParamType(Object.class).addUsingNumber(8686)));
if (method.isEmpty()) {
// for 22.xx, use alternative method
method = dexkit.findMethod(new FindMethod().matcher(new MethodMatcher().paramCount(1).returnType(void.class).addUsingString("deleted", StringMatchType.Equals).addUsingString("membership", StringMatchType.Equals)));

if (method.isEmpty())
throw new RuntimeException("ListUpdateItems method not found");
}
return method.get(0).getClassInstance(classLoader).getConstructors()[0];
public synchronized static Method loadListUpdateItems(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> {
var method = dexkit.findMethod(FindMethod.create().matcher(MethodMatcher.create().addUsingString("Running diff util, updates list size", StringMatchType.Contains)));
if (method.isEmpty())
throw new RuntimeException("ListUpdateItems method not found");
return method.get(0).getMethodInstance(classLoader);
});
}

@@ -1690,6 +1689,10 @@ public static synchronized Class loadUnkTranscript(ClassLoader classLoader) thro
});
}

public static synchronized Class loadTranscriptSegment(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(classLoader, () -> findFirstClassUsingStrings(classLoader, StringMatchType.Contains, "TranscriptionSegment("));
}

public static synchronized Method loadStateChangeMethod(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getMethod(classLoader, () -> findFirstMethodUsingStrings(classLoader, StringMatchType.Contains, "presencestatemanager/startTransitionToUnavailable/new-state"));
}
@@ -1712,4 +1715,11 @@ public static synchronized Class loadAbstractMediaMessageClass(ClassLoader loade
});
}

public static Class<?> loadFragmentClass(ClassLoader classLoader) throws Exception {
return UnobfuscatorCache.getInstance().getClass(classLoader, () -> {
var clazz = findFirstClassUsingStrings(classLoader, StringMatchType.Contains, "mFragmentId=#");
if (clazz == null) throw new RuntimeException("Fragment class not found");
return clazz;
});
}
}
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@
import com.wmods.wppenhacer.utils.IColors;
import com.wmods.wppenhacer.views.WallpaperView;
import com.wmods.wppenhacer.xposed.core.Feature;
import com.wmods.wppenhacer.xposed.core.WppCore;
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
import com.wmods.wppenhacer.xposed.utils.DesignUtils;
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
@@ -75,7 +76,7 @@ private void hookWallpaper() throws Exception {
return;

var clazz = XposedHelpers.findClass("com.whatsapp.HomeActivity", classLoader);
XposedHelpers.findAndHookMethod(clazz.getSuperclass(), "onCreate", Bundle.class, new XC_MethodHook() {
XposedHelpers.findAndHookMethod(clazz, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var activity = (Activity) param.thisObject;
@@ -91,6 +92,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (!checkHomeActivity()) return;
var viewGroup = (ViewGroup) param.getResult();
replaceColors(viewGroup, wallAlpha);
}
@@ -101,18 +103,16 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (!loadTabFrameClass.isInstance(param.thisObject)) return;
if (!checkHomeActivity()) return;
var viewGroup = (ViewGroup) param.thisObject;
var background = viewGroup.getBackground();
try {
var colorfilters = XposedHelpers.getObjectField(background, "A01");
var fields = ReflectionUtils.getFieldsByType(colorfilters.getClass(), ColorStateList.class);
var colorStateList = (ColorStateList) fields.get(0).get(colorfilters);
if (colorStateList == null) return;
var color = IColors.toString(colorStateList.getDefaultColor());
var newColor = navAlpha.get(color);
if (newColor != null) {
background.setTint(IColors.parseColor(newColor));
}
var newColor = IColors.getFromIntColor(colorStateList.getDefaultColor(), navAlpha);
if (newColor == colorStateList.getDefaultColor()) return;
background.setTint(newColor);
} catch (Throwable ignored) {
}
}
@@ -173,25 +173,26 @@ private void hookColors() throws Exception {
case "00a884", "1da457", "21c063", "d9fdd3" ->
IColors.colors.put(c, primaryColor.substring(3));
case "#ff00a884", "#ff1da457", "#ff21c063", "#ff1daa61", "#ff25d366",
"#ffd9fdd3" ->
IColors.colors.put(c, primaryColor);
case "#ff103529" ->
"#ffd9fdd3", "#ff008069" -> IColors.colors.put(c, primaryColor);
case "#ff103529", "#fff1f2f4" ->
IColors.colors.put(c, "#66" + primaryColor.substring(3));
}
}

if (!backgroundColor.equals("0") && DesignUtils.isValidColor(backgroundColor)) {
backgroundColor = backgroundColor.length() == 9 ? backgroundColor : "#ff" + backgroundColor.substring(1);
switch (c) {
case "0b141a" -> IColors.colors.put(c, backgroundColor.substring(3));
case "#ff0b141a", "#ff111b21", "#ff000000" ->
case "0b141a", "0a1014" ->
IColors.colors.put(c, backgroundColor.substring(3));
case "#ff0b141a", "#ff111b21", "#ff000000", "#ff0a1014", "#ff10161a",
"#ff12181c", "#ff20272b", "#ff3a484f" ->
IColors.colors.put(c, backgroundColor);
}
}

if (!secondaryColor.equals("0") && DesignUtils.isValidColor(secondaryColor)) {
secondaryColor = secondaryColor.length() == 9 ? secondaryColor : "#ff" + secondaryColor.substring(1);
if (c.equals("#ff202c33")) {
if (c.equals("#ff202c33") || c.equals("#ff2a2f33")) {
IColors.colors.put(c, secondaryColor);
}
}
@@ -256,7 +257,9 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
private void replaceTransparency(HashMap<String, String> wallpaperColors, float mAlpha) {
var hexAlpha = Integer.toHexString((int) Math.ceil(mAlpha * 255));
hexAlpha = hexAlpha.length() == 1 ? "0" + hexAlpha : hexAlpha;
for (var c : List.of("#ff0b141a", "#ff111b21", "#ff000000", "#ffffffff", "#ff1b8755")) {
for (var c : List.of("#ff0b141a", "#ff10161a", "#ff111b21", "#ff000000",
"#ffffffff", "#ff1b8755", "#ff0a1014", "#ff12181c", "#ff20272b", "#ff3a484f"
)) {
var oldColor = wallpaperColors.get(c);
if (oldColor == null) continue;
var newColor = "#" + hexAlpha + oldColor.substring(3);
@@ -268,7 +271,8 @@ private void replaceTransparency(HashMap<String, String> wallpaperColors, float
private void injectWallpaper(View view) {
var content = (ViewGroup) view;
var rootView = (ViewGroup) content.getChildAt(0);
var header = (ViewGroup) rootView.findViewById(Utils.getID("header", "id"));

var header = content.findViewById(Utils.getID("header", "id"));
replaceColors(header, toolbarAlpha);
var frameLayout = new WallpaperView(rootView.getContext(), prefs, properties);
rootView.addView(frameLayout, 0);
@@ -293,24 +297,11 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
public static class ColorStateListHook extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
var colors = IColors.colors;
var colorStateList = param.args[0];
if (colorStateList != null) {
var mColors = (int[]) XposedHelpers.getObjectField(colorStateList, "mColors");
for (int i = 0; i < mColors.length; i++) {
var sColor = IColors.toString(mColors[i]);
var newColor = colors.get(sColor);
if (newColor != null && newColor.length() == 9) {
mColors[i] = IColors.parseColor(newColor);
} else {
if (!sColor.equals("#0") && !sColor.startsWith("#ff")) {
var sColorSub = sColor.substring(0, 3);
newColor = colors.get(sColor.substring(3));
if (newColor != null) {
mColors[i] = IColors.parseColor(sColorSub + newColor);
}
}
}
mColors[i] = IColors.getFromIntColor(mColors[i], IColors.colors);
}
XposedHelpers.setObjectField(colorStateList, "mColors", mColors);
param.args[0] = colorStateList;
@@ -321,28 +312,30 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
public static class IntBgColorHook extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
var colors = IColors.colors;
var color = (int) param.args[0];
var sColor = IColors.toString(color);

if (param.thisObject instanceof TextView textView) {
var id = Utils.getID("conversations_row_message_count", "id");
if (textView.getId() == id) {
param.args[0] = IColors.parseColor("#ff" + sColor.substring(sColor.length() == 9 ? 3 : 1));
return;
}
}
var newColor = colors.get(sColor);
if (newColor != null && newColor.length() == 9) {
param.args[0] = IColors.parseColor(newColor);
} else {
if (!sColor.equals("#0") && !sColor.startsWith("#ff")) {
var sColorSub = sColor.substring(0, 3);
newColor = colors.get(sColor.substring(3));
if (newColor != null) {
param.args[0] = IColors.parseColor(sColorSub + newColor);
}
} else if (param.thisObject instanceof Paint) {
// This fixes the issue with background colors affecting chat bubbles
if (ReflectionUtils.isCalledFromStrings("getValue")) {
return;
}
}
param.args[0] = IColors.getFromIntColor(color, IColors.colors);
}
}

private boolean checkHomeActivity() {
var homeClass = XposedHelpers.findClass("com.whatsapp.HomeActivity", classLoader);
var currentActivity = WppCore.getCurrentActivity();
return currentActivity != null && homeClass.isInstance(currentActivity);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.wmods.wppenhacer.xposed.features.customization;

import android.content.res.AssetManager;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;

import androidx.annotation.NonNull;

import com.wmods.wppenhacer.utils.DrawableColors;
import com.wmods.wppenhacer.utils.IColors;
import com.wmods.wppenhacer.xposed.core.Feature;
import com.wmods.wppenhacer.xposed.utils.DesignUtils;
import com.wmods.wppenhacer.xposed.utils.Utils;

import java.util.Objects;
import java.util.Properties;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

public class CustomThemeV2 extends Feature {

public CustomThemeV2(@NonNull ClassLoader classLoader, @NonNull XSharedPreferences preferences) {
super(classLoader, preferences);
}

@Override
public void doHook() throws Throwable {

Properties properties = Utils.extractProperties(prefs.getString("custom_css", ""));

var primaryColorInt = prefs.getInt("primary_color", 0);
var secondaryColorInt = prefs.getInt("secondary_color", 0);
var backgroundColorInt = prefs.getInt("background_color", 0);

var primaryColor = DesignUtils.checkSystemColor(properties.getProperty("primary_color", "0"));
var secondaryColor = DesignUtils.checkSystemColor(properties.getProperty("secondary_color", "0"));
var backgroundColor = DesignUtils.checkSystemColor(properties.getProperty("background_color", "0"));

if (prefs.getBoolean("changecolor", false)) {
primaryColor = primaryColorInt == 0 ? "0" : IColors.toString(primaryColorInt);
secondaryColor = secondaryColorInt == 0 ? "0" : IColors.toString(secondaryColorInt);
backgroundColor = backgroundColorInt == 0 ? "0" : IColors.toString(backgroundColorInt);
}

if (prefs.getBoolean("changecolor", false) || Objects.equals(properties.getProperty("change_colors"), "true")) {
for (var c : IColors.colors.keySet()) {
if (!primaryColor.equals("0") && DesignUtils.isValidColor(primaryColor)) {
primaryColor = primaryColor.length() == 9 ? primaryColor : "#ff" + primaryColor.substring(1);
switch (c) {
case "00a884", "1da457", "21c063", "d9fdd3" ->
IColors.colors.put(c, primaryColor.substring(3));
case "#ff00a884", "#ff1da457", "#ff21c063", "#ff1daa61", "#ff25d366",
"#ffd9fdd3" -> IColors.colors.put(c, primaryColor);
case "#ff103529" ->
IColors.colors.put(c, "#66" + primaryColor.substring(3));
}
}

if (!backgroundColor.equals("0") && DesignUtils.isValidColor(backgroundColor)) {
backgroundColor = backgroundColor.length() == 9 ? backgroundColor : "#ff" + backgroundColor.substring(1);
switch (c) {
case "0b141a", "0a1014" ->
IColors.colors.put(c, backgroundColor.substring(3));
case "#ff0b141a", "#ff111b21", "#ff000000", "#ff0a1014", "#ff10161a",
"#ff12181c", "#ff20272b" -> IColors.colors.put(c, backgroundColor);
}
}

if (!secondaryColor.equals("0") && DesignUtils.isValidColor(secondaryColor)) {
secondaryColor = secondaryColor.length() == 9 ? secondaryColor : "#ff" + secondaryColor.substring(1);
if (c.equals("#ff202c33") || c.equals("#ff2a2f33")) {
IColors.colors.put(c, secondaryColor);
}
}
}
}

XposedBridge.hookAllMethods(AssetManager.class, "getResourceValue", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var id = (int) param.args[0];
var typedValue = (TypedValue) param.args[2];
if (id >= 0x7f060000 && id <= 0x7f06ffff) {
if (typedValue.type >= TypedValue.TYPE_FIRST_INT
&& typedValue.type <= TypedValue.TYPE_LAST_INT) {
if (typedValue.data == 0) return;
typedValue.data = IColors.getFromIntColor(typedValue.data, IColors.colors);
}
}
}
});

var resourceImpl = XposedHelpers.findClass("android.content.res.ResourcesImpl", classLoader);
XposedBridge.hookAllMethods(resourceImpl, "loadDrawable", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var drawable = (Drawable) param.getResult();
DrawableColors.replaceColor(drawable, IColors.colors);
}
});

}

@NonNull
@Override
public String getPluginName() {
return "Custom Theme V2";
}

}
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import android.util.LruCache;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -201,6 +202,27 @@ private void setRuleInView(RuleItem ruleItem, View view) {
for (var declaration : ruleItem.rule) {
var property = declaration.getProperty();
switch (property) {
case "parent" -> {
var value = declaration.get(0).toString().trim();
var parent = view.getRootView();
if (!"root".equals(value)) {
parent = parent.findViewById(Utils.getID(value, "id"));
}
if (parent instanceof ViewGroup parentView) {
var oldParent = (View) view.getParent();
if (oldParent.getTag() != "relative") {
((ViewGroup) view.getParent()).removeView(view);
var frameLayout = new FrameLayout(parentView.getContext());
frameLayout.setTag("relative");
var params = new FrameLayout.LayoutParams(view.getLayoutParams());
parentView.addView(frameLayout, 0, params);
frameLayout.addView(view);
view = frameLayout;
} else if (oldParent.getTag() == "relative") {
view = oldParent;
}
}
}
case "background-color" -> {
if (declaration.size() != 2) continue;
var color = (TermColor) declaration.get(0);
Original file line number Diff line number Diff line change
@@ -194,12 +194,20 @@ private void setFilter(int position) {
ReflectionUtils.callMethod(methodInitFilter, null, mConversationFragment);
if (mFilterInstance == null) return;
var listField = ReflectionUtils.getFieldByType(mFilterInstance.getClass(), List.class);
var list = (List<Object>) ReflectionUtils.getField(listField, mFilterInstance);
var list = (List<Object>) ReflectionUtils.getObjectField(listField, mFilterInstance);
if (list == null) return;
var name = position == 0 ? "CONTACTS_FILTER" : "GROUP_FILTER";
var result = list.stream().filter(item -> Objects.equals(XposedHelpers.getObjectField(item, "A01"), name)).findFirst();
if (result.isEmpty()) return;
var index = list.indexOf(result.get());
Object result = null;
for (var item : list) {
for (var field : item.getClass().getFields()) {
if (Objects.equals(XposedHelpers.getObjectField(item, field.getName()), name)) {
result = item;
break;
}
}
}
if (result == null) return;
var index = list.indexOf(result);
ReflectionUtils.callMethod(methodSetFilter, mFilterInstance, index);
} catch (Exception e) {
logDebug(e);
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.ListView;

import androidx.annotation.NonNull;
@@ -46,12 +47,23 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
return;
var view = (ViewGroup) param.getResult();
if (view == null) return;
var mainView = (ListView) view.findViewById(android.R.id.list);
mainView.setNestedScrollingEnabled(true);
var list = view.findViewById(android.R.id.list);
var mStatusContainer = new IGStatusView(WppCore.getCurrentActivity());
var layoutParams = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, Utils.dipToPixels(88));
mStatusContainer.setLayoutParams(layoutParams);
mainView.addHeaderView(mStatusContainer);
if (list instanceof ListView listView) {
listView.setNestedScrollingEnabled(true);
var layoutParams = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, Utils.dipToPixels(88));
mStatusContainer.setLayoutParams(layoutParams);
listView.addHeaderView(mStatusContainer);
} else {
// RecyclerView
var paddingTop = list.getPaddingTop();
var parentView = (ViewGroup) list.getParent();
list.setPadding(0, 0, 0, 0);
var layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, Utils.dipToPixels(88));
layoutParams.topMargin = paddingTop;
mStatusContainer.setLayoutParams(layoutParams);
parentView.addView(mStatusContainer, 0);
}
mListStatusContainer.add(mStatusContainer);
}
});
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
import static de.robv.android.xposed.XposedHelpers.getObjectField;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.BaseAdapter;
@@ -23,6 +24,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
@@ -143,18 +145,26 @@ private void hookTabIcon() throws Exception {
@SuppressLint("ResourceType")
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var superClass = param.thisObject.getClass().getSuperclass();
if (superClass != null && superClass == iconTabMethod.getDeclaringClass()) {
var field1 = superClass.getDeclaredField(iconField.getName()).get(param.thisObject);
var field2 = getObjectField(field1, iconFrameField.getName());
if (field2 == null) return;
var menu = (Menu) getObjectField(field2, iconMenuField.getName());
if (menu == null) return;
// add Icon to menu
var menuItem = (MenuItem) menu.findItem(GROUPS);
if (menuItem != null) {
menuItem.setIcon(Utils.getID("home_tab_communities_selector", "drawable"));
}
var obj = param.thisObject;
var superClass = obj.getClass().getSuperclass();

// for 23.xx, superClass != iconTabMethod.getDeclaringClass()
if (!(superClass != null && superClass == iconTabMethod.getDeclaringClass())) {
var preIconTabField = Unobfuscator.loadPreIconTabField(classLoader);
var field0 = getObjectField(obj, preIconTabField.getName());
superClass = field0.getClass().getSuperclass();
obj = field0;
}

var field1 = superClass.getDeclaredField(iconField.getName()).get(obj);
var field2 = getObjectField(field1, iconFrameField.getName());
if (field2 == null) return;
var menu = (Menu) getObjectField(field2, iconMenuField.getName());
if (menu == null) return;
// add Icon to menu
var menuItem = (MenuItem) menu.findItem(GROUPS);
if (menuItem != null) {
menuItem.setIcon(Utils.getID("home_tab_communities_selector", "drawable"));
}
}
});
@@ -167,7 +177,6 @@ private void hookTabName() throws Exception {
XposedBridge.hookMethod(tabNameMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
var tab = (int) param.args[0];
if (tab == GROUPS) {
param.setResult(UnobfuscatorCache.getInstance().getString("groups"));
@@ -185,23 +194,30 @@ private void hookTabInstance(Class<?> cFrag) throws Exception {

var recreateFragmentMethod = Unobfuscator.loadRecreateFragmentConstructor(classLoader);

var pattern = Pattern.compile("android:switcher:\\d+:(\\d+)");

Class<?> FragmentClass = Unobfuscator.loadFragmentClass(classLoader);

XposedBridge.hookMethod(recreateFragmentMethod, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var object = param.args[2];
var desc = XposedHelpers.getObjectField(object, "A06");
if (desc == null) return;
var split = desc.toString().split(":");
var id = 0;
try {
id = Integer.parseInt(split[split.length - 1]);
} catch (Exception ignored) {
return;
var string = "";
if (param.args[0] instanceof Bundle bundle) {
var state = bundle.getParcelable("state");
if (state == null) return;
string = state.toString();
} else {
string = param.args[2].toString();
}
if (id == GROUPS || id == CHATS) {
var convFragment = XposedHelpers.getObjectField(param.thisObject, "A02");
tabInstances.remove(id);
tabInstances.put(id, convFragment);
var matcher = pattern.matcher(string);
if (matcher.find()) {
var tabId = Integer.parseInt(matcher.group(1));
if (tabId == GROUPS || tabId == CHATS) {
var fragmentField = ReflectionUtils.getFieldByType(param.thisObject.getClass(), FragmentClass);
var convFragment = ReflectionUtils.getObjectField(fragmentField, param.thisObject);
tabInstances.remove(tabId);
tabInstances.put(tabId, convFragment);
}
}
}
});
Original file line number Diff line number Diff line change
@@ -43,10 +43,10 @@ public void doHook() throws Throwable {
XposedBridge.hookMethod(menuStatusMethod, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var fieldObjects = Arrays.stream(param.method.getDeclaringClass().getDeclaredFields()).map(field -> ReflectionUtils.getField(field, param.thisObject)).filter(Objects::nonNull).collect(Collectors.toList());
var fieldObjects = Arrays.stream(param.method.getDeclaringClass().getDeclaredFields()).map(field -> ReflectionUtils.getObjectField(field, param.thisObject)).filter(Objects::nonNull).collect(Collectors.toList());
var menuManager = fieldObjects.stream().filter(menuManagerClass::isInstance).findFirst().orElse(null);
var menuField = ReflectionUtils.getFieldByExtendType(menuManagerClass, Menu.class);
var menu = (Menu) ReflectionUtils.getField(menuField, menuManager);
var menu = (Menu) ReflectionUtils.getObjectField(menuField, menuManager);
var fragmentInstance = fieldObjects.stream().filter(StatusPlaybackBaseFragmentClass::isInstance).findFirst().orElse(null);

var index = (int) XposedHelpers.getObjectField(fragmentInstance, "A00");
Original file line number Diff line number Diff line change
@@ -99,6 +99,9 @@ public void doHook() throws Exception {
propsBoolean.put(6798, true); // show all status
propsBoolean.put(3575, animationEmojis); // auto play emojis settings
propsBoolean.put(9757, animationEmojis); // auto play emojis settings
propsBoolean.put(10639, animationEmojis); // emojis map 1
propsBoolean.put(12495, animationEmojis); // emojis map 2
propsBoolean.put(11066, animationEmojis); // emojis map 3

propsBoolean.put(7589, true); // Media select quality
propsBoolean.put(6972, false); // Media select quality
@@ -127,7 +130,11 @@ public void doHook() throws Exception {
if (audio_transcription) {
Others.propsBoolean.put(8632, true);
Others.propsBoolean.put(2890, true);
Others.propsBoolean.put(9215, true);
Others.propsBoolean.put(9215, false);
Others.propsBoolean.put(9216, true);
Others.propsBoolean.put(6808, true);
Others.propsBoolean.put(10286, true);
Others.propsBoolean.put(11596, true);
}

if (verticalStatus) {
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ private void hookStatusScreen(int ticktype) throws Exception {
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (!prefs.getBoolean("hidestatusview", false)) return;
var fMessageField = ReflectionUtils.getFieldByExtendType(param.thisObject.getClass(), FMessageWpp.TYPE);
var fMessage = new FMessageWpp(ReflectionUtils.getField(fMessageField, param.thisObject));
var fMessage = new FMessageWpp(ReflectionUtils.getObjectField(fMessageField, param.thisObject));
var key = fMessage.getKey();
if (key.isFromMe) return;
var view = (View) param.getResult();
@@ -313,7 +313,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
CompletableFuture.runAsync(() -> {
var keyClass = FMessageWpp.Key.TYPE;
var fieldType = ReflectionUtils.getFieldByType(param.thisObject.getClass(), keyClass);
var keyMessage = ReflectionUtils.getField(fieldType, param.thisObject);
var keyMessage = ReflectionUtils.getObjectField(fieldType, param.thisObject);
var fMessage = WppCore.getFMessageFromKey(keyMessage);
if (fMessage == null) return;
sendBlueTickMedia(fMessage, true);
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
return true;
}
var field = ReflectionUtils.getFieldByType(subCls, loadProfileInfoField.getDeclaringClass());
var jidObj = ReflectionUtils.getField(loadProfileInfoField, ReflectionUtils.getField(field, param.thisObject));
var jidObj = ReflectionUtils.getObjectField(loadProfileInfoField, ReflectionUtils.getObjectField(field, param.thisObject));
var jid = WppCore.stripJID(WppCore.getRawString(jidObj));
var file = WppCore.getContactPhotoFile(jid);
var destPath = Utils.getDestination("Profile Photo");
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
CompletableFuture.runAsync(() -> {
var keyClass = FMessageWpp.Key.TYPE;
var fieldType = ReflectionUtils.getFieldByType(param.thisObject.getClass(), keyClass);
var keyMessageObj = ReflectionUtils.getField(fieldType, param.thisObject);
var keyMessageObj = ReflectionUtils.getObjectField(fieldType, param.thisObject);
var fmessageObj = WppCore.getFMessageFromKey(keyMessageObj);
var fmessage = new FMessageWpp(fmessageObj);
var file = fmessage.getMediaFile();
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package com.wmods.wppenhacer.xposed.features.media;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.RecordingCanvas;
import android.os.Build;
import android.util.Pair;

import androidx.annotation.NonNull;

import com.wmods.wppenhacer.xposed.core.Feature;
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
import com.wmods.wppenhacer.xposed.features.general.Others;
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
import com.wmods.wppenhacer.xposed.utils.Utils;

import org.json.JSONObject;

import java.util.concurrent.atomic.AtomicReference;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XSharedPreferences;
@@ -30,134 +31,136 @@ public MediaQuality(ClassLoader loader, XSharedPreferences preferences) {
public void doHook() throws Exception {
var videoQuality = prefs.getBoolean("videoquality", false);
var imageQuality = prefs.getBoolean("imagequality", false);
var maxSize = (int) prefs.getFloat("video_limit_size", 60);
var realResolution = prefs.getBoolean("video_real_resolution", false);

// Max video size
Others.propsInteger.put(3185, maxSize);
Others.propsInteger.put(3656, maxSize);
Others.propsInteger.put(4155, maxSize);
Others.propsInteger.put(3659, maxSize);
Others.propsInteger.put(4685, maxSize);
Others.propsInteger.put(596, maxSize);

Others.propsBoolean.put(7950, false); // Força o uso do MediaComposer para processar os videos

if (videoQuality) {

Others.propsBoolean.put(5549, true); // Remove o limite de qualidade do video
Others.propsBoolean.put(5549, true); // Use bitrate from json to force video high quality

var jsonProperty = Unobfuscator.loadPropsJsonMethod(classLoader);
XposedBridge.hookMethod(jsonProperty, new XC_MethodHook() {

AtomicReference<XC_MethodHook.Unhook> jsonPropertyHook = new AtomicReference<>();
var unhooked = XposedBridge.hookMethod(jsonProperty, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var index = ReflectionUtils.findIndexOfType(param.args, Integer.class);
if (index == -1) {
logDebug("PropsJson: index int not found");
Utils.showToast("PropsJson: index int not found", 0);
jsonPropertyHook.get().unhook();
return;
}
if ((int) param.args[index] == 5550) {
var json = (JSONObject) param.getResult();
for (int i = 0; i < json.length(); i++) {
var key = (String) json.names().opt(i);
var jSONObject = json.getJSONObject(key);
jSONObject.put("max_bitrate", 16000);
jSONObject.put("max_bandwidth", 90);
}
// Disable video profiles (mobile network)
if ((int) param.args[index] == 5550 || (int) param.args[index] == 9705) {
param.setResult(new JSONObject());
}
}
});

var resolutionMethod = Unobfuscator.loadMediaQualityResolutionMethod(classLoader);
logDebug(Unobfuscator.getMethodDescriptor(resolutionMethod));

XposedBridge.hookMethod(resolutionMethod, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
var pair = new Pair<>(param.args[0], param.args[1]);
param.setResult(pair);
}
});

var bitrateMethod = Unobfuscator.loadMediaQualityBitrateMethod(classLoader);
logDebug(Unobfuscator.getMethodDescriptor(bitrateMethod));

XposedBridge.hookMethod(bitrateMethod, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(96 * 1000 * 1000);
}
});
jsonPropertyHook.set(unhooked);

var videoMethod = Unobfuscator.loadMediaQualityVideoMethod2(classLoader);
logDebug(Unobfuscator.getMethodDescriptor(videoMethod));

var fields = Unobfuscator.loadMediaQualityVideoFields(classLoader);
var mediaFields = Unobfuscator.loadMediaQualityOriginalVideoFields(classLoader);
var mediaTranscodeParams = Unobfuscator.loadMediaQualityVideoFields(classLoader);

XposedBridge.hookMethod(videoMethod, new XC_MethodHook() {
@SuppressLint("DefaultLocale")

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
var resizeVideo = param.getResult();
if ((int) param.args[1] == 3) {
var resizeVideo = param.getResult();
if (prefs.getBoolean("video_real_resolution", false)) {

var sourceWidthField = fields.get("sourceWidth");
var sourceHeightField = fields.get("sourceHeight");
if (realResolution) {
var width = mediaFields.get("widthPx").getInt(param.args[0]);
var height = mediaFields.get("heightPx").getInt(param.args[0]);
var rotationAngle = mediaFields.get("rotationAngle").getInt(param.args[0]);

var sourceWidth = sourceWidthField.getInt(resizeVideo);
var sourceHeight = sourceHeightField.getInt(resizeVideo);
var targetWidthField = mediaTranscodeParams.get("targetWidth");
var targetHeightField = mediaTranscodeParams.get("targetHeight");

var targetWidthField = fields.get("targetWidth");
var targetHeightField = fields.get("targetHeight");
var inverted = rotationAngle == 90 || rotationAngle == 270;

targetHeightField.setInt(resizeVideo, inverted ? width : height);
targetWidthField.setInt(resizeVideo, inverted ? height : width);

targetHeightField.setInt(resizeVideo, sourceHeight);
targetWidthField.setInt(resizeVideo, sourceWidth);
}
if (prefs.getBoolean("video_maxfps", false)) {
XposedHelpers.setIntField(resizeVideo, "A01", 60);
}

}
if (prefs.getBoolean("video_maxfps", false)) {
var frameRateField = mediaTranscodeParams.get("frameRate");
frameRateField.setInt(resizeVideo, 60);
}
}
});

var videoLimitClass = Unobfuscator.loadMediaQualityVideoLimitClass(classLoader);
logDebug(videoLimitClass);
// HD video must be sent in maximum resolution (up to 4K)
if (realResolution) {
Others.propsInteger.put(594, 8000); // chat
Others.propsInteger.put(12852, 8000); // chat
Others.propsInteger.put(3183, 8000); // Stories
Others.propsInteger.put(4685, 8000); // Stories
} else {
Others.propsInteger.put(594, 1920); // chat
Others.propsInteger.put(12852, 1920); // chat
Others.propsInteger.put(3183, 1920); // Stories
Others.propsInteger.put(4685, 1920); // Stories
}

XposedHelpers.findAndHookConstructor(videoLimitClass, int.class, int.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
if (prefs.getBoolean("video_size_limit", false)) {
param.args[0] = 90;
}
param.args[1] = 8000; // 4K Resolution
param.args[2] = 96 * 1000 * 1000; // 96 Mbps
}
});
// Non-HD video must be sent in HD resolution
Others.propsInteger.put(4686, 1280);
Others.propsInteger.put(3654, 1280);

// Max bitrate
Others.propsInteger.put(3755, 96000);
Others.propsInteger.put(3756, 96000);
Others.propsInteger.put(3757, 96000);
Others.propsInteger.put(3758, 96000);

}

if (imageQuality) {
int[] props = {1573, 1575, 1578, 1574, 1576, 1577, 2654, 2656, 6030, 6032};
int max = 10000;
int min = 1000;
for (int index = 0; index < props.length; index++) {
if (index <= 2) {
Others.propsInteger.put(props[index], min);
} else {
Others.propsInteger.put(props[index], max);
}
}
Others.propsInteger.put(2655, 100); // Image quality compression
Others.propsInteger.put(6029, 100); // Image quality compression
Others.propsInteger.put(3657, 100); // Image quality compression

var mediaQualityProcessor = Unobfuscator.loadMediaQualityProcessor(classLoader);
XposedBridge.hookAllConstructors(mediaQualityProcessor, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (param.args.length < 4) return;
param.args[0] = 10000; // maxKb
param.args[1] = 100; // quality
param.args[2] = 10000; // maxEdge
param.args[3] = 10000; // nothing
}
});
// Image Max Size
int maxImageSize = 50 * 1024; // 50MB
Others.propsInteger.put(1577, maxImageSize);
Others.propsInteger.put(6030, maxImageSize);
Others.propsInteger.put(2656, maxImageSize);

// Image Quality
int imageMaxQuality = 100;
Others.propsInteger.put(1581, imageMaxQuality);
Others.propsInteger.put(1575, imageMaxQuality);
Others.propsInteger.put(1578, imageMaxQuality);
Others.propsInteger.put(6029, imageMaxQuality);
Others.propsInteger.put(2655, imageMaxQuality);

// HD image must be sent in maximum 4K resolution
Others.propsBoolean.put(6033, true);
Others.propsInteger.put(2654, 6000); // Only HD images
Others.propsInteger.put(6032, 6000); // Only HD images

// Non-HD image must be sent in HD resolution
Others.propsInteger.put(1580, 4160);
Others.propsInteger.put(1574, 4160);
Others.propsInteger.put(1576, 4160);
Others.propsInteger.put(12902, 4160);

// Prevent crashes in Media preview
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
XposedHelpers.findAndHookMethod(RecordingCanvas.class, "throwIfCannotDraw", Bitmap.class, XC_MethodReplacement.DO_NOTHING);
}

}
}

Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
import com.wmods.wppenhacer.xposed.core.Feature;
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp;
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
import com.wmods.wppenhacer.xposed.utils.DebugUtils;
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;

import java.io.File;
@@ -19,6 +20,7 @@
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;

public class AudioTranscript extends Feature {

@@ -35,21 +37,30 @@ public void doHook() throws Throwable {


var transcribeMethod = Unobfuscator.loadTranscribeMethod(classLoader);
var unkTranscript = Unobfuscator.loadUnkTranscript(classLoader);
var unkTranscriptClass = Unobfuscator.loadUnkTranscript(classLoader);
Class<?> TranscriptionSegmentClass = Unobfuscator.loadTranscriptSegment(classLoader);

XposedBridge.hookMethod(transcribeMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
DebugUtils.debugArgs(param.args);
var pttTranscriptionRequest = param.args[0];
var fieldFMessage = ReflectionUtils.getFieldByExtendType(pttTranscriptionRequest.getClass(), FMessageWpp.TYPE);
var fmessageObj = fieldFMessage.get(pttTranscriptionRequest);
var fmessage = new FMessageWpp(fmessageObj);
File file = fmessage.getMediaFile();
var callback = param.args[1];
var mEnglishInstance = ReflectionUtils.getFieldByExtendType(unkTranscriptClass, unkTranscriptClass).get(null);
var onComplete = ReflectionUtils.findMethodUsingFilter(callback.getClass(), method -> method.getParameterCount() == 4);
String transcript = runTranscript(file);
var unkTranscriptInstance = unkTranscript.getField("A00").get(null);
ReflectionUtils.callMethod(onComplete, callback, unkTranscriptInstance, fmessageObj, transcript, new ArrayList<>());
var segments = new ArrayList<>();
var words = transcript.split(" ");
var totalLength = 0;
for (var word : words) {
segments.add(XposedHelpers.newInstance(TranscriptionSegmentClass, totalLength, word.length(), 100, -1, -1));
totalLength += word.length() + 1;
}
ReflectionUtils.callMethod(onComplete, callback, mEnglishInstance, fmessageObj, transcript, segments);
param.setResult(null);
}
});
Original file line number Diff line number Diff line change
@@ -49,19 +49,19 @@ public void doHook() throws Throwable {
log("HeaderChannelItem: " + headerChannelItem);
var listChannelItem = Unobfuscator.loadListChannelItemClass(classLoader);
log("ListChannelItem: " + listChannelItem);
var listUpdateItems = Unobfuscator.loadListUpdateItemsConstructor(classLoader);
log("ListUpdateItems: " + Unobfuscator.getConstructorDescriptor(listUpdateItems));

XposedBridge.hookMethod(listUpdateItems,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
var list = ReflectionUtils.findArrayOfType(param.args, ArrayList.class);
if (list.isEmpty()) return;
var arrList = (ArrayList<?>) list.get(0).second;
removeItems(arrList, channels, removechannelRec, headerChannelItem, listChannelItem, removeChannelRecClass);
}
});
var listUpdateItems = Unobfuscator.loadListUpdateItems(classLoader);
log("ListUpdateItems: " + Unobfuscator.getMethodDescriptor(listUpdateItems));
XposedBridge.hookMethod(listUpdateItems, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
var results = ReflectionUtils.findArrayOfType(param.args, List.class);
if (results.isEmpty()) return;
var list = (List<?>) results.get(0).second;
var arrList = new ArrayList<>(list);
removeItems(arrList, channels, removechannelRec, headerChannelItem, listChannelItem, removeChannelRecClass);
param.args[results.get(0).first] = arrList;
}
});

XposedBridge.hookAllConstructors(removeChannelRecClass, new XC_MethodHook() {
@Override
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import android.os.Message;
import android.text.TextUtils;
import android.widget.Toast;

import androidx.annotation.NonNull;

@@ -10,6 +11,7 @@
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
import com.wmods.wppenhacer.xposed.features.general.Tasker;
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
import com.wmods.wppenhacer.xposed.utils.Utils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
@@ -34,8 +36,16 @@ public void doHook() throws Throwable {
XposedBridge.hookMethod(onCallReceivedMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Object callinfo = ((Message) param.args[0]).obj;
Object callinfo = null;
Class<?> callInfoClass = XposedHelpers.findClass("com.whatsapp.voipcalling.CallInfo", classLoader);
if (param.args[0] instanceof Message) {
callinfo = ((Message) param.args[0]).obj;
} else if (param.args.length > 1 && callInfoClass.isInstance(param.args[1])) {
callinfo = param.args[1];
} else {
Utils.showToast("Invalid call info", Toast.LENGTH_SHORT);
return;
}
if (callinfo == null || !callInfoClass.isInstance(callinfo)) return;
if ((boolean) XposedHelpers.callMethod(callinfo, "isCaller")) return;
var userJid = XposedHelpers.callMethod(callinfo, "getPeerJid");
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ public static Object getDefaultValue(Class<?> paramType) {
return null;
}

public static Object getField(Field loadProfileInfoField, Object thisObject) {
public static Object getObjectField(Field loadProfileInfoField, Object thisObject) {
try {
return loadProfileInfoField.get(thisObject);
} catch (Exception e) {
8 changes: 8 additions & 0 deletions app/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
@@ -393,4 +393,12 @@
<string name="always_online_sum">إظهار أنك متصل الآن حتى لو قمت بإغلاق واتساب (لا يعمل إذا قمت بإزالته من الإعدادات)</string>
<string name="additional_call_information">معلومات إضافية عن المكالمة</string>
<string name="additional_call_information_sum">تلقي إشعار مع معلومات إضافية بعد انتهاء المكالمة</string>
<string name="contact_s">المُتصل: %s</string>
<string name="phone_number_s">الرقم: +%s</string>
<string name="country_s">الدولة: %s</string>
<string name="city_s">المدينة: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">المنصة: %s</string>
<string name="wpp_version_s">إصدار واتساب: %s</string>
<string name="call_information">معلومات المكالمة</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
@@ -392,4 +392,12 @@
<string name="always_online_sum">Zeige dich online, auch wenn du WhatsApp minimierst (Funktioniert nicht, wenn du es aus den letzten Apps entfernst)</string>
<string name="additional_call_information">Zusätzliche Anrufinformationen</string>
<string name="additional_call_information_sum">Erhalten Sie eine Benachrichtigung mit zusätzlichen Informationen nach dem Ende des Anrufs</string>
<string name="contact_s">Kontakt: %s</string>
<string name="phone_number_s">Nummer: +%s</string>
<string name="country_s">Land: %s</string>
<string name="city_s">Stadt: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Plattform: %s</string>
<string name="wpp_version_s">WhatsApp-Version: %s</string>
<string name="call_information">Anrufinformationen</string>
</resources>
14 changes: 11 additions & 3 deletions app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
@@ -229,10 +229,10 @@
<string name="antidisappearing">Anti Desaparición de mensajes Temporales</string>
<string name="antidisappearing_sum">Los mensajes temporales no serán borrados para usted</string>
<string name="title_audio">Audio</string>
<string name="android_version">SDK de Android</string>
<string name="android_version">Versión de Android (SDK)</string>
<string name="message_removed_on">Este mensaje fue eliminado el %s.</string>
<string name="disable_default_emojis">Desactivar Emojis por Defecto</string>
<string name="theme_mode">Tema Oscuro Wa Enhancer</string>
<string name="theme_mode">Tema Oscuro</string>
<string name="theme_mode_sum">Forzar color de la interfaz en Wa Enhancer</string>
<string name="disable_default_emojis_sum">Desactiva los emojis predeterminados de Whatsapp y usa emojis del sistema\n(NOTA: Los emojis de Whatsapp desaparecerán del selector, usa el teclado para insertar).</string>
<string name="other">Otros</string>
@@ -283,7 +283,7 @@
<string name="viewed_your_message">%s ha visto tu mensaje</string>
<string name="old_statuses">Estados antiguos</string>
<string name="old_statuses_sum">Cambiar a la interfaz de estados antiguos verticalmente y sin canales (NOTA: Puede causar lag en la interfaz)</string>
<string name="force_english">Forzar idioma Ingles en Wa Enhancer</string>
<string name="force_english">Forzar idioma Ingles</string>
<string name="select_status_type">Seleccionar tipo de estado</string>
<string name="open_camera">Abrir cámara</string>
<string name="edit_text">Editar texto</string>
@@ -392,4 +392,12 @@
<string name="always_online_sum">Mostrar \'en línea\' incluso si minimizas WhatsApp (no funciona si lo eliminas de los recientes)</string>
<string name="additional_call_information">Información adicional de llamada</string>
<string name="additional_call_information_sum">Recibir una notificación con información adicional después de que finalice la llamada</string>
<string name="contact_s">Contacto: %s</string>
<string name="phone_number_s">Número: +%s</string>
<string name="country_s">País: %s</string>
<string name="city_s">Ciudad: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Plataforma: %s</string>
<string name="wpp_version_s">Versión de WhatsApp: %s</string>
<string name="call_information">Información de la llamada</string>
</resources>
650 changes: 329 additions & 321 deletions app/src/main/res/values-fr/strings.xml

Large diffs are not rendered by default.

36 changes: 22 additions & 14 deletions app/src/main/res/values-id/strings.xml
Original file line number Diff line number Diff line change
@@ -17,8 +17,8 @@
<string name="segundosnahora">Detik dalam Waktu</string>
<string name="segundosnahora_sum">Tampilkan detik di samping waktu apapun di aplikasi WhatsApp</string>
<string name="textonahora">Teks di samping Waktu</string>
<string name="viewonce">Unlimited View Once</string>
<string name="viewonce_sum">Allows you to open view once media multiple times</string>
<string name="viewonce">Tampilan Tak Terbatas Sekali</string>
<string name="viewonce_sum">Memungkinkan Anda membuka tampilan media sekali beberapa kali</string>
<string name="novotema_sum">Ubah warna dan tema ikon menjadi tema WhatsApp baru</string>
<string name="antirevokestatus">Anti Hapus Status</string>
<string name="antirevokestatus_sum">Status tidak akan dihapus untuk Anda</string>
@@ -72,8 +72,8 @@
(CATATAN: Harus mengaktifkan \"Sembunyikan centang biru\")</string>
<string name="hide_archived_chat">Sembunyikan Obrolan yang Diarsipkan</string>
<string name="hide_archived_chat_sum">Sembunyikan obrolan yang diarsipkan, untuk mengakses klik 5 kali pada judul \"WhatsApp\" di header Layar Beranda</string>
<string name="hide_once_view_seen">Hide View Once Seen</string>
<string name="hide_once_view_seen_sum">Hide that view one media has been seen</string>
<string name="hide_once_view_seen">Sembunyikan Tampilan Setelah Dilihat</string>
<string name="hide_once_view_seen_sum">Sembunyikan tampilan yang telah dilihat satu media</string>
<string name="call_blocker">Blokir Panggilan</string>
<string name="call_blocker_sum">Blokir panggilan WhatsApp berdasarkan jenis privasi</string>
<string name="show_online_dot_in_conversation_list">Tampilkan Titik Online</string>
@@ -232,8 +232,8 @@ Saat Anda mengaktifkan bekukan \"terakhir dilihat dan online\", Anda tidak dapat
<string name="show_toast_on_contact_online_sum">Tampilkan notifikasi mengambang ketika kontak sedang online</string>
<string name="new_context_menu_ui">Menu UI Konteks Baru</string>
<string name="new_context_menu_ui_sum">Aktifkan menu konteks pesan baru bergaya iOS</string>
<string name="filter_items_by_id">Filter Items By ID</string>
<string name="filter_items_by_id_sum">Filter items by id name</string>
<string name="filter_items_by_id">Filter Item Berdasarkan ID</string>
<string name="filter_items_by_id_sum">Filter item berdasarkan nama id</string>
<string name="custom_theme_css">Tema Khusus CSS</string>
<string name="custom_theme_css_sum">Sesuaikan WhatsApp Anda menggunakan gaya CSS</string>
<string name="antidisappearing">Anti Hapus Pesan Sementara</string>
@@ -299,19 +299,19 @@ Saat Anda mengaktifkan bekukan \"terakhir dilihat dan online\", Anda tidak dapat
<string name="select_status_type">Pilih jenis status</string>
<string name="open_camera">Buka Kamera</string>
<string name="edit_text">Edit Teks</string>
<string name="about_info">Wa Enhancer is an Xposed module that enhances your WhatsApp experience by offering advanced privacy features, home screen customization, general tweaks, and media improvements.</string>
<string name="installation">Installation</string>
<string name="installation_desc">1. Ensure that your device is rooted.\n2. Install the Xposed Framework on your device.\n3. Download the Wa Enhancer from the Actions section.\n4. Install the Wa Enhancer APK.\n5. Enable the Wa Enhancer module in the Xposed Installer app.</string>
<string name="go_to_telegram">Go to Telegram</string>
<string name="about_info">Wa Enhancer adalah modul Xposed yang meningkatkan pengalaman WhatsApp Anda dengan menawarkan fitur privasi tingkat lanjut, kustomisasi layar beranda, penyesuaian umum, dan peningkatan media.</string>
<string name="installation">Instalasi</string>
<string name="installation_desc">1. Pastikan perangkat Anda telah di-root.\n2. Instal Xposed Framework di perangkat Anda.\n3. Unduh Wa Enhancer dari bagian Actions.\n4. Instal APK Wa Enhancer.\n5. Aktifkan modul Wa Enhancer di aplikasi Xposed Installer.</string>
<string name="go_to_telegram">Pergi ke Telegram</string>
<string name="go_to_github">Go to GitHub</string>
<string name="donate">Donate</string>
<string name="support">Support</string>
<string name="support_desc">If you encounter any issues or have questions about Wa Enhancer, please visit Telegram.</string>
<string name="support_desc">Jika Anda mengalami masalah atau memiliki pertanyaan tentang Wa Enhancer, silakan kunjungi Telegram.</string>
<string name="license">License</string>
<string name="license_desc">This project is licensed under the GNU License - see the LICENSE file for details.\n\nNote: Please use Wa Enhancer responsibly and in compliance with the terms and conditions of the apps you are modifying. Misuse of this tool may lead to legal consequences.</string>
<string name="license_desc">Proyek ini dilisensikan berdasarkan Lisensi GNU - lihat berkas LICENSE untuk detailnya.\n\nCatatan: Harap gunakan Wa Enhancer secara bertanggung jawab dan sesuai dengan syarat dan ketentuan aplikasi yang Anda modifikasi. Penyalahgunaan alat ini dapat mengakibatkan konsekuensi hukum.</string>
<string name="select_a_color">Select a color</string>
<string name="custom_appearance">Custom Appearance</string>
<string name="custom_filters_sum">Activate filters by ID and Custom CSS</string>
<string name="custom_appearance">Penampilan Kustom</string>
<string name="custom_filters_sum">Aktifkan filter berdasarkan ID dan CSS Kustom</string>
<string name="click_times">Click 5 times on the WhatsApp title</string>
<string name="hold_title">Hold on WhatsApp title</string>
<string name="read_all_mark_as_read">Read all (mark as read)</string>
@@ -404,4 +404,12 @@ Saat Anda mengaktifkan bekukan \"terakhir dilihat dan online\", Anda tidak dapat
<string name="always_online_sum">Show you online even if you minimize WhatsApp (Doesn\'t work if you remove it from recents)</string>
<string name="additional_call_information">Additional call information</string>
<string name="additional_call_information_sum">Receive a notification with additional information after the call ends</string>
<string name="contact_s">Contact: %s</string>
<string name="phone_number_s">Number: +%s</string>
<string name="country_s">Country: %s</string>
<string name="city_s">City: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Platform: %s</string>
<string name="wpp_version_s">WhatsApp Version: %s</string>
<string name="call_information">Call Information</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-in/strings.xml
Original file line number Diff line number Diff line change
@@ -401,4 +401,12 @@ Harap gunakan versi WhatsApp yang didukung!</string>
<string name="always_online_sum">Menampilkan Anda sedang online bahkan jika Anda meminimalkan WhatsApp/n(Tidak berfungsi jika Anda menghapusnya dari yang terbaru)</string>
<string name="additional_call_information">Informasi Panggilan Tambahan</string>
<string name="additional_call_information_sum">Terima pemberitahuan dengan informasi tambahan setelah panggilan berakhir</string>
<string name="contact_s">Kontak: %s</string>
<string name="phone_number_s">Nomor: +%s</string>
<string name="country_s">Negara: %s</string>
<string name="city_s">Kota: %s</string>
<string name="ip_s">Alamat IP: %s</string>
<string name="platform_s">Platform: %s</string>
<string name="wpp_version_s">Versi WhatsApp: %s</string>
<string name="call_information">Informasi Panggilan</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
@@ -392,4 +392,12 @@
<string name="always_online_sum">Mostrami online anche se si minimizza WhatsApp (non funziona se lo si rimuove dai recenti)</string>
<string name="additional_call_information">Informazioni aggiuntive sulla chiamata</string>
<string name="additional_call_information_sum">Ricevi una notifica con ulteriori informazioni dopo la fine della chiamata</string>
<string name="contact_s">Contatto: %s</string>
<string name="phone_number_s">Numero: +%s</string>
<string name="country_s">Paese: %s</string>
<string name="city_s">Città: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Piattaforma: %s</string>
<string name="wpp_version_s">Versione WhatsApp: %s</string>
<string name="call_information">Informazioni Chiamata</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-iw/strings.xml
Original file line number Diff line number Diff line change
@@ -394,4 +394,12 @@
<string name="always_online_sum">הראה שאתה תמיד מחובר בווצאפ - גם אם אתה יוצא מהווצאפ לאפליקציות אחרות (אך התכונה לא תעבוד אם אתה מסיר את הווצאפ מהכרטיסיות של האחרונים)</string>
<string name="additional_call_information">מידע נוסף על שיחות</string>
<string name="additional_call_information_sum">קבל התראה עם מידע נוסף לאחר סיום השיחה בווצאפ</string>
<string name="contact_s">איש קשר: %s</string>
<string name="phone_number_s">מספר טלפון: +%s</string>
<string name="country_s">מדינה: %s</string>
<string name="city_s">עיר: %s</string>
<string name="ip_s">מיקום מדוייק (IP): %s</string>
<string name="platform_s">סוג טלפון: %s</string>
<string name="wpp_version_s">גרסת ווצאפ: %s</string>
<string name="call_information">מידע על השיחה</string>
</resources>
12 changes: 10 additions & 2 deletions app/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@
<string name="call_blocker">Bloquear chamadas</string>
<string name="call_blocker_sum">Bloqueie chamadas do WhatsApp com base no tipo de privacidade</string>
<string name="show_online_dot_in_conversation_list">Mostrar ponto de online na guia de conversas</string>
<string name="show_online_dot_in_conversation_list_sum">Mostre um ponto online verde na tela inicial\n(OBSERVAÇÃO: É necessário ativar a opção online para todos em Configurações > Privacidade > Visto por último e online no WhatsApp)</string>
<string name="show_online_dot_in_conversation_list_sum">Mostre um ponto online verde na tela inicial\n(OBSERVAÇÃO: É necessário ativar a opção online para todos em Configurações &gt; Privacidade &gt; Visto por último e online no WhatsApp)</string>
<string name="show_dnd_button">Mostrar botão Não perturbe</string>
<string name="show_dnd_button_sum">Mostra uma opção para ativar o modo Não perturbe na tela inicial</string>
<string name="dev4mod">Dev4Mod (Desenvolvedor)</string>
@@ -216,7 +216,7 @@
<string name="toolbar_transparency">Transparência da barra superior</string>
<string name="navigation_transparency">Transparência da barra de navegação</string>
<string name="show_online_last_seen_in_conversation_list">Mostrar Online/Visto por último vez na guia de conversas</string>
<string name="show_online_last_seen_in_conversation_list_sum">Mostra um texto online ou visto por último vez na tela inicial.\n(OBSERVAÇÃO: É necessário ativar a opção online para todos em Configurações > Privacidade > Visto por último e online no WhatsApp)</string>
<string name="show_online_last_seen_in_conversation_list_sum">Mostra um texto online ou visto por último vez na tela inicial.\n(OBSERVAÇÃO: É necessário ativar a opção online para todos em Configurações &gt; Privacidade &gt; Visto por último e online no WhatsApp)</string>
<string name="toast_online">%s está online</string>
<string name="show_toast_on_contact_online">Mostrar toast para contato online</string>
<string name="show_toast_on_contact_online_sum">Mostra uma notificação toast quando um contato estiver online</string>
@@ -392,4 +392,12 @@
<string name="always_online_sum">Fique sempre online mesmo que você minimize o WhatsApp. (OBSERVAÇÃO: Não funciona se removê-lo dos recentes)</string>
<string name="additional_call_information">Informações adicionais de chamada</string>
<string name="additional_call_information_sum">Receba uma notificação com informações adicionais após o término da chamada.</string>
<string name="contact_s">Contato: %s</string>
<string name="phone_number_s">Número: +%s</string>
<string name="country_s">País: %s</string>
<string name="city_s">Cidade: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Plataforma: %s</string>
<string name="wpp_version_s">Versão do WhatsApp: %s</string>
<string name="call_information">Informações de chamada</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
@@ -392,4 +392,12 @@
<string name="always_online_sum">Показать вас в сети, даже если вы минимизируете WhatsApp (не работает, если вы удалите из недавних приложений)</string>
<string name="additional_call_information">Дополнительная информация о звонке</string>
<string name="additional_call_information_sum">Получать уведомление с дополнительной информацией после завершения звонка</string>
<string name="contact_s">Контакт: %s</string>
<string name="phone_number_s">Номер: +%s</string>
<string name="country_s">Страна: %s</string>
<string name="city_s">Город: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Платформа: %s</string>
<string name="wpp_version_s">Версия WhatsApp: %s</string>
<string name="call_information">Информация о звонке</string>
</resources>
8 changes: 8 additions & 0 deletions app/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
@@ -392,4 +392,12 @@
<string name="always_online_sum">WhatsApp\'ı küçültseniz bile çevrimiçi olduğunuzu gösterin (Son kullanılanlardan kaldırırsanız çalışmaz)</string>
<string name="additional_call_information">Ek çağrı bilgisi</string>
<string name="additional_call_information_sum">Çağrı sona erdikten sonra ek bilgiler içeren bir bildirim al</string>
<string name="contact_s">İletişim: %s</string>
<string name="phone_number_s">Numara: +%s</string>
<string name="country_s">Ülke: %s</string>
<string name="city_s">Şehir: %s</string>
<string name="ip_s">IP: %s</string>
<string name="platform_s">Platform: %s</string>
<string name="wpp_version_s">WhatsApp Sürümü: %s</string>
<string name="call_information">Arama Bilgisi</string>
</resources>
11 changes: 5 additions & 6 deletions app/src/main/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
@@ -77,11 +77,11 @@
<string name="show_online_dot_in_conversation_list_sum">在聊天列表的联系人头像右上角显示绿色在线小点\n(注意:必须在 WhatsApp 设置的“隐私”菜单中的“最后上线时间和在线状态”中对所有人开放)</string>
<string name="show_dnd_button">显示免打扰按钮</string>
<string name="show_dnd_button_sum">在主页工具栏上显示免打扰按钮</string>
<!-- <string name="dev4mod">Dev4Mod (Contributor)</string> -->
<string name="dev4mod">Dev4Mod (Contributor)</string>
<string name="disable_pinned_limit">禁用置顶限制</string>
<string name="disable_pinned_limit_sum">禁用只能置顶三个联系人的限制</string>
<string name="delete_for_everyone_all_messages">可以对全部聊天消息“在所有人设备删除”</string>
<string name="delete_for_everyone_all_messages_sum">移除"在所有人设备删除"的 24 小时限制</string>
<string name="delete_for_everyone_all_messages_sum">移除\"在所有人设备删除\"的 24 小时限制</string>
<string name="antirevoke_buttons_desable">禁用</string>
<string name="antirevoke_buttons_show_text">显示文本</string>
<string name="antirevoke_buttons_show_icon">显示图标</string>
@@ -136,7 +136,7 @@
<string name="business_in_background">WhatsApp Business(企业版)后台运行中</string>
<string name="sending_read_blue_tick">正在发送蓝色勾号(标记为已读/已查看)</string>
<string name="enable_facebook_style_for_status">启用 Facebook 风格的“动态”</string>
<string name="enable_facebook_style_for_status_sum">将原有的"动态"样式更改为 Facebook 风格</string>
<string name="enable_facebook_style_for_status_sum">将原有的\"动态\"样式更改为 Facebook 风格</string>
<string name="send">发送</string>
<string name="do_you_want_to_send_sticker">您要发送此贴图吗?</string>
<string name="send_sticker">发送贴图</string>
@@ -229,7 +229,7 @@
<string name="antidisappearing">防止信息消失</string>
<string name="antidisappearing_sum">不会为您删除临时消息</string>
<string name="title_audio">音频</string>
<!-- <string name="android_version">Android SDK</string> -->
<string name="android_version">Android SDK</string>
<string name="message_removed_on">该消息已于 %s 删除。</string>
<string name="disable_default_emojis">禁用默认表情符号(Emoji)</string>
<string name="theme_mode">黑暗主题 Wa Enhancer</string>
@@ -287,7 +287,6 @@
<string name="select_status_type">选择动态类型</string>
<string name="open_camera">打开相机</string>
<string name="edit_text">编辑文本</string>
<!-- <string name="developer" translatable="false">Developer: Dev4Mod</string> -->
<string name="about_info">Wa Enhancer 是一个 Xposed 模块,可以让你的 WhatsApp 使用体验更好,提供更强的隐私功能、主页自定义、一些通用调整和媒体改进。</string>
<string name="installation">安装步骤</string>
<string name="installation_desc">1. 确保您的设备已获取 root 权限。\n2. 在您的设备上安装 Xposed 框架。\n3. 从Github的“Actions”部分下载 Wa Enhancer。\n4. 安装 Wa Enhancer APK。\n5. 在 Xposed 框架中启用 Wa Enhancer 模块。</string>
@@ -366,7 +365,7 @@
<string name="show_menu_buttons_as_icons">以图标形式显示菜单按钮</string>
<string name="show_menu_buttons_as_icons_sum">在主页工具栏上以图标形式显示菜单按钮,以方便访问</string>
<string name="starting_cache">在 WhatsApp 中启动 Hook 缓存。这可能需要一段时间。</string>
<!-- <string name="bridge_error">Bridge Failed: Enable System Framework in Lsposed and reboot device</string> -->
<string name="bridge_error">Bridge Failed: Enable System Framework in Lsposed and reboot device</string>
<string name="disable_battery_optimization">禁用电池优化</string>
<string name="bootloader_spoofer">Bootloader 伪装</string>
<string name="bootloader_spoofer_sum">如果您被封禁并收到非官方 Whatsapp 消息,请使用此功能</string>
14 changes: 6 additions & 8 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
@@ -115,22 +115,20 @@
<item>2</item>
</string-array>
<string-array name="supported_versions_wpp">
<item>2.24.16.xx</item>
<item>2.24.17.xx</item>
<item>2.24.18.xx</item>
<item>2.24.19.xx</item>
<item>2.24.20.xx</item>
<item>2.24.21.xx</item>
<item>2.24.22.xx</item>
<item>2.24.23.xx</item>
<item>2.24.24.xx</item>
<item>2.24.25.xx</item>
</string-array>
<string-array name="supported_versions_business">
<item>2.24.16.xx</item>
<item>2.24.17.xx</item>
<item>2.24.18.xx</item>
<item>2.24.19.xx</item>
<item>2.24.20.xx</item>
<item>2.24.21.xx</item>
<item>2.24.22.xx</item>
<item>2.24.23.xx</item>
<item>2.24.24.xx</item>
<item>2.24.25.xx</item>
</string-array>
<string-array name="image_picker">
<item>image/*</item>
4 changes: 2 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -152,8 +152,8 @@
<string name="default_color">Set color #00000000 to default color</string>
<string name="enable_confirmation_to_send_sticker">Confirmation Before Sending Sticker</string>
<string name="enable_confirmation_to_send_sticker_sum">Show a dialog before sending the sticker</string>
<string name="increase_video_size_limit">Increase Video Size Limit</string>
<string name="increase_video_size_limit_sum">Increase Video size limit to 90MB</string>
<string name="increase_video_size_limit">Increase Video Size Limit (MB)</string>
<string name="increase_video_size_limit_sum">Increase Video size limit to 200MB</string>
<string name="send_video_in_real_resolution">Send Video in Real Resolution</string>
<string name="send_video_in_real_resolution_sum">Send Video in Real Resolution for status, group and chats</string>
<string name="send_video_in_60fps">Send Video in 60fps</string>
14 changes: 8 additions & 6 deletions app/src/main/res/xml/fragment_media.xml
Original file line number Diff line number Diff line change
@@ -39,17 +39,19 @@
app:iconSpaceReserved="false"
app:title="@string/title_video">

<com.wmods.wppenhacer.preference.FloatSeekBarPreference
android:defaultValue="60"
app:key="video_limit_size"
app:maxValue="120"
app:minValue="30"
app:title="@string/increase_video_size_limit"
app:valueSpacing="10" />

<rikka.material.preference.MaterialSwitchPreference
app:key="videoquality"
app:summary="@string/videoquality_sum"
app:title="@string/videoquality" />

<rikka.material.preference.MaterialSwitchPreference
app:dependency="videoquality"
app:key="video_size_limit"
app:summary="@string/increase_video_size_limit_sum"
app:title="@string/increase_video_size_limit" />

<rikka.material.preference.MaterialSwitchPreference
app:dependency="videoquality"
app:key="video_real_resolution"
17 changes: 12 additions & 5 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
[IMPROVEMENTS]
* Improvement in multi click functions (Archived Chats and doubled Click to reaction)
[FIXES]
* Fixed the bug in the wallpaper function that made other screens tremble.
* Fixed bug in AssemblyAI that didn't work (Test it and let me know if it's working for you).


[WHATSAPP]
* Added pre-support for version 2.24.22.xx (Obrigado novamente ao frknkrc44)
* Add Initial support for beta 2.24.25.XX

[FEATURES]
* Added the ability to send videos in real resolution.

[IMPROVEMENTS]
* Improvements to the HD video and image function (Now the Whatsapp quality selector works for videos and images with resolutions higher than HD)

[WAE]
* Updated translations
* Added support for Chinese language (Maybe some Chinese outside the country will use it)
* Updated translations
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[versions]
assemblyai-java = "3.0.0"
bcpkix-jdk18on = "1.77"
betterypermissionhelper = "1.0.3"
filepicker = "9.2.5"
@@ -13,6 +14,7 @@ kotlin = "2.0.0"


[libraries]
assemblyai-java = { module = "com.assemblyai:assemblyai-java", version.ref = "assemblyai-java" }
bcpkix-jdk18on = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "bcpkix-jdk18on" }
betterypermissionhelper = { module = "com.waseemsabir:betterypermissionhelper", version.ref = "betterypermissionhelper" }
colorpicker = { module = "com.jaredrummler:colorpicker", version.ref = "colorpicker" }

0 comments on commit 47dec3d

Please sign in to comment.