mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 14:40:50 +01:00
Camera
This commit is contained in:
parent
102774187c
commit
30ec05948b
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
.camera-frame {
|
.camera-frame {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 318px;
|
width: 320px;
|
||||||
height: 318px;
|
height: 320px;
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
margin-left: 11.4px;
|
margin-left: 11.4px;
|
||||||
|
|
||||||
@ -60,7 +60,7 @@
|
|||||||
width: 600px;
|
width: 600px;
|
||||||
|
|
||||||
.effects {
|
.effects {
|
||||||
max-height: 354px;
|
max-height: 363px;
|
||||||
|
|
||||||
.effect-thumbnail {
|
.effect-thumbnail {
|
||||||
border-color: $grid-border-color !important;
|
border-color: $grid-border-color !important;
|
||||||
@ -72,8 +72,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.effect-thumbnail-image {
|
.effect-thumbnail-image {
|
||||||
background: black;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
@ -83,8 +81,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.picture-preview {
|
.picture-preview {
|
||||||
width: 318px;
|
width: 320px;
|
||||||
height: 318px;
|
height: 320px;
|
||||||
|
|
||||||
&.zoomed {
|
&.zoomed {
|
||||||
background-size: 636px;
|
background-size: 636px;
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/camera/events/RoomCameraWidgetManagerEvent';
|
import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/camera/events/RoomCameraWidgetManagerEvent';
|
||||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { IRoomCameraWidgetSelectedEffect } from '../../../../../../nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
||||||
import { GetRoomCameraWidgetManager } from '../../../../api';
|
import { GetRoomCameraWidgetManager } from '../../../../api';
|
||||||
import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent';
|
import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent';
|
||||||
import { useCameraEvent } from '../../../../hooks/events/nitro/camera/camera-event';
|
import { useCameraEvent } from '../../../../hooks/events/nitro/camera/camera-event';
|
||||||
import { useUiEvent } from '../../../../hooks/events/ui/ui-event';
|
import { useUiEvent } from '../../../../hooks/events/ui/ui-event';
|
||||||
import { useRoomContext } from '../../context/RoomContext';
|
|
||||||
import { CameraWidgetViewProps } from './CameraWidgetView.types';
|
import { CameraWidgetViewProps } from './CameraWidgetView.types';
|
||||||
|
import { CameraWidgetContextProvider } from './context/CameraWidgetContext';
|
||||||
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
|
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
|
||||||
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
|
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
|
||||||
|
|
||||||
export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
|
export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
|
|
||||||
const [ effectsReady, setEffectsReady ] = useState(false);
|
const [ effectsReady, setEffectsReady ] = useState(false);
|
||||||
const [ isCaptureVisible, setIsCaptureVisible ] = useState(false);
|
const [ isCaptureVisible, setIsCaptureVisible ] = useState(false);
|
||||||
const [ isEditorVisible, setIsEditorVisible ] = useState(false);
|
const [ isEditorVisible, setIsEditorVisible ] = useState(false);
|
||||||
const [ chosenPicture, setChosenPicture ] = useState<HTMLImageElement>(null);
|
|
||||||
|
const [ cameraRoll, setCameraRoll ] = useState<HTMLImageElement[]>([]);
|
||||||
|
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
|
||||||
|
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
|
||||||
|
|
||||||
const onNitroEvent = useCallback((event: RoomWidgetCameraEvent) =>
|
const onNitroEvent = useCallback((event: RoomWidgetCameraEvent) =>
|
||||||
{
|
{
|
||||||
@ -73,16 +76,21 @@ export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
|
|||||||
setIsCaptureVisible(false);
|
setIsCaptureVisible(false);
|
||||||
setIsEditorVisible(false);
|
setIsEditorVisible(false);
|
||||||
return;
|
return;
|
||||||
case 'capture_choose_picture':
|
case 'capture_edit':
|
||||||
setChosenPicture(value);
|
|
||||||
setIsCaptureVisible(false);
|
setIsCaptureVisible(false);
|
||||||
setIsEditorVisible(true);
|
setIsEditorVisible(true);
|
||||||
return;
|
return;
|
||||||
|
case 'editor_cancel':
|
||||||
|
setIsCaptureVisible(true);
|
||||||
|
setIsEditorVisible(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
( isCaptureVisible && <CameraWidgetCaptureView onCloseClick={ () => processAction('close') } onChoosePicture={ (picture) => processAction('capture_choose_picture', picture) } /> ) ||
|
<CameraWidgetContextProvider value={ { cameraRoll, setCameraRoll, selectedPictureIndex, setSelectedPictureIndex, selectedEffects, setSelectedEffects } }>
|
||||||
( isEditorVisible && <CameraWidgetEditorView onCloseClick={ () => processAction('close') } picture={ chosenPicture } availableEffects={ availableEffects } /> )
|
{ ( isCaptureVisible && <CameraWidgetCaptureView onCloseClick={ () => processAction('close') } onEditClick={ () => processAction('capture_edit') } /> ) ||
|
||||||
|
( isEditorVisible && <CameraWidgetEditorView onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } availableEffects={ availableEffects } /> ) }
|
||||||
|
</CameraWidgetContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
import { createContext, FC, useContext } from 'react';
|
||||||
|
import { CameraWidgetContextProps, ICameraWidgetContext } from './CameraWidgetContext.types';
|
||||||
|
|
||||||
|
const CameraWidgetContext = createContext<ICameraWidgetContext>({
|
||||||
|
cameraRoll: null,
|
||||||
|
setCameraRoll: null,
|
||||||
|
selectedPictureIndex: null,
|
||||||
|
setSelectedPictureIndex: null,
|
||||||
|
selectedEffects: null,
|
||||||
|
setSelectedEffects: null
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CameraWidgetContextProvider: FC<CameraWidgetContextProps> = props =>
|
||||||
|
{
|
||||||
|
return <CameraWidgetContext.Provider value={ props.value }>{ props.children }</CameraWidgetContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCameraWidgetContext = () => useContext(CameraWidgetContext);
|
@ -0,0 +1,15 @@
|
|||||||
|
import { ProviderProps } from 'react';
|
||||||
|
import { IRoomCameraWidgetSelectedEffect } from '../../../../../../../nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
||||||
|
|
||||||
|
export interface ICameraWidgetContext
|
||||||
|
{
|
||||||
|
cameraRoll: HTMLImageElement[],
|
||||||
|
setCameraRoll: (cameraRoll: HTMLImageElement[]) => void,
|
||||||
|
selectedPictureIndex: number,
|
||||||
|
setSelectedPictureIndex: (index: number) => void,
|
||||||
|
selectedEffects: IRoomCameraWidgetSelectedEffect[],
|
||||||
|
setSelectedEffects: (selectedEffects: IRoomCameraWidgetSelectedEffect[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CameraWidgetContextProps extends ProviderProps<ICameraWidgetContext>
|
||||||
|
{}
|
@ -1,25 +1,27 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { NitroRectangle } from 'nitro-renderer';
|
import { NitroRectangle } from 'nitro-renderer';
|
||||||
import { FC, useCallback, useRef, useState } from 'react';
|
import { FC, useCallback, useRef } from 'react';
|
||||||
import { GetRoomEngine } from '../../../../../../api/nitro/room/GetRoomEngine';
|
import { GetRoomEngine } from '../../../../../../api/nitro/room/GetRoomEngine';
|
||||||
import { GetRoomSession } from '../../../../../../api/nitro/session/GetRoomSession';
|
import { GetRoomSession } from '../../../../../../api/nitro/session/GetRoomSession';
|
||||||
import { DraggableWindow } from '../../../../../../hooks/draggable-window/DraggableWindow';
|
import { DraggableWindow } from '../../../../../../hooks/draggable-window/DraggableWindow';
|
||||||
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||||
|
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
||||||
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
|
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
|
||||||
|
|
||||||
export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =>
|
export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =>
|
||||||
{
|
{
|
||||||
const CAMERA_ROLL_LIMIT: number = 5;
|
const { onCloseClick = null, onEditClick = null } = props;
|
||||||
|
|
||||||
const [ picturesTaken, setPicturesTaken ] = useState<HTMLImageElement[]>([]);
|
const CAMERA_ROLL_LIMIT: number = 5;
|
||||||
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
|
|
||||||
const cameraFrameRef = useRef<HTMLDivElement>();
|
const cameraFrameRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const cameraWidgetContext = useCameraWidgetContext();
|
||||||
|
|
||||||
const takePicture = useCallback(() =>
|
const takePicture = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(selectedPictureIndex > -1)
|
if(cameraWidgetContext.selectedPictureIndex > -1)
|
||||||
{
|
{
|
||||||
setSelectedPictureIndex(-1);
|
cameraWidgetContext.setSelectedPictureIndex(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,20 +33,20 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
|
|
||||||
const image = GetRoomEngine().createRoomScreenshot(GetRoomSession().roomId, 1, rectangle);
|
const image = GetRoomEngine().createRoomScreenshot(GetRoomSession().roomId, 1, rectangle);
|
||||||
|
|
||||||
if(picturesTaken.length + 1 === CAMERA_ROLL_LIMIT)
|
if(cameraWidgetContext.cameraRoll.length + 1 === CAMERA_ROLL_LIMIT)
|
||||||
{
|
{
|
||||||
alert(LocalizeText('camera.full.body'));
|
alert(LocalizeText('camera.full.body'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(picturesTaken.length === CAMERA_ROLL_LIMIT)
|
let remainingRoll = cameraWidgetContext.cameraRoll;
|
||||||
|
|
||||||
|
if(cameraWidgetContext.cameraRoll.length === CAMERA_ROLL_LIMIT)
|
||||||
{
|
{
|
||||||
setPicturesTaken(picturesTaken => [ ...picturesTaken.slice(0, CAMERA_ROLL_LIMIT - 1), image ]);
|
remainingRoll = remainingRoll.slice(0, CAMERA_ROLL_LIMIT - 1);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
cameraWidgetContext.setCameraRoll([ ...remainingRoll, image ]);
|
||||||
setPicturesTaken(picturesTaken => [ ...picturesTaken, image ]);
|
}, [ cameraWidgetContext.cameraRoll, cameraWidgetContext.selectedPictureIndex ]);
|
||||||
}
|
|
||||||
}, [ picturesTaken, selectedPictureIndex ]);
|
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
const processAction = useCallback((type: string, value: string | number = null) =>
|
||||||
{
|
{
|
||||||
@ -54,32 +56,37 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
takePicture();
|
takePicture();
|
||||||
return;
|
return;
|
||||||
case 'preview_picture':
|
case 'preview_picture':
|
||||||
setSelectedPictureIndex(Number(value));
|
cameraWidgetContext.setSelectedPictureIndex(Number(value));
|
||||||
return;
|
return;
|
||||||
case 'discard_picture':
|
case 'discard_picture':
|
||||||
setSelectedPictureIndex(-1);
|
cameraWidgetContext.setSelectedPictureIndex(-1);
|
||||||
const newPicturesTaken = picturesTaken;
|
|
||||||
picturesTaken.splice(selectedPictureIndex, 1);
|
const clone = Array.from(cameraWidgetContext.cameraRoll);
|
||||||
setPicturesTaken(newPicturesTaken);
|
clone.splice(cameraWidgetContext.selectedPictureIndex, 1);
|
||||||
|
|
||||||
|
cameraWidgetContext.setCameraRoll(clone);
|
||||||
return;
|
return;
|
||||||
case 'edit_picture':
|
case 'edit_picture':
|
||||||
props.onChoosePicture(picturesTaken[selectedPictureIndex]);
|
onEditClick();
|
||||||
|
return;
|
||||||
|
case 'close':
|
||||||
|
onCloseClick();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, [ picturesTaken, selectedPictureIndex ]);
|
}, [ cameraWidgetContext.selectedPictureIndex, cameraWidgetContext.cameraRoll, onEditClick, onCloseClick ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableWindow handle=".nitro-camera-capture">
|
<DraggableWindow handle=".nitro-camera-capture">
|
||||||
<div className="nitro-camera-capture d-flex flex-column justify-content-center align-items-center">
|
<div className="nitro-camera-capture d-flex flex-column justify-content-center align-items-center">
|
||||||
<div className="camera-canvas">
|
<div className="camera-canvas">
|
||||||
<div className="overflow-auto">
|
<div className="overflow-auto">
|
||||||
<div className="cursor-pointer float-end me-3 mt-2" onClick={ props.onCloseClick }>
|
<div className="cursor-pointer float-end me-3 mt-2" onClick={ event => processAction('close') }>
|
||||||
<i className="fas fa-times"></i>
|
<i className="fas fa-times"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref={ cameraFrameRef } className={'camera-frame ' + classNames({'bg': selectedPictureIndex > -1}) }>
|
<div ref={ cameraFrameRef } className={'camera-frame ' + classNames({'bg': cameraWidgetContext.selectedPictureIndex > -1}) }>
|
||||||
{ selectedPictureIndex > -1 && <div>
|
{ cameraWidgetContext.selectedPictureIndex > -1 && <div>
|
||||||
<img src={ picturesTaken[selectedPictureIndex].src } />
|
<img src={ cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex].src } />
|
||||||
<div className="camera-frame-preview-actions w-100 position-absolute bottom-0 py-2 text-center">
|
<div className="camera-frame-preview-actions w-100 position-absolute bottom-0 py-2 text-center">
|
||||||
<button className="btn btn-success me-3" onClick={ event => processAction('edit_picture') }>{ LocalizeText('camera.editor.button.text') }</button>
|
<button className="btn btn-success me-3" onClick={ event => processAction('edit_picture') }>{ LocalizeText('camera.editor.button.text') }</button>
|
||||||
<button className="btn btn-danger" onClick={ event => processAction('discard_picture') }>{ LocalizeText('camera.delete.button.text') }</button>
|
<button className="btn btn-danger" onClick={ event => processAction('discard_picture') }>{ LocalizeText('camera.delete.button.text') }</button>
|
||||||
@ -90,10 +97,10 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
<div className="camera-button" onClick={ takePicture }></div>
|
<div className="camera-button" onClick={ takePicture }></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ picturesTaken.length > 0 && <div className="camera-roll d-flex justify-content-center py-2">
|
{ cameraWidgetContext.cameraRoll.length > 0 && <div className="camera-roll d-flex justify-content-center py-2">
|
||||||
{ picturesTaken.map((picture, index) =>
|
{ cameraWidgetContext.cameraRoll.map((picture, index) =>
|
||||||
{
|
{
|
||||||
return <img key={ index } className={ (index < picturesTaken.length - 1 ? 'me-2' : '') } src={ picture.src } onClick={ event => processAction('preview_picture', index) } />;
|
return <img key={ index } className={ (index < cameraWidgetContext.cameraRoll.length - 1 ? 'me-2' : '') } src={ picture.src } onClick={ event => processAction('preview_picture', index) } />;
|
||||||
}) }
|
}) }
|
||||||
</div> }
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface CameraWidgetCaptureViewProps
|
export interface CameraWidgetCaptureViewProps
|
||||||
{
|
{
|
||||||
onCloseClick: () => void;
|
onCloseClick: () => void;
|
||||||
onChoosePicture: (picture: HTMLImageElement) => void;
|
onEditClick: () => void;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
|
||||||
import { RoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/RoomCameraWidgetSelectedEffect';
|
import { RoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/RoomCameraWidgetSelectedEffect';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetRoomCameraWidgetManager } from '../../../../../../api';
|
import { GetRoomCameraWidgetManager } from '../../../../../../api';
|
||||||
@ -9,18 +8,22 @@ import { NitroCardView } from '../../../../../../layout/card/NitroCardView';
|
|||||||
import { NitroCardTabsView } from '../../../../../../layout/card/tabs/NitroCardTabsView';
|
import { NitroCardTabsView } from '../../../../../../layout/card/tabs/NitroCardTabsView';
|
||||||
import { NitroCardTabsItemView } from '../../../../../../layout/card/tabs/tabs-item/NitroCardTabsItemView';
|
import { NitroCardTabsItemView } from '../../../../../../layout/card/tabs/tabs-item/NitroCardTabsItemView';
|
||||||
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||||
|
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
||||||
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
|
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
|
||||||
|
|
||||||
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { picture = null, availableEffects = null, onCloseClick = null } = props;
|
const { availableEffects = null, onCloseClick = null, onCancelClick = null } = props;
|
||||||
|
|
||||||
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
|
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
|
||||||
const MY_LEVEL: number = 0;
|
const MY_LEVEL: number = 0;
|
||||||
|
|
||||||
|
const cameraWidgetContext = useCameraWidgetContext();
|
||||||
|
|
||||||
const [ currentTab, setCurrentTab ] = useState(CameraWidgetEditorTabs.COLORMATRIX);
|
const [ currentTab, setCurrentTab ] = useState(CameraWidgetEditorTabs.COLORMATRIX);
|
||||||
|
const [ selectedEffectName, setSelectedEffectName ] = useState(null);
|
||||||
|
const [ effectsThumbnails, setEffectsThumbnails ] = useState<{ name: string, image: HTMLImageElement }[]>([]);
|
||||||
const [ isZoomed, setIsZoomed ] = useState(false);
|
const [ isZoomed, setIsZoomed ] = useState(false);
|
||||||
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
|
|
||||||
const [ effectsThumbnails, setEffectThumbnails ] = useState<{name: string, image: HTMLImageElement}[]>([]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -32,11 +35,11 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
if(effect.colorMatrix) alpha = 0.5;
|
if(effect.colorMatrix) alpha = 0.5;
|
||||||
|
|
||||||
thumbnails.push({name: effect.name, image: GetRoomCameraWidgetManager().applyEffects(picture, [ new RoomCameraWidgetSelectedEffect(effect, alpha) ])});
|
thumbnails.push({name: effect.name, image: GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], [ new RoomCameraWidgetSelectedEffect(effect, alpha) ])});
|
||||||
}
|
}
|
||||||
|
|
||||||
setEffectThumbnails(thumbnails);
|
setEffectsThumbnails(thumbnails);
|
||||||
}, [ picture, availableEffects ]);
|
}, [ cameraWidgetContext.selectedPictureIndex, availableEffects ]);
|
||||||
|
|
||||||
const getEffectThumbnail = useCallback((effectName: string) =>
|
const getEffectThumbnail = useCallback((effectName: string) =>
|
||||||
{
|
{
|
||||||
@ -59,6 +62,50 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, [ currentTab, availableEffects ]);
|
}, [ currentTab, availableEffects ]);
|
||||||
|
|
||||||
|
const getCurrentPicture = useCallback(() =>
|
||||||
|
{
|
||||||
|
return GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], cameraWidgetContext.selectedEffects);
|
||||||
|
}, [ cameraWidgetContext.selectedEffects ]);
|
||||||
|
|
||||||
|
const getEffectRangeConfig = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!selectedEffectName) return [0, 0];
|
||||||
|
|
||||||
|
const selectedEffect = cameraWidgetContext.selectedEffects.find(effect => effect.effect.name === selectedEffectName);
|
||||||
|
|
||||||
|
if(!selectedEffect) return [0, 0];
|
||||||
|
|
||||||
|
let isColormatrix = selectedEffect.effect.colorMatrix != null;
|
||||||
|
|
||||||
|
let max = 255;
|
||||||
|
let step = 1;
|
||||||
|
|
||||||
|
if(isColormatrix)
|
||||||
|
{
|
||||||
|
max = 1;
|
||||||
|
step = 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [max, step, selectedEffect.alpha];
|
||||||
|
}, [ selectedEffectName, cameraWidgetContext.selectedEffects ]);
|
||||||
|
|
||||||
|
const setSelectedEffectAlpha = useCallback((newAlpha: number) =>
|
||||||
|
{
|
||||||
|
if(!selectedEffectName) return;
|
||||||
|
|
||||||
|
const selectedEffectIndex = cameraWidgetContext.selectedEffects.findIndex(effect => effect.effect.name === selectedEffectName);
|
||||||
|
|
||||||
|
if(selectedEffectIndex === -1) return;
|
||||||
|
|
||||||
|
const clone = Array.from(cameraWidgetContext.selectedEffects);
|
||||||
|
|
||||||
|
const selectedEffect = clone[selectedEffectIndex];
|
||||||
|
|
||||||
|
clone[selectedEffectIndex] = new RoomCameraWidgetSelectedEffect(selectedEffect.effect, newAlpha);
|
||||||
|
|
||||||
|
cameraWidgetContext.setSelectedEffects(clone);
|
||||||
|
}, [ selectedEffectName, cameraWidgetContext.selectedEffects ]);
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
const processAction = useCallback((type: string, value: string | number = null) =>
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
@ -66,14 +113,60 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
case 'close':
|
case 'close':
|
||||||
onCloseClick();
|
onCloseClick();
|
||||||
return;
|
return;
|
||||||
|
case 'cancel':
|
||||||
|
onCancelClick();
|
||||||
|
return;
|
||||||
case 'change_tab':
|
case 'change_tab':
|
||||||
setCurrentTab(String(value));
|
setCurrentTab(String(value));
|
||||||
return;
|
return;
|
||||||
|
case 'select_effect':
|
||||||
|
let existingIndex = -1;
|
||||||
|
|
||||||
|
if(cameraWidgetContext.selectedEffects.length > 0)
|
||||||
|
{
|
||||||
|
existingIndex = cameraWidgetContext.selectedEffects.findIndex(effect => effect.effect.name === value);
|
||||||
|
|
||||||
|
/*if(existingIndex > -1)
|
||||||
|
{
|
||||||
|
const clone = Array.from(cameraWidgetContext.selectedEffects);
|
||||||
|
clone.splice(existingIndex, 1);
|
||||||
|
|
||||||
|
cameraWidgetContext.setSelectedEffects(clone);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if(existingIndex === -1)
|
||||||
|
{
|
||||||
|
const effect = availableEffects.find(effect => effect.name === value);
|
||||||
|
|
||||||
|
let alpha = 126;
|
||||||
|
|
||||||
|
if(effect.colorMatrix) alpha = 0.5;
|
||||||
|
|
||||||
|
cameraWidgetContext.setSelectedEffects([...cameraWidgetContext.selectedEffects, new RoomCameraWidgetSelectedEffect(effect, alpha)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selectedEffectName !== value)
|
||||||
|
{
|
||||||
|
setSelectedEffectName(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setSelectedEffectName(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 'clear_effects':
|
||||||
|
setSelectedEffectName(null);
|
||||||
|
cameraWidgetContext.setSelectedEffects([]);
|
||||||
|
return;
|
||||||
|
case 'download':
|
||||||
|
window.open(getCurrentPicture().src, '_blank');
|
||||||
|
return;
|
||||||
case 'zoom':
|
case 'zoom':
|
||||||
setIsZoomed(isZoomed => !isZoomed);
|
setIsZoomed(isZoomed => !isZoomed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, [ onCloseClick ]);
|
}, [ onCloseClick, onCancelClick, availableEffects, cameraWidgetContext.selectedEffects, selectedEffectName ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-camera-editor">
|
<NitroCardView className="nitro-camera-editor">
|
||||||
@ -92,7 +185,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
{ getEffectList().map(effect =>
|
{ getEffectList().map(effect =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<div key={ effect.name } className="col mb-3">
|
<div key={ effect.name } className="col mb-3" onClick={ event => processAction('select_effect', effect.name) }>
|
||||||
<div title={ LocalizeText('camera.effect.name.' + effect.name) } className="effect-thumbnail cursor-pointer position-relative border border-2 rounded d-flex flex-column justify-content-center align-items-center py-1">
|
<div title={ LocalizeText('camera.effect.name.' + effect.name) } className="effect-thumbnail cursor-pointer position-relative border border-2 rounded d-flex flex-column justify-content-center align-items-center py-1">
|
||||||
<div className="effect-thumbnail-image rounded">
|
<div className="effect-thumbnail-image rounded">
|
||||||
<img alt="" className="rounded" src={ getEffectThumbnail(effect.name) } />
|
<img alt="" className="rounded" src={ getEffectThumbnail(effect.name) } />
|
||||||
@ -108,22 +201,26 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<NitroCardTabsView></NitroCardTabsView>
|
<NitroCardTabsView></NitroCardTabsView>
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<div className="bg-black rounded">
|
<div className={ 'd-flex align-items-end picture-preview' + classNames({ ' zoomed': isZoomed }) } style={ { backgroundImage: 'url(' + getCurrentPicture().src + ')' } }>
|
||||||
<div className={ 'picture-preview rounded' + classNames({ ' zoomed': isZoomed }) } style={ { backgroundImage: 'url(' + picture.src + ')' } }></div>
|
{ selectedEffectName && <div className="w-100 p-2 d-flex flex-column justify-content-center bg-black">
|
||||||
|
<div className="w-100 text-center">{ LocalizeText('camera.effect.name.' + selectedEffectName) + ' - ' + getEffectRangeConfig()[2] }</div>
|
||||||
|
<input type="range" min="0" max={ getEffectRangeConfig()[0] } step={ getEffectRangeConfig()[1] } value={ getEffectRangeConfig()[2] } onChange={ event => setSelectedEffectAlpha(Number(event.target.value)) } className="form-range w-100" />
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex mt-2">
|
<div className="d-flex justify-content-between mt-2">
|
||||||
<button className="btn btn-primary btn-sm me-2">{ LocalizeText('save') }</button>
|
<div className="btn-group">
|
||||||
<button className="btn btn-primary btn-sm" onClick={ event => processAction('zoom') }>{ LocalizeText('room.zoom.button.text') }</button>
|
<button className="btn btn-primary" onClick={ event => processAction('clear_effects') }><i className="fas fa-trash"></i></button>
|
||||||
|
<button className="btn btn-primary" onClick={ event => processAction('download') }><i className="fas fa-save"></i></button>
|
||||||
|
<button className="btn btn-primary" onClick={ event => processAction('zoom') }><i className={"fas " + classNames({'fa-search-plus': !isZoomed, 'fa-search-minus': isZoomed})}></i></button>
|
||||||
</div>
|
</div>
|
||||||
</NitroCardContentView>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<NitroCardContentView>
|
|
||||||
<div className="d-flex justify-content-end">
|
<div className="d-flex justify-content-end">
|
||||||
<button className="btn btn-primary me-2">{ LocalizeText('generic.cancel') }</button>
|
<button className="btn btn-primary me-2" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>
|
||||||
<button className="btn btn-success">{ LocalizeText('camera.preview.button.text') }</button>
|
<button className="btn btn-success">{ LocalizeText('camera.preview.button.text') }</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ import { IRoomCameraWidgetEffect } from 'nitro-renderer/src/nitro/camera/IRoomCa
|
|||||||
|
|
||||||
export interface CameraWidgetEditorViewProps
|
export interface CameraWidgetEditorViewProps
|
||||||
{
|
{
|
||||||
picture: HTMLImageElement;
|
|
||||||
availableEffects: IRoomCameraWidgetEffect[];
|
availableEffects: IRoomCameraWidgetEffect[];
|
||||||
onCloseClick: () => void;
|
onCloseClick: () => void;
|
||||||
|
onCancelClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CameraWidgetEditorTabs
|
export class CameraWidgetEditorTabs
|
||||||
|
Loading…
Reference in New Issue
Block a user