5180 fichiers 38.5 Mo 0 téléchargements 218 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / components / camera / CameraWidgetView.tsx
CameraWidgetView.tsx 8.1 Ko Télécharger le fichier
import {
    AddLinkEventTracker,
    GetRoomEngine,
    GetSessionDataManager,
    ILinkEventTracker,
    IRoomCameraWidgetSelectedEffect,
    RemoveLinkEventTracker,
    RoomEngineEvent,
    RoomGeometry,
    RoomSessionEvent
} from '@octane/renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { CameraPicture, GetConfigurationValue, LocalizeText } from '../../api';
import { useAchievements, useCamera, useOctaneEvent, useNotification, useRoom } from '../../hooks';
import { getCameraAchievementLevel } from './CameraAirUtilities';
import { CameraWidgetCaptureView } from './views/CameraWidgetCaptureView';
import { CameraWidgetCheckoutView } from './views/CameraWidgetCheckoutView';
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
import { NativeTextTree } from '../../common/native-text/NativeTextTree';

const MODE_NONE: number = 0;
const MODE_CAPTURE: number = 1;
const MODE_EDITOR: number = 2;
const MODE_CHECKOUT: number = 3;
const CAMERA_CANVAS_ID = 1;
const DEFAULT_ROOM_ZOOM = 1;
const ROOM_ZOOM_EPSILON = 0.001;

const getLogicalRoomZoom = (roomId: number): number => {
    const roomEngine = GetRoomEngine();
    const displayScale = roomEngine.getRoomInstanceRenderingCanvasScale(roomId, CAMERA_CANVAS_ID);
    const geometry = roomEngine.getRoomInstanceGeometry(roomId, CAMERA_CANVAS_ID);
    const geometryScale = geometry?.scale ?? RoomGeometry.SCALE_ZOOMED_IN;

    return displayScale * (geometryScale / RoomGeometry.SCALE_ZOOMED_IN);
};

const isDefaultRoomZoom = (roomId: number): boolean => Math.abs(getLogicalRoomZoom(roomId) - DEFAULT_ROOM_ZOOM) <= ROOM_ZOOM_EPSILON;

