Commit 7b592ee5 authored by haukao's avatar haukao
Browse files

Added the ability to restore templates already used in the session :)

Issue #12
parent 51b9fbd8
/**
* Enum for keeping track of the colors
*/
export enum Color {
RANDOM = -1,
RED = 0,
GREEN = 1,
BLUE = 2,
}
import { Color } from "./Enums";
/**
* All the animation-functions will have a specification of color (or default = Color.RANDOM) and a boolean clear (or default = false)
*/
......@@ -35,8 +26,14 @@ const randomRGB = (specification: Color = Color.RANDOM): string => {
const greenMult: number = specification === Color.GREEN ? 255 : 50;
const blueMult: number = specification === Color.BLUE ? 255 : 50;
const red: string = toPaddedHexString(Math.floor(Math.random() * redMult), 2);
const green: string = toPaddedHexString(Math.floor(Math.random() * greenMult), 2);
const blue: string = toPaddedHexString(Math.floor(Math.random() * blueMult), 2);
const green: string = toPaddedHexString(
Math.floor(Math.random() * greenMult),
2
);
const blue: string = toPaddedHexString(
Math.floor(Math.random() * blueMult),
2
);
return red + green + blue;
};
......
......@@ -3,9 +3,12 @@ import Exhibition from "./components/Exhibition";
import { fetchPoetryFromPoetryDB } from "./PoetryAPI";
import Header from "./components/Header";
import LocalStorageManager from "./LocalStorageManager";
import { animate, Color } from "./Animations";
import { animate } from "./Animations";
import { Color, Theme, Font } from "./Enums";
import "./App.css";
import SessionStorageManager from "./SessionStorageManager";
const ssm: SessionStorageManager = new SessionStorageManager();
/**
* Main function loaded into the page from index.tsx
*/
......@@ -26,23 +29,46 @@ const App: React.FC = () => {
* loading: boolean
* favourites: number[]
* theme: number
* font: Font = {
* ESTABAN = "Estaban",
* LOBSTER = "Lobster",
* }
* color: Color = {
* RANDOM = -1,
* RED = 0,
* GREEN = 1,
* BLUE = 2,
* }
* userEdit: boolean
* errorDisplay: boolean
* sessionStack: SessionConfig = {
* color: Color,
* font: Font,
* theme: Theme
* }
*/
const [installationList, setInstallationList] = useState<InstallationList>();
const [installation, setInstallation] = useState<Installation>();
const [currentIndex, setCurrentIndex] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false);
const [favourites, setFavourites] = useState<number[]>([]);
const [theme, setTheme] = useState<number>(0);
const [theme, setTheme] = useState<Theme>(Theme.DARK);
const [font, setFont] = useState<Font>(Font.ESTEBAN);
const [color, setColor] = useState<Color>(Color.RANDOM);
const [userEdit, setUserEdit] = useState<boolean>(true);
const [errorDisplay, setErrorDisplay] = useState<boolean>(false);
const [sessionStack, setSessionStack] = useState<SessionConfig[]>([]);
const lsm: LocalStorageManager = new LocalStorageManager();
/**
* Calls the loadPoetry method one time when the page is loaded.
*/
useEffect(() => {
loadPoetry();
fetchFromLocalStorage();
if (userEdit) {
loadPoetry();
fetchFromLocalStorage();
fetchFromSessionStorage();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
......@@ -50,20 +76,27 @@ const App: React.FC = () => {
* Will load the user state with the config saved in localstorage. If nothing is stored in the localstorage, it will use
* the default config constant located inside the LocalStorageManager.
*/
const fetchFromLocalStorage = () => {
const fetchFromLocalStorage = (): void => {
const config: UserConfig = lsm.getUserConfig();
setFavourites(config.favourites);
setTheme(config.theme);
console.log(
`Loading user with favourites: ${config.favourites} and theme: ${config.theme}`
);
};
const fetchFromSessionStorage = (): void => {
const stack: SessionConfig[] = ssm.parse();
if (!stack || stack.length < sessionStack.length) {
return;
}
setSessionStack(stack);
};
/**
* Loads the installationList and installation states with the information fetched from PoetryDB's API.
*/
const loadPoetry = async () => {
const loadPoetry = async (): Promise<void> => {
setLoading(true);
const fetchedPoetryList:
| Installation[]
......@@ -84,13 +117,19 @@ const App: React.FC = () => {
* @param specification - the color specification
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
const drawAnimation = (specification: Color = Color.RANDOM) => {
const drawAnimation = (
specification: Color = Color.RANDOM,
force: boolean = false
) => {
let index: number = currentIndex;
if (index > 1) {
index = 1;
}
if (userEdit || specification !== Color.RANDOM) {
if (userEdit || force) {
animate(index, specification);
setColor(specification);
console.log("Color: " + specification);
updateHistory(theme, specification, font);
}
setUserEdit(false);
};
......@@ -118,7 +157,7 @@ const App: React.FC = () => {
* Sets the installation and currentIndex state for the next poetry based on the boolean provided.
* @param {boolean} forward - whether or not to go to forward in the list
*/
const changePoetry = (forward: boolean) => {
const changePoetry = (forward: boolean): void => {
if (installationList === undefined) return;
setUserEdit(true);
const index: number = forwardOrBackward(currentIndex, forward);
......@@ -130,7 +169,7 @@ const App: React.FC = () => {
* Will either remove or add the installation at the given index to the favourites.
* @param index - index of the installation
*/
const toggleFavourite = (index: number) => {
const toggleFavourite = (index: number): void => {
if (isFavourite(index)) {
removeFavorite(index);
} else {
......@@ -142,7 +181,7 @@ const App: React.FC = () => {
* Returns true if the given index is in the favourites array, else false
* @param index - index of the installation
*/
const isFavourite = (index: number) => {
const isFavourite = (index: number): boolean => {
return favourites.includes(index);
};
......@@ -150,8 +189,8 @@ const App: React.FC = () => {
* Adds the given index to the favourites array
* @param index - index of the installation
*/
const addFavourite = (index: number) => {
const newFavs = [...favourites, index];
const addFavourite = (index: number): void => {
const newFavs: number[] = [...favourites, index];
setFavourites(newFavs);
lsm.change("favourites", newFavs);
};
......@@ -160,8 +199,8 @@ const App: React.FC = () => {
* Rempves the given index to the favourites array
* @param index - index of the installation
*/
const removeFavorite = (index: number) => {
const newFavs = favourites.filter((i) => i !== index);
const removeFavorite = (index: number): void => {
const newFavs: number[] = favourites.filter((i) => i !== index);
setFavourites(newFavs);
lsm.change("favourites", newFavs);
};
......@@ -169,15 +208,62 @@ const App: React.FC = () => {
/**
* Will change between the themes available for the web-page
*/
const changeTheme = () => {
const newTheme = theme === 0 ? 1 : 0;
const changeTheme = (newTheme: Theme, save: boolean = true): void => {
setTheme(newTheme);
lsm.change("theme", newTheme);
if (save) {
lsm.change("theme", newTheme);
console.log("Theme " + Number(newTheme + 1));
updateHistory(newTheme, color, font);
}
};
/**
* Adds a new template to the sessionStack based on the current state
* @param newTheme
* @param newColor
* @param newFont
*/
const updateHistory = (
newTheme: Theme,
newColor: Color,
newFont: Font
): void => {
const config: SessionConfig = {
theme: newTheme,
color: newColor,
font: newFont,
};
ssm.add(config);
fetchFromSessionStorage();
};
/**
* Loads the selected template from the template stack
* @param index
*/
const loadSession = (index: number): void => {
const config: SessionConfig = sessionStack[index];
animate(currentIndex, config.color);
changeTheme(config.theme, false);
};
return (
<>
<Header />
<select
id="sessiondropdown"
onChange={(e) => {
loadSession(e.target.selectedIndex);
}}
>
{sessionStack !== undefined
? sessionStack.map((e: SessionConfig) => (
<option key={sessionStack.indexOf(e)}>
{"Template: " + Number(sessionStack.indexOf(e) + 1)}
</option>
))
: null}
</select>
<div id="wrapperdiv">
{loading && (
<div>
......@@ -212,10 +298,12 @@ const App: React.FC = () => {
<button
id="themebutton"
onClick={() => {
changeTheme();
changeTheme(
theme === Theme.DARK ? Theme.LIGHT : Theme.DARK
);
}}
>
{theme === 0 ? "Theme 2" : "Theme 1"}
{theme === 0 ? "Theme 1" : "Theme 2"}
</button>
{
<Exhibition
......@@ -224,7 +312,6 @@ const App: React.FC = () => {
lines={installation.lines}
currentIndex={currentIndex + 1}
audiosource={AUDIO_FILES[currentIndex]}
userEdit={userEdit}
toggleFavourite={toggleFavourite}
isFavourite={isFavourite}
drawAnimation={drawAnimation}
......
export enum Font {
ESTEBAN = "Esteban",
LOBSTER = "Lobster",
}
export enum Theme {
DARK = 0,
LIGHT = 1,
}
export enum Color {
RANDOM = -1,
RED = 0,
GREEN = 1,
BLUE = 2,
}
import { Color, Font, Theme } from "./Enums";
const DEFAULT_SESSION_CONFIG = {
theme: Theme.DARK,
color: Color.RANDOM,
font: Font.ESTEBAN,
};
/**
* Handles writing and reading from sessionstorage
*/
class SessionStorageManager {
sessionStorageNotUndefined: boolean;
history: SessionConfig[];
constructor() {
this.sessionStorageNotUndefined =
typeof window["sessionStorage"] != undefined &&
window["sessionStorage"] != null;
this.history = [];
}
/**
* Checks whether the given config (template) already exists in the sessionstack
* @param config - the config to check
*/
exists = (config: SessionConfig): boolean => {
for (let c of this.history) {
if (JSON.stringify(c) === JSON.stringify(config)) {
return true;
}
}
return false;
};
/**
* Adds a new config to the sessionstack if it is not already in it
* @param config - the config to check
*/
add = (config: SessionConfig): void => {
if (!this.exists(config)) {
this.history.push(config);
this.change("session", JSON.stringify(this.history));
}
};
/**
* Returns an array of SessionConfigs parsed from the sessionstorage
*/
parse = (): SessionConfig[] => {
return JSON.parse(sessionStorage.getItem("session")!);
};
/**
* Sets the given value to the given key
* @param key
* @param value
*/
change(key: string, value: any): void {
sessionStorage[key] = value;
}
/**
* Will clear the sessionStorage of all user-stored information. Can also wipe the whole sessionStorage if ordered to.
* @param wipe - wheter or not to reset to DEFAULT_SESSION_CONFIG or wipe the whole sessionStorage
*/
clear(wipe: boolean = false): void {
if (this.sessionStorageNotUndefined) {
sessionStorage.clear();
if (!wipe) {
this.change("font", DEFAULT_SESSION_CONFIG.font);
this.change("theme", DEFAULT_SESSION_CONFIG.theme);
this.change("color", DEFAULT_SESSION_CONFIG.color);
}
}
}
}
export default SessionStorageManager;
......@@ -57,11 +57,9 @@ class AudioPlayer extends Component<AudioPlayerProps, { muted: boolean }> {
render() {
return (
<span>
<button onClick={this.mute}>
{this.state.muted ? "Unmute" : "Mute"}
</button>
</span>
);
}
}
......
import React, { useEffect } from "react";
import { Color } from "../Animations";
import { Color } from "../Enums";
import AudioPlayer from "./AudioPlayer";
/**
......@@ -12,7 +12,6 @@ const Exhibition: React.FC<Installation> = ({
lines,
currentIndex,
audiosource,
userEdit,
toggleFavourite,
isFavourite,
drawAnimation,
......@@ -29,7 +28,7 @@ const Exhibition: React.FC<Installation> = ({
* @param specification - the color specification
*/
const canvasColor = (specification: Color) => {
drawAnimation(specification);
drawAnimation(specification, true);
};
return (
......
type Installation = {
title: string;
author: string;
lines: string[] | undefined;
currentIndex: number;
audiosource: HTMLAudioElement;
userEdit: boolean;
toggleFavourite: (index: number) => void;
isFavourite: (index: number) => boolean;
drawAnimation: (specification?: Color) => void;
drawAnimation: (specification?: Color, force?: boolean) => void;
};
type InstallationList = {
......@@ -22,7 +20,13 @@ type StorageItem = {
type UserConfig = {
favourites: number[];
theme: number;
theme: Theme;
};
type SessionConfig = {
theme: Theme;
color: Color;
font: Font;
};
type AudioPlayerProps = {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment