Files
discord-decomp/modules/video_calls/native/components/StreamTile.tsx
T
2026-11-01 12:12:55 +02:00

126 lines
6.6 KiB
TypeScript

// Metro module 10544 (f10545).
import { memo, useCallback } from "react";
import { StyleSheet, View } from "react-native";
import ApplicationStreamingStore from "../../../../stores/ApplicationStreamingStore";
import AuthenticationStore from "../../../../stores/AuthenticationStore";
import { ApplicationStreamStates } from "../../../../Constants";
import { MediaEngineContextTypes } from "../../../../_bundle/Module4250";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { hexWithOpacity } from "../../../../utils/ColorUtils";
import { Text } from "../../../../design/components/Text/native/Text";
import { LegacyText, Icon } from "../../../../design/void/native";
import { useStateFromStores } from "../../../../_bundle/Module589";
import useVideoStreamError from "../../../errors/hooks/useVideoStreamError";
import VideoEmptyState, { VideoEmptyTypes } from "../../../../components_native/calls/stream/VideoEmptyState";
import { intl, t } from "../../../../intl/index.native";
import NicknameUtils from "../../../../utils/NicknameUtils";
import VideoRenderer, { ResizeMode } from "./VideoRenderer";
import StreamQualityLiveIndicator from "../../../go_live/native/StreamQualityLiveIndicator";
import { VideoSpinnerContext } from "../../../../lib/VideoSpinnerTimer";
import useParticipantTileTapGesture from "../useParticipantTileTapGesture";
import { GestureDetector } from "../../../../_bundle/Module5273";
import { PressableOpacity } from "../../../../design/void/Pressables/native/Pressables";
import Module10569 from "../../../../_bundle/Module10569";
let useStyles, Component, Component2;
const StreamTextOverlay = function StreamTextOverlay(props) {
const { title, subtext } = props;
const styles2 = useStyles();
return <View style={styles2.screenMessageContainer}>
<Text style={styles2.screenMessageText} variant="text-md/semibold" color="text-overlay-light">{title}</Text>
{subtext != null ? <LegacyText style={styles2.screenMessageSubtext}>{subtext}</LegacyText> : null}
</View>;
};
useStyles = createStyles({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
width: "100%",
backgroundColor: Module712.colors.BLACK
},
screenMessageContainer: {
...StyleSheet.absoluteFillObject,
flex: 1,
padding: 8,
alignItems: "center",
justifyContent: "center",
backgroundColor: hexWithOpacity(Module712.unsafe_rawColors.BLACK, 0.7)
},
screenMessageText: {
lineHeight: 18
},
screenMessageSubtext: {
color: Module712.unsafe_rawColors.PRIMARY_300,
fontSize: 14,
lineHeight: 18,
textAlign: "center"
},
statusWrapper: {
position: "absolute",
bottom: 8,
right: 8,
backgroundColor: hexWithOpacity(Module712.unsafe_rawColors.PRIMARY_700, 0.5),
borderRadius: Module712.radii.md,
width: 24,
height: 24,
justifyContent: "center",
alignItems: "center"
},
liveTag: {
position: "absolute",
right: 8,
top: 8
}
});
Component = memo(function({ participant, streamId, user, resizeMode, gestureEnabled, removeEmptyStateButton, removeEmptyStateImage }) {
const styles = useStyles();
const stateFromStores = useStateFromStores([ApplicationStreamingStore], () => ApplicationStreamingStore.getActiveStreamForStreamKey(participant.id));
const videoStreamError = useVideoStreamError(MediaEngineContextTypes.STREAM, participant.user.id);
if (stateFromStores != null) {
const state = stateFromStores.state;
if (ApplicationStreamStates.FAILED === state) {
return <VideoEmptyState stream={stateFromStores} removeCloseButton={removeEmptyStateButton} removeSplashImage={removeEmptyStateImage} type={VideoEmptyTypes.STREAM_FAILED} style={StyleSheet.absoluteFill} />;
}
if (ApplicationStreamStates.ENDED === state) {
return <VideoEmptyState stream={stateFromStores} removeCloseButton={removeEmptyStateButton} removeSplashImage={removeEmptyStateImage} type={VideoEmptyTypes.STREAM_ENDED} style={StyleSheet.absoluteFill} />;
}
const r14 = ApplicationStreamStates.RECONNECTING === state ? <StreamTextOverlay title={intl.string(t["pdFFK+"])} /> : ApplicationStreamStates.PAUSED === state ? <StreamTextOverlay title={intl.string(t["5q17w5"])} subtext={intl.formatToPlainString(t.meVVlb, {
username: NicknameUtils.getName(stateFromStores.guildId, stateFromStores.channelId, user)
})} /> : null;
if (videoStreamError != null) {
return <VideoEmptyState stream={stateFromStores} removeCloseButton={removeEmptyStateButton} removeSplashImage={removeEmptyStateImage} type={VideoEmptyTypes.STREAM_FAILED} style={StyleSheet.absoluteFill} avError={videoStreamError} />;
}
return <>
<VideoRenderer resizeMode={resizeMode} streamId={streamId} gestureEnabled={gestureEnabled} renderTag={() => <StreamQualityLiveIndicator style={styles.liveTag} participant={participant} />} videoSpinnerContext={stateFromStores.ownerId === AuthenticationStore.getId() ? VideoSpinnerContext.SELF_STREAM : VideoSpinnerContext.REMOTE_STREAM} userId={user.id} paused={stateFromStores.state === ApplicationStreamStates.PAUSED} />
{r14}
</>;
}
return null;
});
Component2 = memo(function({ onFullScreen, style }) {
return <PressableOpacity accessibilityRole="button" onPress={onFullScreen} style={[useStyles().statusWrapper, style]} hitSlop={{
top: 4,
left: 4,
right: 4,
bottom: 4
}}>
<Icon source={Module10569} size={Icon.Sizes.SMALL} color={Module712.unsafe_rawColors.WHITE} />
</PressableOpacity>;
});
export default function StreamTile(props) {
const { participant: participant2, onSingleTap, onDoubleTap, resizeMode = ResizeMode.CONTAIN, gestureEnabled, removeEmptyStateButton, removeEmptyStateImage, onFullScreen, fullscreenIconStyle, style } = props;
const styles2 = useStyles();
return <GestureDetector gesture={useParticipantTileTapGesture({
onSingleTapStart: useCallback(() => onSingleTap == null ? void 0 : onSingleTap(participant2), [onSingleTap, participant2]),
onDoubleTapStart: useCallback(() => onDoubleTap == null ? void 0 : onDoubleTap(participant2), [onDoubleTap, participant2])
})}>
<View style={[styles2.container, style]}>
<Component streamId={participant2.streamId} participant={participant2} user={participant2.user} resizeMode={resizeMode} gestureEnabled={gestureEnabled} removeEmptyStateButton={removeEmptyStateButton} removeEmptyStateImage={removeEmptyStateImage} />
{onFullScreen != null && <Component2 onFullScreen={onFullScreen} style={fullscreenIconStyle} />}
</View>
</GestureDetector>;
};
export { StreamTextOverlay };