Camera updates

This commit is contained in:
Bill 2021-08-05 02:26:43 -04:00
parent 351a446483
commit 28539e6923
17 changed files with 214 additions and 214 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

View File

@ -476,13 +476,13 @@
&.icon-camera-colormatrix {
background: url('../images/icons/camera-colormatrix.png');
width: 32px;
height: 14px;
height: 21px;
}
&.icon-camera-composite {
background: url('../images/icons/camera-composite.png');
width: 32px;
height: 14px;
height: 21px;
}
&.icon-user-profile {

View File

@ -1,30 +1,41 @@
.nitro-camera-capture {
.nitro-close {
top: 7px;
right: 9px;
position: relative;
.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 {
position: relative;
width: 340px;
height: 462px;
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
.camera-frame {
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);
}
}
background-position: -1px -1px;
z-index: 2;
.camera-button {
width: 94px;
@ -33,14 +44,26 @@
margin-top: 362px;
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
background-position: -340px 0px;
background-position: -343px -321px;
&:hover {
background-position: -340px -94px;
background-position: -535px -321px;
}
&: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);
}
}
}

View File

@ -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 { 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 { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent';
import { useCameraEvent } from '../../../../hooks/events/nitro/camera/camera-event';
import { useUiEvent } from '../../../../hooks/events/ui/ui-event';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages/message-event';
import { CameraPicture } from './common/CameraPicture';
import { CameraWidgetContextProvider } from './context/CameraWidgetContext';
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
import { CameraWidgetCheckoutView } from './views/checkout/CameraWidgetCheckoutView';
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 =>
{
const [ effectsReady, setEffectsReady ] = useState(false);
const [ isCaptureVisible, setIsCaptureVisible ] = useState(false);
const [ isEditorVisible, setIsEditorVisible ] = useState(false);
const [ isCheckoutVisible, setIsCheckoutVisible ] = useState(false);
const [ myLevel, setMyLevel ] = useState(10);
const [ cameraRoll, setCameraRoll ] = useState<HTMLImageElement[]>([]);
const [ mode, setMode ] = useState<number>(MODE_NONE);
const [ availableEffects, setAvailableEffects ] = useState<IRoomCameraWidgetEffect[]>([]);
const [ cameraRoll, setCameraRoll ] = useState<CameraPicture[]>([]);
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
const [ selectedEffects, setSelectedEffects ] = useState<IRoomCameraWidgetSelectedEffect[]>([]);
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) =>
{
switch(event.type)
{
case RoomWidgetCameraEvent.SHOW_CAMERA:
setIsCaptureVisible(true);
setMode(MODE_CAPTURE);
return;
case RoomWidgetCameraEvent.HIDE_CAMERA:
setIsCaptureVisible(false);
setIsEditorVisible(false);
setIsCheckoutVisible(false);
setMode(MODE_NONE);
return;
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
setIsCaptureVisible(value => !value);
setIsEditorVisible(false);
setIsCheckoutVisible(false);
setMode(prevValue =>
{
if(!prevValue) return MODE_CAPTURE;
else return MODE_NONE;
});
return;
}
}, []);
@ -51,78 +53,68 @@ export const CameraWidgetView: FC<{}> = props =>
useUiEvent(RoomWidgetCameraEvent.HIDE_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) =>
{
setEffectsReady(true);
setAvailableEffects(Array.from(GetRoomCameraWidgetManager().effects.values()))
}, []);
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(() =>
{
if(!GetRoomCameraWidgetManager().isLoaded)
{
GetRoomCameraWidgetManager().init();
SendMessageHook(new RequestCameraConfigurationComposer());
return;
}
setEffectsReady(true);
}, []);
const processAction = useCallback((type: string, value: any = null) =>
const processAction = useCallback((type: string) =>
{
switch(type)
{
case 'close':
setIsCaptureVisible(false);
setIsEditorVisible(false);
setIsCheckoutVisible(false);
setMode(MODE_NONE);
return;
case 'capture_edit':
setIsCaptureVisible(false);
setIsEditorVisible(true);
case 'edit':
setMode(MODE_EDITOR);
return;
case 'delete':
setCameraRoll(prevValue =>
{
const clone = [ ...prevValue ];
clone.splice(selectedPictureIndex, 1);
return clone;
});
return;
case 'editor_cancel':
setIsCaptureVisible(true);
setIsEditorVisible(false);
setIsCheckoutVisible(false);
setMode(MODE_CAPTURE);
return;
case 'editor_checkout':
setIsEditorVisible(false);
setIsCheckoutVisible(true);
case 'checkout':
setMode(MODE_CHECKOUT);
return;
}
}, []);
}, [ selectedPictureIndex ]);
return (
<CameraWidgetContextProvider value={ { cameraRoll, setCameraRoll, selectedPictureIndex, setSelectedPictureIndex, selectedEffects, setSelectedEffects, isZoomed, setIsZoomed } }>
{ isCaptureVisible && <CameraWidgetCaptureView onCloseClick={ () => processAction('close') } onEditClick={ () => processAction('capture_edit') } /> }
{ isEditorVisible && <CameraWidgetEditorView myLevel={ myLevel } onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } onCheckoutClick={ () => processAction('editor_checkout') } availableEffects={ availableEffects } /> }
{ isCheckoutVisible && <CameraWidgetCheckoutView onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } price={ price }></CameraWidgetCheckoutView> }
{ (mode === MODE_CAPTURE) && <CameraWidgetCaptureView onClose={ () => processAction('close') } onEdit={ () => processAction('edit') } onDelete={ () => processAction('delete') } /> }
{ (mode === MODE_EDITOR) && <CameraWidgetEditorView myLevel={ myLevel } onClose={ () => processAction('close') } onCancel={ () => processAction('editor_cancel') } onCheckout={ () => processAction('checkout') } availableEffects={ availableEffects } /> }
{ (mode === MODE_CHECKOUT) && <CameraWidgetCheckoutView onCloseClick={ () => processAction('close') } onCancelClick={ () => processAction('editor_cancel') } price={ price }></CameraWidgetCheckoutView> }
</CameraWidgetContextProvider>
);
}

