src/views/assessment/freetext/FreeTextView.js
import React from 'react';
import {
Keyboard,
KeyboardAvoidingView,
Platform,
ScrollView,
StyleSheet,
TextInput,
TouchableWithoutFeedback,
} from 'react-native';
import Animated, {ZoomInRight, ZoomOutRight} from 'react-native-reanimated';
import ClearAllButton from '../components/buttons/ClearAllButton';
import ColorSelectorHorizontal from '../components/ColorSelectorHorizontal';
import ConfirmationMenu from '../components/ConfirmationMenu';
import ConfirmationBoxOverlay from '../../../components/dialogBoxes/ConfirmationBoxOverlay';
import FontColorButton from '../components/buttons/FontColorButton';
import Helper from '../../../components/helper/Helper';
import LeftMenu from '../components/LeftMenu';
import PaperColorButton from '../components/buttons/PaperColorButton';
import SaveAlertBoxOverlay from '../../../components/dialogBoxes/SaveAlertBoxOverlay';
import {
getAssessment,
getComment,
setComment,
} from '../../../objects/Assessment';
import {ButtonPosition} from '../../../utils/DimensionsConstants';
import {ColorPalette} from '../../../utils/ColorConstants';
import {globalStyles} from '../../../styles/styles';
import {Module} from '../../../utils/ModuleConstants';
/**
* The view where the user can write free text.
* @param {function} setShowFreeText - If set to false, the user is redirected back to menu
* @returns {Object} The view for freetext
*/
export default function FreeTextView({setShowFreeText}) {
//Get colors for this assessment or null if there are no colors.
const previousTextColor = getAssessment().comment.textColor;
const previousPaperColor = getAssessment().comment.paperColor;
//State for text (Initialized to previous text for this assessment)
const [text, setText] = React.useState(getComment());
//If true => the user change color of paper. If false the user change color of text
const [colorPaper, setColorPaper] = React.useState(false);
//State to determine wheter ColorSelector is active
const [showColors, setShowColors] = React.useState(false);
//State for text color (Initialized to previosTextColor or black if there are no previous)
const [textColor, setTextColor] = React.useState(
previousTextColor == null ? 'black' : previousTextColor,
);
//State for paper color (Initialized to previosPaperColor or ALMOST_WHITE if there are no previous)
const [paperColor, setPaperColor] = React.useState(
previousPaperColor == null
? ColorPalette.ALMOST_WHITE
: previousPaperColor,
);
//Function to toggle ColorSelector
const toggleColorMenu = () => setShowColors(!showColors);
//Function to reset component
const reset = () => {
setText('');
setTextColor('black');
setPaperColor(ColorPalette.ALMOST_WHITE);
};
//Reference to scrollview
const scrollViewRef = React.useRef();
//Logic to ensure the keyboard does not cover where the user is writing
const keyboardShown = Keyboard.addListener('keyboardDidShow', () => {
if (scrollViewRef.current != null)
scrollViewRef.current.scrollToEnd({
animated: true,
});
});
//Setting the visibility of the alert window
const [alertBoxVisible, setAlertBoxVisible] = React.useState(false);
//Toggling the alert window
const toggleAlertBoxVisibility = () => {
setAlertBoxVisible(!alertBoxVisible);
};
//Function to display alert window
const displayAlertBox = () => setAlertBoxVisible(true);
//Setting the visibility of the confirmation window
const [confirmationBoxVisible, setConfirmationBoxVisible] =
React.useState(false);
//Toggling the confirmation window
const toggleConfirmationBoxVisibility = () => {
setConfirmationBoxVisible(!confirmationBoxVisible);
};
//Function to remove the confirmation and go back to menu
const hideConfirmationBox = () => {
setConfirmationBoxVisible(false);
setShowFreeText(false);
};
//The actual component
return (
<Animated.View //Entire component is animated
style={[globalStyles.background, styles.container]}
entering={ZoomInRight} //Zooms in and out from right
exiting={ZoomOutRight}>
<LeftMenu module={Module.FREE_TEXT} />
<KeyboardAvoidingView //To ensure keyboard is not covering text
style={[styles.textContainer, {backgroundColor: paperColor}]}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
<TouchableWithoutFeedback //If user presses outside of keyboard, the keyboard is closed
onPress={() => Keyboard.dismiss()}
style={styles.dummyTouchableWOFeedback}>
<ScrollView //Text is scrollview, so user can write long text and still se what they are writing
style={styles.scrollView}
ref={scrollViewRef} //Binding to the scrollViewRef
onContentSizeChange={() =>
//When text gets larger (needs new line), automatically scrolls to last line.
scrollViewRef.current.scrollToEnd({
animated: true,
})
}>
<TextInput //Where the user writes
value={text} //The text state is value
style={[
styles.textInput,
{
color: textColor, //Color of text is textColor state
fontFamily: 'Noteworthy-Bold',
},
]}
placeholder="Trykk her og skriv!" //If no text
onChangeText={text => {
setText(text); //Always have updated text inside text variable
setShowColors(false);
}}
multiline={true} //Text can be multiple lines
/>
</ScrollView>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
{/* All the different buttons */}
<Animated.View style={styles.writingTools}>
<FontColorButton //Button for changing color of text
position={ButtonPosition.RIGHT}
fillColor={textColor} //Make icon change colors to current textcolor
onPress={() => {
//When pressed, make colorselector update text
Keyboard.dismiss(); //Remove keyboard
if (!colorPaper || !showColors) toggleColorMenu();
//Should update color of text
setColorPaper(false);
}}
/>
<PaperColorButton //Button for changing color of paper
position={ButtonPosition.RIGHT}
fillColor={paperColor} //Make icon change colors to current papercolor
onPress={() => {
Keyboard.dismiss(); //Remove keyboard
//When pressed, make colorselector update paper
if (colorPaper || !showColors) toggleColorMenu();
setColorPaper(true); //Should update color of paper
}}
/>
<ClearAllButton //Button for clearing the paper (reset)
position={ButtonPosition.RIGHT}
onPress={() => {
reset();
}}
/>
</Animated.View>
{showColors && (
<ColorSelectorHorizontal //The colorselector.
//Needs to know what to color
showsPaperColorMenu={colorPaper}
showsBrushColorMenu={!colorPaper}
//And function to update the colors
updateBrushColor={setTextColor}
updatePaperColor={setPaperColor}
/>
)}
<ConfirmationMenu //Button to save text
onPressClose={displayAlertBox} //Includes logic for going back to menu
onPressOk={() => {
setComment(text, textColor, paperColor); //Save
keyboardShown.remove(); //Cleanup
setConfirmationBoxVisible(true); //Notify user that text is saved
}}
/>
<SaveAlertBoxOverlay //If user only exits, they still can save
modalVisible={alertBoxVisible}
onModalRequestCloseAction={toggleAlertBoxVisibility}
onPressCancelButtonAction={toggleAlertBoxVisibility}
onPressSaveButtonAction={() => {
//User wants to save
setComment(text, textColor, paperColor); //Save
keyboardShown.remove(); //Cleanup
setShowFreeText(false); //Goes back to menu
setConfirmationBoxVisible(true); //Notify user
}}
onPressDeleteButtonAction={() => {
//User dont want to save
reset(); //Reset
setShowFreeText(false); //Goes back to main menu
}}
message={'Vil du lagre teksten din ?'} //The displaytext
/>
<ConfirmationBoxOverlay //Notify the user that text is saved
modalVisible={confirmationBoxVisible}
onModalRequestCloseAction={toggleConfirmationBoxVisibility}
onPressOkButtonAction={hideConfirmationBox}
message={'Din tekst er lagret !'} //Display text
/>
{/* The helper for freetext (id === 3) */}
<Helper id={3} />
</Animated.View>
);
}
/**
* Local styles
* @type {Object}
*/
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
},
textContainer: {
flex: 4.5,
marginTop: '5%',
height: '80%',
},
dummyTouchableWOFeedback: {
backgroundColor: 'yellow',
width: '100%',
height: '100%',
flex: 1,
},
scrollView: {
flex: 1,
padding: 20,
},
textInput: {
height: '100%',
marginHorizontal: '5%',
marginVertical: '5%',
fontSize: 25,
textAlign: 'left',
},
writingTools: {
flex: 0.8,
flexDirection: 'column',
height: '75%',
right: 0,
alignItems: 'center',
marginTop: '10%',
},
buttonContainer: {
position: 'absolute',
alignItems: 'flex-end',
bottom: 0,
right: 0,
},
button: {
margin: 15,
},
});