Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IT2810 H20
Team 61
Prosjekt 2
Commits
7b592ee5
Commit
7b592ee5
authored
Sep 23, 2020
by
haukao
Browse files
Added the ability to restore templates already used in the session :)
Issue
#12
parent
51b9fbd8
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/Animations.ts
View file @
7b592ee5
/**
* 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
;
};
...
...
src/App.tsx
View file @
7b592ee5
...
...
@@ -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
}
...
...
src/Enums.ts
0 → 100644
View file @
7b592ee5
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
,
}
src/SessionStorageManager.ts
0 → 100644
View file @
7b592ee5
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
;
src/components/AudioPlayer.tsx
View file @
7b592ee5
...
...
@@ -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
>
);
}
}
...
...
src/components/Exhibition.tsx
View file @
7b592ee5
import
React
,
{
useEffect
}
from
"
react
"
;
import
{
Color
}
from
"
../
Animation
s
"
;
import
{
Color
}
from
"
../
Enum
s
"
;
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
(
...
...
src/types.d.ts
View file @
7b592ee5
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
=
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment