Home Reference Source

src/views/assessment/drawing/DrawingView.js

import React, {useRef, useState} from 'react';
import {View, StyleSheet} from 'react-native';
import Animated, {SlideInRight} from 'react-native-reanimated';
import {SketchCanvas} from '@terrylinla/react-native-sketch-canvas';

import ColorSelectorHorizontal from '../components/ColorSelectorHorizontal';
import ConfirmationMenu from '../components/ConfirmationMenu';
import ConfirmationBoxOverlay from '../../../components/dialogBoxes/ConfirmationBoxOverlay';
import DrawButton from '../components/buttons/DrawButton';
import EraserButton from '../components/buttons/EraserButton';
import Helper from '../../../components/helper/Helper';
import LeftMenu from '../components/LeftMenu';
import SaveAlertBoxOverlay from '../../../components/dialogBoxes/SaveAlertBoxOverlay';
import StrokeWidthSlider from './components/StrokeWidthSlider';

import {getActivityType, setDrawing} from '../../../objects/Assessment';
import {getFilename} from '../../../database/ActivityTypesDAO';

import {ButtonPosition} from '../../../utils/DimensionsConstants';
import {ColorPalette} from '../../../utils/ColorConstants';
import {globalStyles} from '../../../styles/styles';
import {Module} from '../../../utils/ModuleConstants';

/**
 * Minimum stroke width
 * @type {number}
 */
const MINIMUM_STROKE_WIDTH = 3;

/**
 * Maximum stroke widht
 * @type {number}
 */
const MAXIMUM_STROKE_WIDTH = 50;

/**
 * Starting paper color
 * @type {number}
 */
const STARTING_PAPER_COLOR = ColorPalette.ALMOST_WHITE;

/**
 * Starting brush color
 * @type {number}
 */
const STARTING_BRUSH_COLOR = ColorPalette.BLACK;

/**
 * Startin stroke width
 * @type {number}
 */
const STARTING_STROKE_WIDTH = 8;

/**
 * The view where the user can draw.
 * @param {boolean} setShowDrawingView - If set to false, user is redirected back to menu
 * @returns {Object} The view for drawing
 */
