generated from vendetta-mod/plugin-template
-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import settingPage from "./setting"; | ||
import { makeDefaults } from "./util"; | ||
|
||
import { before, after } from "@vendetta/patcher"; | ||
import { storage } from "@vendetta/plugin"; | ||
import { logger } from "@vendetta"; | ||
import { React, ReactNative, FluxDispatcher, constants } from "@vendetta/metro/common" | ||
import { find, findByProps, findByStoreName, findByName } from "@vendetta/metro"; | ||
import { General } from "@vendetta/ui/components"; | ||
import { semanticColors } from "@vendetta/ui"; | ||
|
||
const { Text } = General; | ||
|
||
const ThemeStore = findByStoreName("ThemeStore"); | ||
const resolveSemanticColor = find(m => m.default?.internal?.resolveSemanticColor)?.default.internal.resolveSemanticColor | ||
?? find(m => m.meta?.resolveSemanticColor)?.meta.resolveSemanticColor ?? (() => {}); | ||
|
||
const UserStore = findByStoreName("UserStore"); | ||
const RelationshipStore = findByStoreName("RelationshipStore"); | ||
const GuildMemberStore = findByStoreName("GuildMemberStore"); | ||
const TypingWrapper = findByProps("TYPING_WRAPPER_HEIGHT"); | ||
const { DCDChatManager } = ReactNative.NativeModules; | ||
|
||
makeDefaults(storage, { | ||
colors: { | ||
hex: "#DAFAF0", | ||
}, | ||
switches: { | ||
enableUsername: true, | ||
enableReply: false, | ||
enableType: false, | ||
}, | ||
}) | ||
|
||
function resolveColor(s) { | ||
if(s?.colors?.hex) return ReactNative.processColor(s.colors.hex) | ||
return 0; | ||
} | ||
|
||
const patches = []; | ||
|
||
export default { | ||
onLoad: () => { | ||
patches.push( | ||
before("updateRows", DCDChatManager, (args) => { | ||
let rows = JSON.parse(args[1]); | ||
|
||
for (const row of rows) { | ||
const { message } = row | ||
if(!message) continue; | ||
|
||
const handleColor = (m) => { | ||
return m.usernameColor = resolveColor(storage) | ||
}; | ||
|
||
if(storage?.switches?.enableUsername) { | ||
handleColor(message) | ||
} | ||
|
||
if( | ||
message?.referencedMessage?.message && | ||
storage?.switches?.enableReply | ||
) { | ||
handleColor(message?.referencedMessage?.message) | ||
} | ||
} | ||
args[1] = JSON.stringify(rows); | ||
}), | ||
|
||
after("default", TypingWrapper, ([{ channel }], res) => { | ||
if (!storage?.switches?.enableType) return; | ||
if (!res) return; | ||
const Typing = res.props?.children; | ||
const defaultTypingColor = resolveSemanticColor(ThemeStore.theme, semanticColors.HEADER_SECONDARY); | ||
|
||
const unpatchTyping = after("type", Typing, (_, res) => { | ||
React.useEffect(() => () => { unpatchTyping() }, []); | ||
const typingThing = res?.props?.children?.[0]?.props?.children?.[1]?.props; | ||
|
||
if ( | ||
!typingThing || | ||
!typingThing.children || | ||
typingThing.children?.toLowerCase() === "several people are typing..." | ||
) return; | ||
|
||
const users = TypingWrapper.useTypingUserIds(channel.id).map(user => { | ||
const member = GuildMemberStore.getMember(channel.guild_id, user); | ||
const userobj = UserStore.getUser(user); | ||
const name = (member?.nick || RelationshipStore.getNickname(user) || userobj.globalName || userobj.username); | ||
const color = (storage?.colors?.hex || defaultTypingColor); | ||
|
||
return {displayName: name, displayColor: color}; | ||
}); | ||
|
||
function userElem(user) { | ||
return React.createElement( | ||
Text, | ||
{ | ||
style: { | ||
color: user.displayColor, | ||
fontFamily: constants.Fonts.DISPLAY_SEMIBOLD | ||
} | ||
}, | ||
user.displayName | ||
); | ||
}; | ||
|
||
if (!users || users.length < 1) return; | ||
|
||
typingThing.children = ( | ||
users.length === 1 ? | ||
[userElem(users[0]), " is typing..."] : | ||
[ | ||
...users.slice(0, users.length - 1).flatMap((el, i) => [userElem(el), i < (users.length-2) ? ", " : " and "]), | ||
userElem(users[users.length - 1]), " are typing..." | ||
] | ||
) | ||
}); | ||
}), | ||
) | ||
}, | ||
onUnload: () => { | ||
patches.forEach(un => un()); | ||
}, | ||
settings: settingPage | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"name": "Custom Username Color 0.1", | ||
"description": "Override Username Colors and customize them.", | ||
"authors": [ | ||
{ | ||
"name": "Angelica", | ||
"id": "692632336961110087" | ||
} | ||
], | ||
"main": "index.js", | ||
"vendetta": { | ||
"icon": "ic_legacy_username" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import * as util from "./util"; | ||
|
||
import { ReactNative } from "@vendetta/metro/common"; | ||
import { General, Forms } from "@vendetta/ui/components"; | ||
import { getAssetIDByName } from "@vendetta/ui/assets"; | ||
import { storage } from "@vendetta/plugin"; | ||
import { useProxy } from "@vendetta/storage"; | ||
import { find, findByName, findByProps, findByStoreName } from "@vendetta/metro"; | ||
import { showToast } from "@vendetta/ui/toasts"; | ||
|
||
const { openLazy, hideActionSheet } = findByProps("openLazy", "hideActionSheet"); | ||
const { ScrollView, View, Text, TouchableOpacity, TextInput, Pressable, Image } = General; | ||
const { FormIcon, FormSwitchRow, FormSwitch, FormRow, FormInput, FormDivider } = Forms; | ||
const CustomColorPickerActionSheet = findByName("CustomColorPickerActionSheet"); | ||
|
||
function numToHex(numericColor) { | ||
const red = (numericColor >> 16) & 255; | ||
const green = (numericColor >> 8) & 255; | ||
const blue = numericColor & 255; | ||
return `#${((1 << 24) | (red << 16) | (green << 8) | blue).toString(16).slice(1)}`; | ||
} | ||
|
||
function createSwitch(id, label, sub, def, icon) { | ||
return { id, label, sub, def, icon } | ||
} | ||
|
||
|
||
const switches = [ | ||
createSwitch("enableUsername", "Toggle for username", null, true, null), | ||
createSwitch("enableReply", "Toggle for replied messages", null, false, null), | ||
createSwitch("enableType", "Toggle for typing indicator", null, false, null) | ||
|
||
] | ||
|
||
export default () => { | ||
useProxy(storage); | ||
|
||
const pc = (inp) => ReactNative.processColor(inp); | ||
|
||
const whenPressed = () => util?.openSheet( | ||
CustomColorPickerActionSheet, { | ||
color: (pc(storage?.colors?.hex) || 0), | ||
onSelect: (color) => { | ||
const hex = numToHex(color) | ||
storage.colors.hex = hex | ||
// showToast(storage.colors.hex) | ||
} | ||
} | ||
); | ||
|
||
return ( | ||
<ScrollView> | ||
<FormRow | ||
label="Color" | ||
subLabel="Click to Update" | ||
onPress={whenPressed} | ||
trailing={ | ||
<TouchableOpacity onPress={whenPressed}> | ||
<Image | ||
source={{ uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mJsrQAAAgwBAJ9P6qYAAAAASUVORK5CYII=' }} | ||
style={{ | ||
width: 96, | ||
height: 96, | ||
borderRadius: 10, | ||
backgroundColor: storage?.colors?.hex || "#000" | ||
}} | ||
/> | ||
</TouchableOpacity> | ||
} | ||
/> | ||
{ | ||
switches?.map((obj, index) => { | ||
return (<> | ||
<FormRow | ||
label={obj?.label} | ||
subLabel={obj?.sub} | ||
leading={obj?.icon && <FormIcon style={{ opacity: 1 }} source={getAssetIDByName(obj?.icon)} />} | ||
trailing={ | ||
("id" in obj) ? ( | ||
<FormSwitch | ||
value={storage?.switches[obj?.id] ?? obj?.def} | ||
onValueChange={ (value) => (storage.switches[obj?.id] = value) } | ||
/> | ||
) : undefined | ||
} | ||
/> | ||
{index !== switches?.length - 1 && <FormDivider />} | ||
</>) | ||
}) | ||
} | ||
</ScrollView> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { logger } from "@vendetta"; | ||
import { find, findByName, findByProps, findByStoreName } from "@vendetta/metro"; | ||
|
||
const { openLazy, hideActionSheet } = findByProps("openLazy", "hideActionSheet"); | ||
|
||
export function makeDefaults(object, defaults) { | ||
if (object != undefined) { | ||
if (defaults != undefined) { | ||
for (const key of Object.keys(defaults)) { | ||
if (typeof defaults[key] === "object" && !Array.isArray(defaults[key])) { | ||
if (typeof object[key] !== "object") object[key] = {}; | ||
makeDefaults(object[key], defaults[key]); | ||
} | ||
else { | ||
object[key] ??= defaults[key]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
export function openSheet(sheet, props) { | ||
try { | ||
openLazy( | ||
new Promise((call) => call({ default: sheet })), | ||
"ActionSheet", | ||
props | ||
); | ||
} | ||
catch (e) { | ||
logger.error(e.stack); | ||
showToast( | ||
"Got error when opening ActionSheet! Please check debug logs" | ||
); | ||
} | ||
} |