import React, { useEffect, useCallback } from 'react';
import { useSearchParams, useNavigate } from 'react-router-dom';
import TUIRoomEngine, { TUIRoomEvents } from "@tencentcloud/tuiroom-engine-js";
import { Avatar, LiveView, LiveGift, LiveListEvent, BarrageList, BarrageInput, LiveAudienceList, useLiveListState, useLiveAudienceState, useLoginState, useRoomEngine } from 'tuikit-atomicx-react';
import { UIKitProvider, IconChevronLeft, MessageBox, Dialog, useUIKit } from '@tencentcloud/uikit-base-component-react';
import styles from './LivePlayerView.module.scss';
interface LivePlayerProps {
className?: string;
}
const LivePlayer: React.FC<LivePlayerProps> = ({ className }) => {
const { t } = useUIKit();
const navigate = useNavigate();
const roomEngine = useRoomEngine();
const { currentLive, leaveLive, subscribeEvent, unsubscribeEvent } = useLiveListState();
const { audienceCount } = useLiveAudienceState();
const handleAutoPlayFailed = useCallback(() => {
MessageBox.alert({
content: 'Content is ready, click the [Play] button to start playback',
confirmText: 'Play',
showClose: false,
modal: false,
});
}, []);
const handleKickedOutOfLive = useCallback(() => {
Dialog.open({
content: 'You have been kicked out of the live room',
confirmText: 'Confirm',
className: styles.livePlayer__liveDialog,
showCancel: false,
showClose: false,
modal: true,
center: true,
onConfirm: () => {
Dialog.close();
},
onClose: () => {
},
});
}, [navigate]);
const handleLiveEnded = useCallback(() => {
Dialog.open({
content: 'The live stream has ended',
confirmText: 'Confirm',
className: styles.livePlayer__liveDialog,
showCancel: false,
showClose: false,
modal: true,
center: true,
onConfirm: () => {
Dialog.close();
},
onClose: () => {
},
});
}, [navigate]);
const handleLeaveLive = useCallback(async () => {
try {
await leaveLive();
navigate('/live-list');
} catch (error) {
console.error('Failed to leave live:', error);
MessageBox.alert({
content: 'Failed to leave live room, please try again',
confirmText: 'Confirm',
showClose: false,
modal: true,
});
}
}, [leaveLive, navigate]);
useEffect(() => {
if (roomEngine.instance) {
roomEngine.instance.on(TUIRoomEvents.onAutoPlayFailed, handleAutoPlayFailed);
} else {
TUIRoomEngine.once("ready", () => {
roomEngine.instance?.on(TUIRoomEvents.onAutoPlayFailed, handleAutoPlayFailed);
});
}
subscribeEvent(LiveListEvent.ON_LIVE_ENDED, handleLiveEnded);
subscribeEvent(LiveListEvent.ON_KICKED_OUT_OF_LIVE, handleKickedOutOfLive);
return () => {
roomEngine.instance?.off(TUIRoomEvents.onAutoPlayFailed, handleAutoPlayFailed);
unsubscribeEvent(LiveListEvent.ON_LIVE_ENDED, handleLiveEnded);
unsubscribeEvent(LiveListEvent.ON_KICKED_OUT_OF_LIVE, handleKickedOutOfLive);
};
}, [handleAutoPlayFailed, handleLiveEnded, handleKickedOutOfLive, roomEngine.instance, subscribeEvent, unsubscribeEvent]);
return (
<div className={`${styles.livePlayer} ${className || ''}`}>
<div className={styles.livePlayer__left}>
<div className={styles.livePlayer__header}>
<div className={styles.livePlayer__headerContent}>
<IconChevronLeft
className={styles.livePlayer__headerChevronLeft}
size="32"
onClick={handleLeaveLive}
/>
<Avatar
className={styles.livePlayer__headerAvatar}
src={currentLive?.liveOwner?.avatarUrl}
size={32}
/>
<span>{currentLive?.liveOwner?.userName || currentLive?.liveOwner?.userId}</span>
</div>
</div>
<div className={styles.livePlayer__player}>
<LiveView />
</div>
<div className={styles.livePlayer__giftContainer}>
<LiveGift />
</div>
</div>
<div className={styles.livePlayer__right}>
<div className={styles.livePlayer__audienceList}>
<div className={styles.livePlayer__audienceListTitle}>
<span>{t('Audience List')} </span>
<span className={styles.livePlayer__audienceCount}>({audienceCount})</span>
</div>
<div className={styles.livePlayer__audienceListContent}>
<LiveAudienceList height="100%" />
</div>
</div>
<div className={styles.livePlayer__messageList}>
<div className={styles.livePlayer__messageListTitle}>
<span>{t('Message List')}</span>
</div>
<div className={styles.livePlayer__messageListContent}>
<BarrageList />
<BarrageInput />
</div>
</div>
</div>
</div>
);
};
const LivePlayerView: React.FC = () => {
const [searchParams] = useSearchParams();
const { loginUserInfo, login, setSelfInfo } = useLoginState();
const { joinLive } = useLiveListState();
useEffect(() => {
const liveId = searchParams.get('liveId') || '';
if (liveId) {
joinLive({ liveId });
}
}, [searchParams, joinLive]);
const initLogin = useCallback(async () => {
try {
await login({
SDKAppID: 0,
userID: '',
userSig: '',
});
await setSelfInfo({
userName: '',
avatarUrl: '',
});
} catch (error) {
console.error('Login failed:', error);
}
}, [login, setSelfInfo]);
useEffect(() => {
async function init() {
await initLogin();
}
if (!loginUserInfo?.userId) {
init();
} else {
console.log('[LiveList]User already logged in:', loginUserInfo.userId);
}
}, [initLogin, loginUserInfo?.userId]);
return (
<UIKitProvider theme="dark" language='zh-CN'>
<div className={styles.livePlayerView}>
<div className={styles.livePlayerView__body}>
<LivePlayer />
</div>
</div>
</UIKitProvider>
);
};
export default LivePlayerView