Skip to content

Commit 8196cc3

Browse files
committed
Added Antied Zero
Antied Alternative Without Styling
1 parent 05e4f02 commit 8196cc3

7 files changed

Lines changed: 425 additions & 0 deletions

File tree

angel/antiedzero/Settings.jsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { React, NavigationNative } from "@vendetta/metro/common";
2+
import { useProxy } from "@vendetta/storage";
3+
import { storage } from "@vendetta/plugin";
4+
import { Forms } from "@vendetta/ui/components";
5+
import { getAssetIDByName } from "@vendetta/ui/assets"
6+
7+
import CreditsPage from './components/credits';
8+
9+
const { FormRow } = Forms;
10+
11+
export default function SettingPage() {
12+
useProxy(storage);
13+
14+
const navigation = NavigationNative.useNavigation();
15+
16+
const openCreditPage = () => {
17+
navigation.push("VendettaCustomPage", {
18+
title: `Credits & Support`,
19+
render: () => React.createElement(CreditsPage)
20+
})
21+
}
22+
23+
return (<>
24+
<FormRow
25+
label="CREDITS"
26+
subLabel="See the people behind the plugin and ways to support its development."
27+
onPress={openCreditPage}
28+
trailing={<FormRow.Icon source={getAssetIDByName("ic_arrow_right")} />}
29+
/>
30+
</>)
31+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { storage } from "@vendetta/plugin"
2+
import { useProxy } from "@vendetta/storage"
3+
import { React, url } from "@vendetta/metro/common";
4+
import { Forms, General } from "@vendetta/ui/components";
5+
import { getAssetIDByName } from "@vendetta/ui/assets"
6+
import { findByStoreName } from "@vendetta/metro";
7+
8+
const UserStore = findByStoreName("UserStore");
9+
10+
const { ScrollView, View, Image } = General;
11+
const { FormArrow, FormRow, FormSection, FormDivider } = Forms;
12+
13+
const devs = [
14+
{ name: 'Angel', role: 'Author & Maintainer', uuid: "692632336961110087" }
15+
];
16+
17+
const qa = [
18+
{ name: 'Moodle', role: 'Quality Assurance', uuid: "807170846497570848" },
19+
{ name: 'Rairof', role: 'Quality Assurance', uuid: "923212189123346483" },
20+
{ name: 'Catinette', role: 'Quality Assurance', uuid: "1302022854740807730" },
21+
{ name: 'Win8.1VMUser', role: "Quality Assurance", uuid: "793935599702507542" }
22+
];
23+
const links = [
24+
{
25+
label: 'Source Code',
26+
url: 'https://github.com/angelix1/MP',
27+
},
28+
{
29+
label: 'Tip via PayPal',
30+
url: 'https://paypal.me/alixymizuki',
31+
},
32+
{
33+
label: 'Buy me a Ko-fi',
34+
url: 'https://ko-fi.com/angel_wolf',
35+
},
36+
];
37+
38+
39+
export default function CreditsPage() {
40+
useProxy(storage)
41+
42+
const open = (uri) => url.openURL(uri).catch(() => {});
43+
44+
const getUser = id => UserStore?.getUser(id) || Object.values(UserStore?.getUsers()).find(u => u.id === id) || null;
45+
46+
const getUserPng = id => {
47+
const u = getUser(id);
48+
return u?.getAvatarURL?.()?.replace('webp', 'png') || null
49+
};
50+
51+
const box = u => (<Image source={{ uri: u }} style={{ width: 40, height: 40, borderRadius: 20 }} />);
52+
53+
return (<>
54+
<ScrollView>
55+
<FormSection title="Developers">
56+
{devs.map((p, i) => {
57+
58+
const avatarUri = getUserPng(p?.uuid)
59+
60+
return (<FormRow
61+
key={i}
62+
label={p.name}
63+
subLabel={p.role}
64+
leading={avatarUri ? box(avatarUri) : null}
65+
/>)
66+
})}
67+
</FormSection>
68+
<FormSection title="Testers">
69+
{qa.map((p, i) => {
70+
71+
const avatarUri = getUserPng(p?.uuid)
72+
73+
return (<FormRow
74+
key={i}
75+
label={p.name}
76+
subLabel={p.role}
77+
leading={avatarUri ? box(avatarUri) : null}
78+
/>)
79+
})}
80+
</FormSection>
81+
<FormDivider />
82+
83+
<FormSection title="Support & Source">
84+
<View style={{ margin: 50 }}>
85+
{links.map((l, i) => {
86+
87+
let finalIcon = l.icon ? (
88+
l.icon?.startsWith("https") ?
89+
(<Image source={{ uri: l.icon }} style={{ width: 120, height: 40 }} />) :
90+
(<FormRow.Icon source={getAssetIDByName(l.icon)}/>)
91+
) : null;
92+
93+
94+
return (
95+
<FormRow
96+
key={i}
97+
label={l.label}
98+
leading={finalIcon}
99+
trailing={<FormArrow />}
100+
onPress={() => open(l.url)}
101+
/>
102+
)
103+
})}
104+
</View>
105+
</FormSection>
106+
<FormDivider />
107+
108+
{/* extra bottom pad so last row isn’t hidden by inset */}
109+
<View style={{ height: 40 }} />
110+
</ScrollView>
111+
</>)
112+
}
113+

angel/antiedzero/index.jsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import fluxDispatchPatch from "./patches/flux_dispatch";
2+
import selfEditPatch from "./patches/self_edit";
3+
4+
import actionsheet from "./patches/actionsheet";
5+
import SettingPage from "./Settings";
6+
7+
export const regexEscaper = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
8+
export let isEnabled = false;
9+
10+
const deletedMessageArray = new Map();
11+
let unpatch;
12+
13+
// [Function, ArrayOfArguments]
14+
const patches = [
15+
[fluxDispatchPatch, [deletedMessageArray]],
16+
[actionsheet, []],
17+
[selfEditPatch, []]
18+
];
19+
20+
21+
// helper func
22+
const patcher = () => patches.forEach(([fn, args]) => fn(...args));
23+
24+
unpatch = patcher();
25+
26+
export default {
27+
onLoad: () => {
28+
isEnabled = true;
29+
},
30+
onUnload: () => {
31+
isEnabled = false;
32+
33+
unpatch?.()
34+
},
35+
settings: SettingPage
36+
}

angel/antiedzero/manifest.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name":"Antied Zero",
3+
"originalName": "Antied Zero",
4+
"description":"Keeps a temporary record of deleted messages and any edits until you reload the app.",
5+
"main": "index.jsx",
6+
"authors": [
7+
{
8+
"name": "Angelw0lf",
9+
"id": "692632336961110087"
10+
}
11+
],
12+
"vendetta": {
13+
"icon":"ic_edit_24px"
14+
}
15+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { before, after } from "@vendetta/patcher";
2+
import { getAssetIDByName } from "@vendetta/ui/assets";
3+
import { findInReactTree } from "@vendetta/utils";
4+
import { FluxDispatcher, React } from "@vendetta/metro/common";
5+
import { showToast } from "@vendetta/ui/toasts";
6+
import { findByProps } from '@vendetta/metro';
7+
import { regexEscaper, isEnabled } from "..";
8+
9+
const ActionSheet = findByProps("openLazy", "hideActionSheet")
10+
const MessageStore = findByProps("getMessage", "getMessages");
11+
const ChannelStore = findByProps("getChannel", "getDMFromUserId");
12+
const ChannelMessages = findByProps("_channelMessages");
13+
const { ActionSheetRow } = findByProps("ActionSheetRow");
14+
15+
function someFunc(a) {
16+
// return a?.props?.label == i18n?.Messages?.MESSAGE_ACTION_REPLY
17+
return a?.props?.label?.toLowerCase?.() == 'reply'
18+
}
19+
20+
export default () => before("openLazy", ActionSheet, ([component, args, actionMessage]) => {
21+
if(isEnabled) {
22+
try {
23+
const message = actionMessage?.message;
24+
25+
if (args !== "MessageLongPressActionSheet" || !message) return;
26+
27+
component.then((instance) => {
28+
const unpatch = after("default", instance, (_, comp) => {
29+
try {
30+
31+
React.useEffect(() => () => { unpatch() }, []);
32+
33+
const buttons = findInReactTree(comp, c => c?.find?.(someFunc))
34+
if (!buttons) return comp;
35+
36+
const position = Math.max(
37+
buttons.findIndex(someFunc),
38+
buttons.length - 1
39+
);
40+
41+
let originalMessage = null;
42+
43+
if (message?.channel_id && message?.id) {
44+
originalMessage = MessageStore.getMessage(message?.channel_id, message?.id);
45+
46+
if(!originalMessage) {
47+
const channel = ChannelMessages.get(message?.channel_id);
48+
originalMessage = channel?.get(message?.id);
49+
}
50+
}
51+
52+
if(!originalMessage) return comp;
53+
54+
const escapedBuffer = regexEscaper("`[ EDITED ]`\n\n");
55+
56+
const separator = new RegExp(escapedBuffer, 'gmi');
57+
const checkIfBufferExist = separator.test(message.content);
58+
59+
if(checkIfBufferExist) {
60+
const targetPos = position || 1;
61+
62+
buttons.splice(targetPos, 0, (
63+
<ActionSheetRow
64+
label="Remove Edit History"
65+
subLabel={`Added by Antied Zero`}
66+
icon={<ActionSheetRow.Icon source={getAssetIDByName("ic_edit_24px")}/>}
67+
onPress={() => {
68+
69+
const lats = message?.content?.split(separator);
70+
const targetMessage = lats[lats.length - 1];
71+
72+
FluxDispatcher.dispatch({
73+
type: "MESSAGE_UPDATE",
74+
message: {
75+
...message,
76+
message_reference: message?.message_reference || message?.messageReference || null,
77+
content: `${targetMessage}`,
78+
guild_id: ChannelStore.getChannel(originalMessage.channel_id).guild_id,
79+
},
80+
otherPluginBypass: true
81+
})
82+
83+
ActionSheet.hideActionSheet()
84+
showToast("History Removed", getAssetIDByName("ic_edit_24px"))
85+
86+
}}/>
87+
))
88+
}
89+
}
90+
catch (e) {
91+
showToast("[ANTIED Zero] Crash on ActionSheet, check debug log for more info")
92+
console.error("[ANTIED Zero] Error > ActionSheet:Component Patch\n", e)
93+
}
94+
})
95+
})
96+
}
97+
catch (e) {
98+
showToast("[ANTIED Zero] Crash on ActionSheet, check debug log for more info")
99+
console.error("[ANTIED Zero] Error > ActionSheet Patch\n", e)
100+
}
101+
}
102+
})

0 commit comments

Comments
 (0)