Camera updates
BIN
src/assets/images/room-widgets/camera-widget/btn.png
Normal file
After Width: | Height: | Size: 830 B |
BIN
src/assets/images/room-widgets/camera-widget/btn_down.png
Normal file
After Width: | Height: | Size: 1000 B |
BIN
src/assets/images/room-widgets/camera-widget/btn_hi.png
Normal file
After Width: | Height: | Size: 935 B |
BIN
src/assets/images/room-widgets/camera-widget/cam_bg.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 15 KiB |
BIN
src/assets/images/room-widgets/camera-widget/viewfinder.png
Normal file
After Width: | Height: | Size: 959 B |
@ -476,13 +476,13 @@
|
|||||||
&.icon-camera-colormatrix {
|
&.icon-camera-colormatrix {
|
||||||
background: url('../images/icons/camera-colormatrix.png');
|
background: url('../images/icons/camera-colormatrix.png');
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 14px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-camera-composite {
|
&.icon-camera-composite {
|
||||||
background: url('../images/icons/camera-composite.png');
|
background: url('../images/icons/camera-composite.png');
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 14px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-user-profile {
|
&.icon-user-profile {
|
||||||
|
@ -1,30 +1,41 @@
|
|||||||
.nitro-camera-capture {
|
.nitro-camera-capture {
|
||||||
.nitro-close {
|
position: relative;
|
||||||
top: 7px;
|
|
||||||
right: 9px;
|
.header-close {
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
box-shadow: 0 0 0 1.5px $white;
|
||||||
|
border: 2px solid #921911;
|
||||||
|
background: repeating-linear-gradient(rgba(245,80,65,1), rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%);
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 1px 3px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-area {
|
||||||
|
position: absolute;
|
||||||
|
top: 37px;
|
||||||
|
left: 10px;
|
||||||
|
width: 320px;
|
||||||
|
height: 320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.camera-canvas {
|
.camera-canvas {
|
||||||
|
position: relative;
|
||||||
width: 340px;
|
width: 340px;
|
||||||
height: 462px;
|
height: 462px;
|
||||||
|
|
||||||
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
||||||
|
background-position: -1px -1px;
|
||||||
.camera-frame {
|
z-index: 2;
|
||||||
position: absolute;
|
|
||||||
width: 320px;
|
|
||||||
height: 320px;
|
|
||||||
margin-top: 37px;
|
|
||||||
margin-left: 11.4px;
|
|
||||||
|
|
||||||
&.bg {
|
|
||||||
background: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.camera-frame-preview-actions {
|
|
||||||
background: rgba(0, 0, 0, .5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.camera-button {
|
.camera-button {
|
||||||
width: 94px;
|
width: 94px;
|
||||||
@ -33,14 +44,26 @@
|
|||||||
margin-top: 362px;
|
margin-top: 362px;
|
||||||
|
|
||||||
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
||||||
background-position: -340px 0px;
|
background-position: -343px -321px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-position: -340px -94px;
|
background-position: -535px -321px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-position: -340px -188px;
|
background-position: -439px -321px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-view-finder {
|
||||||
|
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
||||||
|
background-position: -343px -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-frame {
|
||||||
|
|
||||||
|
.camera-frame-preview-actions {
|
||||||
|
background: rgba(0, 0, 0, .5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,50 @@
|
|||||||
import { RoomWidgetCameraConfigurationComposer, RoomWidgetCameraConfigurationEvent } from 'nitro-renderer';
|
import { InitCameraMessageEvent, IRoomCameraWidgetEffect, RequestCameraConfigurationComposer } from 'nitro-renderer';
|
||||||
import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/camera/events/RoomCameraWidgetManagerEvent';
|
import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/camera/events/RoomCameraWidgetManagerEvent';
|
||||||
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
||||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
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 { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages/message-event';
|
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages/message-event';
|
||||||
|
import { CameraPicture } from './common/CameraPicture';
|
||||||
import { CameraWidgetContextProvider } from './context/CameraWidgetContext';
|
import { CameraWidgetContextProvider } from './context/CameraWidgetContext';
|
||||||
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
|
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
|
||||||
import { CameraWidgetCheckoutView } from './views/checkout/CameraWidgetCheckoutView';
|
import { CameraWidgetCheckoutView } from './views/checkout/CameraWidgetCheckoutView';
|
||||||
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
|
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
|
||||||
|
|
||||||
|
const MODE_NONE: number = 0;
|
||||||
|
const MODE_CAPTURE: number = 1;
|
||||||
|
const MODE_EDITOR: number = 2;
|
||||||
|
const MODE_CHECKOUT: number = 3;
|
||||||
|
|
||||||
export const CameraWidgetView: FC<{}> = props =>
|
export const CameraWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ effectsReady, setEffectsReady ] = useState(false);
|
const [ mode, setMode ] = useState<number>(MODE_NONE);
|
||||||
|
const [ availableEffects, setAvailableEffects ] = useState<IRoomCameraWidgetEffect[]>([]);
|
||||||
const [ isCaptureVisible, setIsCaptureVisible ] = useState(false);
|
const [ cameraRoll, setCameraRoll ] = useState<CameraPicture[]>([]);
|
||||||
const [ isEditorVisible, setIsEditorVisible ] = useState(false);
|
|
||||||
const [ isCheckoutVisible, setIsCheckoutVisible ] = useState(false);
|
|
||||||
|
|
||||||
const [ myLevel, setMyLevel ] = useState(10);
|
|
||||||
const [ cameraRoll, setCameraRoll ] = useState<HTMLImageElement[]>([]);
|
|
||||||
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
|
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
|
||||||
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
|
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
|
||||||
const [ isZoomed, setIsZoomed ] = useState(false);
|
const [ isZoomed, setIsZoomed ] = useState(false);
|
||||||
const [ price, setPrice ] = useState<{credits: Number, points: Number, pointsType: number}>(null);
|
const [ myLevel, setMyLevel ] = useState(10);
|
||||||
|
const [ price, setPrice ] = useState<{ credits: number, duckets: number, publishDucketPrice: number }>(null);
|
||||||
|
|
||||||
const onNitroEvent = useCallback((event: RoomWidgetCameraEvent) =>
|
const onNitroEvent = useCallback((event: RoomWidgetCameraEvent) =>
|
||||||
{
|
{
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
{
|
{
|
||||||
case RoomWidgetCameraEvent.SHOW_CAMERA:
|
case RoomWidgetCameraEvent.SHOW_CAMERA:
|
||||||
setIsCaptureVisible(true);
|
setMode(MODE_CAPTURE);
|
||||||
return;
|
return;
|
||||||
case RoomWidgetCameraEvent.HIDE_CAMERA:
|
case RoomWidgetCameraEvent.HIDE_CAMERA:
|
||||||
setIsCaptureVisible(false);
|
setMode(MODE_NONE);
|
||||||
setIsEditorVisible(false);
|
|
||||||
setIsCheckoutVisible(false);
|
|
||||||
return;
|
return;
|
||||||
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
|
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
|
||||||
setIsCaptureVisible(value => !value);
|
setMode(prevValue =>
|
||||||
setIsEditorVisible(false);
|
{
|
||||||
setIsCheckoutVisible(false);
|
if(!prevValue) return MODE_CAPTURE;
|
||||||
|
else return MODE_NONE;
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@ -51,78 +53,68 @@ export const CameraWidgetView: FC<{}> = props =>
|
|||||||
useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onNitroEvent);
|
useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onNitroEvent);
|
||||||
useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onNitroEvent);
|
useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onNitroEvent);
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(price) return;
|
|
||||||
|
|
||||||
SendMessageHook(new RoomWidgetCameraConfigurationComposer());
|
|
||||||
}, [ price ]);
|
|
||||||
|
|
||||||
const onCameraConfigurationEvent = useCallback((event: RoomWidgetCameraConfigurationEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setPrice({ credits: parser.credits, points: parser.points, pointsType: parser.pointsType });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(RoomWidgetCameraConfigurationEvent, onCameraConfigurationEvent);
|
|
||||||
|
|
||||||
const availableEffects = useMemo(() =>
|
|
||||||
{
|
|
||||||
if(!effectsReady) return null;
|
|
||||||
|
|
||||||
return Array.from(GetRoomCameraWidgetManager().effects.values());
|
|
||||||
}, [ effectsReady ]);
|
|
||||||
|
|
||||||
const onRoomCameraWidgetManagerEvent = useCallback((event: RoomCameraWidgetManagerEvent) =>
|
const onRoomCameraWidgetManagerEvent = useCallback((event: RoomCameraWidgetManagerEvent) =>
|
||||||
{
|
{
|
||||||
setEffectsReady(true);
|
setAvailableEffects(Array.from(GetRoomCameraWidgetManager().effects.values()))
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useCameraEvent(RoomCameraWidgetManagerEvent.INITIALIZED, onRoomCameraWidgetManagerEvent);
|
useCameraEvent(RoomCameraWidgetManagerEvent.INITIALIZED, onRoomCameraWidgetManagerEvent);
|
||||||
|
|
||||||
|
const onCameraConfigurationEvent = useCallback((event: InitCameraMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setPrice({ credits: parser.creditPrice, duckets: parser.ducketPrice, publishDucketPrice: parser.publishDucketPrice });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(InitCameraMessageEvent, onCameraConfigurationEvent);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!GetRoomCameraWidgetManager().isLoaded)
|
if(!GetRoomCameraWidgetManager().isLoaded)
|
||||||
{
|
{
|
||||||
GetRoomCameraWidgetManager().init();
|
GetRoomCameraWidgetManager().init();
|
||||||
|
|
||||||
|
SendMessageHook(new RequestCameraConfigurationComposer());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEffectsReady(true);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: any = null) =>
|
const processAction = useCallback((type: string) =>
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case 'close':
|
case 'close':
|
||||||
setIsCaptureVisible(false);
|
setMode(MODE_NONE);
|
||||||
setIsEditorVisible(false);
|
|
||||||
setIsCheckoutVisible(false);
|
|
||||||
return;
|
return;
|
||||||
case 'capture_edit':
|
case 'edit':
|
||||||
setIsCaptureVisible(false);
|
setMode(MODE_EDITOR);
|
||||||
setIsEditorVisible(true);
|
return;
|
||||||
|
case 'delete':
|
||||||
|
setCameraRoll(prevValue =>
|
||||||
|
{
|
||||||
|
const clone = [ ...prevValue ];
|
||||||
|
|
||||||
|
clone.splice(selectedPictureIndex, 1);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
case 'editor_cancel':
|
case 'editor_cancel':
|
||||||
setIsCaptureVisible(true);
|
setMode(MODE_CAPTURE);
|
||||||
setIsEditorVisible(false);
|
|
||||||
setIsCheckoutVisible(false);
|
|
||||||
return;
|
return;
|
||||||
case 'editor_checkout':
|
case 'checkout':
|
||||||
setIsEditorVisible(false);
|
setMode(MODE_CHECKOUT);
|
||||||
setIsCheckoutVisible(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, [ selectedPictureIndex ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CameraWidgetContextProvider value={ { cameraRoll, setCameraRoll, selectedPictureIndex, setSelectedPictureIndex, selectedEffects, setSelectedEffects, isZoomed, setIsZoomed } }>
|
<CameraWidgetContextProvider value={ { cameraRoll, setCameraRoll, selectedPictureIndex, setSelectedPictureIndex, selectedEffects, setSelectedEffects, isZoomed, setIsZoomed } }>
|
||||||
{ isCaptureVisible && <CameraWidgetCaptureView onCloseClick={ () => processAction('close') } onEditClick={ () => processAction('capture_edit') } /> }
|
{ (mode === MODE_CAPTURE) && <CameraWidgetCaptureView onClose={ () => processAction('close') } onEdit={ () => processAction('edit') } onDelete={ () => processAction('delete') } /> }
|
||||||
{ isEditorVisible && <CameraWidgetEditorView myLevel={ myLevel } onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } onCheckoutClick={ () => processAction('editor_checkout') } availableEffects={ availableEffects } /> }
|
{ (mode === MODE_EDITOR) && <CameraWidgetEditorView myLevel={ myLevel } onClose={ () => processAction('close') } onCancel={ () => processAction('editor_cancel') } onCheckout={ () => processAction('checkout') } availableEffects={ availableEffects } /> }
|
||||||
{ isCheckoutVisible && <CameraWidgetCheckoutView onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } price={ price }></CameraWidgetCheckoutView> }
|
{ (mode === MODE_CHECKOUT) && <CameraWidgetCheckoutView onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } price={ price }></CameraWidgetCheckoutView> }
|
||||||
</CameraWidgetContextProvider>
|
</CameraWidgetContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
8
src/views/room/widgets/camera/common/CameraPicture.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { NitroTexture } from 'nitro-renderer';
|
||||||
|
|
||||||
|
export class CameraPicture
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
public texture: NitroTexture,
|
||||||
|
public imageUrl: string) {}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
|
||||||
import { ProviderProps } from 'react';
|
import { ProviderProps } from 'react';
|
||||||
|
import { CameraPicture } from '../common/CameraPicture';
|
||||||
|
|
||||||
export interface ICameraWidgetContext
|
export interface ICameraWidgetContext
|
||||||
{
|
{
|
||||||
cameraRoll: HTMLImageElement[],
|
cameraRoll: CameraPicture[],
|
||||||
setCameraRoll: (cameraRoll: HTMLImageElement[]) => void,
|
setCameraRoll: (cameraRoll: CameraPicture[]) => void,
|
||||||
selectedPictureIndex: number,
|
selectedPictureIndex: number,
|
||||||
setSelectedPictureIndex: (index: number) => void,
|
setSelectedPictureIndex: (index: number) => void,
|
||||||
selectedEffects: IRoomCameraWidgetSelectedEffect[],
|
selectedEffects: IRoomCameraWidgetSelectedEffect[],
|
||||||
|
@ -1,103 +1,81 @@
|
|||||||
import classNames from 'classnames';
|
import { NitroRectangle, TextureUtils } from 'nitro-renderer';
|
||||||
import { NitroRectangle } from 'nitro-renderer';
|
|
||||||
import { FC, useCallback, useRef } from 'react';
|
import { FC, useCallback, useRef } from 'react';
|
||||||
import { GetRoomEngine, GetRoomSession } from '../../../../../../api';
|
import { GetRoomEngine, GetRoomSession } from '../../../../../../api';
|
||||||
import { DraggableWindow } from '../../../../../../layout/draggable-window/DraggableWindow';
|
import { DraggableWindow } from '../../../../../../layout/draggable-window/DraggableWindow';
|
||||||
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||||
|
import { CameraPicture } from '../../common/CameraPicture';
|
||||||
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
||||||
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
|
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
|
||||||
|
|
||||||
|
const CAMERA_ROLL_LIMIT: number = 5;
|
||||||
|
|
||||||
export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =>
|
export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { onCloseClick = null, onEditClick = null } = props;
|
const { onClose = null, onEdit = null, onDelete = null } = props;
|
||||||
|
const { cameraRoll = null, setCameraRoll = null, selectedPictureIndex = -1, setSelectedPictureIndex = null } = useCameraWidgetContext();
|
||||||
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
const CAMERA_ROLL_LIMIT: number = 5;
|
const selectedPicture = ((selectedPictureIndex > -1) ? cameraRoll[selectedPictureIndex] : null);
|
||||||
const cameraFrameRef = useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const cameraWidgetContext = useCameraWidgetContext();
|
const getCameraBounds = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!elementRef || !elementRef.current) return null;
|
||||||
|
|
||||||
|
const frameBounds = elementRef.current.getBoundingClientRect();
|
||||||
|
|
||||||
|
return new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const takePicture = useCallback(() =>
|
const takePicture = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(cameraWidgetContext.selectedPictureIndex > -1)
|
if(selectedPictureIndex > -1)
|
||||||
{
|
{
|
||||||
cameraWidgetContext.setSelectedPictureIndex(-1);
|
setSelectedPictureIndex(-1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const frameBounds = cameraFrameRef.current.getBoundingClientRect();
|
const texture = GetRoomEngine().createTextureFromRoom(GetRoomSession().roomId, 1, getCameraBounds());
|
||||||
|
|
||||||
if(!frameBounds) return;
|
const clone = [ ...cameraRoll ];
|
||||||
|
|
||||||
const rectangle = new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height));
|
if(clone.length >= CAMERA_ROLL_LIMIT)
|
||||||
|
|
||||||
const texture = GetRoomEngine().createTextureFromRoom(GetRoomSession().roomId, 1, rectangle);
|
|
||||||
|
|
||||||
if(cameraWidgetContext.cameraRoll.length + 1 === CAMERA_ROLL_LIMIT)
|
|
||||||
{
|
{
|
||||||
alert(LocalizeText('camera.full.body'));
|
alert(LocalizeText('camera.full.body'));
|
||||||
|
|
||||||
|
clone.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let remainingRoll = cameraWidgetContext.cameraRoll;
|
clone.push(new CameraPicture(texture, TextureUtils.generateImageUrl(texture)));
|
||||||
|
|
||||||
if(cameraWidgetContext.cameraRoll.length === CAMERA_ROLL_LIMIT)
|
setCameraRoll(clone);
|
||||||
{
|
}, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex ]);
|
||||||
remainingRoll = remainingRoll.slice(0, CAMERA_ROLL_LIMIT - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//cameraWidgetContext.setCameraRoll([ ...remainingRoll, image ]);
|
|
||||||
}, [ cameraWidgetContext ]);
|
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case 'take_picture':
|
|
||||||
takePicture();
|
|
||||||
return;
|
|
||||||
case 'preview_picture':
|
|
||||||
cameraWidgetContext.setSelectedPictureIndex(Number(value));
|
|
||||||
return;
|
|
||||||
case 'discard_picture':
|
|
||||||
cameraWidgetContext.setSelectedPictureIndex(-1);
|
|
||||||
|
|
||||||
const clone = Array.from(cameraWidgetContext.cameraRoll);
|
|
||||||
clone.splice(cameraWidgetContext.selectedPictureIndex, 1);
|
|
||||||
|
|
||||||
cameraWidgetContext.setCameraRoll(clone);
|
|
||||||
return;
|
|
||||||
case 'edit_picture':
|
|
||||||
onEditClick();
|
|
||||||
return;
|
|
||||||
case 'close':
|
|
||||||
onCloseClick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, [ takePicture, cameraWidgetContext, onEditClick, onCloseClick ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableWindow handle=".nitro-camera-capture">
|
<DraggableWindow>
|
||||||
<div className="nitro-camera-capture d-flex flex-column justify-content-center align-items-center">
|
<div className="d-flex flex-column justify-content-center align-items-center nitro-camera-capture">
|
||||||
<div className="camera-canvas">
|
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
|
||||||
<div className="position-absolute header-close" onClick={ event => processAction('close') }>
|
<div className="camera-canvas drag-handler">
|
||||||
<i className="fas fa-times"/>
|
<div className="position-absolute header-close" onClick={ onClose }>
|
||||||
|
<i className="fas fa-times" />
|
||||||
</div>
|
</div>
|
||||||
<div ref={ cameraFrameRef } className={'camera-frame ' + classNames({'bg': cameraWidgetContext.selectedPictureIndex > -1}) }>
|
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
|
||||||
{ cameraWidgetContext.selectedPictureIndex > -1 && <div>
|
{ selectedPicture &&
|
||||||
<img alt="" src={ cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex].src } />
|
<div className="camera-area camera-frame">
|
||||||
<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" title={ LocalizeText('camera.editor.button.tooltip') } onClick={ event => processAction('edit_picture') }>{ LocalizeText('camera.editor.button.text') }</button>
|
<button className="btn btn-success me-3" title={ LocalizeText('camera.editor.button.tooltip') } onClick={ onEdit }>{ 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={ onDelete }>{ LocalizeText('camera.delete.button.text') }</button>
|
||||||
</div>
|
</div>
|
||||||
</div> }
|
</div> }
|
||||||
</div>
|
|
||||||
<div className="d-flex justify-content-center">
|
<div className="d-flex justify-content-center">
|
||||||
<div className="camera-button" title={ LocalizeText('camera.take.photo.button.tooltip') } onClick={ takePicture }></div>
|
<div className="camera-button" title={ LocalizeText('camera.take.photo.button.tooltip') } onClick={ takePicture } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ cameraWidgetContext.cameraRoll.length > 0 && <div className="camera-roll d-flex justify-content-center py-2">
|
{ (cameraRoll.length > 0) &&
|
||||||
{ cameraWidgetContext.cameraRoll.map((picture, index) =>
|
<div className="camera-roll d-flex justify-content-center py-2">
|
||||||
|
{ cameraRoll.map((picture, index) =>
|
||||||
{
|
{
|
||||||
return <img alt="" key={ index } className={ (index < cameraWidgetContext.cameraRoll.length - 1 ? 'me-2' : '') } src={ picture.src } onClick={ event => processAction('preview_picture', index) } />;
|
return <img alt="" key={ index } className={ (index < (cameraRoll.length - 1) ? 'me-2' : '') } src={ picture.imageUrl } onClick={ event => setSelectedPictureIndex(index) } />;
|
||||||
}) }
|
}) }
|
||||||
</div> }
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export interface CameraWidgetCaptureViewProps
|
export interface CameraWidgetCaptureViewProps
|
||||||
{
|
{
|
||||||
onCloseClick: () => void;
|
onClose: () => void;
|
||||||
onEditClick: () => void;
|
onEdit: () => void;
|
||||||
|
onDelete: () => void;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
/* eslint-disable jsx-a11y/anchor-is-valid */
|
||||||
import { RoomWidgetCameraPublishComposer, RoomWidgetCameraPublishedEvent, RoomWidgetCameraPurchaseComposer, RoomWidgetCameraPurchaseSuccessfulEvent } from 'nitro-renderer';
|
import { CameraPublishStatusMessageEvent, CameraPurchaseOKMessageEvent, PublishPhotoMessageComposer, PurchasePhotoMessageComposer } from 'nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { GetRoomCameraWidgetManager } from '../../../../../../api/nitro/camera/GetRoomCameraWidgetManager';
|
import { GetRoomCameraWidgetManager } from '../../../../../../api/nitro/camera/GetRoomCameraWidgetManager';
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages/message-event';
|
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages/message-event';
|
||||||
@ -12,36 +12,35 @@ import { CameraWidgetCheckoutViewProps } from './CameraWidgetCheckoutView.types'
|
|||||||
export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props =>
|
export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { onCloseClick = null, onCancelClick = null, price = null } = props;
|
const { onCloseClick = null, onCancelClick = null, price = null } = props;
|
||||||
|
|
||||||
const cameraWidgetContext = useCameraWidgetContext();
|
|
||||||
|
|
||||||
const [ picturesBought, setPicturesBought ] = useState(0);
|
const [ picturesBought, setPicturesBought ] = useState(0);
|
||||||
const [ wasPicturePublished, setWasPicturePublished ] = useState(false);
|
const [ wasPicturePublished, setWasPicturePublished ] = useState(false);
|
||||||
const [ isWaiting, setIsWaiting ] = useState(false);
|
const [ isWaiting, setIsWaiting ] = useState(false);
|
||||||
const [ publishCooldown, setPublishCooldown ] = useState(0);
|
const [ publishCooldown, setPublishCooldown ] = useState(0);
|
||||||
|
const { cameraRoll = null, selectedPictureIndex = -1, selectedEffects = null, isZoomed = false } = useCameraWidgetContext();
|
||||||
|
|
||||||
const onCameraPurchaseSuccessfulEvent = useCallback((event: RoomWidgetCameraPurchaseSuccessfulEvent) =>
|
const onCameraPurchaseOKMessageEvent = useCallback((event: CameraPurchaseOKMessageEvent) =>
|
||||||
{
|
{
|
||||||
setPicturesBought(value => value + 1);
|
setPicturesBought(value => value + 1);
|
||||||
setIsWaiting(false);
|
setIsWaiting(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onRoomWidgetCameraPublishedEvent = useCallback((event: RoomWidgetCameraPublishedEvent) =>
|
CreateMessageHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
|
||||||
|
|
||||||
|
const onCameraPublishStatusMessageEvent = useCallback((event: CameraPublishStatusMessageEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
setPublishCooldown(parser.cooldownSeconds);
|
setPublishCooldown(parser.secondsToWait);
|
||||||
setWasPicturePublished(parser.wasSuccessful);
|
setWasPicturePublished(parser.ok);
|
||||||
setIsWaiting(false);
|
setIsWaiting(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
CreateMessageHook(RoomWidgetCameraPurchaseSuccessfulEvent, onCameraPurchaseSuccessfulEvent);
|
CreateMessageHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);
|
||||||
CreateMessageHook(RoomWidgetCameraPublishedEvent, onRoomWidgetCameraPublishedEvent);
|
|
||||||
|
|
||||||
const getCurrentPicture = useCallback(() =>
|
const getCurrentPicture = useCallback(() =>
|
||||||
{
|
{
|
||||||
return GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], cameraWidgetContext.selectedEffects, cameraWidgetContext.isZoomed);
|
return GetRoomCameraWidgetManager().applyEffects(cameraRoll[selectedPictureIndex].texture, selectedEffects, isZoomed);
|
||||||
}, [ cameraWidgetContext ]);
|
}, [ cameraRoll, selectedPictureIndex, selectedEffects, isZoomed ]);
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
const processAction = useCallback((type: string, value: string | number = null) =>
|
||||||
{
|
{
|
||||||
@ -54,13 +53,13 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
|
|||||||
if(isWaiting) return;
|
if(isWaiting) return;
|
||||||
|
|
||||||
setIsWaiting(true);
|
setIsWaiting(true);
|
||||||
SendMessageHook(new RoomWidgetCameraPurchaseComposer());
|
SendMessageHook(new PurchasePhotoMessageComposer('1_1627697499'));
|
||||||
return;
|
return;
|
||||||
case 'publish':
|
case 'publish':
|
||||||
if(isWaiting) return;
|
if(isWaiting) return;
|
||||||
|
|
||||||
setIsWaiting(true);
|
setIsWaiting(true);
|
||||||
SendMessageHook(new RoomWidgetCameraPublishComposer());
|
SendMessageHook(new PublishPhotoMessageComposer());
|
||||||
return;
|
return;
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
onCancelClick();
|
onCancelClick();
|
||||||
@ -88,7 +87,7 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
|
|||||||
<div className="bg-muted rounded p-2 text-black mb-2">
|
<div className="bg-muted rounded p-2 text-black mb-2">
|
||||||
<div className="d-flex justify-content-between align-items-center">
|
<div className="d-flex justify-content-between align-items-center">
|
||||||
<div className="me-2">
|
<div className="me-2">
|
||||||
<div className="fw-bold d-flex justify-content-start">{ LocalizeText(wasPicturePublished ? 'camera.publish.successful' : 'camera.publish.explanation') }{ !wasPicturePublished && price.points > 0 && <>: { price.points } <CurrencyIcon type={ price.pointsType } /></> }</div>
|
<div className="fw-bold d-flex justify-content-start">{ LocalizeText(wasPicturePublished ? 'camera.publish.successful' : 'camera.publish.explanation') }{ !wasPicturePublished && price.duckets > 0 && <>: { price.duckets } <CurrencyIcon type={ price.publishDucketPrice } /></> }</div>
|
||||||
<div>{ LocalizeText(wasPicturePublished ? 'camera.publish.success.short.info' : 'camera.publish.detailed.explanation') }</div>
|
<div>{ LocalizeText(wasPicturePublished ? 'camera.publish.success.short.info' : 'camera.publish.detailed.explanation') }</div>
|
||||||
{ wasPicturePublished && <a href="#">{ LocalizeText('camera.link.to.published') }</a> }
|
{ wasPicturePublished && <a href="#">{ LocalizeText('camera.link.to.published') }</a> }
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,5 +2,5 @@ export interface CameraWidgetCheckoutViewProps
|
|||||||
{
|
{
|
||||||
onCloseClick: () => void;
|
onCloseClick: () => void;
|
||||||
onCancelClick: () => void;
|
onCancelClick: () => void;
|
||||||
price: {credits: Number, points: Number, pointsType: number};
|
price: { credits: number, duckets: number, publishDucketPrice: number };
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,15 @@ import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
|||||||
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
|
||||||
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
|
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
|
||||||
|
|
||||||
|
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
|
||||||
|
|
||||||
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { availableEffects = null, myLevel = null, onCloseClick = null, onCancelClick = null, onCheckoutClick = null } = props;
|
const { availableEffects = null, myLevel = 1, onClose = null, onCancel = null, onCheckout = null } = props;
|
||||||
|
const [ currentTab, setCurrentTab ] = useState(TABS[0]);
|
||||||
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
|
|
||||||
|
|
||||||
const cameraWidgetContext = useCameraWidgetContext();
|
|
||||||
|
|
||||||
const [ currentTab, setCurrentTab ] = useState(CameraWidgetEditorTabs.COLORMATRIX);
|
|
||||||
const [ selectedEffectName, setSelectedEffectName ] = useState(null);
|
const [ selectedEffectName, setSelectedEffectName ] = useState(null);
|
||||||
const [ effectsThumbnails, setEffectsThumbnails ] = useState<{ name: string, image: HTMLImageElement }[]>([]);
|
const [ effectsThumbnails, setEffectsThumbnails ] = useState<{ name: string, image: HTMLImageElement }[]>([]);
|
||||||
|
const { cameraRoll = null, selectedPictureIndex = -1, selectedEffects = null, isZoomed = false, setSelectedEffects = null, setIsZoomed = null } = useCameraWidgetContext();
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -25,11 +23,11 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
for(const effect of availableEffects)
|
for(const effect of availableEffects)
|
||||||
{
|
{
|
||||||
thumbnails.push({name: effect.name, image: GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false)});
|
thumbnails.push({name: effect.name, image: GetRoomCameraWidgetManager().applyEffects(cameraRoll[selectedPictureIndex].texture, [ new RoomCameraWidgetSelectedEffect(effect, 1) ], false)});
|
||||||
}
|
}
|
||||||
|
|
||||||
setEffectsThumbnails(thumbnails);
|
setEffectsThumbnails(thumbnails);
|
||||||
}, [ cameraWidgetContext, availableEffects ]);
|
}, [ cameraRoll, selectedPictureIndex, availableEffects ]);
|
||||||
|
|
||||||
const getEffectThumbnail = useCallback((effectName: string) =>
|
const getEffectThumbnail = useCallback((effectName: string) =>
|
||||||
{
|
{
|
||||||
@ -54,24 +52,24 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
const getCurrentPicture = useCallback(() =>
|
const getCurrentPicture = useCallback(() =>
|
||||||
{
|
{
|
||||||
return GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], cameraWidgetContext.selectedEffects, cameraWidgetContext.isZoomed);
|
return GetRoomCameraWidgetManager().applyEffects(cameraRoll[selectedPictureIndex].texture, selectedEffects, isZoomed);
|
||||||
}, [ cameraWidgetContext ]);
|
}, [ cameraRoll, selectedPictureIndex, selectedEffects, isZoomed ]);
|
||||||
|
|
||||||
const getCurrentEffectAlpha = useCallback(() =>
|
const getCurrentEffectAlpha = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(!selectedEffectName) return 0;
|
if(!selectedEffectName) return 0;
|
||||||
|
|
||||||
const selectedEffect = cameraWidgetContext.selectedEffects.find(effect => effect.effect.name === selectedEffectName);
|
const selectedEffect = selectedEffects.find(effect => effect.effect.name === selectedEffectName);
|
||||||
|
|
||||||
if(!selectedEffect) return 0;
|
if(!selectedEffect) return 0;
|
||||||
|
|
||||||
return selectedEffect.alpha;
|
return selectedEffect.alpha;
|
||||||
}, [ selectedEffectName, cameraWidgetContext.selectedEffects ]);
|
}, [ selectedEffectName, selectedEffects ]);
|
||||||
|
|
||||||
const getEffectIndex = useCallback((effectName) =>
|
const getEffectIndex = useCallback((effectName) =>
|
||||||
{
|
{
|
||||||
return cameraWidgetContext.selectedEffects.findIndex(effect => effect.effect.name === effectName);
|
return selectedEffects.findIndex(effect => effect.effect.name === effectName);
|
||||||
}, [ cameraWidgetContext.selectedEffects ])
|
}, [ selectedEffects ])
|
||||||
|
|
||||||
const setSelectedEffectAlpha = useCallback((newAlpha: number) =>
|
const setSelectedEffectAlpha = useCallback((newAlpha: number) =>
|
||||||
{
|
{
|
||||||
@ -81,27 +79,27 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
if(selectedEffectIndex === -1) return;
|
if(selectedEffectIndex === -1) return;
|
||||||
|
|
||||||
const clone = Array.from(cameraWidgetContext.selectedEffects);
|
const clone = Array.from(selectedEffects);
|
||||||
|
|
||||||
const selectedEffect = clone[selectedEffectIndex];
|
const selectedEffect = clone[selectedEffectIndex];
|
||||||
|
|
||||||
clone[selectedEffectIndex] = new RoomCameraWidgetSelectedEffect(selectedEffect.effect, newAlpha);
|
clone[selectedEffectIndex] = new RoomCameraWidgetSelectedEffect(selectedEffect.effect, newAlpha);
|
||||||
|
|
||||||
cameraWidgetContext.setSelectedEffects(clone);
|
setSelectedEffects(clone);
|
||||||
}, [ selectedEffectName, getEffectIndex, cameraWidgetContext ]);
|
}, [ selectedEffectName, getEffectIndex, selectedEffects, setSelectedEffects ]);
|
||||||
|
|
||||||
const processAction = useCallback((type: string, value: string | number = null) =>
|
const processAction = useCallback((type: string, value: string | number = null) =>
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case 'close':
|
case 'close':
|
||||||
onCloseClick();
|
onClose();
|
||||||
return;
|
return;
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
onCancelClick();
|
onCancel();
|
||||||
return;
|
return;
|
||||||
case 'checkout':
|
case 'checkout':
|
||||||
onCheckoutClick();
|
onCheckout();
|
||||||
return;
|
return;
|
||||||
case 'change_tab':
|
case 'change_tab':
|
||||||
setCurrentTab(String(value));
|
setCurrentTab(String(value));
|
||||||
@ -110,7 +108,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
{
|
{
|
||||||
let existingIndex = -1;
|
let existingIndex = -1;
|
||||||
|
|
||||||
if(cameraWidgetContext.selectedEffects.length > 0)
|
if(selectedEffects.length > 0)
|
||||||
{
|
{
|
||||||
existingIndex = getEffectIndex(value);
|
existingIndex = getEffectIndex(value);
|
||||||
}
|
}
|
||||||
@ -123,7 +121,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
if(effect.minLevel > myLevel) return;
|
if(effect.minLevel > myLevel) return;
|
||||||
|
|
||||||
cameraWidgetContext.setSelectedEffects([...cameraWidgetContext.selectedEffects, new RoomCameraWidgetSelectedEffect(effect, 0.5)]);
|
setSelectedEffects([...selectedEffects, new RoomCameraWidgetSelectedEffect(effect, 0.5)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(effect && effect.minLevel > myLevel) return;
|
if(effect && effect.minLevel > myLevel) return;
|
||||||
@ -144,32 +142,32 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
|
|
||||||
if(existingIndex > -1)
|
if(existingIndex > -1)
|
||||||
{
|
{
|
||||||
const effect = cameraWidgetContext.selectedEffects[existingIndex];
|
const effect = selectedEffects[existingIndex];
|
||||||
|
|
||||||
if(effect.effect.name === selectedEffectName)
|
if(effect.effect.name === selectedEffectName)
|
||||||
{
|
{
|
||||||
setSelectedEffectName(null);
|
setSelectedEffectName(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const clone = Array.from(cameraWidgetContext.selectedEffects);
|
const clone = Array.from(selectedEffects);
|
||||||
clone.splice(existingIndex, 1);
|
clone.splice(existingIndex, 1);
|
||||||
|
|
||||||
cameraWidgetContext.setSelectedEffects(clone);
|
setSelectedEffects(clone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 'clear_effects':
|
case 'clear_effects':
|
||||||
setSelectedEffectName(null);
|
setSelectedEffectName(null);
|
||||||
cameraWidgetContext.setSelectedEffects([]);
|
setSelectedEffects([]);
|
||||||
return;
|
return;
|
||||||
case 'download':
|
case 'download':
|
||||||
window.open(getCurrentPicture().src, '_blank');
|
window.open(getCurrentPicture().src, '_blank');
|
||||||
return;
|
return;
|
||||||
case 'zoom':
|
case 'zoom':
|
||||||
cameraWidgetContext.setIsZoomed(!cameraWidgetContext.isZoomed);
|
setIsZoomed(!isZoomed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, [onCloseClick, onCancelClick, onCheckoutClick, cameraWidgetContext, getCurrentPicture, myLevel, selectedEffectName, getEffectIndex, availableEffects]);
|
}, [ onClose, onCancel, onCheckout, getCurrentPicture, myLevel, selectedEffectName, getEffectIndex, availableEffects, isZoomed, setIsZoomed, selectedEffects, setSelectedEffects ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-camera-editor">
|
<NitroCardView className="nitro-camera-editor">
|
||||||
@ -219,7 +217,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
|||||||
<div className="btn-group">
|
<div className="btn-group">
|
||||||
<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('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('download') }><i className="fas fa-save"></i></button>
|
||||||
<button className="btn btn-primary" onClick={ event => processAction('zoom') }><i className={"fas " + classNames({'fa-search-plus': !cameraWidgetContext.isZoomed, 'fa-search-minus': cameraWidgetContext.isZoomed})}></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>
|
||||||
<div className="d-flex justify-content-end">
|
<div className="d-flex justify-content-end">
|
||||||
<button className="btn btn-primary me-2" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>
|
<button className="btn btn-primary me-2" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>
|
||||||
|
@ -4,9 +4,9 @@ export interface CameraWidgetEditorViewProps
|
|||||||
{
|
{
|
||||||
availableEffects: IRoomCameraWidgetEffect[];
|
availableEffects: IRoomCameraWidgetEffect[];
|
||||||
myLevel: number;
|
myLevel: number;
|
||||||
onCloseClick: () => void;
|
onClose: () => void;
|
||||||
onCancelClick: () => void;
|
onCancel: () => void;
|
||||||
onCheckoutClick: () => void;
|
onCheckout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CameraWidgetEditorTabs
|
export class CameraWidgetEditorTabs
|
||||||
|