export default function DrawingView({setShowDrawingView}) {
    // Background color of canvas
    const paperColor = STARTING_PAPER_COLOR;

    // Color of the brush
    const [brushColor, setBrushColor] = useState(STARTING_BRUSH_COLOR);

    // Current color used to paint
    const [currentStrokeColor, setCurrentStrokeColor] = useState(brushColor);

    // Width of the brush stroke
    const [strokeWidth, setStrokeWidth] = useState(STARTING_STROKE_WIDTH);

    // Whether or not the canvas is set to background image
    const [hasBackgroundImage, setHasBackgroundImage] = useState(false);

    // Whether or not the color menu is displayed
    const showsBrushColorMenu = true;

    // Save alert box overlay:
    const [alertBoxVisible, setAlertBoxVisible] = React.useState(false);
    const toggleAlertBoxVisibility = () => {
        setAlertBoxVisible(!alertBoxVisible);
    };
    const displayAlertBox = () => setAlertBoxVisible(true);

    // Confirmation box overlay:
    const [confirmationBoxVisible, setConfirmationBoxVisible] =
        React.useState(false);
    const toggleConfirmationBoxVisibility = () => {
        setConfirmationBoxVisible(!confirmationBoxVisible);
    };
    const hideConfirmationBox = () => {
        setConfirmationBoxVisible(false);
        setShowDrawingView(false);
    };

    // Settings for saving/deleting the drawing
    const foldername = 'AktivitetsmodulRN';
    const filename = String(Math.ceil(Math.random() * 100000000));
    const saveDrawingAction = () => {
        setAlertBoxVisible(false);
        setConfirmationBoxVisible(true);

        try {
            canvasRef.current.save(
                'png', // imageType
                false, // transparent
                foldername, // folder
                // 'AktivitetsmodulRN'
                filename,
                // String(Math.ceil(Math.random() * 100000000)), // filename
                true, // includeImage
                false, // includeText
                true, // cropToImageSize
            );

            const path = foldername + '/' + filename;
            setDrawing(path);
            console.log('Drawing saved as ', path);
        } catch (error) {
            console.log('Save drawing with error ', error);
        }
    };

    // Deleting the drawing
    const deleteDrawingAction = () => {
        toggleAlertBoxVisibility;
        setDrawing(null);
        setShowDrawingView(false);
    };

    // Reference to the canvas itself
    const canvasRef = useRef(null);

    // Settings for using the activity picture as drawing background.
    const ACTIVITY_IMAGE_FILENAME = getFilename(getActivityType());
    const toggleBackgroundImage = () =>
        setHasBackgroundImage(!hasBackgroundImage);

    // Initialization
    const updateStrokeWidth = width => setStrokeWidth(width);
    // const updatePaperColor = color => setPaperColor(color);
    const updateBrushColor = color => {
        setBrushColor(color);
        setCurrentStrokeColor(color);
    };

    const paint = () => {
        setCurrentStrokeColor(brushColor);
    };
    const erase = () => {
        setCurrentStrokeColor(ColorPalette.ERASER);
    };

    return (
        <View style={[globalStyles.background, styles.container]}>
            {/* Left side menu containing activity image, avatar, clear and undo buttons */}
            <LeftMenu
                module={Module.DRAWING}
                toggleBackgroundImage={toggleBackgroundImage}
                canvasRef={canvasRef}
            />
            {/* The canvas for drawing */}
            <SketchCanvas
                ref={canvasRef}
                style={[
                    styles.canvas,
                    {
                        overflow: 'hidden',
                        backgroundColor: hasBackgroundImage
                            ? 'transparent'
                            : paperColor,
                    },
                ]}
                strokeColor={currentStrokeColor}
                strokeWidth={strokeWidth}
                localSourceImage={{
                    filename: hasBackgroundImage ? ACTIVITY_IMAGE_FILENAME : '',
                    directory: SketchCanvas.MAIN_BUNDLE,
                    mode: 'ScaleToFill',
                }}
            />
            {/* The right side menu with all drawing tools */}
            <Animated.View
                style={styles.illustrationTools}
                entering={SlideInRight} // No exiting effect
            >
                <DrawButton
                    position={ButtonPosition.RIGHT}
                    fillColor={brushColor}
                    onPress={paint}
                />
                <EraserButton position={ButtonPosition.RIGHT} onPress={erase} />
                <StrokeWidthSlider
                    componentStyle={styles.slider}
                    brushColor={brushColor}
                    strokeWidth={strokeWidth}
                    minimumStrokeWidth={MINIMUM_STROKE_WIDTH}
                    maximumStrokeWidth={MAXIMUM_STROKE_WIDTH}
                    updateStrokeWidth={updateStrokeWidth}
                />
            </Animated.View>
            {/* Menu for selecting colors */}
            <ColorSelectorHorizontal
                showsBrushColorMenu={showsBrushColorMenu}
                updateBrushColor={updateBrushColor}
            />
            {/* Closing and saving buttons */}
            <ConfirmationMenu
                onPressClose={displayAlertBox}
                onPressOk={saveDrawingAction}
            />
            {/* Save alert */}
            <SaveAlertBoxOverlay
                modalVisible={alertBoxVisible}
                onModalRequestCloseAction={toggleAlertBoxVisibility}
                onPressCancelButtonAction={toggleAlertBoxVisibility}
                onPressSaveButtonAction={saveDrawingAction}
                onPressDeleteButtonAction={deleteDrawingAction}
                message={'Vil du lagre tegningen din ?'}
            />
            {/* Save confirmation */}
            <ConfirmationBoxOverlay
                modalVisible={confirmationBoxVisible}
                onModalRequestCloseAction={toggleConfirmationBoxVisibility}
                onPressOkButtonAction={hideConfirmationBox}
                message={'Din tegning er lagret !'}
            />
            <Helper id={4} />
        </View>
    );
}

/**
 * Local styles
 * @type {Object}
 */
const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'row',
        width: '100%',
        height: '100%',
    },
    canvas: {
        flex: 4.2,
        marginTop: '5%',
        aspectRatio: 4 / 3,
    },
    utils: {
        flexDirection: 'row',
        backgroundColor: 'gray',
    },
    illustrationTools: {
        flex: 0.7,
        flexDirection: 'column',
        marginTop: '3%',
        alignItems: 'flex-end',
        justifyContent: 'flex-start',
        alignContent: 'flex-start',
    },
    slider: {
        height: '35%',
    },
});