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

635 lines
29 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, Space } 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';
import { getKeyOpenChildWindow } from '@/utils/package/public';
const fs = require('fs').promises;
const { exec } = require('child_process');
const StupWizard = forwardRef((props: any, ref: any) => {
useImperativeHandle(ref, () => ({
changeModal: (index: number = 0) => {
if (location.hash.indexOf('/meeting') === -1) {
agora.init()
}
setList((res: any) => {
res.forEach((item: any) => {
item.active = false
});
res[index].active = true;
return res
})
setIsStupWizard(true)
}
}))
const [list, setList] = useState([
{
title: '通用',
icon: ImageUrl.icon45,
iconActive: ImageUrl.icon45Active,
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={async () => {
if (location.hash.indexOf('/meeting') === -1) {
agora.release()
}
const isOpen = await getKeyOpenChildWindow('shareScreenWindow')
if (isOpen) {
window.electron.mainWindowHide()
}
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 { list } = res
setVideoDeviceManager({
list: list.map((row: any) => {
return {
value: row.deviceId,
label: row.deviceName
}
}),
item: setting.videoDeviceId,
})
if (setting.videoDeviceId && list.length) {
await agora.setVideoDeviceManager(setting.videoDeviceId)
await agora.startPreview('videoPreview', Number(userInfo.screenShareId))
}
})
}
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,
isAINoiseReduction: true,
aINoiseReduction: 1
});
const setting = JSON.parse(storage.getItem('setting') as string)
useEffect(() => {
getAudioMediaList()
agora.registerEventHandler({
onAudioVolumeIndication: (speakers: any) => {
const totalVolume = speakers.length ? speakers[0].volume : 0
const percentage = (totalVolume / 255) * 100
const dom = document.getElementById('deviceTest') as any;
if (dom) {
dom.style.width = `${percentage}%`
}
}
})
}, []);
const getAudioMediaList = async (): Promise<void> => {
const {
playBackList,
ecordingList,
ecordingVolume
} = await agora.getAudioMediaList();
if (!setting.ecordingVolume) {
setting.ecordingVolume = ecordingVolume;
}
if (!setting.playBackVolume) {
setting.playBackVolume = 127;
}
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,
ecordingItem: setting.ecordingDeviceId,
ecordingVolume: setting.ecordingVolume,
playBackVolume: setting.playBackVolume,
autoEcordingVolume: setting.autoEcordingVolume,
isAINoiseReduction: setting.isAINoiseReduction,
aINoiseReduction: setting.aINoiseReduction,
})
}
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>
<div>
<Checkbox checked={audioDeviceManager.isAINoiseReduction} onChange={(e) => {
setting.isAINoiseReduction = e.target.checked;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
isAINoiseReduction: e.target.checked
})
agora.setAINSMode(e.target.checked, audioDeviceManager.aINoiseReduction)
}}>
AI降噪
</Checkbox>
</div>
<div style={{ margin: '10px 0 0 20px' }}>
<Radio.Group onChange={(e) => {
setting.aINoiseReduction = e.target.value;
storage.setItem('setting', JSON.stringify(setting))
setAudioDeviceManager({
...audioDeviceManager,
aINoiseReduction: e.target.value
})
agora.setAINSMode(audioDeviceManager.isAINoiseReduction, e.target.value)
}} disabled={!audioDeviceManager.isAINoiseReduction} value={audioDeviceManager.aINoiseReduction}>
<Space direction="vertical">
<Radio value={0}></Radio>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
</Space>
</Radio.Group>
</div>
</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 [isRecordingTips, setIsRecordingTips] = useState(false)
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)
} else {
setFilePath(setting.recordingFilesPath);
}
if (setting.isRecordingTips === undefined) {
setting.isRecordingTips = true;
}
storage.setItem('setting', JSON.stringify(setting))
setIsRecordingTips(setting.isRecordingTips)
window.addEventListener('customStorageChange', handleCustomStorageChange);
return () => {
window.removeEventListener('customStorageChange', handleCustomStorageChange);
};
}, [])
const handleCustomStorageChange = (e: any): void => {
if (e.key === 'setting') {
const setting = JSON.parse(storage.getItem('setting') as string)
setFilePath(setting.recordingFilesPath)
}
};
return (
<>
<div>
<span></span>
<div className={styles.recordingComponents}>
<div>
<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>
<span></span>
<div>
<Checkbox onChange={async (e) => {
setting.isRecordingTips = e.target.checked;
storage.setItem('setting', JSON.stringify(setting))
setIsRecordingTips(e.target.checked)
}} checked={isRecordingTips}></Checkbox>
</div>
</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') {
const setting = JSON.parse(storage.getItem('setting') as string)
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