Skip to content

Commit a056b6a

Browse files
committed
feat(Status): Refactor status features with new StatusItemWpp abstraction and Kotlin migration
1 parent 848ab96 commit a056b6a

8 files changed

Lines changed: 282 additions & 304 deletions

File tree

app/src/main/java/com/wmods/wppenhacer/xposed/core/components/FStatusWpp.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import com.wmods.wppenhacer.xposed.utils.ReflectionUtils
66
import de.robv.android.xposed.XC_MethodHook
77
import de.robv.android.xposed.XposedBridge
88
import de.robv.android.xposed.XposedHelpers
9+
import java.io.File
910
import java.lang.reflect.Field
1011
import java.lang.reflect.Method
1112

12-
class FStatusWpp(fstatus: Any?) {
13+
class FStatusWpp(val fstatus: Any?) {
1314

1415
companion object {
1516

17+
private lateinit var classFMediaStatus: Class<*>
1618
private lateinit var methodGetStatusByKey: Method
1719

1820
lateinit var TYPE: Class<*>
@@ -34,6 +36,7 @@ class FStatusWpp(fstatus: Any?) {
3436
mStatusStore = param.thisObject
3537
}
3638
})
39+
classFMediaStatus = Unobfuscator.loadFMediaStatusClass(classLoader)
3740
}
3841

3942
@JvmStatic
@@ -59,15 +62,17 @@ class FStatusWpp(fstatus: Any?) {
5962
throw RuntimeException("Object is not a FStatus Instance")
6063
}
6164

65+
val isMediaFile by lazy {
66+
classFMediaStatus.isInstance(fstatus)
67+
}
68+
6269

6370
val fStatusKey by lazy {
64-
try {
65-
FStatusKey(fieldFStatusKey.get(fstatus))
66-
} catch (e: Exception) {
67-
XposedBridge.log(e)
68-
}
71+
FStatusKey(fieldFStatusKey.get(fstatus))
6972
}
7073

