Files
discord-decomp/modules/voice_panel/native/prejoin/VoicePanelPreJoinContent.tsx
T
2026-11-01 12:12:55 +02:00

517 lines
23 KiB
TypeScript

// Metro module 15984 (f15985).
import { useContext, useCallback, useState, memo, useEffect } from "react";
import { StyleSheet } from "react-native";
import EmbeddedActivitiesStore from "../../../activities/EmbeddedActivitiesStore";
import GameConsoleStore from "../../../game_console/GameConsoleStore";
import VoiceChannelBlockedUserStore from "../../../shared_space_warnings/VoiceChannelBlockedUserStore";
import ApplicationStreamingStore from "../../../../stores/ApplicationStreamingStore";
import AuthenticationStore from "../../../../stores/AuthenticationStore";
import ChannelStore from "../../../../stores/ChannelStore";
import PermissionStore from "../../../../stores/PermissionStore";
import SessionsStore from "../../../../stores/SessionsStore";
import UserStore from "../../../../stores/UserStore";
import VoiceStateStore from "../../../../stores/VoiceStateStore";
import SortedVoiceStateStore from "../../../../stores/views/SortedVoiceStateStore";
import { MODE_CHANGE_PHYSICS } from "../../VoicePanelConstants";
import { EDGE_GUTTER } from "../card/VoicePanelCardConstants";
import { AnalyticEvents, AnalyticsSections, Permissions } from "../../../../Constants";
import { VoiceChannelWarningSurfaces } from "../../../shared_space_warnings/SharedSpaceWarningConstants";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import { BASE_VOICE_PANEL_HEADER_HEIGHT } from "../header/calculateVoicePanelHeaderSpecs";
import Module712 from "../../../../_bundle/Module712";
import VoicePanelStateContext from "../VoicePanelStateContext";
import SelectedChannelActionCreators from "../../../../actions/SelectedChannelActionCreators";
import { watchStream } from "../../../../actions/StreamActionCreators";
import { encodeStreamKey } from "../../../go_live/utils/StreamKeyUtils";
import { useStateFromStores } from "../../../../_bundle/Module589";
import NativeView from "../../../core/native/NativeView";
import { Text } from "../../../../design/components/Text/native/Text";
import { t, intl } from "../../../../intl/index.native";
import { VoicePanelStreamPreview } from "../shared/VoicePanelStreamPreview";
import useGetOrFetchApplications from "../../../applications/useGetOrFetchApplications";
import { getEmbeddedActivityLocationChannelId } from "../../../activities/utils/embeddedActivityLocationUtils";
import useActivityUsers from "../../../activities/useActivityUsers";
import { getWindowDimensions } from "../../../screen/useWindowDimensions.native";
import * as _ReanimatedRexport from "../../../reanimated/ReanimatedRexport";
import { useAnimatedReaction, useAnimatedStyle } from "../../../reanimated/ReanimatedRexport";
import { useEmbeddedActivityJoinability, EmbeddedActivityJoinability } from "../../../activities/utils/getEmbeddedActivityJoinability";
import handlePressJoinActivity, { maybeJoinEmbeddedActivity } from "../../../activities/handlePressJoinActivity";
import useEmbeddedActivityBackground from "../../../activities/utils/useEmbeddedActivityBackground";
import { PressableOpacity } from "../../../../design/void/Pressables/native/Pressables";
import ActivityShelfItemBackground from "../controls/activities/ActivityShelfItemBackground";
import { Button } from "../../../../design/components/Button/native/Button.native";
import useTrackImpression from "../../../app_analytics/useTrackImpression";
import { ImpressionNames } from "../../../../_bundle/Module503";
import { CircleErrorIcon } from "../../../../design/components/Icon/native/redesign/generated/CircleErrorIcon";
import { VoicePanelFormSection, MemberRowItem } from "../shared/FormComponents";
import NicknameUtils from "../../../../utils/NicknameUtils";
import { TableRow } from "../../../../design/components/TableRow/native/TableRow.native";
import roundToNearestPixel from "../utils/roundToNearestPixel";
import useShowChannelOptInNotice from "../../../opt_in_channels/useShowChannelOptInNotice";
import useAnalyticsLocations from "../../../app_analytics/useAnalyticsLocations";
import AnalyticsLocation from "../../../app_analytics/AnalyticsLocation";
import AnalyticsUtils from "../../../../utils/AnalyticsUtils";
import VoicePanelChannelOptInNotice from "../shared/VoicePanelChannelOptInNotice";
import * as _spring from "../../../../design/animation/reanimated/spring/spring";
import * as _TransitionGroup from "../../../../design/components/TransitionGroup/TransitionGroup";
import { TransitionItem } from "../../../../design/components/TransitionGroup/TransitionGroup";
import ReanimatedNativeView from "../../../core/native/ReanimatedNativeView";
import useIsConnectedToVoiceChannel from "../hooks/useIsConnectedToVoiceChannel";
import { areVoicePanelPreJoinContentPropsEqual } from "./VoicePanelPreJoinUtils";
let useStyles, Component2, __initData, __initData2, ActivityInfo, Component, RoomMembersSection, RoomMembers, Component3, VoicePanelPreJoinContentInner, __initData3, __initData4, PreJoinTransitioner, renderItem;
const StreamPreview = function StreamPreview(props) {
let stateFromStores;
const { voiceState, stream, channelId } = props;
stateFromStores = void 0;
const styles = useStyles();
const context = useContext(VoicePanelStateContext);
const { mode, setFocused } = context;
const callback = useCallback(() => {
SelectedChannelActionCreators.selectVoiceChannel(channelId);
watchStream(stream, {
forceMultiple: true
});
setFocused(encodeStreamKey(stream));
}, [channelId, stream, setFocused]);
stateFromStores = useStateFromStores([ChannelStore], () => ChannelStore.getChannel(channelId));
const stateFromStores2 = useStateFromStores([PermissionStore], () => PermissionStore.can(Permissions.CONNECT, stateFromStores));
const I0mOAs = t.I0mOAs;
let nick = voiceState.nick;
if (nick == null) {
nick = voiceState.user.username;
}
return <NativeView style={styles.activityInfoWrapper}>
<Text variant="text-sm/semibold" style={styles.activityInfoHeader} color="text-default">
{intl.format(I0mOAs, {
username: nick
})}
</Text>
<NativeView style={styles.previewImageWrapper}>
<VoicePanelStreamPreview mode={mode} disabled={!stateFromStores2} stream={stream} onPress={callback} />
</NativeView>
</NativeView>;
};
ActivityInfo = function ActivityInfo(props) {
let setState, embeddedActivityJoinability, c22675_7;
const { activity, analyticsLocations } = props;
setState = void 0;
embeddedActivityJoinability = void 0;
c22675_7 = void 0;
const styles = useStyles();
const [inputApplication] = useGetOrFetchApplications([activity.applicationId]);
const activityUsers = useActivityUsers(activity.applicationId, getEmbeddedActivityLocationChannelId(activity.location));
const context = useContext(VoicePanelStateContext);
const { channelId: channelId2, windowDimensions } = context;
let size;
[size, setState] = useState(() => getWindowDimensions().width - 2 * (EDGE_GUTTER + 16));
const u = () => windowDimensions.get().width;
u.__closure = {
windowDimensions
};
u.__workletHash = 16837592262556;
u.__initData = __initData;
const c = function c(a0, a1) {
if (a0 !== a1) {
_ReanimatedRexport.runOnJS(setState)(a0 - 2 * (EDGE_GUTTER + 16));
}
};
c.__closure = {
runOnJS: _ReanimatedRexport.runOnJS,
setActivityPreviewWidth: setState,
EDGE_GUTTER
};
c.__workletHash = 1481130207412;
c.__initData = __initData2;
useAnimatedReaction(u, c);
embeddedActivityJoinability = useEmbeddedActivityJoinability({
userId: AuthenticationStore.getId(),
channelId: channelId2,
application: inputApplication
});
const r2 = embeddedActivityJoinability === EmbeddedActivityJoinability.CAN_JOIN;
c22675_7 = r2;
const callback = useCallback(() => {
let c28195_0 = async () => {
L13: {
if (c22675_7) {
if (inputApplication != null) {
await maybeJoinEmbeddedActivity({
channelId: channelId2,
applicationId: inputApplication.id,
launchId: activity.launchId,
inputApplication,
analyticsLocations
});
break L13;
}
} else {
SelectedChannelActionCreators.selectVoiceChannel(channelId2);
}
return void 0;
}
};
handlePressJoinActivity({
embeddedActivityJoinability,
handleCanJoin: function() {
return c28195_0.apply(this, arguments);
}
});
}, [activity.launchId, analyticsLocations, inputApplication, r2, channelId2, embeddedActivityJoinability]);
const embeddedActivityBackground = useEmbeddedActivityBackground({
applicationId: activity.applicationId,
size,
names: ["embedded_background"]
});
const r3 = inputApplication == null;
let r87 = null;
if (!r3) {
const r111 = [<Text variant="text-sm/semibold" style={styles.activityInfoHeader} color="text-default">
{intl.format(t["n/IJ6Y"], {
n: activityUsers.length
})}
</Text>, ,];
const r126 = [<NativeView style={styles.previewImage}>
<ActivityShelfItemBackground imageBackground={embeddedActivityBackground} aspectRatio={1.7777777777777777} />
</NativeView>, ,];
const props2 = {
text: intl.formatToPlainString(t["YV/hE8"], {
name: inputApplication.name
}),
size: "sm",
iconPosition: "start",
variant: "primary-overlay",
icon: null,
onPress: null
};
const Icon = Button.Icon;
let uri = inputApplication.getIconURL(20);
if (uri == null) {
uri = void 0;
}
props2.icon = <Icon variant="entity" source={{
uri,
width: 20,
height: 20
}} />;
props2.onPress = callback;
r126[1] = <NativeView style={styles.joinButtonWrapper}>
<Button {...props2} />
</NativeView>;
r111[1] = <PressableOpacity activeOpacity={0.7} onPress={callback} style={styles.previewImageWrapper} accessible={false}>{r126}</PressableOpacity>;
r87 = <NativeView style={styles.activityInfoWrapper}>{r111}</NativeView>;
}
return r87;
};
RoomMembersSection = function RoomMembersSection(props) {
const { title, members, channelId: channelId3, guildId } = props;
return <VoicePanelFormSection title={title} hasIcons>
{(() => {
const r0 = [];
for (const member of members) {
const key = member;
const user = UserStore.getUser(member);
if (user != null) {
const user2 = user;
r0.push(<MemberRowItem key={key} user={user2} channelId={channelId3} guildId={guildId} nick={NicknameUtils.getName(guildId, channelId3, user2)} />);
}
}
return r0;
})()}
</VoicePanelFormSection>;
};
RoomMembers = function RoomMembers(props) {
const { members: members2, streamingMembers, blockedMembers, ignoredMembers } = props;
const context = useContext(VoicePanelStateContext);
const { channelId: channelId4, guildId: guildId2 } = context;
const [state, setState2] = useState(20);
const r36 = blockedMembers.size + ignoredMembers.size;
const r9 = members2.length - r36;
return <>
{[r36 > 0 && <Component channelId={channelId4} blockedUserIds={blockedMembers} ignoredUserIds={ignoredMembers} />, streamingMembers.map((streamingMember) => {
const [voiceState, stream2] = streamingMember;
return <StreamPreview key={stream2.ownerId} channelId={channelId4} voiceState={voiceState} stream={stream2} />;
}), blockedMembers.size > 0 && <RoomMembersSection title={intl.formatToPlainString(t.pGJ1Qy, {
n: blockedMembers.size
})} members={blockedMembers} channelId={channelId4} guildId={guildId2} />, ignoredMembers.size > 0 && <RoomMembersSection title={intl.formatToPlainString(t["/pXOCN"], {
n: ignoredMembers.size
})} members={ignoredMembers} channelId={channelId4} guildId={guildId2} />, r9 > 0 && <VoicePanelFormSection hasIcons title={r36 === 0 ? intl.formatToPlainString(t.vloEU7, {
n: members2.length
}) : intl.formatToPlainString(t.R0h4pE, {
n: r9
})}>
{(() => {
const r0 = [];
for (const item of members2) {
if (!(r0.length >= state)) {
if (blockedMembers.has(item.user.id) || ignoredMembers.has(item.user.id)) {
continue;
}
r0.push(<MemberRowItem key={item.user.id} user={item.user} channelId={channelId4} guildId={guildId2} nick={NicknameUtils.getName(guildId2, channelId4, item.user)} />);
continue;
}
break;
}
return r0;
})()}
{r9 > state && <TableRow label={intl.string(t.F4MCUO)} onPress={() => setState2(state + 20)} />}
</VoicePanelFormSection>]}
</>;
};
PreJoinTransitioner = function PreJoinTransitioner(props) {
const { transitionState, transitionCleanUp, ...props2 } = props;
const styles = useStyles();
const context = useContext(VoicePanelStateContext);
const { windowDimensions: windowDimensions2, controlsSpecs, safeArea, preJoinContentSize, useReducedMotion } = context;
const l = function l() {
const height = windowDimensions2.get().height;
const r38 = {
paddingBottom: height - roundToNearestPixel(0.8 * height) + controlsSpecs.get().height + safeArea.get().bottom,
opacity: null,
transform: null
};
const YEETED = _TransitionGroup.TransitionStates.YEETED;
let r46 = 1;
r38.opacity = _spring.withSpring(transitionState === YEETED ? 0 : 1);
if (!(!useReducedMotion.get() && transitionState === _TransitionGroup.TransitionStates.YEETED)) {
r46 = 0;
}
const r59 = _ReanimatedRexport.interpolate(r46, [0, 1], [0, 400]);
const r60 = function(r3 = false) {
if (r3) {
r3 = transitionState === _TransitionGroup.TransitionStates.YEETED;
}
if (r3) {
_ReanimatedRexport.runOnJS(transitionCleanUp)();
}
};
r60.__closure = {
transitionState,
TransitionStates: _TransitionGroup.TransitionStates,
runOnJS: _ReanimatedRexport.runOnJS,
transitionCleanUp
};
r60.__workletHash = 2541522666097;
r60.__initData = __initData4;
r38.transform = [{
translateY: _spring.withSpring(r59, MODE_CHANGE_PHYSICS, "respect-motion-settings", r60)
}];
return r38;
};
l.__closure = {
windowDimensions: windowDimensions2,
roundToNearestPixel,
controlsSpecs,
safeArea,
withSpring: _spring.withSpring,
transitionState,
TransitionStates: _TransitionGroup.TransitionStates,
interpolate: _ReanimatedRexport.interpolate,
useReducedMotion,
MODE_CHANGE_PHYSICS,
runOnJS: _ReanimatedRexport.runOnJS,
transitionCleanUp
};
l.__workletHash = 16643118377748;
l.__initData = __initData3;
return <ReanimatedNativeView style={useAnimatedStyle(l)} collapsable={false}>
<NativeView onLayout={useCallback((a0) => {
preJoinContentSize.set(roundToNearestPixel(a0.nativeEvent.layout.height));
}, [preJoinContentSize])} collapsable={false} style={styles.contentWrapper}>
<VoicePanelPreJoinContentInner {...props2} />
</NativeView>
</ReanimatedNativeView>;
};
renderItem = function renderItem(a0, a1, a2, a3) {
return <PreJoinTransitioner key={a0} transitionState={a2} transitionCleanUp={a3} {...a1} />;
};
useStyles = createStyles({
contentWrapper: {
paddingTop: EDGE_GUTTER + BASE_VOICE_PANEL_HEADER_HEIGHT + EDGE_GUTTER,
gap: 24,
paddingBottom: 16
},
channelInfoWrapper: {
paddingHorizontal: 16
},
subheading: {
textAlign: "center",
paddingTop: 16,
paddingBottom: 16
},
previewImageWrapper: {
position: "relative",
width: "100%",
aspectRatio: 1.7777777777777777,
borderRadius: Module712.radii.lg,
overflow: "hidden",
justifyContent: "center",
backgroundColor: Module712.colors.BLACK
},
previewImage: {
...StyleSheet.absoluteFillObject,
opacity: 0.5
},
activityInfoWrapper: {
paddingHorizontal: 16
},
activityInfoHeader: {
marginBottom: 8
},
joinButtonWrapper: {
...StyleSheet.absoluteFillObject,
display: "flex",
alignItems: "center",
justifyContent: "center"
},
optInChannelsContainer: {
marginHorizontal: 16
},
blockedMemberWarning: {
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_8,
padding: Module712.space.PX_8,
borderRadius: Module712.radii.xs,
borderColor: Module712.colors.ICON_FEEDBACK_WARNING,
borderWidth: 1,
backgroundColor: Module712.colors.BACKGROUND_FEEDBACK_WARNING,
marginHorizontal: Module712.space.PX_16
},
consolePreJoinPadding: {
height: 36
}
});
Component2 = memo(function({ hasMembers }) {
const styles = useStyles();
return hasMembers ? null : <NativeView style={styles.channelInfoWrapper}>
<Text variant="text-sm/medium" color="text-default" style={styles.subheading}>
{intl.string(t.sS2J0G)}
</Text>
</NativeView>;
});
__initData = {
code: "function VoicePanelPreJoinContentTsx1(){const{windowDimensions}=this.__closure;return windowDimensions.get().width;}"
};
__initData2 = {
code: "function VoicePanelPreJoinContentTsx2(width,previous){const{runOnJS,setActivityPreviewWidth,EDGE_GUTTER}=this.__closure;if(width===previous)return;runOnJS(setActivityPreviewWidth)(width-(EDGE_GUTTER+16)*2);}"
};
Component = memo(function({ channelId: channelId8, blockedUserIds, ignoredUserIds }) {
const styles = useStyles();
useTrackImpression({
name: ImpressionNames.VOICE_CHANNEL_BLOCKED_USER_WARNING,
properties: {
channel_id: channelId8,
blocked_user_ids: Array.from(blockedUserIds),
warning_surface: VoiceChannelWarningSurfaces.PRE_JOIN_SHEET
}
});
const size = ignoredUserIds.size;
const size2 = blockedUserIds.size;
const r38 = intl.string(t.CjrALd);
return <NativeView style={styles.blockedMemberWarning}>
<CircleErrorIcon color="text-feedback-warning" />
<Text variant="text-sm/bold" color="interactive-text-active" style={{
flexShrink: 1
}}>
{size2 > 0 && size > 0 ? intl.string(t.MpRfpC) : size > 0 ? intl.format(t.u9trAZ, {
n: size
}) : intl.format(t["6X29zb"], {
n: size2
})}
{" "}
{r38 != null ? <Text variant="heading-sm/semibold">{r38}</Text> : null}
</Text>
</NativeView>;
});
Component3 = memo(function({ channelId: channelId5 }) {
const styles = useStyles();
return useStateFromStores([AuthenticationStore, GameConsoleStore, VoiceStateStore, SessionsStore], () => {
let r13 = VoiceStateStore.getVoiceStateForSession(AuthenticationStore.getId(), GameConsoleStore.getRemoteSessionId());
if (r13 == null) {
r13 = void 0;
}
let r19 = GameConsoleStore.getAwaitingRemoteSessionInfo()?.channelId === channelId5;
if (!r19) {
let r21 = r13?.channelId === channelId5;
if (r21) {
let r24 = r13?.sessionId;
if (r24 == null) {
r24 = "";
}
r21 = SessionsStore.getSessionById(r24) != null;
}
r19 = r21;
}
return r19;
}, [channelId5]) ? <NativeView style={styles.consolePreJoinPadding} /> : null;
});
VoicePanelPreJoinContentInner = memo(function VoicePanelPreJoinContentInner(props) {
let analyticsLocations2;
const { members: members3, streamingMembers, blockedMembers: blockedMembers2, ignoredMembers: ignoredMembers2, activities } = props;
analyticsLocations2 = void 0;
const styles = useStyles();
const context = useContext(VoicePanelStateContext);
const { channelId: channelId6, guildId: guildId3 } = context;
const stateFromStores2 = useStateFromStores([ChannelStore], () => ChannelStore.getChannel(channelId6));
const showChannelOptInNotice = useShowChannelOptInNotice(stateFromStores2);
analyticsLocations2 = useAnalyticsLocations(AnalyticsLocation.VOICE_PANEL_PRE_JOIN).analyticsLocations;
useEffect(() => {
AnalyticsUtils.track(AnalyticEvents.VIEW_VOICE_CHANNEL, {
guild_id: guildId3,
channel_id: channelId6,
location_stack: analyticsLocations2
});
}, [channelId6, guildId3, analyticsLocations2]);
return <>
<Component2 hasMembers={members3.length > 0} />
{showChannelOptInNotice ? <VoicePanelChannelOptInNotice style={styles.optInChannelsContainer} channel={stateFromStores2} analyticsSection={AnalyticsSections.CHANNEL} /> : null}
{activities.map((a0) => <ActivityInfo key={a0.launchId} activity={a0} analyticsLocations={analyticsLocations2} />)}
{(members3.length > 0 || blockedMembers2.size > 0 || ignoredMembers2.size > 0) && <RoomMembers members={members3} streamingMembers={streamingMembers} blockedMembers={blockedMembers2} ignoredMembers={ignoredMembers2} />}
<Component3 channelId={channelId6} />
</>;
});
__initData3 = {
code: "function VoicePanelPreJoinContentTsx3(){const{windowDimensions,roundToNearestPixel,controlsSpecs,safeArea,withSpring,transitionState,TransitionStates,interpolate,useReducedMotion,MODE_CHANGE_PHYSICS,runOnJS,transitionCleanUp}=this.__closure;const{height:windowHeight}=windowDimensions.get();return{paddingBottom:windowHeight-roundToNearestPixel(windowHeight*0.8)+controlsSpecs.get().height+safeArea.get().bottom,opacity:withSpring(transitionState===TransitionStates.YEETED?0:1),transform:[{translateY:withSpring(interpolate(!useReducedMotion.get()&&transitionState===TransitionStates.YEETED?1:0,[0,1],[0,400]),MODE_CHANGE_PHYSICS,'respect-motion-settings',function(finished=false){finished&&transitionState===TransitionStates.YEETED&&runOnJS(transitionCleanUp)();})}]};}"
};
__initData4 = {
code: "function VoicePanelPreJoinContentTsx4(finished=false){const{transitionState,TransitionStates,runOnJS,transitionCleanUp}=this.__closure;finished&&transitionState===TransitionStates.YEETED&&runOnJS(transitionCleanUp)();}"
};
const r150 = memo(function VoicePanelPreJoinWrapper() {
const context = useContext(VoicePanelStateContext);
const { channelId: channelId7, guildId: guildId4 } = context;
const isConnectedToVoiceChannel = useIsConnectedToVoiceChannel(channelId7);
let c22681_2 = isConnectedToVoiceChannel;
return <TransitionItem item={useStateFromStores([SortedVoiceStateStore, VoiceChannelBlockedUserStore, EmbeddedActivitiesStore, ApplicationStreamingStore], () => {
if (c22681_2) {
return void 0;
}
let r9 = guildId4;
if (guildId4 == null) {
r9 = void 0;
}
const voiceStatesForChannelAlt = SortedVoiceStateStore.getVoiceStatesForChannelAlt(channelId7, r9);
const blockedUsersForVoiceChannel = VoiceChannelBlockedUserStore.getBlockedUsersForVoiceChannel(channelId7);
const ignoredUsersForVoiceChannel = VoiceChannelBlockedUserStore.getIgnoredUsersForVoiceChannel(channelId7);
return {
members: voiceStatesForChannelAlt,
activities: EmbeddedActivitiesStore.getEmbeddedActivitiesForChannel(channelId7),
streamingMembers: (() => {
const r0 = [];
for (const item of voiceStatesForChannelAlt) {
if (item.voiceState.selfStream) {
const streamForUser = ApplicationStreamingStore.getStreamForUser(item.user.id, guildId4);
if (streamForUser != null) {
r0.push([item, streamForUser]);
}
}
}
return r0;
})(),
blockedMembers: blockedUsersForVoiceChannel,
ignoredMembers: ignoredUsersForVoiceChannel
};
}, [isConnectedToVoiceChannel, channelId7, guildId4], areVoicePanelPreJoinContentPropsEqual)} renderItem={renderItem} />;
});
export default r150;