Skip to content

Commit e5202ae

Browse files
committed
Add Custom Privacy Manager
Signed-off-by: Dev4Mod <[email protected]>
1 parent aacae21 commit e5202ae

File tree

6 files changed

+262
-39
lines changed

6 files changed

+262
-39
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.wmods.wppenhacer.adapter;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.content.SharedPreferences;
6+
import android.graphics.Color;
7+
import android.view.View;
8+
import android.view.ViewGroup;
9+
import android.widget.ArrayAdapter;
10+
import android.widget.Button;
11+
import android.widget.LinearLayout;
12+
import android.widget.TextView;
13+
14+
import androidx.annotation.NonNull;
15+
import androidx.annotation.Nullable;
16+
17+
import com.wmods.wppenhacer.xposed.utils.DesignUtils;
18+
import com.wmods.wppenhacer.xposed.utils.Utils;
19+
20+
import java.util.List;
21+
22+
public class CustomPrivacyAdapter extends ArrayAdapter {
23+
24+
private final Class<?> contactClass;
25+
private final SharedPreferences prefs;
26+
private final Class<?> groupClass;
27+
private final List<Item> items;
28+
29+
public CustomPrivacyAdapter(Context context, SharedPreferences preferences, List<Item> mlist, Class<?> contactClass, Class<?> groupClass) {
30+
super(context, 0);
31+
this.contactClass = contactClass;
32+
this.groupClass = groupClass;
33+
this.items = mlist;
34+
this.prefs = preferences;
35+
}
36+
37+
@NonNull
38+
@Override
39+
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
40+
Item item = items.get(position);
41+
ViewHolder holder;
42+
if (convertView == null) {
43+
holder = new ViewHolder();
44+
convertView = createLayout(holder);
45+
convertView.setTag(holder);
46+
} else {
47+
holder = (ViewHolder) convertView.getTag();
48+
}
49+
holder.textView.setText(item.name);
50+
convertView.setOnClickListener(v -> {
51+
// Only Groups
52+
if (item.number.length() > 15) {
53+
Intent intent = new Intent(getContext(), groupClass);
54+
intent.putExtra("gid", item.number + "@g.us");
55+
getContext().startActivity(intent);
56+
return;
57+
}
58+
Intent intent = new Intent(getContext(), contactClass);
59+
intent.putExtra("jid", item.number + "@s.whatsapp.net");
60+
getContext().startActivity(intent);
61+
});
62+
holder.button.setOnClickListener(v -> {
63+
items.remove(position);
64+
this.prefs.edit().remove(item.key).apply();
65+
notifyDataSetChanged();
66+
});
67+
68+
return convertView;
69+
}
70+
71+
@Override
72+
public int getCount() {
73+
return items.size();
74+
}
75+
76+
private ViewGroup createLayout(ViewHolder holder) {
77+
LinearLayout layout = new LinearLayout(getContext());
78+
layout.setOrientation(LinearLayout.HORIZONTAL);
79+
layout.setPadding(Utils.dipToPixels(25), 0, Utils.dipToPixels(25), 0);
80+
81+
TextView textView = new TextView(getContext());
82+
var layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
83+
layoutParams.weight = 1;
84+
textView.setLayoutParams(layoutParams);
85+
layout.addView(textView);
86+
holder.textView = textView;
87+
88+
Button button = new Button(getContext());
89+
var buttonParams = new LinearLayout.LayoutParams(Utils.dipToPixels(40), Utils.dipToPixels(40));
90+
button.setLayoutParams(buttonParams);
91+
var drawable = DesignUtils.createDrawable("stroke_border", Color.BLACK);
92+
button.setBackground(DesignUtils.alphaDrawable(drawable, DesignUtils.getPrimaryTextColor(), 25));
93+
button.setText("X");
94+
layout.addView(button);
95+
holder.button = button;
96+
97+
return layout;
98+
}
99+
100+
static class ViewHolder {
101+
TextView textView;
102+
Button button;
103+
}
104+
105+
public static class Item {
106+
public String name;
107+
public String number;
108+
public String key;
109+
}
110+
111+
112+
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/WppCore.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ public static Activity getCurrentConversation() {
388388
return null;
389389
}
390390