74+
75+
7176
val fMessage: FMessageWpp? by lazy {
7277
try {
7378
FMessageWpp(WppCore.getFMessageFromFStatus(fstatus))
@@ -77,6 +82,18 @@ class FStatusWpp(fstatus: Any?) {
7782
}
7883
}
7984

85+
fun getMediaFile(): File? {
86+
if (!isMediaFile) return null
87+
val item = classFMediaStatus.getField("A00").get(fstatus) ?: return null
88+
return item.javaClass.declaredMethods.first {
89+
it.returnType == File::class.java
90+
}.apply { isAccessible = true }.invoke(item) as? File
91+
}
92+
93+
override fun toString(): String {
94+
return "FStatusWpp(fstatus=$fstatus, isMedia=$isMediaFile, fStatusKey=$fStatusKey)"
95+
}
96+
8097
class FStatusKey {
8198

8299
companion object {
@@ -93,7 +110,7 @@ class FStatusWpp(fstatus: Any?) {
93110
}
94111

95112
@JvmField
96-
var senderJid: Any? = null
113+
var senderJid: FMessageWpp.UserJid
97114

98115
/**
99116
* The underlying key object from WhatsApp's code.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.wmods.wppenhacer.xposed.core.components
2+
3+
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils
4+
import java.io.File
5+
import java.lang.reflect.Field
6+
7+
class StatusItemWpp private constructor(
8+
val fStatus: FStatusWpp?,
9+
private val directFMessage: FMessageWpp?
10+
) {
11+
val fMessage: FMessageWpp?
12+
get() = directFMessage ?: fStatus?.fMessage
13+
14+
val isFromMe: Boolean
15+
get() = directFMessage?.key?.isFromMe ?: fStatus?.fStatusKey?.isFromMe ?: false
16+
17+
val messageID: String
18+
get() = directFMessage?.key?.messageID ?: fStatus?.fStatusKey?.messageID ?: ""
19+
20+
val senderJid: FMessageWpp.UserJid?
21+
get() = directFMessage?.userJid ?: fStatus?.fStatusKey?.senderJid
22+
23+
val isMediaFile: Boolean
24+
get() = directFMessage?.isMediaFile ?: fStatus?.isMediaFile ?: false
25+
26+
fun getMediaFile(): File? = directFMessage?.mediaFile ?: fStatus?.getMediaFile()
27+
28+
companion object {
29+
private val fStatusFieldCache = mutableMapOf<Class<*>, Field?>()
30+
31+
@JvmStatic
32+
fun from(obj: Any?): StatusItemWpp? {
33+
if (obj == null) return null
34+
val fMsgField = ReflectionUtils.findFieldUsingFilterIfExists(obj.javaClass) { f ->
35+
FMessageWpp.TYPE.isAssignableFrom(f.type)
36+
}
37+
fMsgField?.get(obj)?.let { return StatusItemWpp(null, FMessageWpp(it)) }
38+
val fStatusField = fStatusFieldCache.getOrPut(obj.javaClass) {
39+
ReflectionUtils.findFieldUsingFilterIfExists(obj.javaClass) { f ->
40+
FStatusWpp.TYPE.isAssignableFrom(f.type)
41+
}
42+
}
43+
fStatusField?.get(obj)?.let { return StatusItemWpp(FStatusWpp(it), null) }
44+
return null
45+
}
46+
}
47+
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/devkit/Unobfuscator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2933,4 +2933,9 @@ public static Field loadGetCurrentPageInHomeField(@NotNull ClassLoader classLoad
29332933
throw new NoSuchFieldException("CurrentPageInHome field not found");
29342934
});
29352935
}
2936+
2937+
public static @NonNull Class<?> loadFMediaStatusClass(@NonNull ClassLoader classLoader) throws Exception {
2938+
return UnobfuscatorCache.getInstance().getClass(classLoader, ()-> findFirstClassUsingStrings(classLoader,StringMatchType.Contains,"FStatusMedia/mediaDataV2"));
2939+
2940+
}
29362941
}

app/src/main/java/com/wmods/wppenhacer/xposed/features/general/AntiRevoke.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.wmods.wppenhacer.xposed.core.Feature
99
import com.wmods.wppenhacer.xposed.core.WppCore
1010
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp
1111
import com.wmods.wppenhacer.xposed.core.components.FStatusWpp
12+
import com.wmods.wppenhacer.xposed.core.components.StatusItemWpp
1213
import com.wmods.wppenhacer.xposed.core.components.WaContactWpp
1314
import com.wmods.wppenhacer.xposed.core.db.DelMessageStore
1415
import com.wmods.wppenhacer.xposed.core.db.MessageStore
@@ -46,7 +47,8 @@ class AntiRevoke(loader: ClassLoader, preferences: XSharedPreferences) :
4647
val safeArgs = param.args?.filterNotNull() ?: return null
4748
safeArgs.firstOrNull { FMessageWpp.TYPE.isInstance(it) }?.let { return FMessageWpp(it) }
4849
val arg0 = param.args?.getOrNull(0) ?: return null
49-
return MenuStatusListener.getFMessageFromStatusData(arg0)
50+
val statusItem = StatusItemWpp.from(arg0) ?: return null
51+
return statusItem.fMessage
5052
}
5153

5254

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,47 @@
1-
package com.wmods.wppenhacer.xposed.features.general;
2-
3-
4-
import android.view.Menu;
5-
import android.view.MenuItem;
6-
7-
import androidx.annotation.NonNull;
8-
9-
import com.wmods.wppenhacer.R;
10-
import com.wmods.wppenhacer.xposed.core.Feature;
11-
import com.wmods.wppenhacer.xposed.core.WppCore;
12-
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp;
13-
import com.wmods.wppenhacer.xposed.core.db.MessageStore;
14-
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator;
15-
import com.wmods.wppenhacer.xposed.features.listeners.MenuStatusListener;
16-
17-
import org.luckypray.dexkit.query.enums.StringMatchType;
18-
19-
import java.util.List;
20-
21-
import de.robv.android.xposed.XSharedPreferences;
22-
23-
public class DeleteStatus extends Feature {
24-
25-
26-
public DeleteStatus(@NonNull ClassLoader classLoader, @NonNull XSharedPreferences preferences) {
27-
super(classLoader, preferences);
28-
}
29-
30-
@Override
31-
public void doHook() throws Throwable {
32-
33-
var StatusPlaybackActivityClass = Unobfuscator.findFirstClassUsingName(classLoader, StringMatchType.EndsWith, "StatusPlaybackActivity");
34-
35-
var item = new MenuStatusListener.OnMenuItemStatusListener() {
36-
37-
@Override
38-
public MenuItem addMenu(Menu menu, List<FMessageWpp> fMessageWppList, int currentIndex) {
39-
if (menu.findItem(R.string.delete_for_me) != null) return null;
40-
var fMessage = fMessageWppList.get(currentIndex);
41-
if (fMessage.getKey().isFromMe) return null;
42-
return menu.add(0, R.string.delete_for_me, 0, R.string.delete_for_me);
1+
package com.wmods.wppenhacer.xposed.features.general
2+
3+
import android.view.Menu
4+
import android.view.MenuItem
5+
import com.wmods.wppenhacer.R
6+
import com.wmods.wppenhacer.xposed.core.Feature
7+
import com.wmods.wppenhacer.xposed.core.WppCore
8+
import com.wmods.wppenhacer.xposed.core.db.MessageStore
9+
import com.wmods.wppenhacer.xposed.core.devkit.Unobfuscator
10+
import com.wmods.wppenhacer.xposed.features.listeners.MenuStatusListener
11+
import de.robv.android.xposed.XSharedPreferences
12+
import org.luckypray.dexkit.query.enums.StringMatchType
13+
14+
class DeleteStatus(classLoader: ClassLoader, preferences: XSharedPreferences) : Feature(classLoader, preferences) {
15+
16+
@Throws(Throwable::class)
17+
override fun doHook() {
18+
val statusPlaybackActivityClass = Unobfuscator.findFirstClassUsingName(classLoader, StringMatchType.EndsWith, "StatusPlaybackActivity")
19+
20+
val item = object : MenuStatusListener.OnMenuItemStatusListener() {
21+
22+
override fun addMenu(menu: Menu, statusData: MenuStatusListener.StatusData): MenuItem? {
23+
if (menu.findItem(R.string.delete_for_me) != null) return null
24+
if (statusData.currentItem.isFromMe) return null
25+
return menu.add(0, R.string.delete_for_me, 0, R.string.delete_for_me)
4326
}
4427

45-
@Override
46-
public void onClick(MenuItem item, Object fragmentInstance, List<FMessageWpp> fMessageWppList, int currentIndex) {
28+
override fun onClick(item: MenuItem, statusData: MenuStatusListener.StatusData) {
4729
try {
48-
var key = fMessageWppList.get(currentIndex).getKey();
49-
MessageStore.getInstance().deleteStatusByMessageKey(key.messageID);
50-
var activity = WppCore.getCurrentActivity();
51-
if (activity != null && StatusPlaybackActivityClass.isInstance(activity)) {
52-
activity.recreate();
30+
MessageStore.getInstance().deleteStatusByMessageKey(statusData.currentItem.messageID)
31+
32+
val activity = WppCore.getCurrentActivity()
33+
if (activity != null && statusPlaybackActivityClass.isInstance(activity)) {
34+
activity.recreate()
5335
}
54-
} catch (Exception e) {
55-
logDebug(e);
36+
} catch (e: Exception) {
37+
logDebug(e)
5638
}
5739
}
58-
};
59-
MenuStatusListener.getMenuStatuses().add(item);
40+
}
41+
MenuStatusListener.menuStatuses.add(item)
6042
}
6143

62-
@NonNull
63-
@Override
64-
public String getPluginName() {
65-
return "Delete Status";
44+
override fun getPluginName(): String {
45+
return "Delete Status"
6646
}
6747
}

0 commit comments

Comments
 (0)