Files
discord-decomp/modules/icymi/native/ICYMICardInteractionRow.tsx
T
2026-11-01 12:12:55 +02:00

603 lines
22 KiB
TypeScript

// Metro module 15369 (f15370).
import { useCallback, useMemo, useEffect, useState } from "react";
import { View, Image, ScrollView } from "react-native";
import ThreadMessageStore from "../../threads/ThreadMessageStore";
import ChannelStore from "../../../stores/ChannelStore";
import GuildVerificationStore from "../../../stores/GuildVerificationStore";
import PermissionStore from "../../../stores/PermissionStore";
import { Permissions, HorizontalGradient } from "../../../Constants";
import { EmojiIntention } from "../../emojis/EmojiConstants";
import { jsxs } from "react/jsx-runtime";
import { toReactionEmoji } from "../../reactions/ReactionUtils";
import { ReactionLocations, addReaction } from "../../reactions/ReactionActionCreators";
import { createStyles } from "../../../design/components/Styles/native/createStyles";
import Module712 from "../../../_bundle/Module712";
import { isAndroid } from "../../../utils/PlatformUtils";
import { hexWithOpacity } from "../../../utils/ColorUtils";
import { useStateFromStores, useStateFromStoresObject } from "../../../_bundle/Module589";
import { openEmojiPickerActionSheet } from "../../emoji_picker/native/openEmojiPickerActionSheet";
import { PressableOpacity, PressableHighlight } from "../../../design/void/Pressables/native/Pressables";
import { intl, t } from "../../../intl/index.native";
import { ReactionIcon } from "../../../design/components/Icon/native/redesign/generated/ReactionIcon";
import { Text } from "../../../design/components/Text/native/Text";
import { useEmojiColorPalette } from "../../emojis/hooks/useEmojiColorPalette";
import { hex2rgb } from "../../../_bundle/int2hslRaw";
import AvatarUtils from "../../../utils/AvatarUtils";
import { handleAddOrRemoveReaction } from "../../messages/native/MessagesUtils";
import ActivityEmoji from "../../activity_status/native/ActivityEmoji";
import AnimatedCounter from "../../forums/native/posts/AnimatedCounter";
import ForwardingIcon from "../../forwarding/native/ForwardingIcon";
import { ArrowAngleLeftUpIcon } from "../../../design/components/Icon/native/redesign/generated/ArrowAngleLeftUpIcon";
import { navigateToPost } from "./ICYMIShared";
import { ChatIcon } from "../../../design/components/Icon/native/redesign/generated/ChatIcon";
import { ReactionTypes } from "../../messages/MessageReactionsTypes";
import canAddNewReactions from "../../reactions/canAddNewReactions";
import { useCanForwardMessage } from "../../forwarding/canForwardMessage";
import ICYMIActionCreators from "../ICYMIActionCreators";
import { openForwardModal } from "../../forwarding/native/ForwardModalUtils";
import { createPendingReply } from "../../replies/PendingReplyActionCreators";
import { useToken } from "../../../design/tokens/native/useToken";
import Module4611 from "../../../_bundle/Module4611";
import Module689 from "../../../_bundle/Module689";
import { ChevronSmallRightIcon } from "../../../design/components/Icon/native/redesign/generated/ChevronSmallRightIcon";
function $mk96251($env) {
return () => {
let r10;
const r2 = $env;
const r3 = r2[1];
if (r3 != null && r2[0] != null) {
const r4 = $env.$parent;
let thread = r4[9].getChannel(r3.id);
if (thread == null) {
thread = null;
}
const r11 = r4[8];
let messageCount = r11.getCount(r3.id);
if (messageCount == null) {
messageCount = 0;
}
r10 = {
thread,
messageCount,
mostRecentMessage: r11.getMostRecentMessage(r3.id)
};
} else {
r10 = {
thread: null,
messageCount: 0,
mostRecentMessage: null
};
}
return r10;
};
}
function $mk96252($env) {
return () => {
const r4 = $env;
const r5 = r4[1];
if (r5 != null && r4[0] != null && (r5.hasFlag($env.$parent[12].HAS_THREAD) || r4[2]) && $env.$parent[8].getMostRecentMessage(r5.id) == null) {
const r17 = $env.$parent;
const r18 = r17[1];
const r19 = r17[2];
r18(r19[17]).preload(r4[0].id, r5.id);
r18(r19[18]).fetchMessages({
channelId: r5.id,
isPreload: true,
limit: 25
});
}
};
}
let EmojiReaction, ForwardButton, ReplyButton, ThreadAsCommentsButton, c10921_19, useStyles;
let env10921 = {};
const AddEmojiButton = function AddEmojiButton(props) {
const { channel, onPressEmoji } = props;
let showText = props.showText;
const { disabled, handleItemInteracted } = props;
const styles = useStyles();
const props2 = {
onPress: useCallback(() => {
handleItemInteracted("press_reaction_picker", {
actionGestureType: "press",
actionTargetElement: "reaction_picker_button",
actionIntentType: "open",
actionDestinationType: null
});
openEmojiPickerActionSheet({
pickerIntention: EmojiIntention.REACTION,
autoFocus: false,
startExpanded: false,
onPressEmoji,
channel,
guildId: channel?.guild_id
});
}, [channel, onPressEmoji, handleItemInteracted]),
style: [styles.emojiContainer, styles.addEmojiContainer, disabled ? styles.disabled : null],
accessible: true,
accessibilityLabel: intl.string(t.lfIHs4),
disabled,
children: null
};
const children = [<ReactionIcon size="sm" />, ,];
if (showText) {
showText = <Text variant="text-sm/semibold" color="redesign-button-tertiary-text">
{intl.string(t.m9O1gd)}
</Text>;
}
children[1] = showText;
props2.children = children;
return <PressableOpacity {...props2} />;
};
EmojiReaction = function EmojiReaction(props) {
const { messageId, channel: channel2, reaction, count, isBurstReaction, handleItemInteracted: handleItemInteracted2 } = props;
const styles = useStyles();
let burst_colors = reaction.burst_colors;
if (burst_colors == null) {
burst_colors = [];
}
const emojiColorPalette = useEmojiColorPalette(burst_colors);
const r2 = emojiColorPalette != null;
let backgroundColor2 = "";
if (r2) {
const backgroundColor = emojiColorPalette?.backgroundColor;
let r33 = emojiColorPalette?.opacity;
if (r33 == null) {
r33 = 0.15;
}
let r34 = hex2rgb(backgroundColor, r33);
if (r34 == null) {
r34 = "";
}
backgroundColor2 = r34;
}
const r35 = {
backgroundColor: backgroundColor2,
borderColor: emojiColorPalette?.backgroundColor
};
const r41 = emojiColorPalette?.accentColor != null ? {
color: emojiColorPalette.accentColor
} : null;
const emoji = reaction.emoji;
let r17 = isBurstReaction ? reaction.me_burst : reaction.me;
const r44 = r17 ? styles.selected : void 0;
const stateFromStores2 = useStateFromStores([GuildVerificationStore], () => channel2.guild_id != null && GuildVerificationStore.canChatInGuild(channel2.guild_id));
const memo2 = useMemo(() => emoji.id != null ? {
uri: AvatarUtils.getEmojiURL({
id: emoji.id,
animated: emoji.animated,
size: 48
})
} : void 0, [emoji]);
const callback2 = useCallback(() => {
handleItemInteracted2("press_reaction", {
actionGestureType: "press",
actionTargetElement: "toggle_existing_reaction_button",
actionIntentType: "react",
actionDestinationType: null
});
handleAddOrRemoveReaction(messageId, channel2, reaction, isBurstReaction, ReactionLocations.MESSAGE);
}, [channel2, isBurstReaction, messageId, reaction, handleItemInteracted2]);
const style = [styles.emojiContainer, r44, isBurstReaction ? r35 : isBurstReaction];
const r102 = [<View style={[styles.innerEmojiContainer, r17 ? styles.selectedInnerEmojiContainer : r17]}>
{emoji.id == null ? <Text variant="text-md/medium" color="interactive-text-default" style={[styles.defaultEmoji, styles.emojiText]} allowFontScaling={false}>{emoji.name}</Text> : isAndroid() ? <Image style={[styles.defaultEmoji, styles.emojiImage]} source={memo2} /> : <ActivityEmoji emoji={emoji} size={c10921_19} style={styles.defaultEmoji} animate />}
</View>, ,];
const style2 = [styles.innerTextContainer, ,];
if (r17) {
r17 = styles.selectedInnerTextContainer;
}
style2[1] = r17;
r102[1] = <View style={style2}>
<AnimatedCounter animate count={count} textStyle={isBurstReaction ? r41 : null} textVariant="text-md/semibold" />
</View>;
return <PressableOpacity style={style} onPress={callback2} accessible accessibilityLabel={emoji.name} disabled={!stateFromStores2}>{r102}</PressableOpacity>;
};
ForwardButton = function ForwardButton(props) {
const { onPress, disabled } = props;
const styles = useStyles();
return <PressableOpacity onPress={onPress} style={[styles.emojiContainer, styles.addEmojiContainer, disabled ? styles.disabled : null]} accessible disabled={disabled} accessibilityLabel={intl.string(t.xIUfJS)}>
<ForwardingIcon size="sm" />
</PressableOpacity>;
};
ReplyButton = function ReplyButton(props) {
const { onPress, disabled } = props;
const styles = useStyles();
return <PressableOpacity onPress={onPress} style={[styles.emojiContainer, styles.addEmojiContainer, disabled ? styles.disabled : null]} accessible disabled={disabled} accessibilityLabel={intl.string(t["5NwaNY"])}>
<ArrowAngleLeftUpIcon size="sm" />
</PressableOpacity>;
};
ThreadAsCommentsButton = function ThreadAsCommentsButton(props) {
const { parentMessage, threadData, style, handleItemInteracted: handleItemInteracted3 } = props;
const styles = useStyles();
const stateFromStores2 = useStateFromStores([PermissionStore], () => PermissionStore.canWithPartialContext(Permissions.VIEW_CHANNEL, {
channelId: parentMessage.id
}));
const callback2 = useCallback(() => {
handleItemInteracted3("press_comments", {
actionGestureType: "press",
actionTargetElement: "thread_comments_button",
actionIntentType: "navigate",
actionDestinationType: "channel"
});
if (parentMessage != null && threadData.thread != null) {
navigateToPost(parentMessage.getChannelId(), threadData.thread.guild_id, parentMessage.id);
}
}, [parentMessage, threadData.thread, handleItemInteracted3]);
if (stateFromStores2 && threadData.messageCount !== 0) {
if (threadData.thread != null && threadData.mostRecentMessage != null) {
return <PressableHighlight style={[styles.comments, style]} onPress={callback2}>
{(0, jsxs)(View, {
style: styles.commentCount,
children: [<ChatIcon style={styles.commentsIcon} />, <Text variant="text-md/semibold" color="text-strong">
{threadData.messageCount > 9 ? "9+" : threadData.messageCount}
</Text>]
})}
</PressableHighlight>;
}
return <PressableHighlight style={[styles.comments, style]} onPress={callback2}>
<View style={styles.commentCount}>
<ChatIcon style={styles.commentsIcon} />
</View>
</PressableHighlight>;
}
return null;
};
c10921_19 = 20;
useStyles = createStyles(() => {
const emojiContainer = {
flexDirection: "row",
backgroundColor: Module712.colors.REDESIGN_BUTTON_TERTIARY_BACKGROUND,
borderRadius: Module712.radii.sm,
flexShrink: 3,
paddingHorizontal: 8,
gap: 6
};
const width = c10921_19;
return {
container: {
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
justifyContent: "space-between"
},
replyForwardButtonContainer: {
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
gap: 6
},
emojisRowContainer: {
position: "relative",
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
gap: 6
},
emojisContainer: {
position: "relative",
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
gap: 6
},
emojiContainer,
innerEmojiContainer: {
paddingVertical: 5
},
selectedInnerEmojiContainer: {
paddingVertical: 4
},
addEmojiContainer: {
minHeight: 30,
alignItems: "center"
},
disabled: {
opacity: 0.4
},
defaultEmoji: {
width,
height: width
},
emojiText: {
lineHeight: isAndroid() ? 16 : width,
fontSize: 16,
textAlign: "center",
paddingTop: 2
},
selectedInnerTextContainer: {
paddingBottom: 3.5
},
innerTextContainer: {
alignSelf: "flex-end",
paddingBottom: 4.5
},
emojiImage: {
resizeMode: "contain",
width,
height: width
},
selected: {
borderColor: Module712.unsafe_rawColors.BRAND_560,
borderWidth: 1,
paddingHorizontal: 7,
backgroundColor: hexWithOpacity(Module712.unsafe_rawColors.BRAND_500, 0.3)
},
gradient: {
position: "absolute",
right: 0,
top: 0,
bottom: 0,
width: 48
},
overflowChevron: {
position: "absolute",
right: 0
},
comments: {
paddingVertical: 6,
paddingHorizontal: 8,
backgroundColor: Module712.colors.REDESIGN_BUTTON_TERTIARY_BACKGROUND,
borderRadius: Module712.radii.sm,
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: 8
},
commentCount: {
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: 4,
justifySelf: "end"
},
commentsIcon: {
width: 20,
height: 20,
tintColor: Module712.colors.INTERACTIVE_TEXT_DEFAULT
}
};
});
export default function ICYMICardInteractionRow(props) {
let r113, children, props2, props3;
let c21926_7, memo, canForwardMessage, stateFromStores, callback, setState;
const { message, channel: channel3, guild, hideAdditionalButtons = false } = props;
let c21926_2 = hideAdditionalButtons;
let isKeyMessage = props.isKeyMessage;
if (isKeyMessage === void 0) {
isKeyMessage = false;
}
let c21926_3 = isKeyMessage;
const { inForum = false, backgroundVariant = "primary" } = props;
let env21927;
let c21926_4 = backgroundVariant;
const { id, itemType } = props;
c21926_7 = void 0;
memo = void 0;
canForwardMessage = void 0;
stateFromStores = void 0;
callback = void 0;
setState = void 0;
const styles = useStyles();
const r12 = env21927 = {
$parent: env10921
};
env21927[0] = guild;
env21927[1] = message;
env21927[2] = inForum;
const stateFromStoresObject = useStateFromStoresObject([ChannelStore, ThreadMessageStore], $mk96251(r12));
const { thread, messageCount, mostRecentMessage } = stateFromStoresObject;
const id2 = guild?.id;
L32: {
useEffect($mk96252(r12), [id2, inForum, message, guild]);
const threadData2 = {
thread,
messageCount,
mostRecentMessage
};
c21926_7 = threadData2;
memo = useMemo(() => {
const r4 = [];
let c28010_0 = r4;
message.reactions.forEach((reaction) => {
if (reaction.me_vote == null) {
if (reaction.burst_count > 0) {
c28010_0.push({
...reaction,
type: ReactionTypes.BURST
});
}
if (reaction.count > 0) {
c28010_0.push({
...reaction,
type: ReactionTypes.NORMAL
});
}
}
});
return r4;
}, [message.reactions]);
const memo2 = useMemo(() => channel3 != null && canAddNewReactions(channel3), [channel3]);
canForwardMessage = useCanForwardMessage(message);
stateFromStores = useStateFromStores([PermissionStore], () => PermissionStore.can(Permissions.SEND_MESSAGES, channel3));
const memo3 = useMemo(() => {
const r0 = c21926_2 ? 6 : 4;
const r1 = c21926_7.messageCount > 0 ? r0 - 1 : r0;
const r12 = memo.length > r1 ? memo.length - r1 : 0;
const showThreadAsComments = c21926_7.messageCount > 0;
let showReplyForwardButtons = !c21926_2;
if (!c21926_2) {
let r18 = stateFromStores;
if (!stateFromStores) {
r18 = canForwardMessage;
}
showReplyForwardButtons = r18;
}
return {
hasOverflow: r12 > 0,
showReplyForwardButtons,
showThreadAsComments
};
}, [hideAdditionalButtons, threadData2.messageCount, memo.length, stateFromStores, canForwardMessage]);
const hasOverflow = memo3.hasOverflow;
let showReplyForwardButtons = memo3.showReplyForwardButtons;
let showThreadAsComments = memo3.showThreadAsComments;
callback = useCallback((a0, a1) => {
ICYMIActionCreators.itemInteracted(id, itemType, a0);
ICYMIActionCreators.feedItemActioned({
itemId: id,
itemType,
actionParameters: a1
});
}, [id, itemType]);
const callback2 = useCallback((a0, a1) => {
callback("press_reaction", {
actionGestureType: "press",
actionTargetElement: "add_new_reaction_button",
actionIntentType: "open",
actionDestinationType: null
});
const id3 = channel3.id;
const id2 = message.id;
if (a0 != null) {
addReaction(id3, id2, toReactionEmoji(a0), ReactionLocations.MESSAGE, {
burst: a1
});
}
}, [channel3.id, message.id, callback]);
const callback4 = useCallback(() => {
callback("press_forward", {
actionGestureType: "press",
actionTargetElement: "forward_button",
actionIntentType: "share",
actionDestinationType: "channel"
});
openForwardModal({
message,
source: "icymi-tab"
});
}, [message, callback]);
const callback5 = useCallback(() => {
callback("press_reply", {
actionGestureType: "press",
actionTargetElement: "reply_button",
actionIntentType: "reply",
actionDestinationType: "channel"
});
navigateToPost(channel3.id, channel3.guild_id, message.id);
createPendingReply({
channel: channel3,
message,
shouldMention: true,
showMentionToggle: true
});
}, [channel3, message, callback]);
const token = useToken(useMemo(() => {
if (c21926_3) {
return Module712.colors.MESSAGE_HIGHLIGHT_BACKGROUND_DEFAULT;
}
if (c21926_4 === "primary") {
return Module712.colors.CARD_BACKGROUND_DEFAULT;
}
if (c21926_4 === "secondary") {
return Module712.colors.CARD_SECONDARY_BG;
}
if (c21926_4 === "base") {
return Module712.colors.BACKGROUND_BASE_LOW;
}
}, [backgroundVariant, isKeyMessage]));
let state;
[state, setState] = useState(true);
const callback3 = useCallback(({ nativeEvent }) => {
setState(!(nativeEvent.contentOffset.x + nativeEvent.layoutMeasurement.width >= nativeEvent.contentSize.width));
}, []);
const callback6 = useCallback(() => {
callback("scroll_reaction_row", {
actionGestureType: "swipe",
actionTargetElement: "reaction_row_container",
actionIntentType: "scroll",
actionDestinationType: null
});
}, [callback]);
if (memo.length === 0) {
r113 = null;
if (hideAdditionalButtons) {
break L32;
}
}
L31: {
props2 = {
style: styles.container,
children: null
};
props3 = {
style: styles.emojisRowContainer,
children: null
};
if (!(memo.length > 0)) {
children = null;
if (!memo2) {
break L31;
}
}
let r128 = hideAdditionalButtons ? !hideAdditionalButtons : showReplyForwardButtons ? showReplyForwardButtons : showThreadAsComments;
if (r128) {
if (showThreadAsComments) {
showThreadAsComments = <ThreadAsCommentsButton threadData={threadData2} parentMessage={message} handleItemInteracted={callback} />;
}
const r133 = [showThreadAsComments, ,];
if (showReplyForwardButtons) {
showReplyForwardButtons = <>
<ReplyButton onPress={callback5} disabled={!stateFromStores} />
<ForwardButton onPress={callback4} disabled={!canForwardMessage} />
</>;
}
r133[1] = showReplyForwardButtons;
r128 = <View style={styles.replyForwardButtonContainer}>{r133}</View>;
}
children = <View style={[styles.emojisContainer]}>
<ScrollView horizontal scrollEnabled={hasOverflow} contentContainerStyle={{
gap: 6
}} onScroll={callback3} onScrollEndDrag={callback6} showsHorizontalScrollIndicator={false}>
{r128}
{memo.map((item, index) => <View key={`reaction-${index}`}>
<EmojiReaction messageId={message.id} channel={channel3} reaction={item} count={item.type === ReactionTypes.BURST ? item.burst_count : item.count} isBurstReaction={item.type === ReactionTypes.BURST} handleItemInteracted={callback} />
</View>)}
{hideAdditionalButtons ? null : memo2 ? <AddEmojiButton channel={channel3} onPressEmoji={callback2} handleItemInteracted={callback} /> : null}
</ScrollView>
{hasOverflow ? state ? <>
<Module4611 style={styles.gradient} start={HorizontalGradient.START} end={HorizontalGradient.END} colors={[Module689(token).alpha(0).hex(), token, token]} locations={[0, 0.8, 1]} />
<ChevronSmallRightIcon style={[styles.overflowChevron]} size="xs" color="icon-muted" />
</> : null : null}
</View>;
}
props3.children = children;
props2.children = <View {...props3} />;
r113 = <View {...props2} />;
}
return r113;
};
export function onAddReaction(a0, a1, a2, a3) {
if (a2 != null) {
addReaction(a0, a1, toReactionEmoji(a2), ReactionLocations.MESSAGE, {
burst: a3
});
}
}
export function useThread(a0, a1, a2) {
let env21922;
const r2 = env21922 = {
$parent: env10921
};
env21922[0] = a0;
env21922[1] = a1;
env21922[2] = a2;
const stateFromStoresObject = useStateFromStoresObject([ChannelStore, ThreadMessageStore], $mk96251(r2));
const { thread, messageCount, mostRecentMessage } = stateFromStoresObject;
const id2 = a0?.id;
useEffect($mk96252(r2), [id2, a2, a1, a0]);
return {
thread,
messageCount,
mostRecentMessage
};
}