mirror of
https://github.com/pavlobu/deskreen.git
synced 2025-06-01 23:30:09 -07:00
Merge pull request #12 from pavlobu/client-ui
Client and Host UI improvements
This commit is contained in:
commit
6230424192
@ -12,12 +12,15 @@
|
|||||||
"@types/react": "^16.9.0",
|
"@types/react": "^16.9.0",
|
||||||
"@types/react-dom": "^16.9.0",
|
"@types/react-dom": "^16.9.0",
|
||||||
"@types/ua-parser-js": "^0.7.33",
|
"@types/ua-parser-js": "^0.7.33",
|
||||||
|
"i18next": "^19.8.4",
|
||||||
|
"i18next-http-backend": "^1.0.21",
|
||||||
"jest-sonar-reporter": "^2.0.0",
|
"jest-sonar-reporter": "^2.0.0",
|
||||||
"node-forge": "^0.9.1",
|
"node-forge": "^0.9.1",
|
||||||
"pixelmatch": "^5.2.1",
|
"pixelmatch": "^5.2.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-flexbox-grid": "^2.1.2",
|
"react-flexbox-grid": "^2.1.2",
|
||||||
|
"react-i18next": "^11.7.4",
|
||||||
"react-player": "^2.6.2",
|
"react-player": "^2.6.2",
|
||||||
"react-reveal": "^1.2.2",
|
"react-reveal": "^1.2.2",
|
||||||
"react-scripts": "3.4.3",
|
"react-scripts": "3.4.3",
|
||||||
|
4
app/client/public/locales/en/translation.json
Normal file
4
app/client/public/locales/en/translation.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Waiting for user to click ALLOW button on screen sharing device...": "Waiting for user to click ALLOW button on screen sharing device...",
|
||||||
|
"Wating for user to select source to share from screen sharing device...": "Wating for user to select source to share from screen sharing device..."
|
||||||
|
}
|
4
app/client/public/locales/ru/translation.json
Normal file
4
app/client/public/locales/ru/translation.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Waiting for user to click ALLOW button on screen sharing device...": "Жду когда пользователь нажмет кнопку РАЗРЕШИТЬ доступ к экрану компьютера...",
|
||||||
|
"Wating for user to select source to share from screen sharing device...": "Жду когда пользователь выберет весь экран или окно приложения для демонстрации..."
|
||||||
|
}
|
4
app/client/public/locales/ua/translation.json
Normal file
4
app/client/public/locales/ua/translation.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"Waiting for user to click ALLOW button on screen sharing device...": "Чекаэмо коли користувач натисне кнопку ДОЗВОЛИТИ доступ до екрану комп'ютера...",
|
||||||
|
"Wating for user to select source to share from screen sharing device...": "Чекаю коли користувач вибере весь екран або вікно програми для демонстрації..."
|
||||||
|
}
|
@ -1,12 +1,20 @@
|
|||||||
import React, { useEffect, useState, useRef, useContext } from 'react';
|
import React, {
|
||||||
import { H3, Button } from '@blueprintjs/core';
|
useEffect,
|
||||||
|
useState,
|
||||||
|
useRef,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
} from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import i18n from './config/i18n';
|
||||||
|
import { H3, Position, Toaster } from '@blueprintjs/core';
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid';
|
import { Grid, Row, Col } from 'react-flexbox-grid';
|
||||||
import { findDOMNode } from 'react-dom';
|
import { findDOMNode } from 'react-dom';
|
||||||
import ReactPlayer from 'react-player';
|
import ReactPlayer from 'react-player';
|
||||||
import screenfull from 'screenfull';
|
import screenfull from 'screenfull';
|
||||||
import Crypto from './utils/crypto';
|
import Crypto from './utils/crypto';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import LocalTestPeer from './features/PeerConnection';
|
import PeerConnection from './features/PeerConnection';
|
||||||
import VideoAutoQualityOptimizer from './features/VideoAutoQualityOptimizer';
|
import VideoAutoQualityOptimizer from './features/VideoAutoQualityOptimizer';
|
||||||
import ConnectingIndicator from './components/ConnectingIndicator';
|
import ConnectingIndicator from './components/ConnectingIndicator';
|
||||||
import MyDeviceInfoCard from './components/MyDeviceInfoCard';
|
import MyDeviceInfoCard from './components/MyDeviceInfoCard';
|
||||||
@ -15,24 +23,34 @@ import {
|
|||||||
LIGHT_UI_BACKGROUND,
|
LIGHT_UI_BACKGROUND,
|
||||||
} from './constants/styleConstants';
|
} from './constants/styleConstants';
|
||||||
import { AppContext } from './providers/AppContextProvider';
|
import { AppContext } from './providers/AppContextProvider';
|
||||||
import ToggleDarkModeSwitch from './components/ToggleDarkModeSwitch';
|
import PlayerControlPanel from './components/PlayerControlPanel';
|
||||||
|
import { VideoQuality } from './features/PeerConnection/VideoQualityEnum';
|
||||||
|
import { REACT_PLAYER_WRAPPER_ID } from './constants/appConstants';
|
||||||
|
import { TFunction } from 'i18next';
|
||||||
|
import ErrorDialog from './components/ErrorDialog';
|
||||||
|
import { ErrorMessage } from './components/ErrorDialog/ErrorMessageEnum';
|
||||||
|
|
||||||
const Fade = require('react-reveal/Fade');
|
const Fade = require('react-reveal/Fade');
|
||||||
const Slide = require('react-reveal/Slide');
|
const Slide = require('react-reveal/Slide');
|
||||||
|
|
||||||
function getPromptContent(step: number) {
|
function getPromptContent(step: number, t: TFunction) {
|
||||||
switch (step) {
|
switch (step) {
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
<H3>Waiting for user to click "Allow" on screen sharing device...</H3>
|
<H3>
|
||||||
|
{t(
|
||||||
|
'Waiting for user to click ALLOW button on screen sharing device...'
|
||||||
|
)}
|
||||||
|
</H3>
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
return <H3>Connected!</H3>;
|
return <H3>Connected!</H3>;
|
||||||
case 3:
|
case 3:
|
||||||
return (
|
return (
|
||||||
<H3>
|
<H3>
|
||||||
Wating for user to select source to share from screen sharing
|
{t(
|
||||||
device...
|
'Wating for user to select source to share from screen sharing device...'
|
||||||
|
)}
|
||||||
</H3>
|
</H3>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
@ -41,10 +59,23 @@ function getPromptContent(step: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { isDarkTheme, setIsDarkThemeHook } = useContext(AppContext);
|
const { isDarkTheme, setIsDarkThemeHook } = useContext(AppContext);
|
||||||
|
const [isErrorDialogOpen, setIsErrorDialogOpen] = useState(false);
|
||||||
|
|
||||||
|
const [toaster, setToaster] = useState<undefined | Toaster>();
|
||||||
|
|
||||||
|
const refHandlers = {
|
||||||
|
toaster: (ref: Toaster) => {
|
||||||
|
setToaster(ref);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const player = useRef(null);
|
const player = useRef(null);
|
||||||
const [promptStep, setPromptStep] = useState(1);
|
const [promptStep, setPromptStep] = useState(1);
|
||||||
|
const [dialogErrorMessage, setDialogErrorMessage] = useState<ErrorMessage>(
|
||||||
|
ErrorMessage.UNKNOWN_ERROR
|
||||||
|
);
|
||||||
const [connectionIconType, setConnectionIconType] = useState<
|
const [connectionIconType, setConnectionIconType] = useState<
|
||||||
'feed' | 'feed-subscribed'
|
'feed' | 'feed-subscribed'
|
||||||
>('feed');
|
>('feed');
|
||||||
@ -56,43 +87,73 @@ function App() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [playing, setPlaying] = useState(true);
|
const [playing, setPlaying] = useState(true);
|
||||||
|
const [isFullScreenOn, setIsFullScreenOn] = useState(false);
|
||||||
const [url, setUrl] = useState();
|
const [url, setUrl] = useState();
|
||||||
|
const [screenSharingSourceType, setScreenSharingSourceType] = useState<
|
||||||
|
'screen' | 'window'
|
||||||
|
>('screen');
|
||||||
const [isWithControls, setIsWithControls] = useState(!screenfull.isEnabled);
|
const [isWithControls, setIsWithControls] = useState(!screenfull.isEnabled);
|
||||||
const [isShownTextPrompt, setIsShownTextPrompt] = useState(false);
|
const [isShownTextPrompt, setIsShownTextPrompt] = useState(false);
|
||||||
const [isShownSpinnerIcon, setIsShownSpinnerIcon] = useState(false);
|
const [isShownSpinnerIcon, setIsShownSpinnerIcon] = useState(false);
|
||||||
const [spinnerIconType, setSpinnerIconType] = useState<
|
const [spinnerIconType, setSpinnerIconType] = useState<
|
||||||
'desktop' | 'application'
|
'desktop' | 'application'
|
||||||
>('desktop');
|
>('desktop');
|
||||||
|
const [videoQuality, setVideoQuality] = useState<VideoQuality>(
|
||||||
|
VideoQuality.Q_AUTO
|
||||||
|
);
|
||||||
|
const [peer, setPeer] = useState<undefined | PeerConnection>();
|
||||||
|
|
||||||
|
const changeLanguage = (lng: string) => {
|
||||||
|
i18n.changeLanguage(lng);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!peer) return;
|
||||||
|
if (!peer.isStreamStarted) return;
|
||||||
|
peer.setVideoQuality(videoQuality);
|
||||||
|
}, [videoQuality, peer]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.style.backgroundColor = isDarkTheme
|
document.body.style.backgroundColor = isDarkTheme
|
||||||
? DARK_UI_BACKGROUND
|
? DARK_UI_BACKGROUND
|
||||||
: LIGHT_UI_BACKGROUND;
|
: LIGHT_UI_BACKGROUND;
|
||||||
|
}, [isDarkTheme]);
|
||||||
|
|
||||||
const peer = new LocalTestPeer(
|
useEffect(() => {
|
||||||
setUrl,
|
if (!peer) {
|
||||||
new Crypto(),
|
const _peer = new PeerConnection(
|
||||||
new VideoAutoQualityOptimizer(),
|
setUrl,
|
||||||
setMyDeviceDetails,
|
new Crypto(),
|
||||||
() => {
|
new VideoAutoQualityOptimizer(),
|
||||||
setConnectionIconType('feed-subscribed');
|
isDarkTheme,
|
||||||
|
setMyDeviceDetails,
|
||||||
|
() => {
|
||||||
|
setConnectionIconType('feed-subscribed');
|
||||||
|
|
||||||
setIsShownTextPrompt(false);
|
|
||||||
setIsShownTextPrompt(true);
|
|
||||||
setPromptStep(2);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setIsShownTextPrompt(false);
|
setIsShownTextPrompt(false);
|
||||||
setIsShownTextPrompt(true);
|
setIsShownTextPrompt(true);
|
||||||
setPromptStep(3);
|
setPromptStep(2);
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setIsShownTextPrompt(true);
|
setIsShownTextPrompt(false);
|
||||||
}, 100);
|
setIsShownTextPrompt(true);
|
||||||
}, []);
|
setPromptStep(3);
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
setScreenSharingSourceType,
|
||||||
|
setIsDarkThemeHook,
|
||||||
|
changeLanguage,
|
||||||
|
setDialogErrorMessage,
|
||||||
|
setIsErrorDialogOpen
|
||||||
|
);
|
||||||
|
|
||||||
|
setPeer(_peer);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsShownTextPrompt(true);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}, [setIsDarkThemeHook, isDarkTheme, peer]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// infinite use effect
|
// infinite use effect
|
||||||
@ -102,22 +163,11 @@ function App() {
|
|||||||
spinnerIconType === 'desktop' ? 'application' : 'desktop'
|
spinnerIconType === 'desktop' ? 'application' : 'desktop'
|
||||||
);
|
);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}, [isShownSpinnerIcon]);
|
}, [isShownSpinnerIcon, spinnerIconType]);
|
||||||
|
|
||||||
const handleClickFullscreen = () => {
|
const handlePlayPause = useCallback(() => {
|
||||||
// @ts-ignore Property 'request' does not exist on type '{ isEnabled: false; }'.
|
|
||||||
screenfull.request(findDOMNode(player.current));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePlayPause = () => {
|
|
||||||
setPlaying(!playing);
|
setPlaying(!playing);
|
||||||
};
|
}, [playing]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.body.style.backgroundColor = isDarkTheme
|
|
||||||
? DARK_UI_BACKGROUND
|
|
||||||
: LIGHT_UI_BACKGROUND;
|
|
||||||
}, [isDarkTheme]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (url !== undefined) {
|
if (url !== undefined) {
|
||||||
@ -157,7 +207,6 @@ function App() {
|
|||||||
: LIGHT_UI_BACKGROUND,
|
: LIGHT_UI_BACKGROUND,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ToggleDarkModeSwitch />
|
|
||||||
<Row
|
<Row
|
||||||
bottom="xs"
|
bottom="xs"
|
||||||
style={{
|
style={{
|
||||||
@ -189,7 +238,7 @@ function App() {
|
|||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
<div id="prompt-text" style={{ fontSize: '20px' }}>
|
<div id="prompt-text" style={{ fontSize: '20px' }}>
|
||||||
{getPromptContent(promptStep)}
|
{getPromptContent(promptStep, t)}
|
||||||
</div>
|
</div>
|
||||||
</Fade>
|
</Fade>
|
||||||
</div>
|
</div>
|
||||||
@ -221,22 +270,22 @@ function App() {
|
|||||||
height: '100vh',
|
height: '100vh',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<PlayerControlPanel
|
||||||
onClick={() => setIsWithControls(true)}
|
onSwitchChangedCallback={(isEnabled) => setIsWithControls(isEnabled)}
|
||||||
onTouchStart={() => setIsWithControls(true)}
|
isDefaultPlayerTurnedOn={isWithControls}
|
||||||
>
|
handleClickFullscreen={() => {
|
||||||
Help! I'm having troubles to zoom in on my device
|
if (!screenfull.isEnabled) return;
|
||||||
</Button>
|
// @ts-ignore Property 'request' does not exist on type '{ isEnabled: false; }'.
|
||||||
<Button onClick={handlePlayPause} onTouchStart={handlePlayPause}>
|
screenfull.request(findDOMNode(player.current));
|
||||||
PLAY!
|
setIsFullScreenOn(!isFullScreenOn);
|
||||||
</Button>
|
}}
|
||||||
<Button
|
handleClickPlayPause={handlePlayPause}
|
||||||
onClick={handleClickFullscreen}
|
isPlaying={playing}
|
||||||
onTouchStart={handleClickFullscreen}
|
setVideoQuality={setVideoQuality}
|
||||||
>
|
selectedVideoQuality={videoQuality}
|
||||||
ENTER FULL SCREEN
|
screenSharingSourceType={screenSharingSourceType}
|
||||||
</Button>
|
toaster={toaster}
|
||||||
<ToggleDarkModeSwitch />
|
/>
|
||||||
<div
|
<div
|
||||||
id="video-container"
|
id="video-container"
|
||||||
style={{
|
style={{
|
||||||
@ -245,6 +294,7 @@ function App() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
id="player-wrapper-id"
|
||||||
className="player-wrapper"
|
className="player-wrapper"
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@ -253,19 +303,12 @@ function App() {
|
|||||||
>
|
>
|
||||||
<ReactPlayer
|
<ReactPlayer
|
||||||
ref={player}
|
ref={player}
|
||||||
id="video-local-test-peer-sees"
|
id={REACT_PLAYER_WRAPPER_ID}
|
||||||
playing={playing}
|
playing={playing}
|
||||||
playsinline={true}
|
playsinline={true}
|
||||||
controls={isWithControls}
|
controls={isWithControls}
|
||||||
muted={true}
|
muted={true}
|
||||||
// url={mergedStream}
|
|
||||||
url={(url as unknown) as MediaStream}
|
url={(url as unknown) as MediaStream}
|
||||||
// width={url.getVideoTracks()[0].getSettings().width}
|
|
||||||
// height={url.getVideoTracks()[0].getSettings().height}
|
|
||||||
// onPlay={setProperCanvasWidth}
|
|
||||||
// wrapper="div"
|
|
||||||
// width={window.screen.width}
|
|
||||||
// height={window.screen.height}
|
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
style={{
|
style={{
|
||||||
@ -278,6 +321,11 @@ function App() {
|
|||||||
<canvas id="comparison-canvas" style={{ display: 'none' }}></canvas>
|
<canvas id="comparison-canvas" style={{ display: 'none' }}></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Toaster ref={refHandlers.toaster} position={Position.TOP_LEFT} />
|
||||||
|
<ErrorDialog
|
||||||
|
errorMessage={dialogErrorMessage}
|
||||||
|
isOpen={isErrorDialogOpen}
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
export enum ErrorMessage {
|
||||||
|
UNKNOWN_ERROR = 'An unknonw error uccured.',
|
||||||
|
DENY_TO_CONNECT = 'You were not allowed to connect.',
|
||||||
|
DICONNECTED = 'You were disconnected.',
|
||||||
|
NOT_ALLOWED = 'You were not allowed to connect.',
|
||||||
|
}
|
3
app/client/src/components/ErrorDialog/index.css
Normal file
3
app/client/src/components/ErrorDialog/index.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.error-dialog-backdrop {
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
70
app/client/src/components/ErrorDialog/index.tsx
Normal file
70
app/client/src/components/ErrorDialog/index.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Classes,
|
||||||
|
Dialog,
|
||||||
|
Divider,
|
||||||
|
H1,
|
||||||
|
H2,
|
||||||
|
H3,
|
||||||
|
Icon,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { Col, Row } from 'react-flexbox-grid';
|
||||||
|
import './index.css';
|
||||||
|
import { ErrorMessage } from './ErrorMessageEnum';
|
||||||
|
|
||||||
|
interface ErrorDialogProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
errorMessage: ErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErrorDialog(props: ErrorDialogProps) {
|
||||||
|
const { errorMessage, isOpen } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
className="error-dialog"
|
||||||
|
autoFocus
|
||||||
|
canEscapeKeyClose
|
||||||
|
canOutsideClickClose
|
||||||
|
enforceFocus
|
||||||
|
isOpen={isOpen}
|
||||||
|
usePortal
|
||||||
|
style={{
|
||||||
|
width: '90%',
|
||||||
|
maxWidth: '1200px',
|
||||||
|
}}
|
||||||
|
backdropClassName="error-dialog-backdrop"
|
||||||
|
>
|
||||||
|
<Row center="xs" style={{ marginTop: '10px' }}>
|
||||||
|
<Col xs={12}>
|
||||||
|
<H3 className={Classes.TEXT_MUTED}>Descreen Error Dialog</H3>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row middle="xs" center="xs" style={{ padding: '20px', width: '100%' }}>
|
||||||
|
<Col xs={12} md={10} lg={6}>
|
||||||
|
<Row middle="xs" center="xs">
|
||||||
|
<Col xs={1}>
|
||||||
|
<Icon icon="error" iconSize={52} color="#8A9BA8" />
|
||||||
|
</Col>
|
||||||
|
<Col xs={11}>
|
||||||
|
<H1
|
||||||
|
className={Classes.TEXT_DISABLED}
|
||||||
|
style={{ marginBottom: '0px' }}
|
||||||
|
>
|
||||||
|
Something wrong happened :(
|
||||||
|
</H1>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider />
|
||||||
|
<div className={Classes.DIALOG_BODY}>
|
||||||
|
<H3 className={Classes.TEXT_MUTED}>{errorMessage}</H3>
|
||||||
|
<Divider />
|
||||||
|
<H2>You may close this browser window then try to connect again.</H2>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorDialog;
|
@ -1,9 +1,10 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Callout, Card, H3, Text, Tooltip, Position } from '@blueprintjs/core';
|
import { Callout, Card, H3, Text, Tooltip, Position } from '@blueprintjs/core';
|
||||||
import { AppContext } from '../../providers/AppContextProvider';
|
import { AppContext } from '../../providers/AppContextProvider';
|
||||||
|
import {
|
||||||
const LIGHT_UI_BACKGROUND = 'rgba(240, 248, 250, 1)';
|
DARK_UI_BACKGROUND,
|
||||||
const DARK_UI_BACKGROUND = '#293742';
|
LIGHT_UI_BACKGROUND,
|
||||||
|
} from '../../constants/styleConstants';
|
||||||
|
|
||||||
interface MyDeviceDetailsCardProps {
|
interface MyDeviceDetailsCardProps {
|
||||||
deviceDetails: DeviceDetails;
|
deviceDetails: DeviceDetails;
|
||||||
@ -27,10 +28,18 @@ function MyDeviceInfoCard(props: MyDeviceDetailsCardProps) {
|
|||||||
<Callout>
|
<Callout>
|
||||||
<Text>Device Type: {myDeviceType}</Text>
|
<Text>Device Type: {myDeviceType}</Text>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content="This should match with 'Device IP' in alert displayed on your computer, where Deskreen is running."
|
content="This should match with 'Device IP' in alert popup appeared on your computer, where Deskreen is running."
|
||||||
position={Position.TOP}
|
position={Position.TOP}
|
||||||
>
|
>
|
||||||
<div style={{ fontWeight: 900, backgroundColor: '#00f99273' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
fontWeight: 900,
|
||||||
|
backgroundColor: '#00f99273',
|
||||||
|
paddingLeft: '10px',
|
||||||
|
paddingRight: '10px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Text>Device IP: {myIP}</Text>
|
<Text>Device IP: {myIP}</Text>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -38,8 +47,8 @@ function MyDeviceInfoCard(props: MyDeviceDetailsCardProps) {
|
|||||||
<Text>Device OS: {myOS}</Text>
|
<Text>Device OS: {myOS}</Text>
|
||||||
</Callout>
|
</Callout>
|
||||||
<Text className="bp3-text-muted">
|
<Text className="bp3-text-muted">
|
||||||
These details should match with the ones that you see in alert on
|
These details should match with the ones that you see in alert popup on
|
||||||
sharing device.
|
screen sharing device.
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
326
app/client/src/components/PlayerControlPanel/index.tsx
Normal file
326
app/client/src/components/PlayerControlPanel/index.tsx
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
useCallback,
|
||||||
|
} from 'react';
|
||||||
|
import {
|
||||||
|
Alignment,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
H5,
|
||||||
|
Switch,
|
||||||
|
Divider,
|
||||||
|
Text,
|
||||||
|
Icon,
|
||||||
|
Tooltip,
|
||||||
|
Position,
|
||||||
|
Popover,
|
||||||
|
Classes,
|
||||||
|
Toaster,
|
||||||
|
Intent,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import FullScreenEnter from '../../images/fullscreen_24px.svg';
|
||||||
|
import FullScreenExit from '../../images/fullscreen_exit-24px.svg';
|
||||||
|
import DeskreenIconPNG from '../../images/deskreen_logo_128x128.png';
|
||||||
|
import RedHeartTwemojiPNG from '../../images/red_heart_2764_twemoji_120x120.png';
|
||||||
|
import { Col, Row } from 'react-flexbox-grid';
|
||||||
|
import screenfull from 'screenfull';
|
||||||
|
import { VideoQuality } from '../../features/PeerConnection/VideoQualityEnum';
|
||||||
|
import { REACT_PLAYER_WRAPPER_ID } from '../../constants/appConstants';
|
||||||
|
|
||||||
|
const videoQualityButtonStyle: React.CSSProperties = {
|
||||||
|
width: '100%',
|
||||||
|
textAlign: 'center',
|
||||||
|
};
|
||||||
|
|
||||||
|
interface PlayerControlPanelProps {
|
||||||
|
onSwitchChangedCallback: (isEnabled: boolean) => void;
|
||||||
|
isPlaying: boolean;
|
||||||
|
isDefaultPlayerTurnedOn: boolean;
|
||||||
|
handleClickFullscreen: () => void;
|
||||||
|
handleClickPlayPause: () => void;
|
||||||
|
setVideoQuality: (q: VideoQuality) => void;
|
||||||
|
selectedVideoQuality: VideoQuality;
|
||||||
|
screenSharingSourceType: 'screen' | 'window';
|
||||||
|
toaster: undefined | Toaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PlayerControlPanel(props: PlayerControlPanelProps) {
|
||||||
|
|
||||||
|
const {
|
||||||
|
isPlaying,
|
||||||
|
onSwitchChangedCallback,
|
||||||
|
isDefaultPlayerTurnedOn,
|
||||||
|
handleClickPlayPause,
|
||||||
|
handleClickFullscreen,
|
||||||
|
selectedVideoQuality,
|
||||||
|
setVideoQuality,
|
||||||
|
screenSharingSourceType,
|
||||||
|
toaster,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const isFullScreenAPIAvailable = useMemo(() => screenfull.isEnabled, []);
|
||||||
|
|
||||||
|
const [isFullScreenOn, setIsFullScreenOn] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!screenfull.isEnabled) return;
|
||||||
|
// @ts-ignore
|
||||||
|
screenfull.on('change', () => {
|
||||||
|
// @ts-ignore
|
||||||
|
setIsFullScreenOn(screenfull.isFullscreen);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClickFullscreenWhenDefaultPlayerIsOn = useCallback(() => {
|
||||||
|
const player = document.querySelector(
|
||||||
|
`#${REACT_PLAYER_WRAPPER_ID} > video`
|
||||||
|
);
|
||||||
|
if (!player) return;
|
||||||
|
// @ts-ignore
|
||||||
|
if (player.requestFullScreen) {
|
||||||
|
// @ts-ignore
|
||||||
|
player.requestFullScreen();
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (player.webkitRequestFullScreen) {
|
||||||
|
// @ts-ignore
|
||||||
|
player.webkitRequestFullScreen();
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (player.mozRequestFullScreen) {
|
||||||
|
// @ts-ignore
|
||||||
|
player.mozRequestFullScreen();
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (player.msRequestFullscreen) {
|
||||||
|
// @ts-ignore
|
||||||
|
player.msRequestFullscreen();
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (player.webkitEnterFullscreen) {
|
||||||
|
// @ts-ignore
|
||||||
|
player.webkitEnterFullscreen(); //for iphone this code worked
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card elevation={4}>
|
||||||
|
<Row between="xs" middle="xs">
|
||||||
|
<Col xs={12} md={3}>
|
||||||
|
<Tooltip
|
||||||
|
content="Click to visit our website"
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button minimal>
|
||||||
|
<Row middle="xs" style={{ opacity: '0.75' }}>
|
||||||
|
<Col xs={4}>
|
||||||
|
<img src={DeskreenIconPNG} width={42} height={42} alt="logo" />
|
||||||
|
</Col>
|
||||||
|
<Col xs={8}>
|
||||||
|
<H5 style={{ marginBottom: '0px' }}>Deskreen</H5>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
content="If you like Deskreen, consider donating! Deskreen is free and opensource forever! You can help us to make Deskreen even better!"
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button>
|
||||||
|
<Row start="xs">
|
||||||
|
<Col xs>
|
||||||
|
<img
|
||||||
|
src={RedHeartTwemojiPNG}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
style={{ transform: 'translateY(2px)' }}
|
||||||
|
alt="heart"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col xs>
|
||||||
|
<div
|
||||||
|
style={{ transform: 'translateY(2px) translateX(-5px)' }}
|
||||||
|
>
|
||||||
|
<Text>Donate!</Text>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col xs={12} md={6}>
|
||||||
|
<Row center="xs" style={{ height: '42px' }}>
|
||||||
|
<Row
|
||||||
|
center="xs"
|
||||||
|
middle="xs"
|
||||||
|
style={{
|
||||||
|
borderRadius: '20px',
|
||||||
|
backgroundColor: '#137CBD',
|
||||||
|
width: '190px',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row style={{ width: '100%' }} middle="xs" center="xs">
|
||||||
|
<Button
|
||||||
|
minimal
|
||||||
|
onClick={() => {
|
||||||
|
handleClickPlayPause();
|
||||||
|
toaster?.show({
|
||||||
|
icon: isPlaying ? 'pause' : 'play',
|
||||||
|
intent: Intent.PRIMARY,
|
||||||
|
message: isPlaying
|
||||||
|
? 'Video stream is paused.'
|
||||||
|
: 'Video stream is playing',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: '85px',
|
||||||
|
minWidth: '70px',
|
||||||
|
color: 'white',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row>
|
||||||
|
<Col xs>
|
||||||
|
<Icon
|
||||||
|
icon={isPlaying ? 'pause' : 'play'}
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col xs>
|
||||||
|
<Text className="bp3-text-large">
|
||||||
|
{isPlaying ? 'Pause' : 'Play'}
|
||||||
|
</Text>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Button>
|
||||||
|
<Divider
|
||||||
|
style={{
|
||||||
|
height: '20px',
|
||||||
|
borderRight: '1px solid #ffffffa8',
|
||||||
|
borderBottom: '1px solid #ffffffa8',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{screenSharingSourceType === 'window' ? (
|
||||||
|
<Tooltip
|
||||||
|
content="You can't change video quality when sharing a window. You can change quality only when shering entire screen."
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button minimal disabled>
|
||||||
|
<Icon icon="cog" color="#A7B6C2" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<Popover
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
<H5>Video Quality:</H5>
|
||||||
|
<Divider />
|
||||||
|
{Object.values(VideoQuality).map(
|
||||||
|
(q: VideoQuality) => {
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Button
|
||||||
|
minimal
|
||||||
|
active={selectedVideoQuality === q}
|
||||||
|
style={videoQualityButtonStyle}
|
||||||
|
onClick={() => {
|
||||||
|
setVideoQuality(q);
|
||||||
|
toaster?.show({
|
||||||
|
icon: 'clean',
|
||||||
|
intent: Intent.PRIMARY,
|
||||||
|
message: `Video quality has been changed to ${q}`,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{q}
|
||||||
|
</Button>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
popoverClassName={Classes.POPOVER_CONTENT_SIZING}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
content="Video Quality"
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button minimal>
|
||||||
|
<Icon icon="cog" color="white" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
<Divider
|
||||||
|
style={{
|
||||||
|
height: '20px',
|
||||||
|
borderRight: '1px solid #ffffffa8',
|
||||||
|
borderBottom: '1px solid #ffffffa8',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
content="Enter Full Screen Mode"
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
minimal
|
||||||
|
onClick={() => {
|
||||||
|
if (isDefaultPlayerTurnedOn) {
|
||||||
|
handleClickFullscreenWhenDefaultPlayerIsOn();
|
||||||
|
} else {
|
||||||
|
handleClickFullscreen();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={isFullScreenOn ? FullScreenExit : FullScreenEnter}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
style={{
|
||||||
|
transform: 'scale(1.5) translateY(1px)',
|
||||||
|
filter:
|
||||||
|
'invert(100%) sepia(100%) saturate(0%) hue-rotate(127deg) brightness(107%) contrast(102%)',
|
||||||
|
}}
|
||||||
|
alt="fullscreen-toggle"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
<Col xs={12} md={3}>
|
||||||
|
<Row end="xs">
|
||||||
|
<Col xs={12}>
|
||||||
|
<Switch
|
||||||
|
onChange={() => {
|
||||||
|
onSwitchChangedCallback(!isDefaultPlayerTurnedOn);
|
||||||
|
toaster?.show({
|
||||||
|
icon: 'video',
|
||||||
|
intent: Intent.PRIMARY,
|
||||||
|
message: `Default video player has been turned ${
|
||||||
|
isDefaultPlayerTurnedOn ? 'OFF' : 'ON'
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
innerLabel={isDefaultPlayerTurnedOn ? 'ON' : 'OFF'}
|
||||||
|
inline
|
||||||
|
label={`Default Video Player`}
|
||||||
|
alignIndicator={Alignment.RIGHT}
|
||||||
|
checked={isDefaultPlayerTurnedOn}
|
||||||
|
disabled={!isFullScreenAPIAvailable}
|
||||||
|
style={{
|
||||||
|
marginBottom: '0px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlayerControlPanel;
|
@ -1,12 +1,10 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Icon, Text, Switch, Classes, Alignment } from '@blueprintjs/core';
|
import { Switch, Classes, Alignment } from '@blueprintjs/core';
|
||||||
import { Row, Col } from 'react-flexbox-grid';
|
|
||||||
import { AppContext } from '../../providers/AppContextProvider';
|
import { AppContext } from '../../providers/AppContextProvider';
|
||||||
|
|
||||||
function ToggleDarkModeSwitch() {
|
function ToggleDarkModeSwitch() {
|
||||||
const { isDarkTheme, setIsDarkThemeHook } = useContext(AppContext)
|
const { isDarkTheme, setIsDarkThemeHook } = useContext(AppContext)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch
|
<Switch
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
|
43
app/client/src/config/i18n.ts
Normal file
43
app/client/src/config/i18n.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
import Backend from 'i18next-http-backend';
|
||||||
|
|
||||||
|
// don't want to use this?
|
||||||
|
// have a look at the Quick start guide
|
||||||
|
// for passing in lng and translations on init
|
||||||
|
|
||||||
|
i18n
|
||||||
|
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
|
||||||
|
// learn more: https://github.com/i18next/i18next-http-backend
|
||||||
|
.use(Backend)
|
||||||
|
// pass the i18n instance to react-i18next.
|
||||||
|
.use(initReactI18next)
|
||||||
|
// init i18next
|
||||||
|
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||||
|
.init({
|
||||||
|
// fallbackLng: 'ua',
|
||||||
|
lng: 'en',
|
||||||
|
saveMissing: true,
|
||||||
|
saveMissingTo: 'all',
|
||||||
|
fallbackLng: 'en', // TODO: to generate missing keys use false as value here, will be useful when custom nodejs server is created to store missing values
|
||||||
|
debug: true, // change to true to see debug message logs in browser console
|
||||||
|
whitelist: ['en', 'ru', 'ua'],
|
||||||
|
|
||||||
|
backend: {
|
||||||
|
// path where resources get loaded from
|
||||||
|
loadPath: '/locales/{{lng}}/{{ns}}.json',
|
||||||
|
// TODO: in future implement custom nodejs server that accepts missing translations POST requests and updates .missing.json files accordingly. Here is how to do so: https://www.robinwieruch.de/react-internationalization . it can be simple nodejs server that can be started when 'yarn dev' is running, need to ckagne package.json file then
|
||||||
|
// path to post missing resources
|
||||||
|
addPath: '/locales/{{lng}}/{{ns}}.json',
|
||||||
|
// jsonIndent to use when storing json files
|
||||||
|
jsonIndent: 2,
|
||||||
|
},
|
||||||
|
|
||||||
|
keySeparator: false, // we do not use keys in form messages.welcome
|
||||||
|
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false, // react already safes from xss
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
8
app/client/src/constants/appConstants.ts
Normal file
8
app/client/src/constants/appConstants.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export const REACT_PLAYER_WRAPPER_ID = 'react-player-wrapper-id';
|
||||||
|
export const VIDEO_QUALITY_TO_DECIMAL = {
|
||||||
|
'25%': 0.25, // Q_25_PERCENT
|
||||||
|
'40%': 0.40, // Q_40_PERCENT
|
||||||
|
'60%': 0.60, // Q_60_PERCENT
|
||||||
|
'80%': 0.80, // Q_80_PERCENT
|
||||||
|
'100%': 1, // Q_100_PERCENT
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
export enum VideoQuality {
|
||||||
|
Q_AUTO = 'Auto',
|
||||||
|
Q_25_PERCENT = '25%',
|
||||||
|
Q_40_PERCENT = '40%',
|
||||||
|
Q_60_PERCENT = '60%',
|
||||||
|
Q_80_PERCENT = '80%',
|
||||||
|
Q_100_PERCENT = '100%',
|
||||||
|
}
|
@ -10,7 +10,16 @@ import {
|
|||||||
import setSdpMediaBitrate from './setSdpMediaBitrate';
|
import setSdpMediaBitrate from './setSdpMediaBitrate';
|
||||||
import Crypto from '../../utils/crypto';
|
import Crypto from '../../utils/crypto';
|
||||||
import VideoAutoQualityOptimizer from '../VideoAutoQualityOptimizer';
|
import VideoAutoQualityOptimizer from '../VideoAutoQualityOptimizer';
|
||||||
import { getBrowserFromUAParser, getDeviceTypeFromUAParser, getOSFromUAParser } from '../../utils/userAgentParserHelpers';
|
import {
|
||||||
|
getBrowserFromUAParser,
|
||||||
|
getDeviceTypeFromUAParser,
|
||||||
|
getOSFromUAParser,
|
||||||
|
} from '../../utils/userAgentParserHelpers';
|
||||||
|
import { VideoQuality } from './VideoQualityEnum';
|
||||||
|
import prepareDataMessageToChangeQuality from './prepareDataMessageToChangeQuality';
|
||||||
|
import { VIDEO_QUALITY_TO_DECIMAL } from './../../constants/appConstants';
|
||||||
|
import prepareDataMessageToGetSharingSourceType from './prepareDataMessageToGetSharingSourceType';
|
||||||
|
import { ErrorMessage } from '../../components/ErrorDialog/ErrorMessageEnum';
|
||||||
|
|
||||||
interface LocalPeerUser {
|
interface LocalPeerUser {
|
||||||
username: string;
|
username: string;
|
||||||
@ -37,7 +46,7 @@ interface ReceiveEncryptedMessagePayload {
|
|||||||
keys: { sessionKey: string; signingKey: string }[];
|
keys: { sessionKey: string; signingKey: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class LocalTestPeer {
|
export default class PeerConnection {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
|
||||||
socket: any;
|
socket: any;
|
||||||
@ -48,7 +57,7 @@ export default class LocalTestPeer {
|
|||||||
|
|
||||||
partner: PartnerPeerUser = nullUser;
|
partner: PartnerPeerUser = nullUser;
|
||||||
|
|
||||||
peer: any;
|
peer: null | SimplePeer.Instance = null;
|
||||||
|
|
||||||
myIP = '';
|
myIP = '';
|
||||||
|
|
||||||
@ -72,24 +81,49 @@ export default class LocalTestPeer {
|
|||||||
|
|
||||||
largeMismatchFramesCount: number;
|
largeMismatchFramesCount: number;
|
||||||
|
|
||||||
isRequestedHalfQuality: boolean;
|
screenSharingSourceType: string | undefined = undefined;
|
||||||
|
|
||||||
|
videoQuality = VideoQuality.Q_AUTO;
|
||||||
|
|
||||||
videoAutoQualityOptimizer: VideoAutoQualityOptimizer;
|
videoAutoQualityOptimizer: VideoAutoQualityOptimizer;
|
||||||
|
|
||||||
|
isDarkTheme: boolean;
|
||||||
|
|
||||||
|
isStreamStarted: boolean = false;
|
||||||
|
|
||||||
setMyDeviceDetails: (details: DeviceDetails) => void;
|
setMyDeviceDetails: (details: DeviceDetails) => void;
|
||||||
|
|
||||||
hostAllowedToConnectCallback: () => void;
|
hostAllowedToConnectCallback: () => void;
|
||||||
|
|
||||||
|
setScreenSharingSourceTypeCallback: (s: 'screen' | 'window') => void;
|
||||||
|
|
||||||
|
setIsDarkThemeCallback: (val: boolean) => void;
|
||||||
|
|
||||||
|
setAppLanguageCallback: (newLang: string) => void;
|
||||||
|
|
||||||
|
setDialogErrorMessageCallback: (message: ErrorMessage) => void;
|
||||||
|
|
||||||
|
setIsErrorDialogOpen: (val: boolean) => void;
|
||||||
|
|
||||||
|
errorDialogMessage = ErrorMessage.UNKNOWN_ERROR;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
setUrlCallback: any,
|
setUrlCallback: any,
|
||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
videoAutoQualityOptimizer: VideoAutoQualityOptimizer,
|
videoAutoQualityOptimizer: VideoAutoQualityOptimizer,
|
||||||
|
isDarkTheme: boolean,
|
||||||
setMyDeviceDetailsCallback: (details: DeviceDetails) => void,
|
setMyDeviceDetailsCallback: (details: DeviceDetails) => void,
|
||||||
hostAllowedToConnectCallback: () => void
|
hostAllowedToConnectCallback: () => void,
|
||||||
|
setScreenSharingSourceTypeCallback: (s: 'screen' | 'window') => void,
|
||||||
|
setIsDarkThemeCallback: (val: boolean) => void,
|
||||||
|
setAppLanguageCallback: (newLang: string) => void,
|
||||||
|
setDialogErrorMessageCallback: (message: ErrorMessage) => void,
|
||||||
|
setIsErrorDialogOpen: (val: boolean) => void
|
||||||
) {
|
) {
|
||||||
this.setUrlCallback = setUrlCallback;
|
this.setUrlCallback = setUrlCallback;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.videoAutoQualityOptimizer = videoAutoQualityOptimizer;
|
this.videoAutoQualityOptimizer = videoAutoQualityOptimizer;
|
||||||
|
this.isDarkTheme = isDarkTheme;
|
||||||
this.setMyDeviceDetails = setMyDeviceDetailsCallback;
|
this.setMyDeviceDetails = setMyDeviceDetailsCallback;
|
||||||
this.hostAllowedToConnectCallback = hostAllowedToConnectCallback;
|
this.hostAllowedToConnectCallback = hostAllowedToConnectCallback;
|
||||||
this.roomId = encodeURI(window.location.pathname.replace('/', ''));
|
this.roomId = encodeURI(window.location.pathname.replace('/', ''));
|
||||||
@ -97,15 +131,51 @@ export default class LocalTestPeer {
|
|||||||
this.uaParser = new UAParser();
|
this.uaParser = new UAParser();
|
||||||
this.createUserAndInitSocket();
|
this.createUserAndInitSocket();
|
||||||
this.createPeer();
|
this.createPeer();
|
||||||
|
this.setScreenSharingSourceTypeCallback = setScreenSharingSourceTypeCallback;
|
||||||
|
this.setIsDarkThemeCallback = setIsDarkThemeCallback;
|
||||||
|
this.setAppLanguageCallback = setAppLanguageCallback;
|
||||||
|
this.setDialogErrorMessageCallback = setDialogErrorMessageCallback;
|
||||||
|
this.setIsErrorDialogOpen = setIsErrorDialogOpen;
|
||||||
|
|
||||||
this.video = null;
|
this.video = null;
|
||||||
this.canvas = null;
|
this.canvas = null;
|
||||||
this.largeMismatchFramesCount = 0;
|
this.largeMismatchFramesCount = 0;
|
||||||
this.isRequestedHalfQuality = false;
|
|
||||||
|
if (!this.roomId || this.roomId === '') {
|
||||||
|
setDialogErrorMessageCallback(ErrorMessage.UNKNOWN_ERROR);
|
||||||
|
setIsErrorDialogOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
if (!this.socket.connected) {
|
||||||
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.DENY_TO_CONNECT);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.DENY_TO_CONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
log(...toLog: any[]) {
|
setVideoQuality(videoQuality: VideoQuality) {
|
||||||
console.log('LocalTestPeer - ', ...toLog);
|
this.videoQuality = videoQuality;
|
||||||
|
this.videoQualityChangedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrorDialogMessage(message: ErrorMessage) {
|
||||||
|
this.errorDialogMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
videoQualityChangedCallback() {
|
||||||
|
if (this.videoQuality !== VideoQuality.Q_AUTO) {
|
||||||
|
this.peer?.send(
|
||||||
|
prepareDataMessageToChangeQuality(
|
||||||
|
VIDEO_QUALITY_TO_DECIMAL[this.videoQuality]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.peer?.send(prepareDataMessageToChangeQuality(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createPeer() {
|
createPeer() {
|
||||||
@ -127,23 +197,26 @@ export default class LocalTestPeer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
peer.on('stream', (stream) => {
|
peer.on('stream', (stream) => {
|
||||||
setTimeout(() => {
|
|
||||||
(document.querySelector(
|
|
||||||
'#video-local-test-peer-sees'
|
|
||||||
) as any).srcObject = stream;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
this.videoAutoQualityOptimizer.setGoodQualityCallback(() => {
|
this.videoAutoQualityOptimizer.setGoodQualityCallback(() => {
|
||||||
this.peer.send('set good quality');
|
if (this.videoQuality === VideoQuality.Q_AUTO) {
|
||||||
|
this.peer?.send(prepareDataMessageToChangeQuality(1));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.videoAutoQualityOptimizer.setHalfQualityCallbak(() => {
|
this.videoAutoQualityOptimizer.setHalfQualityCallbak(() => {
|
||||||
this.peer.send('set half quality');
|
if (this.videoQuality === VideoQuality.Q_AUTO) {
|
||||||
|
this.peer?.send(prepareDataMessageToChangeQuality(0.5));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.videoAutoQualityOptimizer.startOptimizationLoop();
|
this.videoAutoQualityOptimizer.startOptimizationLoop();
|
||||||
|
|
||||||
this.setUrlCallback(stream);
|
this.setUrlCallback(stream);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.peer?.send(prepareDataMessageToGetSharingSourceType());
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
this.isStreamStarted = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('signal', (data) => {
|
peer.on('signal', (data) => {
|
||||||
@ -156,6 +229,20 @@ export default class LocalTestPeer {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
peer.on('data', (data) => {
|
||||||
|
const dataJSON = JSON.parse(data);
|
||||||
|
|
||||||
|
if (dataJSON.type === 'screen_sharing_source_type') {
|
||||||
|
this.screenSharingSourceType = dataJSON.payload.value;
|
||||||
|
if (
|
||||||
|
this.screenSharingSourceType === 'screen' ||
|
||||||
|
this.screenSharingSourceType === 'window'
|
||||||
|
) {
|
||||||
|
this.setScreenSharingSourceTypeCallback(this.screenSharingSourceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.peer = peer;
|
this.peer = peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +280,6 @@ export default class LocalTestPeer {
|
|||||||
if (!this.user) return;
|
if (!this.user) return;
|
||||||
if (!this.partner) return;
|
if (!this.partner) return;
|
||||||
const msg = (await prepareMessage(payload, this.user, this.partner)) as any;
|
const msg = (await prepareMessage(payload, this.user, this.partner)) as any;
|
||||||
this.log('encrypted message', msg);
|
|
||||||
this.socket.emit('ENCRYPTED_MESSAGE', msg.toSend);
|
this.socket.emit('ENCRYPTED_MESSAGE', msg.toSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,18 +290,34 @@ export default class LocalTestPeer {
|
|||||||
this.user.privateKey
|
this.user.privateKey
|
||||||
)) as any;
|
)) as any;
|
||||||
if (message.type === 'CALL_USER') {
|
if (message.type === 'CALL_USER') {
|
||||||
this.log('ACCEPTING CALL USER', message);
|
this.peer?.signal(message.payload.signalData);
|
||||||
this.peer.signal(message.payload.signalData);
|
|
||||||
}
|
}
|
||||||
if (message.type === 'DENY_TO_CONNECT') {
|
if (message.type === 'DENY_TO_CONNECT') {
|
||||||
this.log('OH NO, deny to connect...');
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.DENY_TO_CONNECT);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.DENY_TO_CONNECT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (message.type === 'DISCONNECT_BY_HOST_MACHINE_USER') {
|
if (message.type === 'DISCONNECT_BY_HOST_MACHINE_USER') {
|
||||||
this.log('DAMN, you were disconnected by host machine user!');
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.DICONNECTED);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.DICONNECTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (message.type === 'ALLOWED_TO_CONNECT') {
|
if (message.type === 'ALLOWED_TO_CONNECT') {
|
||||||
this.hostAllowedToConnectCallback();
|
this.hostAllowedToConnectCallback();
|
||||||
}
|
}
|
||||||
|
if (message.type === 'APP_THEME') {
|
||||||
|
if (this.isDarkTheme !== message.payload.value) {
|
||||||
|
this.setIsDarkThemeCallback(message.payload.value);
|
||||||
|
this.isDarkTheme = message.payload.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.type === 'APP_LANGUAGE') {
|
||||||
|
this.setAppLanguageCallback(message.payload.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createUserAndInitSocket() {
|
createUserAndInitSocket() {
|
||||||
@ -228,36 +330,33 @@ export default class LocalTestPeer {
|
|||||||
|
|
||||||
this.socket.on('disconnect', () => {
|
this.socket.on('disconnect', () => {
|
||||||
// this.props.toggleSocketConnected(false);
|
// this.props.toggleSocketConnected(false);
|
||||||
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.DICONNECTED);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.DICONNECTED;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('connect', () => {
|
this.socket.on('connect', () => {
|
||||||
this.socket.emit('GET_MY_IP', (ip: string) => {
|
this.socket.emit('GET_MY_IP', (ip: string) => {
|
||||||
// TODO: use set ip callback here, that will change the UI of react component
|
|
||||||
// @ts-ignore
|
|
||||||
// document.querySelector('#my-ip')?.innerHTML = ip;
|
|
||||||
this.myIP = ip;
|
this.myIP = ip;
|
||||||
this.uaParser.setUA(window.navigator.userAgent);
|
this.uaParser.setUA(window.navigator.userAgent);
|
||||||
// const osFromUAParser = this.uaParser.getResult().os;
|
|
||||||
// const deviceTypeFromUAParser = this.uaParser.getResult().device;
|
|
||||||
// const browserFromUAParser = this.uaParser.getResult().browser;
|
|
||||||
|
|
||||||
// this.myOS = `${osFromUAParser.name ? osFromUAParser.name : ''} ${
|
|
||||||
// osFromUAParser.version ? osFromUAParser.version : ''
|
|
||||||
// }`;
|
|
||||||
// this.myDeviceType = deviceTypeFromUAParser.type
|
|
||||||
// ? deviceTypeFromUAParser.type.toString()
|
|
||||||
// : 'computer';
|
|
||||||
this.myOS = getOSFromUAParser(this.uaParser);
|
this.myOS = getOSFromUAParser(this.uaParser);
|
||||||
this.myDeviceType = getDeviceTypeFromUAParser(this.uaParser);
|
this.myDeviceType = getDeviceTypeFromUAParser(this.uaParser);
|
||||||
// this.myBrowser = `${browserFromUAParser.name ? browserFromUAParser.name : ''} ${
|
|
||||||
// browserFromUAParser.version ? browserFromUAParser.version : ''
|
|
||||||
// }`;
|
|
||||||
this.myBrowser = getBrowserFromUAParser(this.uaParser);
|
this.myBrowser = getBrowserFromUAParser(this.uaParser);
|
||||||
|
|
||||||
this.initApp(createdUser, ip);
|
this.initApp(createdUser, ip);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.socket.on('NOT_ALLOWED', () => {
|
||||||
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.NOT_ALLOWED);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.socket.on('USER_ENTER', (payload: { users: PartnerPeerUser[] }) => {
|
this.socket.on('USER_ENTER', (payload: { users: PartnerPeerUser[] }) => {
|
||||||
const filteredPartner = payload.users.filter((v) => {
|
const filteredPartner = payload.users.filter((v) => {
|
||||||
return createdUser.publicKey !== v.publicKey;
|
return createdUser.publicKey !== v.publicKey;
|
||||||
@ -288,6 +387,9 @@ export default class LocalTestPeer {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.sendEncryptedMessage({ type: 'GET_APP_THEME', payload: {} });
|
||||||
|
this.sendEncryptedMessage({ type: 'GET_APP_LANGUAGE', payload: {} });
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.setMyDeviceDetails({
|
this.setMyDeviceDetails({
|
||||||
myIP: this.myIP,
|
myIP: this.myIP,
|
||||||
@ -313,6 +415,11 @@ export default class LocalTestPeer {
|
|||||||
// TODO: call ROOM LOCKED callback to change react component contain ROOM LOCKED message
|
// TODO: call ROOM LOCKED callback to change react component contain ROOM LOCKED message
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// document.querySelector('#my-ip')?.innerHTML = 'ROOM LOCKED';
|
// document.querySelector('#my-ip')?.innerHTML = 'ROOM LOCKED';
|
||||||
|
if (this.errorDialogMessage === ErrorMessage.UNKNOWN_ERROR) {
|
||||||
|
this.setDialogErrorMessageCallback(ErrorMessage.DENY_TO_CONNECT);
|
||||||
|
this.setIsErrorDialogOpen(true);
|
||||||
|
this.errorDialogMessage = ErrorMessage.UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('beforeunload', (_) => {
|
window.addEventListener('beforeunload', (_) => {
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
export default (q: number) => {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"type": "set_video_quality",
|
||||||
|
"payload": {
|
||||||
|
"value": ${q}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
export default () => {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"type": "get_sharing_source_type",
|
||||||
|
"payload": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import pixelmatch from 'pixelmatch';
|
import pixelmatch from 'pixelmatch';
|
||||||
|
import { REACT_PLAYER_WRAPPER_ID } from '../../constants/appConstants';
|
||||||
|
|
||||||
export default class VideoAutoQualityOptimizer {
|
export default class VideoAutoQualityOptimizer {
|
||||||
video: any;
|
video: any;
|
||||||
@ -15,8 +16,6 @@ export default class VideoAutoQualityOptimizer {
|
|||||||
|
|
||||||
halfQualityCallbak = () => {};
|
halfQualityCallbak = () => {};
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
setGoodQualityCallback(callback: () => void) {
|
setGoodQualityCallback(callback: () => void) {
|
||||||
this.goodQualityCallback = callback;
|
this.goodQualityCallback = callback;
|
||||||
}
|
}
|
||||||
@ -66,13 +65,11 @@ export default class VideoAutoQualityOptimizer {
|
|||||||
} else if (mismatchInPercent < 0.1 && this.isRequestedHalfQuality) {
|
} else if (mismatchInPercent < 0.1 && this.isRequestedHalfQuality) {
|
||||||
this.largeMismatchFramesCount = 0;
|
this.largeMismatchFramesCount = 0;
|
||||||
this.isRequestedHalfQuality = false;
|
this.isRequestedHalfQuality = false;
|
||||||
// this.peer.send('set good quality');
|
|
||||||
this.goodQualityCallback();
|
this.goodQualityCallback();
|
||||||
} else if (mismatchInPercent >= 0.1 && !this.isRequestedHalfQuality) {
|
} else if (mismatchInPercent >= 0.1 && !this.isRequestedHalfQuality) {
|
||||||
if (this.largeMismatchFramesCount < 3) {
|
if (this.largeMismatchFramesCount < 3) {
|
||||||
this.largeMismatchFramesCount += 1;
|
this.largeMismatchFramesCount += 1;
|
||||||
} else {
|
} else {
|
||||||
// this.peer.send('set half quality');
|
|
||||||
this.halfQualityCallbak();
|
this.halfQualityCallbak();
|
||||||
this.isRequestedHalfQuality = true;
|
this.isRequestedHalfQuality = true;
|
||||||
}
|
}
|
||||||
@ -85,7 +82,7 @@ export default class VideoAutoQualityOptimizer {
|
|||||||
imageData = null;
|
imageData = null;
|
||||||
} else {
|
} else {
|
||||||
this.video = document.querySelector(
|
this.video = document.querySelector(
|
||||||
'#video-local-test-peer-sees > video'
|
`#${REACT_PLAYER_WRAPPER_ID} > video`
|
||||||
);
|
);
|
||||||
this.canvas = document.getElementById('comparison-canvas');
|
this.canvas = document.getElementById('comparison-canvas');
|
||||||
}
|
}
|
||||||
|
BIN
app/client/src/images/deskreen_logo_128x128.png
Executable file
BIN
app/client/src/images/deskreen_logo_128x128.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
1
app/client/src/images/fullscreen_24px.svg
Normal file
1
app/client/src/images/fullscreen_24px.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>
|
After Width: | Height: | Size: 216 B |
1
app/client/src/images/fullscreen_exit-24px.svg
Normal file
1
app/client/src/images/fullscreen_exit-24px.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/></svg>
|
After Width: | Height: | Size: 215 B |
BIN
app/client/src/images/red_heart_2764_twemoji_120x120.png
Normal file
BIN
app/client/src/images/red_heart_2764_twemoji_120x120.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React, { Suspense } from 'react';
|
||||||
|
import './config/i18n';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
@ -8,7 +9,9 @@ import { AppContextProvider } from './providers/AppContextProvider';
|
|||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<App />
|
<Suspense fallback="loading">
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
</AppContextProvider>
|
</AppContextProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React, { useState, useEffect } from 'react';
|
import { Classes } from '@blueprintjs/core';
|
||||||
|
import React, { useState } from 'react';
|
||||||
// export const LIGHT_UI_BACKGROUND = 'rgba(240, 248, 250, 1)';
|
import {
|
||||||
|
DARK_UI_BACKGROUND,
|
||||||
|
LIGHT_UI_BACKGROUND,
|
||||||
|
} from '../../constants/styleConstants';
|
||||||
|
|
||||||
interface AppContextInterface {
|
interface AppContextInterface {
|
||||||
isDarkTheme: boolean;
|
isDarkTheme: boolean;
|
||||||
@ -19,34 +22,27 @@ export const AppContext = React.createContext<AppContextInterface>(
|
|||||||
|
|
||||||
export const AppContextProvider: React.FC = ({ children }) => {
|
export const AppContextProvider: React.FC = ({ children }) => {
|
||||||
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
||||||
|
const [appLanguage, setAppLanguage] = useState('en');
|
||||||
const getThemeFromHost = () => {
|
|
||||||
// const gotIsDarkThemeFromSettings = settings.hasSync('appIsDarkTheme')
|
|
||||||
// ? settings.getSync('appIsDarkTheme') === 'true'
|
|
||||||
// : false;
|
|
||||||
|
|
||||||
// if (gotIsDarkThemeFromSettings) {
|
|
||||||
// document.body.classList.toggle(Classes.DARK);
|
|
||||||
// document.body.style.backgroundColor = LIGHT_UI_BACKGROUND;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setIsDarkTheme(gotIsDarkThemeFromSettings);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getThemeFromHost();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setIsDarkThemeHook = (val: boolean) => {
|
const setIsDarkThemeHook = (val: boolean) => {
|
||||||
// settings.setSync('appIsDarkTheme', `${val}`);
|
document.body.classList.toggle(Classes.DARK);
|
||||||
setIsDarkTheme(val);
|
|
||||||
|
document.body.style.backgroundColor = val
|
||||||
|
? DARK_UI_BACKGROUND
|
||||||
|
: LIGHT_UI_BACKGROUND;
|
||||||
|
setIsDarkTheme(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
const value = { isDarkTheme, setIsDarkThemeHook };
|
const setAppLanguageHook = (newLang: string) => {
|
||||||
|
setAppLanguage(newLang);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
const value = {
|
||||||
<AppContext.Provider value={value}>
|
isDarkTheme,
|
||||||
{children}
|
setIsDarkThemeHook,
|
||||||
</AppContext.Provider>
|
appLanguage,
|
||||||
);
|
setAppLanguageHook,
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
|
||||||
};
|
};
|
||||||
|
@ -1122,7 +1122,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.5.5":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5":
|
||||||
version "7.12.5"
|
version "7.12.5"
|
||||||
resolved "https://packages.deskreen.com/@babel%2fruntime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
resolved "https://packages.deskreen.com/@babel%2fruntime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
||||||
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
||||||
@ -5535,6 +5535,13 @@ html-minifier-terser@^5.0.1:
|
|||||||
relateurl "^0.2.7"
|
relateurl "^0.2.7"
|
||||||
terser "^4.6.3"
|
terser "^4.6.3"
|
||||||
|
|
||||||
|
html-parse-stringify2@2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://packages.deskreen.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
|
||||||
|
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
|
||||||
|
dependencies:
|
||||||
|
void-elements "^2.0.1"
|
||||||
|
|
||||||
html-webpack-plugin@4.0.0-beta.11:
|
html-webpack-plugin@4.0.0-beta.11:
|
||||||
version "4.0.0-beta.11"
|
version "4.0.0-beta.11"
|
||||||
resolved "https://packages.deskreen.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715"
|
resolved "https://packages.deskreen.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715"
|
||||||
@ -5634,6 +5641,20 @@ https-browserify@^1.0.0:
|
|||||||
resolved "https://packages.deskreen.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
resolved "https://packages.deskreen.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||||
|
|
||||||
|
i18next-http-backend@^1.0.21:
|
||||||
|
version "1.0.21"
|
||||||
|
resolved "https://packages.deskreen.com/i18next-http-backend/-/i18next-http-backend-1.0.21.tgz#cee901b3527dad5165fa91de973b6aa6404c1c37"
|
||||||
|
integrity sha512-UDeHoV2B+31Gr++0KFAVjM5l+SEwePpF6sfDyaDq5ennM9QNJ78PBEMPStwkreEm4h5C8sT7M1JdNQrLcU1Wdg==
|
||||||
|
dependencies:
|
||||||
|
node-fetch "2.6.1"
|
||||||
|
|
||||||
|
i18next@^19.8.4:
|
||||||
|
version "19.8.4"
|
||||||
|
resolved "https://packages.deskreen.com/i18next/-/i18next-19.8.4.tgz#447718f2a26319b8debdbcc6fbc1a9761be7316b"
|
||||||
|
integrity sha512-FfVPNWv+felJObeZ6DSXZkj9QM1Ivvh7NcFCgA8XPtJWHz0iXVa9BUy+QY8EPrCLE+vWgDfV/sc96BgXVo6HAA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.0"
|
||||||
|
|
||||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://packages.deskreen.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://packages.deskreen.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
@ -7418,6 +7439,11 @@ no-case@^3.0.3:
|
|||||||
lower-case "^2.0.1"
|
lower-case "^2.0.1"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
|
|
||||||
|
node-fetch@2.6.1:
|
||||||
|
version "2.6.1"
|
||||||
|
resolved "https://packages.deskreen.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
node-forge@0.9.0:
|
node-forge@0.9.0:
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://packages.deskreen.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
resolved "https://packages.deskreen.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
||||||
@ -9116,6 +9142,14 @@ react-flexbox-grid@^2.1.2:
|
|||||||
flexboxgrid2 "^7.2.0"
|
flexboxgrid2 "^7.2.0"
|
||||||
prop-types "^15.5.8"
|
prop-types "^15.5.8"
|
||||||
|
|
||||||
|
react-i18next@^11.7.4:
|
||||||
|
version "11.7.4"
|
||||||
|
resolved "https://packages.deskreen.com/react-i18next/-/react-i18next-11.7.4.tgz#6c0142e15652d8dd80cd7d857e36efe2e9d4d09a"
|
||||||
|
integrity sha512-Aq0+QVW7NMYuAtk0Stcwp4jWeNTd1p5XefAfBPcjs/4c/2duG3v3G3zdtn8fC8L4EyA/coKLwdULHI+lYTbF8w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.3.1"
|
||||||
|
html-parse-stringify2 "2.0.1"
|
||||||
|
|
||||||
react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4:
|
react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://packages.deskreen.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://packages.deskreen.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
@ -10967,6 +11001,11 @@ vm-browserify@^1.0.1:
|
|||||||
resolved "https://packages.deskreen.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
resolved "https://packages.deskreen.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||||
|
|
||||||
|
void-elements@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://packages.deskreen.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
|
||||||
|
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
|
||||||
|
|
||||||
w3c-hr-time@^1.0.1:
|
w3c-hr-time@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://packages.deskreen.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
resolved "https://packages.deskreen.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
||||||
|
@ -49,7 +49,15 @@ export default function DeviceInfoCallout(props: DeviceInfoCalloutProps) {
|
|||||||
Device Type: <span>{deviceType}</span>
|
Device Type: <span>{deviceType}</span>
|
||||||
</Text>
|
</Text>
|
||||||
<Tooltip content={getContentOfTooltip()} position={Position.TOP}>
|
<Tooltip content={getContentOfTooltip()} position={Position.TOP}>
|
||||||
<div style={{ fontWeight: 900, backgroundColor: '#00f99273' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
fontWeight: 900,
|
||||||
|
backgroundColor: '#00f99273',
|
||||||
|
paddingLeft: '10px',
|
||||||
|
paddingRight: '10px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Text className="bp3-text-large">
|
<Text className="bp3-text-large">
|
||||||
Device IP: <span className="device-ip-span">{deviceIP}</span>
|
Device IP: <span className="device-ip-span">{deviceIP}</span>
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { remote } from 'electron';
|
||||||
import React, { useContext, useCallback, useEffect, useState } from 'react';
|
import React, { useContext, useCallback, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -17,13 +18,14 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Row } from 'react-flexbox-grid';
|
import { Row } from 'react-flexbox-grid';
|
||||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
|
import SharingSessionsService from '../../features/SharingSessionsService';
|
||||||
import {
|
import {
|
||||||
DARK_UI_BACKGROUND,
|
DARK_UI_BACKGROUND,
|
||||||
LIGHT_UI_BACKGROUND,
|
LIGHT_UI_BACKGROUND,
|
||||||
SettingsContext,
|
SettingsContext,
|
||||||
} from '../../containers/SettingsProvider';
|
} from '../../containers/SettingsProvider';
|
||||||
import CloseOverlayButton from '../CloseOverlayButton';
|
import CloseOverlayButton from '../CloseOverlayButton';
|
||||||
import {
|
import i18n_client, {
|
||||||
getLangFullNameToLangISOKeyMap,
|
getLangFullNameToLangISOKeyMap,
|
||||||
getLangISOKeyToLangFullNameMap,
|
getLangISOKeyToLangFullNameMap,
|
||||||
} from '../../configs/i18next.config.client';
|
} from '../../configs/i18next.config.client';
|
||||||
@ -32,6 +34,10 @@ import SettingRowLabelAndInput from './SettingRowLabelAndInput';
|
|||||||
|
|
||||||
const Fade = require('react-reveal/Fade');
|
const Fade = require('react-reveal/Fade');
|
||||||
|
|
||||||
|
const sharingSessionsService = remote.getGlobal(
|
||||||
|
'sharingSessionService'
|
||||||
|
) as SharingSessionsService;
|
||||||
|
|
||||||
interface SettingsOverlayProps {
|
interface SettingsOverlayProps {
|
||||||
isSettingsOpen: boolean;
|
isSettingsOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
@ -57,7 +63,11 @@ export default function SettingsOverlay(props: SettingsOverlayProps) {
|
|||||||
|
|
||||||
const { handleClose, isSettingsOpen } = props;
|
const { handleClose, isSettingsOpen } = props;
|
||||||
|
|
||||||
const { isDarkTheme, setIsDarkThemeHook } = useContext(SettingsContext);
|
const {
|
||||||
|
isDarkTheme,
|
||||||
|
setIsDarkThemeHook,
|
||||||
|
setCurrentLanguageHook,
|
||||||
|
} = useContext(SettingsContext);
|
||||||
|
|
||||||
const [languagesList, setLanguagesList] = useState([] as string[]);
|
const [languagesList, setLanguagesList] = useState([] as string[]);
|
||||||
|
|
||||||
@ -67,7 +77,8 @@ export default function SettingsOverlay(props: SettingsOverlayProps) {
|
|||||||
tmp.push(key);
|
tmp.push(key);
|
||||||
});
|
});
|
||||||
setLanguagesList(tmp);
|
setLanguagesList(tmp);
|
||||||
}, []);
|
setCurrentLanguageHook(i18n_client.language);
|
||||||
|
}, [setCurrentLanguageHook]);
|
||||||
|
|
||||||
const getClassesCallback = useStylesWithTheme(isDarkTheme);
|
const getClassesCallback = useStylesWithTheme(isDarkTheme);
|
||||||
|
|
||||||
@ -76,6 +87,11 @@ export default function SettingsOverlay(props: SettingsOverlayProps) {
|
|||||||
document.body.classList.toggle(Classes.DARK);
|
document.body.classList.toggle(Classes.DARK);
|
||||||
setIsDarkThemeHook(true);
|
setIsDarkThemeHook(true);
|
||||||
}
|
}
|
||||||
|
// TODO: call sharing sessions service here to notify all connected clients about theme change
|
||||||
|
sharingSessionsService.sharingSessions.forEach((sharingSession) => {
|
||||||
|
sharingSession?.appThemeChanged(true);
|
||||||
|
});
|
||||||
|
sharingSessionsService.setAppTheme(true);
|
||||||
}, [isDarkTheme, setIsDarkThemeHook]);
|
}, [isDarkTheme, setIsDarkThemeHook]);
|
||||||
|
|
||||||
const handleToggleLightTheme = useCallback(() => {
|
const handleToggleLightTheme = useCallback(() => {
|
||||||
@ -83,6 +99,11 @@ export default function SettingsOverlay(props: SettingsOverlayProps) {
|
|||||||
document.body.classList.toggle(Classes.DARK);
|
document.body.classList.toggle(Classes.DARK);
|
||||||
setIsDarkThemeHook(false);
|
setIsDarkThemeHook(false);
|
||||||
}
|
}
|
||||||
|
// TODO: call sharing sessions service here to notify all connected clients about theme change
|
||||||
|
sharingSessionsService.sharingSessions.forEach((sharingSession) => {
|
||||||
|
sharingSession?.appThemeChanged(false);
|
||||||
|
});
|
||||||
|
sharingSessionsService.setAppTheme(false);
|
||||||
}, [isDarkTheme, setIsDarkThemeHook]);
|
}, [isDarkTheme, setIsDarkThemeHook]);
|
||||||
|
|
||||||
const onChangeLangueageHTMLSelectHandler = (
|
const onChangeLangueageHTMLSelectHandler = (
|
||||||
@ -92,10 +113,15 @@ export default function SettingsOverlay(props: SettingsOverlayProps) {
|
|||||||
event.currentTarget &&
|
event.currentTarget &&
|
||||||
getLangFullNameToLangISOKeyMap().has(event.currentTarget.value)
|
getLangFullNameToLangISOKeyMap().has(event.currentTarget.value)
|
||||||
) {
|
) {
|
||||||
i18n.changeLanguage(
|
const newLang =
|
||||||
getLangFullNameToLangISOKeyMap().get(event.currentTarget.value) ||
|
getLangFullNameToLangISOKeyMap().get(event.currentTarget.value) ||
|
||||||
'English'
|
'English';
|
||||||
);
|
i18n.changeLanguage(newLang);
|
||||||
|
// TODO: call sharing sessions service here to notify all connected clients about language change
|
||||||
|
sharingSessionsService.sharingSessions.forEach((sharingSession) => {
|
||||||
|
sharingSession?.appLanguageChanged(newLang);
|
||||||
|
});
|
||||||
|
sharingSessionsService.setAppLanguage(newLang);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,15 +67,15 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
tabindex="0"
|
tabindex="0"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-overlayInnerRoot-8 bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
class="makeStyles-overlayInnerRoot-21 bp3-overlay-content bp3-overlay-appear-active"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="react-reveal makeStyles-overlayInsideFade-9 bp3-card"
|
class="react-reveal makeStyles-overlayInsideFade-22 bp3-card"
|
||||||
id="settings-overlay-inner"
|
id="settings-overlay-inner"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-10"
|
class="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-23"
|
||||||
id="close-overlay-button"
|
id="close-overlay-button"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
@ -112,7 +112,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bp3-tab-indicator-wrapper"
|
class="bp3-tab-indicator-wrapper"
|
||||||
style="height: 0px; transform: translateX(0px) translateY(0px); width: 0px; transition: none;"
|
style="height: 0px; transform: translateX(0px) translateY(0px); width: 0px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bp3-tab-indicator"
|
class="bp3-tab-indicator"
|
||||||
@ -131,10 +131,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-25"
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -172,10 +172,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-25"
|
||||||
icon="shield"
|
icon="shield"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -212,10 +212,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-25"
|
||||||
icon="blocked-person"
|
icon="blocked-person"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -267,13 +267,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-20 row middle-xs"
|
class="makeStyles-oneSettingRow-26 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-style makeStyles-settingRowIcon-21"
|
class="bp3-icon bp3-icon-style makeStyles-settingRowIcon-27"
|
||||||
icon="style"
|
icon="style"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -381,13 +381,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-22 row middle-xs"
|
class="makeStyles-oneSettingRow-28 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-23"
|
class="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-29"
|
||||||
icon="translate"
|
icon="translate"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -473,13 +473,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-24 row middle-xs"
|
class="makeStyles-oneSettingRow-30 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-25"
|
class="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-31"
|
||||||
icon="automatic-updates"
|
icon="automatic-updates"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -516,7 +516,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="bp3-control bp3-checkbox makeStyles-checkboxSettings-7"
|
class="bp3-control bp3-checkbox makeStyles-checkboxSettings-20"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
checked=""
|
checked=""
|
||||||
@ -552,15 +552,15 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
tabindex="0"
|
tabindex="0"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-overlayInnerRoot-8 bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
class="makeStyles-overlayInnerRoot-21 bp3-overlay-content bp3-overlay-appear-active"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="react-reveal makeStyles-overlayInsideFade-9 bp3-card"
|
class="react-reveal makeStyles-overlayInsideFade-22 bp3-card"
|
||||||
id="settings-overlay-inner"
|
id="settings-overlay-inner"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-10"
|
class="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-23"
|
||||||
id="close-overlay-button"
|
id="close-overlay-button"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
@ -597,7 +597,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bp3-tab-indicator-wrapper"
|
class="bp3-tab-indicator-wrapper"
|
||||||
style="height: 0px; transform: translateX(0px) translateY(0px); width: 0px; transition: none;"
|
style="height: 0px; transform: translateX(0px) translateY(0px); width: 0px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="bp3-tab-indicator"
|
class="bp3-tab-indicator"
|
||||||
@ -616,10 +616,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-25"
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -657,10 +657,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-25"
|
||||||
icon="shield"
|
icon="shield"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -697,10 +697,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
class="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-12"
|
class="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-25"
|
||||||
icon="blocked-person"
|
icon="blocked-person"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -752,13 +752,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-20 row middle-xs"
|
class="makeStyles-oneSettingRow-26 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-style makeStyles-settingRowIcon-21"
|
class="bp3-icon bp3-icon-style makeStyles-settingRowIcon-27"
|
||||||
icon="style"
|
icon="style"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -866,13 +866,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-22 row middle-xs"
|
class="makeStyles-oneSettingRow-28 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-23"
|
class="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-29"
|
||||||
icon="translate"
|
icon="translate"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -958,13 +958,13 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="col-xs-6"
|
class="col-xs-6"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-oneSettingRow-24 row middle-xs"
|
class="makeStyles-oneSettingRow-30 row middle-xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-25"
|
class="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-31"
|
||||||
icon="automatic-updates"
|
icon="automatic-updates"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1001,7 +1001,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="bp3-control bp3-checkbox makeStyles-checkboxSettings-7"
|
class="bp3-control bp3-checkbox makeStyles-checkboxSettings-20"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
checked=""
|
checked=""
|
||||||
@ -1035,7 +1035,6 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
>
|
>
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
appear={true}
|
|
||||||
classNames="bp3-overlay"
|
classNames="bp3-overlay"
|
||||||
in={true}
|
in={true}
|
||||||
key=".$__backdrop"
|
key=".$__backdrop"
|
||||||
@ -1043,7 +1042,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
timeout={0}
|
timeout={0}
|
||||||
>
|
>
|
||||||
<Transition
|
<Transition
|
||||||
appear={true}
|
appear={false}
|
||||||
enter={true}
|
enter={true}
|
||||||
exit={true}
|
exit={true}
|
||||||
in={true}
|
in={true}
|
||||||
@ -1065,7 +1064,6 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
</Transition>
|
</Transition>
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
appear={true}
|
|
||||||
classNames="bp3-overlay"
|
classNames="bp3-overlay"
|
||||||
in={true}
|
in={true}
|
||||||
key=".$.0"
|
key=".$.0"
|
||||||
@ -1073,7 +1071,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
timeout={0}
|
timeout={0}
|
||||||
>
|
>
|
||||||
<Transition
|
<Transition
|
||||||
appear={true}
|
appear={false}
|
||||||
enter={true}
|
enter={true}
|
||||||
exit={true}
|
exit={true}
|
||||||
in={true}
|
in={true}
|
||||||
@ -1088,7 +1086,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
unmountOnExit={false}
|
unmountOnExit={false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-overlayInnerRoot-8 bp3-overlay-content"
|
className="makeStyles-overlayInnerRoot-21 bp3-overlay-content"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<Fade
|
<Fade
|
||||||
@ -1125,7 +1123,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
refProp="ref"
|
refProp="ref"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="react-reveal makeStyles-overlayInsideFade-9 bp3-card"
|
className="react-reveal makeStyles-overlayInsideFade-22 bp3-card"
|
||||||
id="settings-overlay-inner"
|
id="settings-overlay-inner"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
@ -1134,17 +1132,17 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CloseOverlayButton
|
<CloseOverlayButton
|
||||||
className="makeStyles-absoluteCloseButton-10"
|
className="makeStyles-absoluteCloseButton-23"
|
||||||
isDefaultStyles={true}
|
isDefaultStyles={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
className="makeStyles-closeButton-13 makeStyles-absoluteCloseButton-10"
|
className="makeStyles-closeButton-13 makeStyles-absoluteCloseButton-23"
|
||||||
id="close-overlay-button"
|
id="close-overlay-button"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-10"
|
className="bp3-button makeStyles-closeButton-13 makeStyles-absoluteCloseButton-23"
|
||||||
id="close-overlay-button"
|
id="close-overlay-button"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
@ -1213,7 +1211,6 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
Object {
|
Object {
|
||||||
"height": 0,
|
"height": 0,
|
||||||
"transform": "translateX(0px) translateY(0px)",
|
"transform": "translateX(0px) translateY(0px)",
|
||||||
"transition": "none",
|
|
||||||
"width": 0,
|
"width": 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1245,18 +1242,18 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-tabNavigationRowButton-11"
|
className="makeStyles-tabNavigationRowButton-24"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
className="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-iconInTablLeftButton-12"
|
className="makeStyles-iconInTablLeftButton-25"
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-12"
|
className="bp3-icon bp3-icon-wrench makeStyles-iconInTablLeftButton-25"
|
||||||
icon="wrench"
|
icon="wrench"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1312,18 +1309,18 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-tabNavigationRowButton-11"
|
className="makeStyles-tabNavigationRowButton-24"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
className="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-iconInTablLeftButton-12"
|
className="makeStyles-iconInTablLeftButton-25"
|
||||||
icon="shield"
|
icon="shield"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-12"
|
className="bp3-icon bp3-icon-shield makeStyles-iconInTablLeftButton-25"
|
||||||
icon="shield"
|
icon="shield"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1377,18 +1374,18 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
role="tab"
|
role="tab"
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-tabNavigationRowButton-11"
|
className="makeStyles-tabNavigationRowButton-24"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-tabNavigationRowButton-11 row middle-xs"
|
className="makeStyles-tabNavigationRowButton-24 row middle-xs"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-iconInTablLeftButton-12"
|
className="makeStyles-iconInTablLeftButton-25"
|
||||||
icon="blocked-person"
|
icon="blocked-person"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-12"
|
className="bp3-icon bp3-icon-blocked-person makeStyles-iconInTablLeftButton-25"
|
||||||
icon="blocked-person"
|
icon="blocked-person"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1492,23 +1489,23 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
className="col-xs-6"
|
className="col-xs-6"
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-oneSettingRow-20"
|
className="makeStyles-oneSettingRow-26"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-oneSettingRow-20 row middle-xs"
|
className="makeStyles-oneSettingRow-26 row middle-xs"
|
||||||
>
|
>
|
||||||
<Col>
|
<Col>
|
||||||
<div
|
<div
|
||||||
className=""
|
className=""
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-settingRowIcon-21"
|
className="makeStyles-settingRowIcon-27"
|
||||||
icon="style"
|
icon="style"
|
||||||
iconSize={25}
|
iconSize={25}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-style makeStyles-settingRowIcon-21"
|
className="bp3-icon bp3-icon-style makeStyles-settingRowIcon-27"
|
||||||
icon="style"
|
icon="style"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1701,23 +1698,23 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
className="col-xs-6"
|
className="col-xs-6"
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-oneSettingRow-22"
|
className="makeStyles-oneSettingRow-28"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-oneSettingRow-22 row middle-xs"
|
className="makeStyles-oneSettingRow-28 row middle-xs"
|
||||||
>
|
>
|
||||||
<Col>
|
<Col>
|
||||||
<div
|
<div
|
||||||
className=""
|
className=""
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-settingRowIcon-23"
|
className="makeStyles-settingRowIcon-29"
|
||||||
icon="translate"
|
icon="translate"
|
||||||
iconSize={25}
|
iconSize={25}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-23"
|
className="bp3-icon bp3-icon-translate makeStyles-settingRowIcon-29"
|
||||||
icon="translate"
|
icon="translate"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1840,7 +1837,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
input={
|
input={
|
||||||
<Blueprint3.Checkbox
|
<Blueprint3.Checkbox
|
||||||
checked={true}
|
checked={true}
|
||||||
className="makeStyles-checkboxSettings-7"
|
className="makeStyles-checkboxSettings-20"
|
||||||
label="Enabled"
|
label="Enabled"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -1860,23 +1857,23 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
className="col-xs-6"
|
className="col-xs-6"
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
className="makeStyles-oneSettingRow-24"
|
className="makeStyles-oneSettingRow-30"
|
||||||
middle="xs"
|
middle="xs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-oneSettingRow-24 row middle-xs"
|
className="makeStyles-oneSettingRow-30 row middle-xs"
|
||||||
>
|
>
|
||||||
<Col>
|
<Col>
|
||||||
<div
|
<div
|
||||||
className=""
|
className=""
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-settingRowIcon-25"
|
className="makeStyles-settingRowIcon-31"
|
||||||
icon="automatic-updates"
|
icon="automatic-updates"
|
||||||
iconSize={25}
|
iconSize={25}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-25"
|
className="bp3-icon bp3-icon-automatic-updates makeStyles-settingRowIcon-31"
|
||||||
icon="automatic-updates"
|
icon="automatic-updates"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1927,12 +1924,12 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<Blueprint3.Checkbox
|
<Blueprint3.Checkbox
|
||||||
checked={true}
|
checked={true}
|
||||||
className="makeStyles-checkboxSettings-7"
|
className="makeStyles-checkboxSettings-20"
|
||||||
label="Enabled"
|
label="Enabled"
|
||||||
>
|
>
|
||||||
<Control
|
<Control
|
||||||
checked={true}
|
checked={true}
|
||||||
className="makeStyles-checkboxSettings-7"
|
className="makeStyles-checkboxSettings-20"
|
||||||
inputRef={[Function]}
|
inputRef={[Function]}
|
||||||
label="Enabled"
|
label="Enabled"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@ -1940,7 +1937,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
typeClassName="bp3-checkbox"
|
typeClassName="bp3-checkbox"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
className="bp3-control bp3-checkbox makeStyles-checkboxSettings-7"
|
className="bp3-control bp3-checkbox makeStyles-checkboxSettings-20"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
checked={true}
|
checked={true}
|
||||||
|
@ -43,9 +43,8 @@ const useStyles = makeStyles(() =>
|
|||||||
width: '40px',
|
width: '40px',
|
||||||
borderRadius: '100px !important',
|
borderRadius: '100px !important',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
top: '72px',
|
top: '70px',
|
||||||
left: '-190px !important',
|
left: '-190px !important',
|
||||||
zIndex: 9999,
|
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -119,7 +118,11 @@ export default function ShareEntireScreenOrAppWindowControlGroup(
|
|||||||
/>
|
/>
|
||||||
<Text className="bp3-running-text">Application Window</Text>
|
<Text className="bp3-running-text">Application Window</Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Button active className={classes.orDecorationButton}>
|
<Button
|
||||||
|
active
|
||||||
|
className={classes.orDecorationButton}
|
||||||
|
style={{ zIndex: 999 }}
|
||||||
|
>
|
||||||
OR
|
OR
|
||||||
</Button>
|
</Button>
|
||||||
</ControlGroup>
|
</ControlGroup>
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
import { clipboard, remote } from 'electron';
|
import { clipboard, remote } from 'electron';
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { Button, Text, Tooltip, Position, H2, Dialog } from '@blueprintjs/core';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
Position,
|
||||||
|
Dialog,
|
||||||
|
Classes,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
import QRCode from 'qrcode.react';
|
import QRCode from 'qrcode.react';
|
||||||
import { makeStyles, createStyles } from '@material-ui/core';
|
import { makeStyles, createStyles } from '@material-ui/core';
|
||||||
import { Row, Col } from 'react-flexbox-grid';
|
import { Row, Col } from 'react-flexbox-grid';
|
||||||
import { SettingsContext } from '../../containers/SettingsProvider';
|
import { SettingsContext } from '../../containers/SettingsProvider';
|
||||||
import isProduction from '../../utils/isProduction';
|
import isProduction from '../../utils/isProduction';
|
||||||
import CloseOverlayButton from '../CloseOverlayButton';
|
|
||||||
import SharingSessionService from '../../features/SharingSessionsService';
|
import SharingSessionService from '../../features/SharingSessionsService';
|
||||||
|
|
||||||
const sharingSessionService = remote.getGlobal(
|
const sharingSessionService = remote.getGlobal(
|
||||||
@ -38,17 +45,21 @@ const useStyles = makeStyles(() =>
|
|||||||
dialogQRWrapper: {
|
dialogQRWrapper: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
|
// width: '95%',
|
||||||
|
// hieght: '95%',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
},
|
},
|
||||||
bigQRCodeDialogRoot: {
|
bigQRCodeDialogRoot: {
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
cursor: 'zoom-out',
|
cursor: 'zoom-out',
|
||||||
},
|
},
|
||||||
|
paddingBottom: '0px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const ScanQRStep: React.FC = () => {
|
const ScanQRStep: React.FC = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { isDarkTheme } = useContext(SettingsContext);
|
const { isDarkTheme } = useContext(SettingsContext);
|
||||||
|
|
||||||
@ -73,10 +84,20 @@ const ScanQRStep: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<Text className="bp3-text">Scan the QR code</Text>
|
<Text>
|
||||||
<Text className="bp3-text-muted">
|
<span
|
||||||
( make sure your computer and device are connected on same WiFi )
|
style={{
|
||||||
|
backgroundColor: '#00f99273',
|
||||||
|
fontWeight: 900,
|
||||||
|
paddingRight: '8px',
|
||||||
|
paddingLeft: '8px',
|
||||||
|
borderRadius: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
make sure your computer and device are connected to same WiFi
|
||||||
|
</span>
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text className="bp3-text">{t('Scan the QR code')}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Tooltip content="Click to make bigger" position={Position.LEFT}>
|
<Tooltip content="Click to make bigger" position={Position.LEFT}>
|
||||||
@ -133,50 +154,32 @@ const ScanQRStep: React.FC = () => {
|
|||||||
canEscapeKeyClose
|
canEscapeKeyClose
|
||||||
canOutsideClickClose
|
canOutsideClickClose
|
||||||
transitionDuration={isProduction() ? 700 : 0}
|
transitionDuration={isProduction() ? 700 : 0}
|
||||||
style={{ position: 'relative', top: '-30px' }}
|
style={{ position: 'relative', top: '0px' }}
|
||||||
>
|
>
|
||||||
<Button
|
<Row
|
||||||
id="qr-code-dialog-inner"
|
id="qr-code-dialog-inner"
|
||||||
|
className={Classes.DIALOG_BODY}
|
||||||
|
center="xs"
|
||||||
|
middle="xs"
|
||||||
onClick={() => setIsQRCodeMagnified(false)}
|
onClick={() => setIsQRCodeMagnified(false)}
|
||||||
style={{ paddingTop: '20px', paddingBottom: '13px' }}
|
|
||||||
>
|
>
|
||||||
<Row between="xs" middle="xs">
|
<Col xs={11} className={classes.dialogQRWrapper}>
|
||||||
<Col xs={10}>
|
<QRCode
|
||||||
<H2 style={{ margin: '0px', padding: '0px', marginLeft: '35px' }}>
|
value={`http://${LOCAL_LAN_IP}:${CLIENT_VIEWER_PORT}/${roomID}`}
|
||||||
Scan QR Code
|
level="H"
|
||||||
</H2>
|
renderAs="svg"
|
||||||
</Col>
|
imageSettings={{
|
||||||
<Col xs={2}>
|
// TODO: change image to app icon
|
||||||
<CloseOverlayButton
|
src:
|
||||||
onClick={() => setIsQRCodeMagnified(false)}
|
'https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png',
|
||||||
style={{
|
width: 25,
|
||||||
width: '40px',
|
height: 25,
|
||||||
height: '40px',
|
}}
|
||||||
position: 'relative',
|
width="390px"
|
||||||
borderRadius: '100px',
|
height="390px"
|
||||||
}}
|
/>
|
||||||
/>
|
</Col>
|
||||||
</Col>
|
</Row>
|
||||||
</Row>
|
|
||||||
<Row center="xs">
|
|
||||||
<div className={classes.dialogQRWrapper}>
|
|
||||||
<QRCode
|
|
||||||
value={`http://${LOCAL_LAN_IP}:${CLIENT_VIEWER_PORT}/${roomID}`}
|
|
||||||
level="H"
|
|
||||||
renderAs="svg"
|
|
||||||
imageSettings={{
|
|
||||||
// TODO: change image to app icon
|
|
||||||
src:
|
|
||||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png',
|
|
||||||
width: 25,
|
|
||||||
height: 25,
|
|
||||||
}}
|
|
||||||
width="390px"
|
|
||||||
height="390px"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
</Button>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -237,11 +237,21 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
active={true}
|
active={true}
|
||||||
className="makeStyles-orDecorationButton-6"
|
className="makeStyles-orDecorationButton-6"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
|
@ -236,7 +236,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"backgroundColor": "#00f99273",
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
"fontWeight": 900,
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "10px",
|
||||||
|
"paddingRight": "10px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
@ -74,23 +74,31 @@ exports[`should match exact snapshot on each step 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "8px",
|
||||||
|
"paddingRight": "8px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
make sure your computer and device are connected to same WiFi
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Blueprint3.Text>
|
||||||
<Blueprint3.Text
|
<Blueprint3.Text
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
/>
|
||||||
Scan the QR code
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
|
||||||
<Blueprint3.Text
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
( make sure your computer and device are connected on same WiFi )
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
</Blueprint3.Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -423,7 +431,7 @@ exports[`should match exact snapshot on each step 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
@ -443,7 +451,7 @@ exports[`should match exact snapshot on each step 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
@ -840,11 +848,21 @@ exports[`should match exact snapshot on each step 2`] = `
|
|||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
active={true}
|
active={true}
|
||||||
className="makeStyles-orDecorationButton-9"
|
className="makeStyles-orDecorationButton-9"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button bp3-active makeStyles-orDecorationButton-9"
|
className="bp3-button bp3-active makeStyles-orDecorationButton-9"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
@ -1352,7 +1370,10 @@ exports[`should match exact snapshot on each step 3`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"backgroundColor": "#00f99273",
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
"fontWeight": 900,
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "10px",
|
||||||
|
"paddingRight": "10px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
@ -9,16 +9,24 @@ exports[`<ScanQRStep /> when rendered should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "8px",
|
||||||
|
"paddingRight": "8px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
make sure your computer and device are connected to same WiFi
|
||||||
|
</span>
|
||||||
|
</Blueprint3.Text>
|
||||||
<Blueprint3.Text
|
<Blueprint3.Text
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
/>
|
||||||
Scan the QR code
|
|
||||||
</Blueprint3.Text>
|
|
||||||
<Blueprint3.Text
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
( make sure your computer and device are connected on same WiFi )
|
|
||||||
</Blueprint3.Text>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Blueprint3.Tooltip
|
<Blueprint3.Tooltip
|
||||||
@ -95,83 +103,42 @@ exports[`<ScanQRStep /> when rendered should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
>
|
>
|
||||||
<Blueprint3.Button
|
<Row
|
||||||
|
center="xs"
|
||||||
|
className="bp3-dialog-body"
|
||||||
id="qr-code-dialog-inner"
|
id="qr-code-dialog-inner"
|
||||||
|
middle="xs"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"paddingBottom": "13px",
|
|
||||||
"paddingTop": "20px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Row
|
<Col
|
||||||
between="xs"
|
className="makeStyles-dialogQRWrapper-2"
|
||||||
middle="xs"
|
xs={11}
|
||||||
>
|
>
|
||||||
<Col
|
<QRCode
|
||||||
xs={10}
|
bgColor="#FFFFFF"
|
||||||
>
|
fgColor="#000000"
|
||||||
<Component
|
height="390px"
|
||||||
style={
|
imageSettings={
|
||||||
Object {
|
Object {
|
||||||
"margin": "0px",
|
"height": 25,
|
||||||
"marginLeft": "35px",
|
"src": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png",
|
||||||
"padding": "0px",
|
"width": 25,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
>
|
}
|
||||||
Scan QR Code
|
includeMargin={false}
|
||||||
</Component>
|
level="H"
|
||||||
</Col>
|
renderAs="svg"
|
||||||
<Col
|
size={128}
|
||||||
xs={2}
|
value="http://255.255.255.255:3000/"
|
||||||
>
|
width="390px"
|
||||||
<CloseOverlayButton
|
/>
|
||||||
onClick={[Function]}
|
</Col>
|
||||||
style={
|
</Row>
|
||||||
Object {
|
|
||||||
"borderRadius": "100px",
|
|
||||||
"height": "40px",
|
|
||||||
"position": "relative",
|
|
||||||
"width": "40px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row
|
|
||||||
center="xs"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="makeStyles-dialogQRWrapper-2"
|
|
||||||
>
|
|
||||||
<QRCode
|
|
||||||
bgColor="#FFFFFF"
|
|
||||||
fgColor="#000000"
|
|
||||||
height="390px"
|
|
||||||
imageSettings={
|
|
||||||
Object {
|
|
||||||
"height": 25,
|
|
||||||
"src": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png",
|
|
||||||
"width": 25,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
includeMargin={false}
|
|
||||||
level="H"
|
|
||||||
renderAs="svg"
|
|
||||||
size={128}
|
|
||||||
value="http://255.255.255.255:3000/"
|
|
||||||
width="390px"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
</Blueprint3.Button>
|
|
||||||
</Blueprint3.Dialog>
|
</Blueprint3.Dialog>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
@ -2,12 +2,16 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
import React, { useCallback, useContext } from 'react';
|
import React, { useCallback, useContext } from 'react';
|
||||||
import { Button, Icon, Position, Tooltip } from '@blueprintjs/core';
|
import { Button, Text, Icon, Position, Tooltip } from '@blueprintjs/core';
|
||||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||||
|
import { Col, Row } from 'react-flexbox-grid';
|
||||||
import SettingsOverlay from './SettingsOverlay/SettingsOverlay';
|
import SettingsOverlay from './SettingsOverlay/SettingsOverlay';
|
||||||
import ConnectedDevicesListDrawer from './ConnectedDevicesListDrawer';
|
import ConnectedDevicesListDrawer from './ConnectedDevicesListDrawer';
|
||||||
import { SettingsContext } from '../containers/SettingsProvider';
|
import { SettingsContext } from '../containers/SettingsProvider';
|
||||||
import isProduction from '../utils/isProduction';
|
import isProduction from '../utils/isProduction';
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore fine import here
|
||||||
|
import RedHeartTwemojiPNG from '../images/red_heart_2764_twemoji_120x120.png';
|
||||||
|
|
||||||
const Zoom = require('react-reveal/Zoom');
|
const Zoom = require('react-reveal/Zoom');
|
||||||
const Fade = require('react-reveal/Fade');
|
const Fade = require('react-reveal/Fade');
|
||||||
@ -72,13 +76,41 @@ export default function TopPanel(props: any) {
|
|||||||
setIsDrawerOpen(!isDrawersOpen);
|
setIsDrawerOpen(!isDrawersOpen);
|
||||||
}, [isDrawersOpen]);
|
}, [isDrawersOpen]);
|
||||||
|
|
||||||
|
const renderDonateButton = useCallback(() => {
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
content="If you like Deskreen, consider donating! Deskreen is free and opensource forever! You can help us to make Deskreen even better!"
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button style={{ transform: 'translateY(2px)', marginRight: '10px' }}>
|
||||||
|
<Row start="xs">
|
||||||
|
<Col xs>
|
||||||
|
<img
|
||||||
|
src={RedHeartTwemojiPNG}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
style={{ transform: 'translateY(2px)' }}
|
||||||
|
alt="heart"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col xs>
|
||||||
|
<div style={{ transform: 'translateY(2px) translateX(-5px)' }}>
|
||||||
|
<Text>Donate!</Text>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderConnectedDevicesListButton = useCallback(() => {
|
const renderConnectedDevicesListButton = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
||||||
<Tooltip content="Connected Devices" position={Position.BOTTOM}>
|
<Tooltip content="Connected Devices" position={Position.BOTTOM}>
|
||||||
<Button
|
<Button
|
||||||
id="top-panel-connected-devices-list-button"
|
id="top-panel-connected-devices-list-button"
|
||||||
intent="none"
|
intent="primary"
|
||||||
className={getClassesCallback().topPanelControlButton}
|
className={getClassesCallback().topPanelControlButton}
|
||||||
onClick={handleToggleConnectedDevicesListDrawer}
|
onClick={handleToggleConnectedDevicesListDrawer}
|
||||||
>
|
>
|
||||||
@ -96,7 +128,7 @@ export default function TopPanel(props: any) {
|
|||||||
const renderHelpButton = useCallback(() => {
|
const renderHelpButton = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
||||||
<Tooltip content="Help" position={Position.BOTTOM}>
|
<Tooltip content="Tutorial" position={Position.BOTTOM}>
|
||||||
<Button
|
<Button
|
||||||
id="top-panel-help-button"
|
id="top-panel-help-button"
|
||||||
intent="none"
|
intent="none"
|
||||||
@ -104,7 +136,7 @@ export default function TopPanel(props: any) {
|
|||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
className={getClassesCallback().topPanelIconOfControlButton}
|
className={getClassesCallback().topPanelIconOfControlButton}
|
||||||
icon="help"
|
icon="learning"
|
||||||
iconSize={22}
|
iconSize={22}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
@ -140,12 +172,17 @@ export default function TopPanel(props: any) {
|
|||||||
id="logo-with-popover-visit-website"
|
id="logo-with-popover-visit-website"
|
||||||
className={getClassesCallback().logoWithAppName}
|
className={getClassesCallback().logoWithAppName}
|
||||||
>
|
>
|
||||||
<h4
|
<Tooltip
|
||||||
id="deskreen-top-app-name-header"
|
content="Click to visit our website"
|
||||||
className={getClassesCallback().appNameHeader}
|
position={Position.BOTTOM}
|
||||||
>
|
>
|
||||||
Deskreen
|
<h4
|
||||||
</h4>
|
id="deskreen-top-app-name-header"
|
||||||
|
className={getClassesCallback().appNameHeader}
|
||||||
|
>
|
||||||
|
Deskreen
|
||||||
|
</h4>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Zoom>
|
</Zoom>
|
||||||
);
|
);
|
||||||
@ -154,7 +191,14 @@ export default function TopPanel(props: any) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={getClassesCallback().topPanelRoot}>
|
<div className={getClassesCallback().topPanelRoot}>
|
||||||
{renderLogoWithAppName()}
|
<Row
|
||||||
|
middle="xs"
|
||||||
|
center="xs"
|
||||||
|
style={{ width: '100%', transform: 'translateX(-50px)' }}
|
||||||
|
>
|
||||||
|
<Col>{renderDonateButton()}</Col>
|
||||||
|
<Col>{renderLogoWithAppName()}</Col>
|
||||||
|
</Row>
|
||||||
<div className={getClassesCallback().topPanelControlButtonsRoot}>
|
<div className={getClassesCallback().topPanelControlButtonsRoot}>
|
||||||
<Fade right duration={isProduction() ? 2000 : 0}>
|
<Fade right duration={isProduction() ? 2000 : 0}>
|
||||||
{renderConnectedDevicesListButton()}
|
{renderConnectedDevicesListButton()}
|
||||||
|
@ -151,7 +151,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
style="font-weight: 900; background-color: rgba(0, 249, 146, 0.451);"
|
style="font-weight: 900; background-color: rgba(0, 249, 146, 0.451); padding-left: 10px; padding-right: 10px; border-radius: 20px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -301,7 +301,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class=""
|
class=""
|
||||||
style="font-weight: 900; background-color: rgba(0, 249, 146, 0.451);"
|
style="font-weight: 900; background-color: rgba(0, 249, 146, 0.451); padding-left: 10px; padding-right: 10px; border-radius: 20px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -628,7 +628,10 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"backgroundColor": "#00f99273",
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
"fontWeight": 900,
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "10px",
|
||||||
|
"paddingRight": "10px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
@ -175,11 +175,21 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
active={true}
|
active={true}
|
||||||
className="makeStyles-orDecorationButton-6"
|
className="makeStyles-orDecorationButton-6"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 999,
|
||||||
|
}
|
||||||
|
}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
|
@ -5,22 +5,96 @@ exports[`<TopPanel /> should match exact snapshot 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="makeStyles-topPanelRoot-1"
|
className="makeStyles-topPanelRoot-1"
|
||||||
>
|
>
|
||||||
<Zoom
|
<Row
|
||||||
duration={0}
|
center="xs"
|
||||||
top={true}
|
middle="xs"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateX(-50px)",
|
||||||
|
"width": "100%",
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div
|
<Col>
|
||||||
className="makeStyles-logoWithAppName-9"
|
<Blueprint3.Tooltip
|
||||||
id="logo-with-popover-visit-website"
|
content="If you like Deskreen, consider donating! Deskreen is free and opensource forever! You can help us to make Deskreen even better!"
|
||||||
>
|
hoverCloseDelay={0}
|
||||||
<h4
|
hoverOpenDelay={100}
|
||||||
className="makeStyles-appNameHeader-17"
|
position="bottom"
|
||||||
id="deskreen-top-app-name-header"
|
transitionDuration={100}
|
||||||
>
|
>
|
||||||
Deskreen
|
<Blueprint3.Button
|
||||||
</h4>
|
style={
|
||||||
</div>
|
Object {
|
||||||
</Zoom>
|
"marginRight": "10px",
|
||||||
|
"transform": "translateY(2px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
start="xs"
|
||||||
|
>
|
||||||
|
<Col
|
||||||
|
xs={true}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="heart"
|
||||||
|
height={16}
|
||||||
|
src="test-file-stub"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateY(2px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
width={16}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
xs={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateY(2px) translateX(-5px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
Donate!
|
||||||
|
</Blueprint3.Text>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Blueprint3.Button>
|
||||||
|
</Blueprint3.Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Zoom
|
||||||
|
duration={0}
|
||||||
|
top={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="makeStyles-logoWithAppName-9"
|
||||||
|
id="logo-with-popover-visit-website"
|
||||||
|
>
|
||||||
|
<Blueprint3.Tooltip
|
||||||
|
content="Click to visit our website"
|
||||||
|
hoverCloseDelay={0}
|
||||||
|
hoverOpenDelay={100}
|
||||||
|
position="bottom"
|
||||||
|
transitionDuration={100}
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
className="makeStyles-appNameHeader-17"
|
||||||
|
id="deskreen-top-app-name-header"
|
||||||
|
>
|
||||||
|
Deskreen
|
||||||
|
</h4>
|
||||||
|
</Blueprint3.Tooltip>
|
||||||
|
</div>
|
||||||
|
</Zoom>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-topPanelControlButtonsRoot-25"
|
className="makeStyles-topPanelControlButtonsRoot-25"
|
||||||
>
|
>
|
||||||
@ -41,7 +115,7 @@ exports[`<TopPanel /> should match exact snapshot 1`] = `
|
|||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
className="makeStyles-topPanelControlButton-40"
|
className="makeStyles-topPanelControlButton-40"
|
||||||
id="top-panel-connected-devices-list-button"
|
id="top-panel-connected-devices-list-button"
|
||||||
intent="none"
|
intent="primary"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
@ -56,7 +130,7 @@ exports[`<TopPanel /> should match exact snapshot 1`] = `
|
|||||||
className="makeStyles-topPanelControlButtonMargin-55"
|
className="makeStyles-topPanelControlButtonMargin-55"
|
||||||
>
|
>
|
||||||
<Blueprint3.Tooltip
|
<Blueprint3.Tooltip
|
||||||
content="Help"
|
content="Tutorial"
|
||||||
hoverCloseDelay={0}
|
hoverCloseDelay={0}
|
||||||
hoverOpenDelay={100}
|
hoverOpenDelay={100}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
@ -69,7 +143,7 @@ exports[`<TopPanel /> should match exact snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-topPanelIconOfControlButton-70"
|
className="makeStyles-topPanelIconOfControlButton-70"
|
||||||
icon="help"
|
icon="learning"
|
||||||
iconSize={22}
|
iconSize={22}
|
||||||
/>
|
/>
|
||||||
</Blueprint3.Button>
|
</Blueprint3.Button>
|
||||||
|
@ -8,6 +8,7 @@ import settings from 'electron-settings';
|
|||||||
import config from './app.lang.config';
|
import config from './app.lang.config';
|
||||||
import isProduction from '../utils/isProduction';
|
import isProduction from '../utils/isProduction';
|
||||||
|
|
||||||
|
// TODO: move this outside this file!
|
||||||
export const getLangFullNameToLangISOKeyMap = (): Map<string, string> => {
|
export const getLangFullNameToLangISOKeyMap = (): Map<string, string> => {
|
||||||
const res = new Map<string, string>();
|
const res = new Map<string, string>();
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
@ -19,6 +20,7 @@ export const getLangFullNameToLangISOKeyMap = (): Map<string, string> => {
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: move this outside this file!
|
||||||
export const getLangISOKeyToLangFullNameMap = (): Map<string, string> => {
|
export const getLangISOKeyToLangFullNameMap = (): Map<string, string> => {
|
||||||
const res = new Map<string, string>();
|
const res = new Map<string, string>();
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
@ -23,6 +23,8 @@ jest.mock('electron', () => {
|
|||||||
return {
|
return {
|
||||||
createWaitingForConnectionSharingSession: () =>
|
createWaitingForConnectionSharingSession: () =>
|
||||||
new Promise(() => {}),
|
new Promise(() => {}),
|
||||||
|
setAppLanguage: () => {},
|
||||||
|
setAppTheme: () => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -9,12 +9,16 @@ export const DARK_UI_BACKGROUND = '#293742';
|
|||||||
|
|
||||||
interface SettingsContextInterface {
|
interface SettingsContextInterface {
|
||||||
isDarkTheme: boolean;
|
isDarkTheme: boolean;
|
||||||
|
currentLanguage: string;
|
||||||
setIsDarkThemeHook: (val: boolean) => void;
|
setIsDarkThemeHook: (val: boolean) => void;
|
||||||
|
setCurrentLanguageHook: (newLang: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSettingsContextValue = {
|
const defaultSettingsContextValue = {
|
||||||
isDarkTheme: false,
|
isDarkTheme: false,
|
||||||
setIsDarkThemeHook: () => {},
|
setIsDarkThemeHook: () => {},
|
||||||
|
setCurrentLanguageHook: () => {},
|
||||||
|
currentLanguage: 'en',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsContext = React.createContext<SettingsContextInterface>(
|
export const SettingsContext = React.createContext<SettingsContextInterface>(
|
||||||
@ -23,6 +27,7 @@ export const SettingsContext = React.createContext<SettingsContextInterface>(
|
|||||||
|
|
||||||
export const SettingsProvider: React.FC = ({ children }) => {
|
export const SettingsProvider: React.FC = ({ children }) => {
|
||||||
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
||||||
|
const [currentLanguage, setCurrentLanguage] = useState('en');
|
||||||
|
|
||||||
const loadDarkThemeFromSettings = () => {
|
const loadDarkThemeFromSettings = () => {
|
||||||
const gotIsDarkThemeFromSettings = settings.hasSync('appIsDarkTheme')
|
const gotIsDarkThemeFromSettings = settings.hasSync('appIsDarkTheme')
|
||||||
@ -46,7 +51,16 @@ export const SettingsProvider: React.FC = ({ children }) => {
|
|||||||
setIsDarkTheme(val);
|
setIsDarkTheme(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
const value = { isDarkTheme, setIsDarkThemeHook };
|
const setCurrentLanguageHook = (newLang: string) => {
|
||||||
|
setCurrentLanguage(newLang);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
isDarkTheme,
|
||||||
|
setIsDarkThemeHook,
|
||||||
|
currentLanguage,
|
||||||
|
setCurrentLanguageHook,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsContext.Provider value={value}>
|
<SettingsContext.Provider value={value}>
|
||||||
|
@ -17,6 +17,8 @@ jest.mock('electron', () => {
|
|||||||
return {
|
return {
|
||||||
createWaitingForConnectionSharingSession: () =>
|
createWaitingForConnectionSharingSession: () =>
|
||||||
new Promise(() => {}),
|
new Promise(() => {}),
|
||||||
|
setAppLanguage: () => {},
|
||||||
|
setAppTheme: () => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (globalName === 'connectedDevicesService') {
|
if (globalName === 'connectedDevicesService') {
|
||||||
|
@ -66,7 +66,7 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
|
|
||||||
const [isInterShow, setIsInterShow] = useState(false);
|
const [isInterShow, setIsInterShow] = useState(false);
|
||||||
|
|
||||||
const { isDarkTheme } = useContext(SettingsContext);
|
const { isDarkTheme, currentLanguage } = useContext(SettingsContext);
|
||||||
|
|
||||||
const { addToast } = useToasts();
|
const { addToast } = useToasts();
|
||||||
|
|
||||||
@ -104,8 +104,17 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
},
|
},
|
||||||
isProduction() ? 500 : 0
|
isProduction() ? 500 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// sharingSessionService.setAppLanguage(currentLanguage);
|
||||||
|
// sharingSessionService.setAppTheme(isDarkTheme ? 'dark' : 'light');
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
sharingSessionService.setAppLanguage(currentLanguage);
|
||||||
|
sharingSessionService.setAppTheme(isDarkTheme);
|
||||||
|
}, [currentLanguage, isDarkTheme]);
|
||||||
|
|
||||||
const [activeStep, setActiveStep] = useState(0);
|
const [activeStep, setActiveStep] = useState(0);
|
||||||
const [isEntireScreenSelected, setIsEntireScreenSelected] = useState(false);
|
const [isEntireScreenSelected, setIsEntireScreenSelected] = useState(false);
|
||||||
const [
|
const [
|
||||||
@ -153,7 +162,40 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
setActiveStep(0);
|
setActiveStep(0);
|
||||||
setPendingConnectionDevice(null);
|
setPendingConnectionDevice(null);
|
||||||
setIsUserAllowedConnection(false);
|
setIsUserAllowedConnection(false);
|
||||||
|
|
||||||
|
// const sharingSession =
|
||||||
|
// sharingSessionService.waitingForConnectionSharingSession;
|
||||||
|
// sharingSession?.disconnectByHostMachineUser();
|
||||||
|
// sharingSession?.destory();
|
||||||
|
// sharingSessionService.sharingSessions.delete(sharingSession?.id as string);
|
||||||
|
// sharingSessionService.waitingForConnectionSharingSession = null;
|
||||||
|
|
||||||
|
sharingSessionService
|
||||||
|
.createWaitingForConnectionSharingSession()
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
|
.then((waitingForConnectionSharingSession) => {
|
||||||
|
waitingForConnectionSharingSession.setOnDeviceConnectedCallback(
|
||||||
|
(device: Device) => {
|
||||||
|
connectedDevicesService.setPendingConnectionDevice(device);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => log.error(e));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleResetWithSharingSessionRestart = useCallback(() => {
|
||||||
|
makeSmoothIntermediateStepTransition();
|
||||||
|
setActiveStep(0);
|
||||||
|
setPendingConnectionDevice(null);
|
||||||
|
setIsUserAllowedConnection(false);
|
||||||
|
|
||||||
|
const sharingSession =
|
||||||
|
sharingSessionService.waitingForConnectionSharingSession;
|
||||||
|
sharingSession?.disconnectByHostMachineUser();
|
||||||
|
sharingSession?.destory();
|
||||||
|
sharingSessionService.sharingSessions.delete(sharingSession?.id as string);
|
||||||
sharingSessionService.waitingForConnectionSharingSession = null;
|
sharingSessionService.waitingForConnectionSharingSession = null;
|
||||||
|
|
||||||
sharingSessionService
|
sharingSessionService
|
||||||
.createWaitingForConnectionSharingSession()
|
.createWaitingForConnectionSharingSession()
|
||||||
// eslint-disable-next-line promise/always-return
|
// eslint-disable-next-line promise/always-return
|
||||||
@ -169,7 +211,7 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
|
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
handleReset() {
|
handleReset() {
|
||||||
handleReset();
|
handleResetWithSharingSessionRestart();
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -215,7 +257,7 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
}, [handleNext]);
|
}, [handleNext]);
|
||||||
|
|
||||||
const handleUserClickedDeviceDisconnectButton = useCallback(async () => {
|
const handleUserClickedDeviceDisconnectButton = useCallback(async () => {
|
||||||
handleReset();
|
handleResetWithSharingSessionRestart();
|
||||||
|
|
||||||
addToast(
|
addToast(
|
||||||
<Text>
|
<Text>
|
||||||
@ -224,20 +266,11 @@ const DeskreenStepper = React.forwardRef((_props, ref) => {
|
|||||||
{
|
{
|
||||||
appearance: 'info',
|
appearance: 'info',
|
||||||
autoDismiss: true,
|
autoDismiss: true,
|
||||||
// @ts-ignore: works fine here, ignore
|
// @ts-ignore: works fine here
|
||||||
isdarktheme: `${isDarkTheme}`,
|
isdarktheme: `${isDarkTheme}`,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}, [addToast, handleResetWithSharingSessionRestart, isDarkTheme]);
|
||||||
if (sharingSessionService.waitingForConnectionSharingSession !== null) {
|
|
||||||
const sharingSession =
|
|
||||||
sharingSessionService.waitingForConnectionSharingSession;
|
|
||||||
sharingSession.disconnectByHostMachineUser();
|
|
||||||
sharingSession.destory();
|
|
||||||
sharingSession.setStatus(SharingSessionStatusEnum.NOT_CONNECTED);
|
|
||||||
sharingSessionService.sharingSessions.delete(sharingSession.id);
|
|
||||||
}
|
|
||||||
}, [addToast, handleReset, isDarkTheme]);
|
|
||||||
|
|
||||||
const renderIntermediateOrSuccessStepContent = useCallback(() => {
|
const renderIntermediateOrSuccessStepContent = useCallback(() => {
|
||||||
return activeStep === steps.length ? (
|
return activeStep === steps.length ? (
|
||||||
|
@ -57,63 +57,339 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-topPanelRoot-1"
|
className="makeStyles-topPanelRoot-117"
|
||||||
>
|
>
|
||||||
<Zoom
|
<Row
|
||||||
duration={0}
|
center="xs"
|
||||||
top={true}
|
middle="xs"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateX(-50px)",
|
||||||
|
"width": "100%",
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<RevealBase
|
<div
|
||||||
fraction={0.2}
|
className="row center-xs middle-xs"
|
||||||
inEffect={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"count": 1,
|
"transform": "translateX(-50px)",
|
||||||
"delay": 0,
|
"width": "100%",
|
||||||
"duration": 0,
|
|
||||||
"forever": undefined,
|
|
||||||
"make": [Function],
|
|
||||||
"reverse": undefined,
|
|
||||||
"style": Object {
|
|
||||||
"animationFillMode": "both",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outEffect={
|
|
||||||
Object {
|
|
||||||
"count": 1,
|
|
||||||
"delay": 0,
|
|
||||||
"duration": 0,
|
|
||||||
"forever": undefined,
|
|
||||||
"make": [Function],
|
|
||||||
"reverse": undefined,
|
|
||||||
"style": Object {
|
|
||||||
"animationFillMode": "both",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refProp="ref"
|
|
||||||
top={true}
|
|
||||||
>
|
>
|
||||||
<div
|
<Col>
|
||||||
className="react-reveal makeStyles-logoWithAppName-9"
|
<div
|
||||||
id="logo-with-popover-visit-website"
|
className=""
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"opacity": undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
className="makeStyles-appNameHeader-17"
|
|
||||||
id="deskreen-top-app-name-header"
|
|
||||||
>
|
>
|
||||||
Deskreen
|
<Blueprint3.Tooltip
|
||||||
</h4>
|
content="If you like Deskreen, consider donating! Deskreen is free and opensource forever! You can help us to make Deskreen even better!"
|
||||||
</div>
|
hoverCloseDelay={0}
|
||||||
</RevealBase>
|
hoverOpenDelay={100}
|
||||||
</Zoom>
|
position="bottom"
|
||||||
|
transitionDuration={100}
|
||||||
|
>
|
||||||
|
<Blueprint3.Popover
|
||||||
|
autoFocus={false}
|
||||||
|
boundary="scrollParent"
|
||||||
|
canEscapeKeyClose={false}
|
||||||
|
captureDismiss={false}
|
||||||
|
content="If you like Deskreen, consider donating! Deskreen is free and opensource forever! You can help us to make Deskreen even better!"
|
||||||
|
defaultIsOpen={false}
|
||||||
|
disabled={false}
|
||||||
|
enforceFocus={false}
|
||||||
|
fill={false}
|
||||||
|
hasBackdrop={false}
|
||||||
|
hoverCloseDelay={0}
|
||||||
|
hoverOpenDelay={100}
|
||||||
|
inheritDarkTheme={true}
|
||||||
|
interactionKind="hover-target"
|
||||||
|
lazy={true}
|
||||||
|
minimal={false}
|
||||||
|
modifiers={Object {}}
|
||||||
|
openOnTargetFocus={true}
|
||||||
|
popoverClassName="bp3-tooltip"
|
||||||
|
position="bottom"
|
||||||
|
targetTagName="span"
|
||||||
|
transitionDuration={100}
|
||||||
|
usePortal={true}
|
||||||
|
wrapperTagName="span"
|
||||||
|
>
|
||||||
|
<Manager>
|
||||||
|
<span
|
||||||
|
className="bp3-popover-wrapper"
|
||||||
|
>
|
||||||
|
<Reference
|
||||||
|
innerRef={[Function]}
|
||||||
|
>
|
||||||
|
<InnerReference
|
||||||
|
innerRef={[Function]}
|
||||||
|
setReferenceNode={[Function]}
|
||||||
|
>
|
||||||
|
<Blueprint3.ResizeSensor
|
||||||
|
onResize={[Function]}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="bp3-popover-target"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
>
|
||||||
|
<Blueprint3.Button
|
||||||
|
className=""
|
||||||
|
key=".0"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginRight": "10px",
|
||||||
|
"transform": "translateY(2px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="bp3-button"
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onKeyUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginRight": "10px",
|
||||||
|
"transform": "translateY(2px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabIndex={0}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Blueprint3.Icon
|
||||||
|
key="leftIcon"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="bp3-button-text"
|
||||||
|
key="text"
|
||||||
|
>
|
||||||
|
<Row
|
||||||
|
start="xs"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="row start-xs"
|
||||||
|
>
|
||||||
|
<Col
|
||||||
|
xs={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="col-xs"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="heart"
|
||||||
|
height={16}
|
||||||
|
src="test-file-stub"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateY(2px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
width={16}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col
|
||||||
|
xs={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="col-xs"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"transform": "translateY(2px) translateX(-5px)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
Donate!
|
||||||
|
</div>
|
||||||
|
</Blueprint3.Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</span>
|
||||||
|
<Blueprint3.Icon
|
||||||
|
key="rightIcon"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</Blueprint3.Button>
|
||||||
|
</span>
|
||||||
|
</Blueprint3.ResizeSensor>
|
||||||
|
</InnerReference>
|
||||||
|
</Reference>
|
||||||
|
<Blueprint3.Overlay
|
||||||
|
autoFocus={false}
|
||||||
|
backdropClassName="bp3-popover-backdrop"
|
||||||
|
backdropProps={Object {}}
|
||||||
|
canEscapeKeyClose={false}
|
||||||
|
canOutsideClickClose={false}
|
||||||
|
enforceFocus={false}
|
||||||
|
hasBackdrop={false}
|
||||||
|
isOpen={false}
|
||||||
|
lazy={true}
|
||||||
|
onClose={[Function]}
|
||||||
|
transitionDuration={100}
|
||||||
|
transitionName="bp3-popover"
|
||||||
|
usePortal={true}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Manager>
|
||||||
|
</Blueprint3.Popover>
|
||||||
|
</Blueprint3.Tooltip>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
<Zoom
|
||||||
|
duration={0}
|
||||||
|
top={true}
|
||||||
|
>
|
||||||
|
<RevealBase
|
||||||
|
fraction={0.2}
|
||||||
|
inEffect={
|
||||||
|
Object {
|
||||||
|
"count": 1,
|
||||||
|
"delay": 0,
|
||||||
|
"duration": 0,
|
||||||
|
"forever": undefined,
|
||||||
|
"make": [Function],
|
||||||
|
"reverse": undefined,
|
||||||
|
"style": Object {
|
||||||
|
"animationFillMode": "both",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outEffect={
|
||||||
|
Object {
|
||||||
|
"count": 1,
|
||||||
|
"delay": 0,
|
||||||
|
"duration": 0,
|
||||||
|
"forever": undefined,
|
||||||
|
"make": [Function],
|
||||||
|
"reverse": undefined,
|
||||||
|
"style": Object {
|
||||||
|
"animationFillMode": "both",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refProp="ref"
|
||||||
|
top={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="react-reveal makeStyles-logoWithAppName-125"
|
||||||
|
id="logo-with-popover-visit-website"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"opacity": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Blueprint3.Tooltip
|
||||||
|
content="Click to visit our website"
|
||||||
|
hoverCloseDelay={0}
|
||||||
|
hoverOpenDelay={100}
|
||||||
|
position="bottom"
|
||||||
|
transitionDuration={100}
|
||||||
|
>
|
||||||
|
<Blueprint3.Popover
|
||||||
|
autoFocus={false}
|
||||||
|
boundary="scrollParent"
|
||||||
|
canEscapeKeyClose={false}
|
||||||
|
captureDismiss={false}
|
||||||
|
content="Click to visit our website"
|
||||||
|
defaultIsOpen={false}
|
||||||
|
disabled={false}
|
||||||
|
enforceFocus={false}
|
||||||
|
fill={false}
|
||||||
|
hasBackdrop={false}
|
||||||
|
hoverCloseDelay={0}
|
||||||
|
hoverOpenDelay={100}
|
||||||
|
inheritDarkTheme={true}
|
||||||
|
interactionKind="hover-target"
|
||||||
|
lazy={true}
|
||||||
|
minimal={false}
|
||||||
|
modifiers={Object {}}
|
||||||
|
openOnTargetFocus={true}
|
||||||
|
popoverClassName="bp3-tooltip"
|
||||||
|
position="bottom"
|
||||||
|
targetTagName="span"
|
||||||
|
transitionDuration={100}
|
||||||
|
usePortal={true}
|
||||||
|
wrapperTagName="span"
|
||||||
|
>
|
||||||
|
<Manager>
|
||||||
|
<span
|
||||||
|
className="bp3-popover-wrapper"
|
||||||
|
>
|
||||||
|
<Reference
|
||||||
|
innerRef={[Function]}
|
||||||
|
>
|
||||||
|
<InnerReference
|
||||||
|
innerRef={[Function]}
|
||||||
|
setReferenceNode={[Function]}
|
||||||
|
>
|
||||||
|
<Blueprint3.ResizeSensor
|
||||||
|
onResize={[Function]}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="bp3-popover-target"
|
||||||
|
onBlur={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
className="makeStyles-appNameHeader-133"
|
||||||
|
id="deskreen-top-app-name-header"
|
||||||
|
key=".0"
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
Deskreen
|
||||||
|
</h4>
|
||||||
|
</span>
|
||||||
|
</Blueprint3.ResizeSensor>
|
||||||
|
</InnerReference>
|
||||||
|
</Reference>
|
||||||
|
<Blueprint3.Overlay
|
||||||
|
autoFocus={false}
|
||||||
|
backdropClassName="bp3-popover-backdrop"
|
||||||
|
backdropProps={Object {}}
|
||||||
|
canEscapeKeyClose={false}
|
||||||
|
canOutsideClickClose={false}
|
||||||
|
enforceFocus={false}
|
||||||
|
hasBackdrop={false}
|
||||||
|
isOpen={false}
|
||||||
|
lazy={true}
|
||||||
|
onClose={[Function]}
|
||||||
|
transitionDuration={100}
|
||||||
|
transitionName="bp3-popover"
|
||||||
|
usePortal={true}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Manager>
|
||||||
|
</Blueprint3.Popover>
|
||||||
|
</Blueprint3.Tooltip>
|
||||||
|
</div>
|
||||||
|
</RevealBase>
|
||||||
|
</Zoom>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
<div
|
<div
|
||||||
className="makeStyles-topPanelControlButtonsRoot-25"
|
className="makeStyles-topPanelControlButtonsRoot-141"
|
||||||
>
|
>
|
||||||
<Fade
|
<Fade
|
||||||
duration={0}
|
duration={0}
|
||||||
@ -152,7 +428,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
right={true}
|
right={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="react-reveal makeStyles-topPanelControlButtonMargin-34"
|
className="react-reveal makeStyles-topPanelControlButtonMargin-150"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"opacity": undefined,
|
"opacity": undefined,
|
||||||
@ -214,15 +490,15 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
>
|
>
|
||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
className="makeStyles-topPanelControlButton-40"
|
className="makeStyles-topPanelControlButton-156"
|
||||||
id="top-panel-connected-devices-list-button"
|
id="top-panel-connected-devices-list-button"
|
||||||
intent="none"
|
intent="primary"
|
||||||
key=".0"
|
key=".0"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button makeStyles-topPanelControlButton-40"
|
className="bp3-button bp3-intent-primary makeStyles-topPanelControlButton-156"
|
||||||
id="top-panel-connected-devices-list-button"
|
id="top-panel-connected-devices-list-button"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
@ -238,12 +514,12 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
key="text"
|
key="text"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-topPanelIconOfControlButton-49"
|
className="makeStyles-topPanelIconOfControlButton-165"
|
||||||
icon="th-list"
|
icon="th-list"
|
||||||
iconSize={20}
|
iconSize={20}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-th-list makeStyles-topPanelIconOfControlButton-49"
|
className="bp3-icon bp3-icon-th-list makeStyles-topPanelIconOfControlButton-165"
|
||||||
icon="th-list"
|
icon="th-list"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -327,7 +603,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
right={true}
|
right={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="react-reveal makeStyles-topPanelControlButtonMargin-55"
|
className="react-reveal makeStyles-topPanelControlButtonMargin-171"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"opacity": undefined,
|
"opacity": undefined,
|
||||||
@ -335,7 +611,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Blueprint3.Tooltip
|
<Blueprint3.Tooltip
|
||||||
content="Help"
|
content="Tutorial"
|
||||||
hoverCloseDelay={0}
|
hoverCloseDelay={0}
|
||||||
hoverOpenDelay={100}
|
hoverOpenDelay={100}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
@ -346,7 +622,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
boundary="scrollParent"
|
boundary="scrollParent"
|
||||||
canEscapeKeyClose={false}
|
canEscapeKeyClose={false}
|
||||||
captureDismiss={false}
|
captureDismiss={false}
|
||||||
content="Help"
|
content="Tutorial"
|
||||||
defaultIsOpen={false}
|
defaultIsOpen={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
enforceFocus={false}
|
enforceFocus={false}
|
||||||
@ -389,14 +665,14 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
>
|
>
|
||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
className="makeStyles-topPanelControlButton-61"
|
className="makeStyles-topPanelControlButton-177"
|
||||||
id="top-panel-help-button"
|
id="top-panel-help-button"
|
||||||
intent="none"
|
intent="none"
|
||||||
key=".0"
|
key=".0"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button makeStyles-topPanelControlButton-61"
|
className="bp3-button makeStyles-topPanelControlButton-177"
|
||||||
id="top-panel-help-button"
|
id="top-panel-help-button"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
@ -411,28 +687,33 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
key="text"
|
key="text"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-topPanelIconOfControlButton-70"
|
className="makeStyles-topPanelIconOfControlButton-186"
|
||||||
icon="help"
|
icon="learning"
|
||||||
iconSize={22}
|
iconSize={22}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-help makeStyles-topPanelIconOfControlButton-70"
|
className="bp3-icon bp3-icon-learning makeStyles-topPanelIconOfControlButton-186"
|
||||||
icon="help"
|
icon="learning"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
data-icon="help"
|
data-icon="learning"
|
||||||
height={22}
|
height={22}
|
||||||
viewBox="0 0 20 20"
|
viewBox="0 0 20 20"
|
||||||
width={22}
|
width={22}
|
||||||
>
|
>
|
||||||
<desc>
|
<desc>
|
||||||
help
|
learning
|
||||||
</desc>
|
</desc>
|
||||||
<path
|
<path
|
||||||
d="M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zM7.41 4.62c.65-.54 1.51-.82 2.56-.82.54 0 1.03.08 1.48.25.44.17.83.39 1.14.68.32.29.56.63.74 1.02.17.39.26.82.26 1.27s-.08.87-.24 1.23c-.16.37-.4.73-.71 1.11l-1.21 1.58c-.14.17-.28.33-.32.48-.05.15-.11.35-.11.6v.97H9v-2s.06-.58.24-.81l1.21-1.64c.25-.3.41-.56.51-.77s.14-.44.14-.67c0-.35-.11-.63-.32-.85s-.5-.33-.88-.33c-.37 0-.67.11-.89.33-.22.23-.37.54-.46.94-.03.12-.11.17-.23.16l-1.95-.29c-.12-.01-.16-.08-.14-.22.13-.93.52-1.67 1.18-2.22zM9 14h2.02L11 16H9v-2z"
|
d="M10.551 1.127a1.256 1.256 0 00-1.102 0L.456 5.89c-.608.309-.608.913 0 1.222l8.993 4.762c.334.17.767.17 1.102 0l8.992-4.762c.61-.309.61-.913 0-1.222l-8.992-4.762z"
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
key="0"
|
key="0"
|
||||||
/>
|
/>
|
||||||
|
<path
|
||||||
|
d="M18 6.5l.016 4.514c.002.548.447.99.994.99a.99.99 0 00.99-.99V6.5h-2zM3.366 10.033l6.401 3.358a.5.5 0 00.465 0l6.406-3.358a.25.25 0 01.366.221v5.109a.25.25 0 01-.139.224l-6.64 3.302a.5.5 0 01-.446 0l-6.64-3.302A.25.25 0 013 15.363v-5.108a.25.25 0 01.366-.222z"
|
||||||
|
fillRule="evenodd"
|
||||||
|
key="1"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</Blueprint3.Icon>
|
</Blueprint3.Icon>
|
||||||
@ -500,7 +781,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
right={true}
|
right={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="react-reveal makeStyles-topPanelControlButtonMargin-76"
|
className="react-reveal makeStyles-topPanelControlButtonMargin-192"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"opacity": undefined,
|
"opacity": undefined,
|
||||||
@ -562,14 +843,14 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
>
|
>
|
||||||
<Blueprint3.Button
|
<Blueprint3.Button
|
||||||
className="makeStyles-topPanelControlButton-82"
|
className="makeStyles-topPanelControlButton-198"
|
||||||
id="top-panel-settings-button"
|
id="top-panel-settings-button"
|
||||||
key=".0"
|
key=".0"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="bp3-button makeStyles-topPanelControlButton-82"
|
className="bp3-button makeStyles-topPanelControlButton-198"
|
||||||
id="top-panel-settings-button"
|
id="top-panel-settings-button"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
@ -585,12 +866,12 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
key="text"
|
key="text"
|
||||||
>
|
>
|
||||||
<Blueprint3.Icon
|
<Blueprint3.Icon
|
||||||
className="makeStyles-topPanelIconOfControlButton-91"
|
className="makeStyles-topPanelIconOfControlButton-207"
|
||||||
icon="cog"
|
icon="cog"
|
||||||
iconSize={22}
|
iconSize={22}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="bp3-icon bp3-icon-cog makeStyles-topPanelIconOfControlButton-91"
|
className="bp3-icon bp3-icon-cog makeStyles-topPanelIconOfControlButton-207"
|
||||||
icon="cog"
|
icon="cog"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -1773,23 +2054,31 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "8px",
|
||||||
|
"paddingRight": "8px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
make sure your computer and device are connected to same WiFi
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Blueprint3.Text>
|
||||||
<Blueprint3.Text
|
<Blueprint3.Text
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
/>
|
||||||
Scan the QR code
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
|
||||||
<Blueprint3.Text
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
( make sure your computer and device are connected on same WiFi )
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
</Blueprint3.Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -2122,7 +2411,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
@ -2142,7 +2431,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
|
@ -1059,23 +1059,31 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<Blueprint3.Text>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#00f99273",
|
||||||
|
"borderRadius": "20px",
|
||||||
|
"fontWeight": 900,
|
||||||
|
"paddingLeft": "8px",
|
||||||
|
"paddingRight": "8px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
make sure your computer and device are connected to same WiFi
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Blueprint3.Text>
|
||||||
<Blueprint3.Text
|
<Blueprint3.Text
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="bp3-text"
|
className="bp3-text"
|
||||||
>
|
/>
|
||||||
Scan the QR code
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
|
||||||
<Blueprint3.Text
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="bp3-text-muted"
|
|
||||||
>
|
|
||||||
( make sure your computer and device are connected on same WiFi )
|
|
||||||
</div>
|
|
||||||
</Blueprint3.Text>
|
</Blueprint3.Text>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -1408,7 +1416,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
@ -1428,7 +1436,7 @@ exports[`should match exact snapshot 1`] = `
|
|||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"position": "relative",
|
"position": "relative",
|
||||||
"top": "-30px",
|
"top": "0px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitionDuration={0}
|
transitionDuration={0}
|
||||||
|
@ -2,8 +2,8 @@ export default async (
|
|||||||
sourceID: string,
|
sourceID: string,
|
||||||
width: number | null | undefined = undefined,
|
width: number | null | undefined = undefined,
|
||||||
height: number | null | undefined = undefined,
|
height: number | null | undefined = undefined,
|
||||||
minSizeDivisor = 1,
|
minSizeMultiplier = 1,
|
||||||
maxSizeDivisor = 1,
|
maxSizeMultiplier = 1,
|
||||||
minFrameRate = 15,
|
minFrameRate = 15,
|
||||||
maxFrameRate = 60
|
maxFrameRate = 60
|
||||||
) => {
|
) => {
|
||||||
@ -17,10 +17,10 @@ export default async (
|
|||||||
chromeMediaSource: 'desktop',
|
chromeMediaSource: 'desktop',
|
||||||
chromeMediaSourceId: sourceID,
|
chromeMediaSourceId: sourceID,
|
||||||
|
|
||||||
minWidth: width / minSizeDivisor,
|
minWidth: width * minSizeMultiplier,
|
||||||
maxWidth: width / maxSizeDivisor,
|
maxWidth: width * maxSizeMultiplier,
|
||||||
minHeight: height / minSizeDivisor,
|
minHeight: height * minSizeMultiplier,
|
||||||
maxHeight: height / maxSizeDivisor,
|
maxHeight: height * maxSizeMultiplier,
|
||||||
|
|
||||||
minFrameRate,
|
minFrameRate,
|
||||||
maxFrameRate,
|
maxFrameRate,
|
||||||
|
@ -18,6 +18,7 @@ import Logger from '../../utils/logger';
|
|||||||
import DesktopCapturerSources from '../DesktopCapturerSourcesService';
|
import DesktopCapturerSources from '../DesktopCapturerSourcesService';
|
||||||
import setSdpMediaBitrate from './setSdpMediaBitrate';
|
import setSdpMediaBitrate from './setSdpMediaBitrate';
|
||||||
import getDesktopSourceStreamBySourceID from './getDesktopSourceStreamBySourceID';
|
import getDesktopSourceStreamBySourceID from './getDesktopSourceStreamBySourceID';
|
||||||
|
import prepareDataMessageToSendScreenSourceType from './prepareDataMessageToSendScreenSourceType';
|
||||||
|
|
||||||
const log = new Logger(__filename);
|
const log = new Logger(__filename);
|
||||||
|
|
||||||
@ -69,11 +70,15 @@ export default class PeerConnection {
|
|||||||
prevStreamHeight: number;
|
prevStreamHeight: number;
|
||||||
displayID: string;
|
displayID: string;
|
||||||
sourceDisplaySize: DisplaySize | undefined;
|
sourceDisplaySize: DisplaySize | undefined;
|
||||||
|
appLanguage: string;
|
||||||
|
appColorTheme: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
roomID: string,
|
roomID: string,
|
||||||
sharingSessionID: string,
|
sharingSessionID: string,
|
||||||
user: LocalPeerUser,
|
user: LocalPeerUser,
|
||||||
|
appColorTheme: boolean,
|
||||||
|
appLanguage: string,
|
||||||
roomIDService: RoomIDService,
|
roomIDService: RoomIDService,
|
||||||
connectedDevicesService: ConnectedDevicesService,
|
connectedDevicesService: ConnectedDevicesService,
|
||||||
sharingSessionsService: SharingSessionsService
|
sharingSessionsService: SharingSessionsService
|
||||||
@ -96,11 +101,37 @@ export default class PeerConnection {
|
|||||||
this.prevStreamHeight = -1;
|
this.prevStreamHeight = -1;
|
||||||
this.displayID = '';
|
this.displayID = '';
|
||||||
this.sourceDisplaySize = undefined;
|
this.sourceDisplaySize = undefined;
|
||||||
|
this.appLanguage = appLanguage;
|
||||||
|
this.appColorTheme = appColorTheme;
|
||||||
this.onDeviceConnectedCallback = () => {};
|
this.onDeviceConnectedCallback = () => {};
|
||||||
|
|
||||||
this.initSocketWhenUserCreatedCallback();
|
this.initSocketWhenUserCreatedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAppLanguage(lang: string) {
|
||||||
|
this.appLanguage = lang;
|
||||||
|
this.notifyClientWithNewLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppTheme(theme: boolean) {
|
||||||
|
this.appColorTheme = theme;
|
||||||
|
this.notifyClientWithNewColorTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyClientWithNewLanguage() {
|
||||||
|
this.sendEncryptedMessage({
|
||||||
|
type: 'APP_LANGUAGE',
|
||||||
|
payload: { value: this.appLanguage },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyClientWithNewColorTheme() {
|
||||||
|
this.sendEncryptedMessage({
|
||||||
|
type: 'APP_THEME',
|
||||||
|
payload: { value: this.appColorTheme },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setDesktopCapturerSourceID(id: string) {
|
setDesktopCapturerSourceID(id: string) {
|
||||||
this.desktopCapturerSourceID = id;
|
this.desktopCapturerSourceID = id;
|
||||||
if (process.env.RUN_MODE === 'test') return;
|
if (process.env.RUN_MODE === 'test') return;
|
||||||
@ -137,9 +168,14 @@ export default class PeerConnection {
|
|||||||
this.sendEncryptedMessage({
|
this.sendEncryptedMessage({
|
||||||
type: 'DENY_TO_CONNECT',
|
type: 'DENY_TO_CONNECT',
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
})
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
this.disconnectPartner();
|
.then(() => {
|
||||||
|
this.disconnectPartner();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
log.error(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendUserAllowedToConnect() {
|
sendUserAllowedToConnect() {
|
||||||
@ -153,10 +189,15 @@ export default class PeerConnection {
|
|||||||
this.sendEncryptedMessage({
|
this.sendEncryptedMessage({
|
||||||
type: 'DISCONNECT_BY_HOST_MACHINE_USER',
|
type: 'DISCONNECT_BY_HOST_MACHINE_USER',
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
})
|
||||||
|
// eslint-disable-next-line promise/always-return
|
||||||
this.disconnectPartner();
|
.then(() => {
|
||||||
this.selfDestrory();
|
this.disconnectPartner();
|
||||||
|
this.selfDestrory();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
log.error(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectPartner() {
|
disconnectPartner() {
|
||||||
@ -284,13 +325,10 @@ export default class PeerConnection {
|
|||||||
async receiveEncryptedMessage(payload: ReceiveEncryptedMessagePayload) {
|
async receiveEncryptedMessage(payload: ReceiveEncryptedMessagePayload) {
|
||||||
if (!this.user) return;
|
if (!this.user) return;
|
||||||
const message = await processMessage(payload, this.user.privateKey);
|
const message = await processMessage(payload, this.user.privateKey);
|
||||||
log.info(message);
|
|
||||||
if (message.type === 'CALL_ACCEPTED') {
|
if (message.type === 'CALL_ACCEPTED') {
|
||||||
this.peer.signal(message.payload.signalData);
|
this.peer.signal(message.payload.signalData);
|
||||||
}
|
}
|
||||||
if (message.type === 'DEVICE_DETAILS') {
|
if (message.type === 'DEVICE_DETAILS') {
|
||||||
log.info(message);
|
|
||||||
log.info(message.payload.browser);
|
|
||||||
this.socket.emit(
|
this.socket.emit(
|
||||||
'GET_IP_BY_SOCKET_ID',
|
'GET_IP_BY_SOCKET_ID',
|
||||||
message.payload.socketID,
|
message.payload.socketID,
|
||||||
@ -310,6 +348,18 @@ export default class PeerConnection {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (message.type === 'GET_APP_THEME') {
|
||||||
|
this.sendEncryptedMessage({
|
||||||
|
type: 'APP_THEME',
|
||||||
|
payload: { value: this.appColorTheme },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (message.type === 'GET_APP_LANGUAGE') {
|
||||||
|
this.sendEncryptedMessage({
|
||||||
|
type: 'APP_LANGUAGE',
|
||||||
|
payload: { value: this.appLanguage },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callPeer() {
|
callPeer() {
|
||||||
@ -358,18 +408,21 @@ export default class PeerConnection {
|
|||||||
this.peer = peer;
|
this.peer = peer;
|
||||||
|
|
||||||
this.peer.on('data', async (data) => {
|
this.peer.on('data', async (data) => {
|
||||||
if (`${data}` === 'set half quality') {
|
const dataJSON = JSON.parse(data);
|
||||||
// TODO: later on change to more sophisticated quality change for app window
|
|
||||||
|
if (dataJSON.type === 'set_video_quality') {
|
||||||
|
const maxVideoQualityMultiplier = dataJSON.payload.value;
|
||||||
|
const minVideoQualityMultiplier =
|
||||||
|
maxVideoQualityMultiplier === 1 ? 0.5 : maxVideoQualityMultiplier;
|
||||||
|
|
||||||
if (!this.desktopCapturerSourceID.includes('screen')) return;
|
if (!this.desktopCapturerSourceID.includes('screen')) return;
|
||||||
|
|
||||||
const newStream = await getDesktopSourceStreamBySourceID(
|
const newStream = await getDesktopSourceStreamBySourceID(
|
||||||
this.desktopCapturerSourceID,
|
this.desktopCapturerSourceID,
|
||||||
this.sourceDisplaySize?.width,
|
this.sourceDisplaySize?.width,
|
||||||
this.sourceDisplaySize?.height,
|
this.sourceDisplaySize?.height,
|
||||||
2,
|
minVideoQualityMultiplier,
|
||||||
2,
|
maxVideoQualityMultiplier
|
||||||
15,
|
|
||||||
30
|
|
||||||
);
|
);
|
||||||
const newVideoTrack = newStream.getVideoTracks()[0];
|
const newVideoTrack = newStream.getVideoTracks()[0];
|
||||||
const oldTrack = this.localStream?.getVideoTracks()[0];
|
const oldTrack = this.localStream?.getVideoTracks()[0];
|
||||||
@ -378,23 +431,14 @@ export default class PeerConnection {
|
|||||||
peer.replaceTrack(oldTrack, newVideoTrack, this.localStream);
|
peer.replaceTrack(oldTrack, newVideoTrack, this.localStream);
|
||||||
oldTrack.stop();
|
oldTrack.stop();
|
||||||
}
|
}
|
||||||
} else if (`${data}` === 'set good quality') {
|
}
|
||||||
// TODO: later on change to more sophisticated quality change for app window
|
|
||||||
if (!this.desktopCapturerSourceID.includes('screen')) return;
|
|
||||||
|
|
||||||
const newStream = await getDesktopSourceStreamBySourceID(
|
if (dataJSON.type === 'get_sharing_source_type') {
|
||||||
this.desktopCapturerSourceID,
|
const sourceType = this.desktopCapturerSourceID.includes('screen')
|
||||||
this.sourceDisplaySize?.width,
|
? 'screen'
|
||||||
this.sourceDisplaySize?.height,
|
: 'window';
|
||||||
2,
|
|
||||||
1
|
this.peer.send(prepareDataMessageToSendScreenSourceType(sourceType));
|
||||||
);
|
|
||||||
const newVideoTrack = newStream.getVideoTracks()[0];
|
|
||||||
const oldTrack = this.localStream?.getVideoTracks()[0];
|
|
||||||
if (oldTrack && this.localStream) {
|
|
||||||
peer.replaceTrack(oldTrack, newVideoTrack, this.localStream);
|
|
||||||
oldTrack.stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return peer;
|
return peer;
|
||||||
@ -419,7 +463,7 @@ export default class PeerConnection {
|
|||||||
sourceID,
|
sourceID,
|
||||||
this.sourceDisplaySize?.width,
|
this.sourceDisplaySize?.width,
|
||||||
this.sourceDisplaySize?.height,
|
this.sourceDisplaySize?.height,
|
||||||
2,
|
0.5,
|
||||||
1
|
1
|
||||||
).then((stream) => {
|
).then((stream) => {
|
||||||
this.localStream = stream;
|
this.localStream = stream;
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
export default (s: string) => {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"type": "screen_sharing_source_type",
|
||||||
|
"payload": {
|
||||||
|
"value": "${s}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
@ -26,7 +26,9 @@ describe('SharingSession unit tests', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
'',
|
||||||
|
''
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ export default class SharingSession {
|
|||||||
constructor(
|
constructor(
|
||||||
_roomID: string,
|
_roomID: string,
|
||||||
user: LocalPeerUser,
|
user: LocalPeerUser,
|
||||||
peerConnectionHelperRendererService: PeerConnectionHelperRendererService
|
peerConnectionHelperRendererService: PeerConnectionHelperRendererService,
|
||||||
|
appLanguage: string,
|
||||||
|
isDarkTheme: boolean
|
||||||
) {
|
) {
|
||||||
this.id = uuid.v4();
|
this.id = uuid.v4();
|
||||||
this.deviceID = '';
|
this.deviceID = '';
|
||||||
@ -49,6 +51,8 @@ export default class SharingSession {
|
|||||||
roomID: this.roomID,
|
roomID: this.roomID,
|
||||||
sharingSessionID: this.id,
|
sharingSessionID: this.id,
|
||||||
user,
|
user,
|
||||||
|
appTheme: isDarkTheme,
|
||||||
|
appLanguage,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -107,6 +111,20 @@ export default class SharingSession {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appLanguageChanged(newLang: string) {
|
||||||
|
this.peerConnectionHelperRenderer?.webContents.send(
|
||||||
|
'app-language-changed',
|
||||||
|
newLang
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
appThemeChanged(isDarkTheme: boolean) {
|
||||||
|
this.peerConnectionHelperRenderer?.webContents.send(
|
||||||
|
'app-color-theme-changed',
|
||||||
|
isDarkTheme
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
addStatusChangeListener(callback: SharingSessionStatusChangeListener): void {
|
addStatusChangeListener(callback: SharingSessionStatusChangeListener): void {
|
||||||
this.statusChangeListeners.push(callback);
|
this.statusChangeListeners.push(callback);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ export default class SharingSessionService {
|
|||||||
connectedDevicesService: ConnectedDevicesService;
|
connectedDevicesService: ConnectedDevicesService;
|
||||||
rendererWebrtcHelpersService: RendererWebrtcHelpersService;
|
rendererWebrtcHelpersService: RendererWebrtcHelpersService;
|
||||||
isCreatingNewSharingSession: boolean;
|
isCreatingNewSharingSession: boolean;
|
||||||
|
appLanguage = 'en';
|
||||||
|
isDarkTheme = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
_roomIDService: RoomIDService,
|
_roomIDService: RoomIDService,
|
||||||
@ -38,6 +40,14 @@ export default class SharingSessionService {
|
|||||||
}, 1000 * 60 * 60); // every hour
|
}, 1000 * 60 * 60); // every hour
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAppLanguage(newLang: string): void {
|
||||||
|
this.appLanguage = newLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAppTheme(isDarkTheme: boolean): void {
|
||||||
|
this.isDarkTheme = isDarkTheme;
|
||||||
|
}
|
||||||
|
|
||||||
createUser(): Promise<undefined> {
|
createUser(): Promise<undefined> {
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
@ -75,10 +85,13 @@ export default class SharingSessionService {
|
|||||||
|
|
||||||
createNewSharingSession(_roomID: string): SharingSession {
|
createNewSharingSession(_roomID: string): SharingSession {
|
||||||
const roomID = _roomID || this.roomIDService.getSimpleAvailableRoomID();
|
const roomID = _roomID || this.roomIDService.getSimpleAvailableRoomID();
|
||||||
|
this.roomIDService.markRoomIDAsTaken(roomID);
|
||||||
const sharingSession = new SharingSession(
|
const sharingSession = new SharingSession(
|
||||||
roomID,
|
roomID,
|
||||||
this.user as LocalPeerUser,
|
this.user as LocalPeerUser,
|
||||||
this.rendererWebrtcHelpersService
|
this.rendererWebrtcHelpersService,
|
||||||
|
this.appLanguage,
|
||||||
|
this.isDarkTheme
|
||||||
);
|
);
|
||||||
this.sharingSessions.set(sharingSession.id, sharingSession);
|
this.sharingSessions.set(sharingSession.id, sharingSession);
|
||||||
return sharingSession;
|
return sharingSession;
|
||||||
@ -87,7 +100,6 @@ export default class SharingSessionService {
|
|||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
changeSharingSessionStatusToSharing(sharingSession: SharingSession) {
|
changeSharingSessionStatusToSharing(sharingSession: SharingSession) {
|
||||||
sharingSession.status = SharingSessionStatusEnum.SHARING;
|
sharingSession.status = SharingSessionStatusEnum.SHARING;
|
||||||
this.roomIDService.markRoomIDAsTaken(sharingSession.roomID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pollForInactiveSessions(): void {
|
pollForInactiveSessions(): void {
|
||||||
|
BIN
app/images/red_heart_2764_twemoji_120x120.png
Normal file
BIN
app/images/red_heart_2764_twemoji_120x120.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -3,5 +3,6 @@
|
|||||||
"Signaling server is running on port": "Signaling server is running on port ⚓",
|
"Signaling server is running on port": "Signaling server is running on port ⚓",
|
||||||
"ru": "Русский",
|
"ru": "Русский",
|
||||||
"en": "English",
|
"en": "English",
|
||||||
"ua": "Українська"
|
"ua": "Українська",
|
||||||
|
"Scan the QR code": "Scan the QR code"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"ru": "ru",
|
|
||||||
"en": "en"
|
|
||||||
}
|
|
@ -3,5 +3,6 @@
|
|||||||
"Signaling server is running on port": "Сигнальный сервер работает на порте ⚓",
|
"Signaling server is running on port": "Сигнальный сервер работает на порте ⚓",
|
||||||
"ru": "Русский",
|
"ru": "Русский",
|
||||||
"en": "English",
|
"en": "English",
|
||||||
"ua": "Українська"
|
"ua": "Українська",
|
||||||
|
"Scan the QR code": "Отсканируйте QR код"
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
"Signaling server is running on port": "Сигнальный сервер працює на порту ⚓",
|
"Signaling server is running on port": "Сигнальный сервер працює на порту ⚓",
|
||||||
"ru": "Русский",
|
"ru": "Русский",
|
||||||
"en": "English",
|
"en": "English",
|
||||||
"ua": "Українська"
|
"ua": "Українська",
|
||||||
|
"Scan the QR code": "Відскануйте QR код"
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ ipcRenderer.on('create-peer-connection-with-data', (_, data) => {
|
|||||||
data.roomID,
|
data.roomID,
|
||||||
data.sharingSessionID,
|
data.sharingSessionID,
|
||||||
data.user,
|
data.user,
|
||||||
|
data.appTheme, // TODO getAppTheme
|
||||||
|
data.appLanguage, // TODO getLanguage
|
||||||
roomIDService,
|
roomIDService,
|
||||||
connectedDevicesService,
|
connectedDevicesService,
|
||||||
sharingSessionsService
|
sharingSessionsService
|
||||||
@ -48,3 +50,11 @@ ipcRenderer.on('deny-connection-for-partner', () => {
|
|||||||
ipcRenderer.on('send-user-allowed-to-connect', () => {
|
ipcRenderer.on('send-user-allowed-to-connect', () => {
|
||||||
peerConnection.sendUserAllowedToConnect();
|
peerConnection.sendUserAllowedToConnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('app-color-theme-changed', (_, newTheme: boolean) => {
|
||||||
|
peerConnection.setAppTheme(newTheme);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('app-language-changed', (_, newLang: string) => {
|
||||||
|
peerConnection.setAppLanguage(newLang);
|
||||||
|
});
|
||||||
|
@ -33,4 +33,8 @@ export default class RoomIDService {
|
|||||||
public unmarkRoomIDAsTaken(id: string) {
|
public unmarkRoomIDAsTaken(id: string) {
|
||||||
this.takenRoomIDs.delete(id);
|
this.takenRoomIDs.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isRoomIDTaken(id: string) {
|
||||||
|
return this.takenRoomIDs.has(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import { getIO } from '.';
|
|||||||
import socketsIPService from './socketsIPService';
|
import socketsIPService from './socketsIPService';
|
||||||
import getStore from './store';
|
import getStore from './store';
|
||||||
|
|
||||||
|
const LOCALHOST_SOCKET_IP = '::1';
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
socketId: string;
|
socketId: string;
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
@ -152,7 +154,8 @@ export default class Socket implements SocketOPTS {
|
|||||||
{
|
{
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
publicKey: payload.publicKey,
|
publicKey: payload.publicKey,
|
||||||
isOwner: (room.users || []).length === 0,
|
isOwner:
|
||||||
|
LOCALHOST_SOCKET_IP === socket.request.connection.remoteAddress,
|
||||||
ip: payload.ip ? payload.ip : '',
|
ip: payload.ip ? payload.ip : '',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -22,6 +22,7 @@ import getStore from './store';
|
|||||||
import Logger from '../utils/logger';
|
import Logger from '../utils/logger';
|
||||||
import isProduction from '../utils/isProduction';
|
import isProduction from '../utils/isProduction';
|
||||||
import SocketsIPService from './socketsIPService';
|
import SocketsIPService from './socketsIPService';
|
||||||
|
import getDeskreenGlobal from '../mainProcessHelpers/getDeskreenGlobal';
|
||||||
|
|
||||||
const log = new Logger('app/server/index.ts');
|
const log = new Logger('app/server/index.ts');
|
||||||
|
|
||||||
@ -90,25 +91,34 @@ io.sockets.on('connection', (socket) => {
|
|||||||
io.on('connection', async (socket) => {
|
io.on('connection', async (socket) => {
|
||||||
const { roomId } = socket.handshake.query;
|
const { roomId } = socket.handshake.query;
|
||||||
|
|
||||||
const roomIdHash = getRoomIdHash(roomId);
|
setTimeout(async () => {
|
||||||
|
if (!getDeskreenGlobal().roomIDService.isRoomIDTaken(roomId)) {
|
||||||
|
socket.emit('NOT_ALLOWED');
|
||||||
|
setTimeout(() => {
|
||||||
|
socket.disconnect();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
const roomIdHash = getRoomIdHash(roomId);
|
||||||
|
|
||||||
let room = await store.get('rooms', roomIdHash);
|
let room = await store.get('rooms', roomIdHash);
|
||||||
room = JSON.parse(room || '{}');
|
room = JSON.parse(room || '{}');
|
||||||
|
|
||||||
// eslint-disable-next-line no-new
|
// eslint-disable-next-line no-new
|
||||||
new DarkwireSocket({
|
new DarkwireSocket({
|
||||||
roomIdOriginal: roomId,
|
roomIdOriginal: roomId,
|
||||||
roomId: roomIdHash,
|
roomId: roomIdHash,
|
||||||
socket,
|
socket,
|
||||||
room,
|
room,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}, 1000); // timeout 1 second for throttling malitios connections
|
||||||
});
|
});
|
||||||
|
|
||||||
const init = async (PORT: number) => {
|
const init = async (PORT: number) => {
|
||||||
pollForInactiveRooms();
|
pollForInactiveRooms();
|
||||||
|
|
||||||
return server.listen(PORT, () => {
|
return server.listen(PORT, () => {
|
||||||
log.info(`Signaling server is online at port ${PORT}`);
|
log.info(`Deskreen signaling server is online at port ${PORT}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
14
app/utils/ProcessedMessage.d.ts
vendored
14
app/utils/ProcessedMessage.d.ts
vendored
@ -17,6 +17,18 @@ type DeviceDetailsMessageWithPayload = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type GetAppThemeMessageWithPayload = {
|
||||||
|
type: 'GET_APP_THEME';
|
||||||
|
payload: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type GetAppLanguageMessageWithPayload = {
|
||||||
|
type: 'GET_APP_LANGUAGE';
|
||||||
|
payload: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
type ProcessedMessage =
|
type ProcessedMessage =
|
||||||
| CallAcceptedMessageWithPayload
|
| CallAcceptedMessageWithPayload
|
||||||
| DeviceDetailsMessageWithPayload;
|
| DeviceDetailsMessageWithPayload
|
||||||
|
| GetAppThemeMessageWithPayload
|
||||||
|
| GetAppLanguageMessageWithPayload;
|
||||||
|
@ -108,8 +108,8 @@ async function openLargeQRCodeDialog(t) {
|
|||||||
await t.click(magnifyQRCodeButton());
|
await t.click(magnifyQRCodeButton());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickCrossButtonToCloseDialog(t) {
|
async function clickOnLargeQRCodeDialog(t) {
|
||||||
await t.click(crossCloseDialogButton());
|
await t.click(largeQRCodeDialog());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openConnectedDeviceInfoPopover(t) {
|
async function openConnectedDeviceInfoPopover(t) {
|
||||||
@ -239,7 +239,7 @@ test(`when large QR overflow is opened,
|
|||||||
|
|
||||||
it should close large QR code overflow`, async (t) => {
|
it should close large QR code overflow`, async (t) => {
|
||||||
await openLargeQRCodeDialog(t);
|
await openLargeQRCodeDialog(t);
|
||||||
await clickCrossButtonToCloseDialog(t);
|
await clickOnLargeQRCodeDialog(t);
|
||||||
|
|
||||||
const largeQrCodeDialogExists = largeQRCodeDialog().exists;
|
const largeQrCodeDialogExists = largeQRCodeDialog().exists;
|
||||||
await t.expect(largeQrCodeDialogExists).notOk();
|
await t.expect(largeQrCodeDialogExists).notOk();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user