export const CameraWidgetView: FC<{}> = (props) => {
    const [mode, setMode] = useState<number>(MODE_NONE);
    const [base64Url, setSavedPictureUrl] = useState<string>(null);
    // What the checkout sends when the server renders (camera.render.mode "server"): the photo's scene, effects, zoom.
    const [checkout, setCheckout] = useState<{ picture: CameraPicture; effects: IRoomCameraWidgetSelectedEffect[]; zoom: number }>(null);
    const {
        availableEffects = [],
        selectedPictureIndex = -1,
        setSelectedPictureIndex = null,
        setActivePictureSlotIndex = null,
        cameraRoll = Array(5).fill(null),
        setCameraRoll = null,
        price = { credits: 0, duckets: 0, publishDucketPrice: 0 }
    } = useCamera();
    const { achievementCategories = [] } = useAchievements();
    const { simpleAlert = null } = useNotification();
    const { roomSession = null } = useRoom();

    const myLevel = useMemo(() => getCameraAchievementLevel(achievementCategories), [achievementCategories]);

    const openCamera = useCallback(() => {
        if (!roomSession) return;

        if (!isDefaultRoomZoom(roomSession.roomId)) {
            simpleAlert(LocalizeText('camera.zoom.missing.body'), null, null, null, LocalizeText('camera.zoom.missing.header'));
            return;
        }

        setSelectedPictureIndex(-1);
        setMode(MODE_CAPTURE);
    }, [roomSession, setSelectedPictureIndex, simpleAlert]);

    const processAction = (type: string) => {
        switch (type) {
            case 'close':
                setSelectedPictureIndex(-1);
                setMode(MODE_NONE);
                return;
            case 'edit':
                if (selectedPictureIndex < 0 || !cameraRoll[selectedPictureIndex]) return;

                if (!GetConfigurationValue<boolean>('camera.effects.enabled', true)) {
                    checkoutPictureUrl(cameraRoll[selectedPictureIndex].imageUrl);
                    return;
                }

                setMode(MODE_EDITOR);
                return;
            case 'delete':
                if (selectedPictureIndex < 0) return;

                cameraRoll[selectedPictureIndex]?.texture?.destroy?.(true);
                setCameraRoll((previous) => previous.map((picture, index) => (index === selectedPictureIndex ? null : picture)));
                setActivePictureSlotIndex(selectedPictureIndex);
                // AIR returns to the live viewfinder after deleting the selected
                // roll slot; it never previews whichever photo shifted into it.
                setSelectedPictureIndex(-1);
                return;
            case 'editor_cancel':
                openCamera();
                return;
        }
    };

    const checkoutPictureUrl = (pictureUrl: string, effects: IRoomCameraWidgetSelectedEffect[] = [], zoom: number = 1) => {
        if (GetSessionDataManager().isSafetyLocked) {
            simpleAlert(LocalizeText('notifications.text.safety_locked'), null, null, null, LocalizeText('generic.alert.title'));

            // With effects disabled AIR enters the (headless) lab directly from
            // the viewfinder, then disposes it when the safety check refuses
            // checkout. There is no editor window to return to in that path.
            if (!GetConfigurationValue<boolean>('camera.effects.enabled', true)) {
                setSelectedPictureIndex(-1);
                setMode(MODE_NONE);
            }

            return;
        }

        setSavedPictureUrl(pictureUrl);
        setCheckout({ picture: cameraRoll[selectedPictureIndex] ?? null, effects, zoom });
        setMode(MODE_CHECKOUT);
    };

    useOctaneEvent<RoomSessionEvent>(RoomSessionEvent.ENDED, (event) => {
        setSelectedPictureIndex(-1);
        setMode(MODE_NONE);
    });

    useOctaneEvent<RoomEngineEvent>(RoomEngineEvent.ROOM_ZOOMED, (event) => {
        if (!roomSession || event.roomId !== roomSession.roomId || isDefaultRoomZoom(event.roomId)) return;

        setSelectedPictureIndex(-1);
        setMode(MODE_NONE);
    });

    useEffect(() => {
        const linkTracker: ILinkEventTracker = {
            linkReceived: (url: string) => {
                const parts = url.split('/');

                if (parts.length < 2) return;

                switch (parts[1]) {
                    case 'show':
                        openCamera();
                        return;
                    case 'hide':
                        setSelectedPictureIndex(-1);
                        setMode(MODE_NONE);
                        return;
                    case 'toggle':
                        setSelectedPictureIndex(-1);

                        if (mode === MODE_NONE) openCamera();
                        else setMode(MODE_NONE);
                        return;
                }
            },
            eventUrlPrefix: 'camera/'
        };

        AddLinkEventTracker(linkTracker);

        return () => RemoveLinkEventTracker(linkTracker);
    }, [mode, openCamera, setSelectedPictureIndex]);

    if (mode === MODE_NONE) return null;

    return (
        <NativeTextTree>
            <>
                {mode === MODE_CAPTURE && (
                    <CameraWidgetCaptureView
                        onClose={() => processAction('close')}
                        onDelete={() => processAction('delete')}
                        onEdit={() => processAction('edit')}
                    />
                )}
                {mode === MODE_EDITOR && cameraRoll[selectedPictureIndex] && (
                    <CameraWidgetEditorView
                        availableEffects={availableEffects}
                        myLevel={myLevel}
                        picture={cameraRoll[selectedPictureIndex]}
                        onCancel={() => processAction('editor_cancel')}
                        onCheckout={checkoutPictureUrl}
                        onClose={() => processAction('close')}
                    />
                )}
                {mode === MODE_CHECKOUT && (
                    <CameraWidgetCheckoutView
                        availableEffects={availableEffects}
                        base64Url={base64Url}
                        effects={checkout?.effects}
                        picture={checkout?.picture}
                        zoom={checkout?.zoom}
                        price={price}
                        onCancelClick={() => processAction('editor_cancel')}
                        onCloseClick={() => processAction('editor_cancel')}
                    ></CameraWidgetCheckoutView>
                )}
            </>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser