WGShare.Client.Electron/src/components/StupWizard/index.tsx

588 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import styles from '@/components/StupWizard/index.module.scss'
import ImageUrl from '@/utils/package/ImageUrl';
import {Button, Checkbox, Empty, Input, message, Modal, Popover, Radio, Select, Slider} from 'antd';
import {forwardRef, useEffect, useImperativeHandle, useState} from "react";
import agora from '@/utils/package/agora'
import {CloseOutlined, LoadingOutlined, QuestionCircleOutlined} from '@ant-design/icons';
import {storage} from '@/utils';
import path from 'path';
const fs = require('fs').promises;
const {exec} = require('child_process');
const StupWizard = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
changeModal: () => {
if (location.hash.indexOf('/meeting') === -1) {
agora.init()
}
setIsStupWizard(true)
}
}))
const [list, setList] = useState([
{
title: '通用',
icon: ImageUrl.icon39,
iconActive: ImageUrl.icon39Active,
active: true,
},
{
title: '视频',
icon: ImageUrl.icon39,
iconActive: ImageUrl.icon39Active,
active: false,
},
{
title: '音频',
icon: ImageUrl.icon40,
iconActive: ImageUrl.icon40Active,
active: false,
},
{
title: '录制',
icon: ImageUrl.icon41,
iconActive: ImageUrl.icon41Active,
active: false,
},
{
title: '共享文件',
icon: ImageUrl.icon42,
iconActive: ImageUrl.icon42Active,
active: false,
}
])
const [isStupWizard, setIsStupWizard] = useState(false);
return (
<>
<Modal
title=""
open={isStupWizard}
footer={null}
closable={false}
destroyOnClose={true}
centered
width={'70vw'}
className='modal-padding'>
<div className={styles.stupWizard}>
<div className={styles.stupWizardLeft}>
{list.map((row: any, index: number) => {
return (
<div key={index} className={`${row.active ? styles.active : ''}`} onClick={async () => {
const newList = [...list];
newList.forEach(item => item.active = false);
newList[index].active = true;
setList(newList)
agora.stopPlaybackDeviceTest()
agora.stopRecordingDeviceTest()
}}>
<img src={row.active ? row.iconActive : row.icon} alt=""/>
<span>{row.title}</span>
</div>
)
})}
</div>
<div className={styles.stupWizardRight}>
<CloseOutlined style={{
position: 'absolute',
color: 'white',
right: '20px',
top: '16px',
cursor: 'pointer'
}}
onClick={() => {
if (location.hash.indexOf('/meeting') === -1) {
agora.release()
}
setIsStupWizard(false)
}}
/>
{list[0].active ? <CurrencyComponents/> : null}
{list[1].active ? <VideoComponents/> : null}
{list[2].active ? <AudioComponents/> : null}
{list[3].active ? <RecordingComponents/> : null}
{list[4].active ? <FileComponents/> : null}
</div>
</div>
</Modal>
</>
)
})
const CurrencyComponents = () => {
const [optionsValue, setOperationValue] = useState<'hide' | 'quit'>('hide');
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
setOperationValue(setting.closeSetting)
}, []);
return (
<>
<div>
<span></span>
<div className={styles.currencyComponents}>
<div>
<div>
<span></span>
<Radio.Group onChange={(e: any) => {
setting.closeSetting = e.target.value;
storage.setItem('setting', JSON.stringify(setting))
setOperationValue(e.target.value)
}} style={{flexShrink: 0, margin: '10px 0'}} value={optionsValue}>
<Radio value={'quit'}>退</Radio>
<Radio value={'hide'}>退</Radio>
</Radio.Group>
</div>
</div>
</div>
</div>
</>
)
}
const VideoComponents = () => {
const [videoDeviceManager, setVideoDeviceManager] = useState<any>({
list: [],
item: null,
});
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
getVideoDeviceList()
}, []);
const getVideoDeviceList = async (): Promise<void> => {
const userInfo = JSON.parse(storage.getItem('user') as string)
agora.getVideoDeviceManager().then(async (res) => {
const {item, list} = res
if ((!setting.videoDeviceId && item) || (!(list.find((item: any) => item.deviceId === setting.videoDeviceId)) && item)) {
setting.videoDeviceId = item
}
if (!list.length) {
setting.videoDeviceId = ''
}
storage.setItem('setting', JSON.stringify(setting))
setVideoDeviceManager({
list: list.map((row: any) => {
return {
value: row.deviceId,
label: row.deviceName
}
}),
item: setting.videoDeviceId ? setting.videoDeviceId : item || null,
})
if (setting.videoDeviceId && list.length) {
await agora.setVideoDeviceManager(setting.videoDeviceId)
await agora.startPreview('videoPreview', Number(userInfo.account))
}
})
}
return (
<>
<div>
<span></span>
<div className={styles.videoComponents}>
{
videoDeviceManager.item ?
<div>
<div id='videoPreview'>
<LoadingOutlined style={{
position: 'absolute',
color: 'white',
right: '50%',
fontSize: '30px',
top: '50%',
}}/>
</div>
</div> :
<div>
<div style={{display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<Empty description={'未检测到摄像头'}/>
</div>
</div>
}
<div>
<span></span>
<Popover
content={
<span
style={{
color: 'white'
}}>
</span>
}
title=""
>
<QuestionCircleOutlined style={{
color: 'white',
cursor: 'pointer',
marginRight: '10px'
}}/>
</Popover>
<Select
placeholder={videoDeviceManager.list.length ? '请选择设备' : '未检测到摄像头'}
options={videoDeviceManager.list} style={{flexGrow: 1, marginRight: '10px'}}
value={videoDeviceManager.item} onChange={async (e) => {
setting.videoDeviceId = e;
storage.setItem('setting', JSON.stringify(setting))
setVideoDeviceManager({
...videoDeviceManager,
item: e
})
agora.setVideoDeviceManager(e)
}}/>
</div>
</div>
</div>
</>
)
}
const AudioComponents = () => {
const [audioDeviceManager, setAudioDeviceManager] = useState<any>({
playBackList: [],
ecordingList: [],
playBackItem: null,
ecordingItem: null,
playBackVolume: 0,
playBackActive: false,
ecordingActive: false,
ecordingVolume: 0,
autoEcordingVolume: true,
});
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
getAudioMediaList()
agora.registerEventHandler({
onAudioVolumeIndication: (percentage: number) => {
const dom = document.getElementById('deviceTest') as any;
if (dom) {
dom.style.width = `${percentage}%`
}
}
})
}, []);
const getAudioMediaList = async (): Promise<void> => {
const {
playBackList,
ecordingList,
playBackItem,
ecordingItem,
ecordingVolume
} = await agora.getAudioMediaList();
if ((!setting.ecordingDeviceId && ecordingItem.deviceId) || (!(ecordingList.find((item: any) => item.deviceId === setting.ecordingDeviceId)) && ecordingItem.deviceId)) {
setting.ecordingDeviceId = ecordingItem.deviceId
}
if ((!setting.playBackDeviceId && playBackItem.deviceId) || (!(playBackList.find((item: any) => item.deviceId === setting.playBackDeviceId)) && playBackItem.deviceId)) {
setting.playBackDeviceId = playBackItem.deviceId
}
if (!ecordingList.length) {
setting.ecordingDeviceId = ''
}
if (!playBackList.length) {
setting.playBackDeviceId = ''
}
if (!setting.ecordingVolume) {
setting.ecordingVolume = ecordingVolume;
}
if (!setting.playBackVolume) {
setting.playBackVolume = 127;
}
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
playBackList: playBackList.map((row: any) => {
return {
value: row.deviceId,
label: row.deviceName
}
}),
ecordingList: ecordingList.map((row: any) => {
return {
value: row.deviceId,
label: row.deviceName
}
}),
playBackItem: setting.playBackDeviceId ? setting.playBackDeviceId : playBackItem.deviceId || null,
ecordingItem: setting.ecordingDeviceId ? setting.ecordingDeviceId : ecordingItem.deviceId || null,
ecordingVolume: setting.ecordingVolume,
playBackVolume: setting.playBackVolume,
autoEcordingVolume: setting.autoEcordingVolume
})
}
return (
<>
<div>
<span></span>
<div className={styles.audioComponents}>
<div>
<div className={styles.audioComponentsSelect}>
<span></span>
<Select
placeholder={audioDeviceManager.ecordingList.length ? '请选择设备' : '未检测到麦克风'}
options={audioDeviceManager.ecordingList} style={{flexGrow: 1}}
value={audioDeviceManager.ecordingItem} onChange={async (e) => {
setting.ecordingDeviceId = e;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
ecordingItem: e
})
agora.setRecordingDevice(e)
}}/>;
{audioDeviceManager.ecordingActive ? <div onClick={() => {
agora.stopRecordingDeviceTest()
setAudioDeviceManager({
...audioDeviceManager,
playBackActive: false,
ecordingActive: false,
})
}}></div> : <div onClick={() => {
agora.stopPlaybackDeviceTest()
agora.startRecordingDeviceTest(100)
setAudioDeviceManager({
...audioDeviceManager,
playBackActive: false,
ecordingActive: true,
})
}}></div>}
</div>
{audioDeviceManager.ecordingActive ? <div className={styles.audioComponentsVolume}>
<img src={ImageUrl.icon36} alt=""/>
<div>
<img src={ImageUrl.icon34} alt=""/>
<div id='deviceTest'>
<img src={ImageUrl.icon35} alt=""/>
</div>
</div>
</div> : null}
<div className={styles.audioComponentsSlider}>
<span></span>
<Slider value={audioDeviceManager.ecordingVolume} style={{flexGrow: 1}} max={255}
onChange={async (e) => {
setting.ecordingVolume = e;
storage.setItem('setting', JSON.stringify(setting))
await agora.setRecordingDeviceVolume(e)
setAudioDeviceManager({
...audioDeviceManager,
ecordingVolume: e,
})
}} disabled={!audioDeviceManager.ecordingItem}/>
</div>
<div>
<Checkbox onChange={async (e) => {
setting.autoEcordingVolume = e.target.checked;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
autoEcordingVolume: e.target.checked
})
}} checked={audioDeviceManager.autoEcordingVolume}></Checkbox>
</div>
</div>
<div>
<div className={styles.audioComponentsSelect}>
<span></span>
<Select
placeholder={audioDeviceManager.playBackList.length ? '请选择设备' : '未检测到麦克风'}
options={audioDeviceManager.playBackList} style={{flexGrow: 1}}
value={audioDeviceManager.playBackItem} onChange={async (e) => {
setting.playBackDeviceId = e;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
playBackItem: e
})
agora.setPlaybackDevice(e)
}}/>;
{audioDeviceManager.playBackActive ? <div onClick={() => {
agora.stopPlaybackDeviceTest()
setAudioDeviceManager({
...audioDeviceManager,
playBackActive: false,
ecordingActive: false,
})
}}></div> : <div onClick={() => {
agora.stopRecordingDeviceTest()
agora.startPlaybackDeviceTest()
setAudioDeviceManager({
...audioDeviceManager,
playBackActive: true,
ecordingActive: false,
})
}}></div>}
</div>
{audioDeviceManager.playBackActive ? <div className={styles.audioComponentsVolume}>
<img src={ImageUrl.icon36} alt=""/>
<div>
<img src={ImageUrl.icon34} alt=""/>
<div id='deviceTest'>
<img src={ImageUrl.icon35} alt=""/>
</div>
</div>
</div> : null}
<div className={styles.audioComponentsSlider}>
<span></span>
<Slider value={audioDeviceManager.playBackVolume} style={{flexGrow: 1}} max={255}
onChange={async (e) => {
setting.playBackVolume = e;
storage.setItem('setting', JSON.stringify(setting))
agora.setPlaybackDeviceVolume(e)
setAudioDeviceManager({
...audioDeviceManager,
playBackVolume: e,
})
}} disabled={!audioDeviceManager.playBackItem}/>
</div>
</div>
</div>
</div>
</>
)
}
const RecordingComponents = () => {
const [filePath, setFilePath] = useState('')
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
if (!setting.recordingFilesPath) {
// 获取安装父目录
const currentDirectory = __dirname;
const parentDirectory = path.resolve(currentDirectory, '../../Downloads');
setting.recordingFilesPath = parentDirectory;
setFilePath(setting.recordingFilesPath)
storage.setItem('setting', JSON.stringify(setting))
} else {
setFilePath(setting.recordingFilesPath);
}
window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => {
window.removeEventListener('customStorageChange', handleCustomStorageChange);
};
}, [])
const handleCustomStorageChange = (e: any): void => {
if (e.key === 'setting') {
setFilePath(setting.recordingFilesPath)
}
};
return (
<>
<div>
<span></span>
<div className={styles.recordingComponents}>
<span></span>
<div>
<span></span>
<Input
disabled={true}
placeholder="请填入文件路径"
style={{margin: '0 14px', flexGrow: 1}}
value={filePath}
onChange={async (e) => {
setting.recordingFilesPath = e.target.value;
storage.setItem('setting', JSON.stringify(setting))
setFilePath(e.target.value)
}}
/>
<Button type="primary" onClick={() => {
window.electron.selectFilePath({
key: 'recordingFilesPath',
})
}} style={{backgroundColor: '#31353A', marginRight: '10px'}}></Button>
<Button type="primary" onClick={async () => {
try {
await fs.access(filePath, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${filePath}"`);
} else if (process.platform === 'darwin') {
exec(`open "${filePath}"`);
}
} catch (error: any) {
if (error.code === 'ENOENT') {
message.error('文件夹不存在!')
} else {
message.error(error)
}
}
}} style={{backgroundColor: '#31353A'}}></Button>
</div>
</div>
</div>
</>
)
}
const FileComponents = () => {
const [filePath, setFilePath] = useState('')
const [isShareSavePath, setIsShareSavePath] = useState(true)
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
if (!setting.shareFilesPath) {
// 获取安装父目录
const currentDirectory = __dirname;
const parentDirectory = path.resolve(currentDirectory, '../../Downloads');
setting.shareFilesPath = parentDirectory
setFilePath(setting.shareFilesPath)
storage.setItem('setting', JSON.stringify(setting))
} else {
setFilePath(setting.shareFilesPath);
}
setIsShareSavePath(setting.isShareSavePath)
window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => {
window.removeEventListener('customStorageChange', handleCustomStorageChange);
};
}, [])
const handleCustomStorageChange = (e: any): void => {
if (e.key === 'setting') {
setFilePath(setting.shareFilesPath)
}
};
return (
<>
<div>
<span></span>
<div className={styles.fileComponents}>
<span></span>
<div>
<span></span>
<Input
disabled={true}
placeholder="请填入保存目录"
style={{margin: '0 14px', flexGrow: 1}}
value={filePath}
onChange={async (e) => {
setting.shareFilesPath = e.target.value;
storage.setItem('setting', JSON.stringify(setting))
setFilePath(e.target.value)
}}
/>
<Button type="primary" onClick={() => {
window.electron.selectFilePath({
key: 'shareFilesPath',
})
}} style={{backgroundColor: '#31353A', marginRight: '10px'}}></Button>
<Button type="primary" onClick={async () => {
try {
await fs.access(filePath, fs.constants.F_OK);
if (process.platform === 'win32') {
exec(`explorer "${filePath}"`);
} else if (process.platform === 'darwin') {
exec(`open "${filePath}"`);
}
} catch (error: any) {
if (error.code === 'ENOENT') {
message.error('文件夹不存在!')
} else {
message.error(error)
}
}
}} style={{backgroundColor: '#31353A'}}></Button>
</div>
<div>
<Checkbox onChange={async (e) => {
setting.isShareSavePath = e.target.checked;
storage.setItem('setting', JSON.stringify(setting))
setIsShareSavePath(e.target.checked)
}} checked={isShareSavePath}></Checkbox>
</div>
</div>
</div>
</>
)
}
export default StupWizard