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%',
},
});