View File

@ -0,0 +1,8 @@
import { NitroTexture } from 'nitro-renderer';
export class CameraPicture
{
constructor(
public texture: NitroTexture,
public imageUrl: string) {}
}

View File

@ -1,10 +1,11 @@
import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect';
import { ProviderProps } from 'react';
import { CameraPicture } from '../common/CameraPicture';
export interface ICameraWidgetContext
{
cameraRoll: HTMLImageElement[],
setCameraRoll: (cameraRoll: HTMLImageElement[]) => void,
cameraRoll: CameraPicture[],
setCameraRoll: (cameraRoll: CameraPicture[]) => void,
selectedPictureIndex: number,
setSelectedPictureIndex: (index: number) => void,
selectedEffects: IRoomCameraWidgetSelectedEffect[],

View File

@ -1,103 +1,81 @@
import classNames from 'classnames';
import { NitroRectangle } from 'nitro-renderer';
import { NitroRectangle, TextureUtils } from 'nitro-renderer';
import { FC, useCallback, useRef } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../../../../../api';
import { DraggableWindow } from '../../../../../../layout/draggable-window/DraggableWindow';
import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { CameraPicture } from '../../common/CameraPicture';
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types';
const CAMERA_ROLL_LIMIT: number = 5;
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 cameraFrameRef = useRef<HTMLDivElement>();
const selectedPicture = ((selectedPictureIndex > -1) ? cameraRoll[selectedPictureIndex] : null);
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(() =>
{
if(cameraWidgetContext.selectedPictureIndex > -1)
if(selectedPictureIndex > -1)
{
cameraWidgetContext.setSelectedPictureIndex(-1);
setSelectedPictureIndex(-1);
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));
const texture = GetRoomEngine().createTextureFromRoom(GetRoomSession().roomId, 1, rectangle);
if(cameraWidgetContext.cameraRoll.length + 1 === CAMERA_ROLL_LIMIT)
if(clone.length >= CAMERA_ROLL_LIMIT)
{
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)
{
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 ]);
setCameraRoll(clone);
}, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex ]);
return (
<DraggableWindow handle=".nitro-camera-capture">
<div className="nitro-camera-capture d-flex flex-column justify-content-center align-items-center">
<div className="camera-canvas">
<div className="position-absolute header-close" onClick={ event => processAction('close') }>
<DraggableWindow>
<div className="d-flex flex-column justify-content-center align-items-center nitro-camera-capture">
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
<div className="camera-canvas drag-handler">
<div className="position-absolute header-close" onClick={ onClose }>
<i className="fas fa-times" />
</div>
<div ref={ cameraFrameRef } className={'camera-frame ' + classNames({'bg': cameraWidgetContext.selectedPictureIndex > -1}) }>
{ cameraWidgetContext.selectedPictureIndex > -1 && <div>
<img alt="" src={ cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex].src } />
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
{ selectedPicture &&
<div className="camera-area camera-frame">
<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-danger" onClick={ event => processAction('discard_picture') }>{ LocalizeText('camera.delete.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={ onDelete }>{ LocalizeText('camera.delete.button.text') }</button>
</div>
</div> }
</div>
<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>
{ cameraWidgetContext.cameraRoll.length > 0 && <div className="camera-roll d-flex justify-content-center py-2">
{ cameraWidgetContext.cameraRoll.map((picture, index) =>
{ (cameraRoll.length > 0) &&
<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>

View File

@ -1,5 +1,6 @@
export interface CameraWidgetCaptureViewProps
{
onCloseClick: () => void;
onEditClick: () => void;
onClose: () => void;
onEdit: () => void;
onDelete: () => void;
}

View File

@ -1,5 +1,5 @@
/* 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 { GetRoomCameraWidgetManager } from '../../../../../../api/nitro/camera/GetRoomCameraWidgetManager';
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages/message-event';
@ -12,36 +12,35 @@ import { CameraWidgetCheckoutViewProps } from './CameraWidgetCheckoutView.types'
export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props =>
{
const { onCloseClick = null, onCancelClick = null, price = null } = props;
const cameraWidgetContext = useCameraWidgetContext();
const [ picturesBought, setPicturesBought ] = useState(0);
const [ wasPicturePublished, setWasPicturePublished ] = useState(false);
const [ isWaiting, setIsWaiting ] = useState(false);
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);
setIsWaiting(false);
}, []);
const onRoomWidgetCameraPublishedEvent = useCallback((event: RoomWidgetCameraPublishedEvent) =>
CreateMessageHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
const onCameraPublishStatusMessageEvent = useCallback((event: CameraPublishStatusMessageEvent) =>
{
const parser = event.getParser();
setPublishCooldown(parser.cooldownSeconds);
setWasPicturePublished(parser.wasSuccessful);
setPublishCooldown(parser.secondsToWait);
setWasPicturePublished(parser.ok);
setIsWaiting(false);
}, []);
CreateMessageHook(RoomWidgetCameraPurchaseSuccessfulEvent, onCameraPurchaseSuccessfulEvent);
CreateMessageHook(RoomWidgetCameraPublishedEvent, onRoomWidgetCameraPublishedEvent);
CreateMessageHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);
const getCurrentPicture = useCallback(() =>
{
return GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], cameraWidgetContext.selectedEffects, cameraWidgetContext.isZoomed);
}, [ cameraWidgetContext ]);
return GetRoomCameraWidgetManager().applyEffects(cameraRoll[selectedPictureIndex].texture, selectedEffects, isZoomed);
}, [ cameraRoll, selectedPictureIndex, selectedEffects, isZoomed ]);
const processAction = useCallback((type: string, value: string | number = null) =>
{
@ -54,13 +53,13 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
if(isWaiting) return;
setIsWaiting(true);
SendMessageHook(new RoomWidgetCameraPurchaseComposer());
SendMessageHook(new PurchasePhotoMessageComposer('1_1627697499'));
return;
case 'publish':
if(isWaiting) return;
setIsWaiting(true);
SendMessageHook(new RoomWidgetCameraPublishComposer());
SendMessageHook(new PublishPhotoMessageComposer());
return;
case 'cancel':
onCancelClick();
@ -88,7 +87,7 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
<div className="bg-muted rounded p-2 text-black mb-2">
<div className="d-flex justify-content-between align-items-center">
<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>
{ wasPicturePublished && <a href="#">{ LocalizeText('camera.link.to.published') }</a> }
</div>

View File

@ -2,5 +2,5 @@ export interface CameraWidgetCheckoutViewProps
{
onCloseClick: () => void;
onCancelClick: () => void;
price: {credits: Number, points: Number, pointsType: number};
price: { credits: number, duckets: number, publishDucketPrice: number };
}

View File

@ -7,17 +7,15 @@ import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { useCameraWidgetContext } from '../../context/CameraWidgetContext';
import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types';
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
{
const { availableEffects = null, myLevel = null, onCloseClick = null, onCancelClick = null, onCheckoutClick = null } = props;
const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ];
const cameraWidgetContext = useCameraWidgetContext();
const [ currentTab, setCurrentTab ] = useState(CameraWidgetEditorTabs.COLORMATRIX);
export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
{
const { availableEffects = null, myLevel = 1, onClose = null, onCancel = null, onCheckout = null } = props;
const [ currentTab, setCurrentTab ] = useState(TABS[0]);
const [ selectedEffectName, setSelectedEffectName ] = useState(null);
const [ effectsThumbnails, setEffectsThumbnails ] = useState<{ name: string, image: HTMLImageElement }[]>([]);
const { cameraRoll = null, selectedPictureIndex = -1, selectedEffects = null, isZoomed = false, setSelectedEffects = null, setIsZoomed = null } = useCameraWidgetContext();
useEffect(() =>
{
@ -25,11 +23,11 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
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);
}, [ cameraWidgetContext, availableEffects ]);
}, [ cameraRoll, selectedPictureIndex, availableEffects ]);
const getEffectThumbnail = useCallback((effectName: string) =>
{
@ -54,24 +52,24 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
const getCurrentPicture = useCallback(() =>
{
return GetRoomCameraWidgetManager().applyEffects(cameraWidgetContext.cameraRoll[cameraWidgetContext.selectedPictureIndex], cameraWidgetContext.selectedEffects, cameraWidgetContext.isZoomed);
}, [ cameraWidgetContext ]);
return GetRoomCameraWidgetManager().applyEffects(cameraRoll[selectedPictureIndex].texture, selectedEffects, isZoomed);
}, [ cameraRoll, selectedPictureIndex, selectedEffects, isZoomed ]);
const getCurrentEffectAlpha = useCallback(() =>
{
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;
return selectedEffect.alpha;
}, [ selectedEffectName, cameraWidgetContext.selectedEffects ]);
}, [ selectedEffectName, selectedEffects ]);
const getEffectIndex = useCallback((effectName) =>
{
return cameraWidgetContext.selectedEffects.findIndex(effect => effect.effect.name === effectName);
}, [ cameraWidgetContext.selectedEffects ])
return selectedEffects.findIndex(effect => effect.effect.name === effectName);
}, [ selectedEffects ])
const setSelectedEffectAlpha = useCallback((newAlpha: number) =>
{
@ -81,27 +79,27 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
if(selectedEffectIndex === -1) return;
const clone = Array.from(cameraWidgetContext.selectedEffects);
const clone = Array.from(selectedEffects);
const selectedEffect = clone[selectedEffectIndex];
clone[selectedEffectIndex] = new RoomCameraWidgetSelectedEffect(selectedEffect.effect, newAlpha);
cameraWidgetContext.setSelectedEffects(clone);
}, [ selectedEffectName, getEffectIndex, cameraWidgetContext ]);
setSelectedEffects(clone);
}, [ selectedEffectName, getEffectIndex, selectedEffects, setSelectedEffects ]);
const processAction = useCallback((type: string, value: string | number = null) =>
{
switch(type)
{
case 'close':
onCloseClick();
onClose();
return;
case 'cancel':
onCancelClick();
onCancel();
return;
case 'checkout':
onCheckoutClick();
onCheckout();
return;
case 'change_tab':
setCurrentTab(String(value));
@ -110,7 +108,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
{
let existingIndex = -1;
if(cameraWidgetContext.selectedEffects.length > 0)
if(selectedEffects.length > 0)
{
existingIndex = getEffectIndex(value);
}
@ -123,7 +121,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
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;
@ -144,32 +142,32 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
if(existingIndex > -1)
{
const effect = cameraWidgetContext.selectedEffects[existingIndex];
const effect = selectedEffects[existingIndex];
if(effect.effect.name === selectedEffectName)
{
setSelectedEffectName(null);
}
const clone = Array.from(cameraWidgetContext.selectedEffects);
const clone = Array.from(selectedEffects);
clone.splice(existingIndex, 1);
cameraWidgetContext.setSelectedEffects(clone);
setSelectedEffects(clone);
}
}
return;
case 'clear_effects':
setSelectedEffectName(null);
cameraWidgetContext.setSelectedEffects([]);
setSelectedEffects([]);
return;
case 'download':
window.open(getCurrentPicture().src, '_blank');
return;
case 'zoom':
cameraWidgetContext.setIsZoomed(!cameraWidgetContext.isZoomed);
setIsZoomed(!isZoomed);
return;
}
}, [onCloseClick, onCancelClick, onCheckoutClick, cameraWidgetContext, getCurrentPicture, myLevel, selectedEffectName, getEffectIndex, availableEffects]);
}, [ onClose, onCancel, onCheckout, getCurrentPicture, myLevel, selectedEffectName, getEffectIndex, availableEffects, isZoomed, setIsZoomed, selectedEffects, setSelectedEffects ]);
return (
<NitroCardView className="nitro-camera-editor">
@ -219,7 +217,7 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
<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('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 className="d-flex justify-content-end">
<button className="btn btn-primary me-2" onClick={ event => processAction('cancel') }>{ LocalizeText('generic.cancel') }</button>

View File

@ -4,9 +4,9 @@ export interface CameraWidgetEditorViewProps
{
availableEffects: IRoomCameraWidgetEffect[];
myLevel: number;
onCloseClick: () => void;
onCancelClick: () => void;
onCheckoutClick: () => void;
onClose: () => void;
onCancel: () => void;
onCheckout: () => void;
}
export class CameraWidgetEditorTabs