391+
public static SharedPreferences getPrivPrefs() {
392+
return privPrefs;
393+
}
394+
391395
@SuppressLint("ApplySharedPref")
392396
public static void setPrivString(String key, String value) {
393397
privPrefs.edit().putString(key, value).commit();

app/src/main/java/com/wmods/wppenhacer/xposed/features/privacy/CustomPrivacy.java

Lines changed: 134 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,30 @@
33
import android.annotation.SuppressLint;
44
import android.app.Activity;
55
import android.content.Context;
6+
import android.content.SharedPreferences;
67
import android.text.TextUtils;
78
import android.view.Menu;
89
import android.view.View;
910
import android.view.ViewGroup;
11+
import android.widget.ListView;
1012
import android.widget.Toast;
1113

1214
import androidx.annotation.NonNull;
1315

16+
import com.wmods.wppenhacer.adapter.CustomPrivacyAdapter;
1417
import com.wmods.wppenhacer.xposed.core.Feature;
1518
import com.wmods.wppenhacer.xposed.core.WppCore;
1619
import com.wmods.wppenhacer.xposed.core.components.AlertDialogWpp;
20+
import com.wmods.wppenhacer.xposed.features.others.MenuHome;
21+
import com.wmods.wppenhacer.xposed.utils.DesignUtils;
1722
import com.wmods.wppenhacer.xposed.utils.ReflectionUtils;
1823
import com.wmods.wppenhacer.xposed.utils.ResId;
1924
import com.wmods.wppenhacer.xposed.utils.Utils;
2025

2126
import org.json.JSONObject;
2227

2328
import java.lang.reflect.Method;
29+
import java.util.ArrayList;
2430
import java.util.Objects;
2531

2632
import de.robv.android.xposed.XC_MethodHook;
@@ -56,9 +62,7 @@ public void doHook() throws Throwable {
5662

5763
var type = Integer.parseInt(Utils.xprefs.getString("custom_privacy_type", "0"));
5864

59-
6065
if (type == 1) {
61-
6266
var hooker = new WppCore.ActivityChangeState() {
6367
@SuppressLint("ResourceType")
6468
@Override
@@ -101,56 +105,148 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
101105
XposedHelpers.findAndHookMethod(ContactInfoActivityClass, "onCreateOptionsMenu", Menu.class, hooker);
102106
XposedHelpers.findAndHookMethod(GroupInfoActivityClass, "onCreateOptionsMenu", Menu.class, hooker);
103107
}
108+
109+
if (type == 0) return;
110+
111+
var icon = DesignUtils.resizeDrawable(DesignUtils.getDrawable(ResId.drawable.ic_privacy), Utils.dipToPixels(24), Utils.dipToPixels(24));
112+
icon.setTint(0xff8696a0);
113+
MenuHome.menuItems.add((menu, activity) -> menu.add(0, 0, 0, ResId.string.custom_privacy).setIcon(icon).setOnMenuItemClickListener(item -> {
114+
showCustomPrivacyList(activity, ContactInfoActivityClass, GroupInfoActivityClass);
115+
return true;
116+
}));
104117
}
105118

119+
private void showCustomPrivacyList(Activity activity, Class<?> contactClass, Class<?> groupClass) {
120+
121+
SharedPreferences pprefs = WppCore.getPrivPrefs();
122+
var maps = pprefs.getAll();
123+
ArrayList<CustomPrivacyAdapter.Item> list = new ArrayList<>();
124+
for (var key : maps.keySet()) {
125+
if (key.endsWith("_privacy")) {
126+
var number = key.replace("_privacy", "");
127+
Object userJid = WppCore.createUserJid(number + (number.length() > 14 ? "@g.us" : "@s.whatsapp.net"));
128+
129+
var contactName = WppCore.getContactName(userJid);
130+
131+
if (TextUtils.isEmpty(contactName)) {
132+
contactName = number;
133+
}
134+
CustomPrivacyAdapter.Item item = new CustomPrivacyAdapter.Item();
135+
item.name = contactName;
136+
item.number = number;
137+
item.key = key;
138+
list.add(item);
139+
}
140+
}
141+
142+
if (list.isEmpty()) {
143+
Utils.showToast(activity.getString(ResId.string.no_contact_with_custom_privacy), Toast.LENGTH_SHORT);
144+
return;
145+
}
146+
147+
AlertDialogWpp builder = new AlertDialogWpp(activity);
148+
builder.setTitle(ResId.string.custom_privacy);
149+
ListView listView = new ListView(activity);
150+
listView.setAdapter(new CustomPrivacyAdapter(activity, pprefs, list, contactClass, groupClass));
151+
builder.setView(listView);
152+
builder.show();
153+
}
154+
155+
106156
private void showPrivacyDialog(Activity activity, boolean isChat) {
107-
Object userJid;
157+
Object userJid = getUserJid(activity, isChat);
158+
if (userJid == null) return;
159+
160+
String rawJid = WppCore.getRawString(userJid);
161+
String number = WppCore.stripJID(rawJid);
162+
163+
AlertDialogWpp builder = createPrivacyDialog(activity, number);
164+
builder.show();
165+
}
166+
167+
private Object getUserJid(Activity activity, boolean isChat) {
108168
if (isChat) {
109-
userJid = ReflectionUtils.callMethod(chatUserJidMethod, activity);
169+
return ReflectionUtils.callMethod(chatUserJidMethod, activity);
110170
} else {
111-
userJid = ReflectionUtils.callMethod(groupUserJidMethod, activity);
171+
return ReflectionUtils.callMethod(groupUserJidMethod, activity);
112172
}
113-
if (userJid == null) return;
114-
var rawJid = WppCore.getRawString(userJid);
115-
var number = WppCore.stripJID(rawJid);
116-
var builder = new AlertDialogWpp(activity);
173+
}
174+
175+
private AlertDialogWpp createPrivacyDialog(Activity activity, String number) {
176+
AlertDialogWpp builder = new AlertDialogWpp(activity);
117177
builder.setTitle(ResId.string.custom_privacy);
118-
String[] items = {activity.getString(ResId.string.hideread), activity.getString(ResId.string.hidestatusview), activity.getString(ResId.string.hidereceipt), activity.getString(ResId.string.ghostmode), activity.getString(ResId.string.ghostmode_r), activity.getString(ResId.string.block_call)};
119-
String[] itemsKeys = {"HideSeen", "HideViewStatus", "HideReceipt", "HideTyping", "HideRecording", "BlockCall"};
120-
String[] globalKeys = {"hideread", "hidestatusview", "hidereceipt", "ghostmode_t", "ghostmode_r", "call_privacy"};
121178

179+
String[] items = {
180+
activity.getString(ResId.string.hideread),
181+
activity.getString(ResId.string.hidestatusview),
182+
activity.getString(ResId.string.hidereceipt),
183+
activity.getString(ResId.string.ghostmode),
184+
activity.getString(ResId.string.ghostmode_r),
185+
activity.getString(ResId.string.block_call)
186+
};
187+
188+
String[] itemsKeys = {
189+
"HideSeen", "HideViewStatus", "HideReceipt", "HideTyping", "HideRecording", "BlockCall"
190+
};
191+
192+
boolean[] checkedItems = loadPreferences(number, itemsKeys);
193+
194+
builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> checkedItems[which] = isChecked);
195+
builder.setPositiveButton("OK", (dialog, which) -> savePreferences(number, itemsKeys, checkedItems));
196+
builder.setNegativeButton(activity.getString(ResId.string.cancel), null);
197+
198+
return builder;
199+
}
200+
201+
private boolean[] loadPreferences(String number, String[] itemsKeys) {
202+
boolean[] checkedItems = new boolean[itemsKeys.length];
203+
JSONObject json = CustomPrivacy.getJSON(number);
122204

123-
// load prefs
124-
boolean[] checkedItems = new boolean[items.length];
125-
var json = CustomPrivacy.getJSON(number);
126205
for (int i = 0; i < itemsKeys.length; i++) {
127-
if (globalKeys[i].equals("call_privacy")) {
128-
checkedItems[i] = json.optBoolean(itemsKeys[i], Objects.equals(prefs.getString(globalKeys[i], "0"), "1"));
129-
} else {
130-
checkedItems[i] = json.optBoolean(itemsKeys[i], prefs.getBoolean(globalKeys[i], false));
131-
}
206+
String globalKey = getGlobalKey(itemsKeys[i]);
207+
checkedItems[i] = json.optBoolean(itemsKeys[i], getDefaultPreference(globalKey));
132208
}
133209

134-
builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> checkedItems[which] = isChecked);
135-
builder.setPositiveButton("OK", (dialog, which) -> {
136-
try {
137-
JSONObject jsonObject = new JSONObject();
138-
for (int i = 0; i < itemsKeys.length; i++) {
139-
if (globalKeys[i].equals("call_privacy")) {
140-
if (Objects.equals(prefs.getString(globalKeys[i], "0"), "1") != checkedItems[i])
141-
jsonObject.put(itemsKeys[i], checkedItems[i]);
142-
} else {
143-
if (prefs.getBoolean(globalKeys[i], false) != checkedItems[i])
144-
jsonObject.put(itemsKeys[i], checkedItems[i]);
145-
}
210+
return checkedItems;
211+
}
212+
213+
private String getGlobalKey(String itemKey) {
214+
return switch (itemKey) {
215+
case "HideSeen" -> "hideread";
216+
case "HideViewStatus" -> "hidestatusview";
217+
case "HideReceipt" -> "hidereceipt";
218+
case "HideTyping" -> "ghostmode_t";
219+
case "HideRecording" -> "ghostmode_r";
220+
case "BlockCall" -> "call_privacy";
221+
default -> "";
222+
};
223+
}
224+
225+
private boolean getDefaultPreference(String globalKey) {
226+
if (globalKey.equals("call_privacy")) {
227+
return Objects.equals(prefs.getString(globalKey, "0"), "1");
228+
} else {
229+
return prefs.getBoolean(globalKey, false);
230+
}
231+
}
232+
233+
private void savePreferences(String number, String[] itemsKeys, boolean[] checkedItems) {
234+
try {
235+
JSONObject jsonObject = new JSONObject();
236+
for (int i = 0; i < itemsKeys.length; i++) {
237+
String globalKey = getGlobalKey(itemsKeys[i]);
238+
if (globalKey.equals("call_privacy")) {
239+
if (Objects.equals(prefs.getString(globalKey, "0"), "1") != checkedItems[i])
240+
jsonObject.put(itemsKeys[i], checkedItems[i]);
241+
} else {
242+
if (prefs.getBoolean(globalKey, false) != checkedItems[i])
243+
jsonObject.put(itemsKeys[i], checkedItems[i]);
146244
}
147-
WppCore.setPrivJSON(number + "_privacy", jsonObject);
148-
} catch (Exception e) {
149-
Utils.showToast(e.getMessage(), Toast.LENGTH_SHORT);
150245
}
151-
});
152-
builder.setNegativeButton(activity.getString(ResId.string.cancel), null);
153-
builder.show();
246+
WppCore.setPrivJSON(number + "_privacy", jsonObject);
247+
} catch (Exception e) {
248+
Utils.showToast(e.getMessage(), Toast.LENGTH_SHORT);
249+
}
154250
}
155251

156252
@NonNull

app/src/main/java/com/wmods/wppenhacer/xposed/utils/DesignUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,13 @@ public static Bitmap replaceColor(Bitmap bitmap, int oldColor, int newColor, dou
258258

259259
return newBitmap;
260260
}
261+
262+
public static Drawable resizeDrawable(Drawable icon, int width, int height) {
263+
// resize icon
264+
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
265+
Canvas canvas = new Canvas(bitmap);
266+
icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
267+
icon.draw(canvas);
268+
return new BitmapDrawable(Utils.getApplication().getResources(), bitmap);
269+
}
261270
}

app/src/main/java/com/wmods/wppenhacer/xposed/utils/ResId.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public static class string {
101101
public static int call_information;
102102
public static int ask_download_folder;
103103
public static int download_folder_permission;
104+
public static int no_contact_with_custom_privacy;
104105
}
105106

106107
public static class array {

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,10 @@
409409
<string name="update_check_sum">
410410
Enable or Disable Auto Check for Update. This will disable the popup inside the WhatsApp Application.\n
411411
<font color="#FFFF0000">
412-
WARNING: YOU WILL NOT BE NOTIFIED WHEN THERE'S A NEW UPDATE, USE THIS CAREFULLY AND DON'T REPORT ISSUE IF YOU'RE USING OUTDATED VERSION!
412+
WARNING: YOU WILL NOT BE NOTIFIED WHEN THERE\'S A NEW UPDATE, USE THIS CAREFULLY AND DON\'T REPORT ISSUE IF YOU\'RE USING OUTDATED VERSION!
413413
</font>
414414
</string>
415415
<string name="change_default_dpi">Change Default DPI</string>
416416
<string name="change_default_dpi_sum">Change the DPI setting for the application. Use 0 to reset to default.</string>
417+
<string name="no_contact_with_custom_privacy">No contact with custom privacy!</string>
417418
</resources>

0 commit comments

Comments
 (0)