save current learning session and option to resume

Co-authored-by: Niko Lockenvitz <nl@nikolockenvitz.de>
This commit is contained in:
Rene Fischer 2020-07-05 18:00:54 +02:00
parent fe7ccf62ba
commit 9ce6c20583
No known key found for this signature in database
GPG key ID: 5D8E12AC54D3C1B5
9 changed files with 184 additions and 28 deletions

View file

@ -44,6 +44,7 @@ import {
saveToLocalStorage,
SyncItem
} from "./helpers/localStorageHelper";
import continueCurrentLearningSessionIfPresent from "./helpers/continueLearningHelper";
const AppProps = Vue.extend({
props: {
@ -95,8 +96,7 @@ export default class App extends AppProps {
mounted() {
readFromLocalStorage(this);
this.setSelectedStatusForAllDecks(false);
// TODO: check for active learning session
// this.$router.replace("learn");
continueCurrentLearningSessionIfPresent(this.$eventHub, this.$router, this.decks);
}
get numberOfSelectedDecks() {

View file

@ -31,10 +31,20 @@ import Vue from "vue";
import Component from "vue-class-component";
import Rating from "./Rating.vue";
import { Deck, LearningSessionElement, Event } from "../../types";
import {
Deck,
LearningSessionElement,
Event,
CustomDialogOptionsBarChartBar
} from "../../types";
import LearningSessionManager from "../../helpers/learningSessionManager";
import FollowUpLearningSessionManager from "../../helpers/followUpLearningSessionManager";
import { finishLearningDialog } from "../../helpers/finishLearningDialogHelper";
import {
saveLearningSessionManagerDataToLocalStorage,
getLearningSessionManagerDataFromLocalStorage
} from "../../helpers/learningSessionStorageHelper";
const LearnProps = Vue.extend({
props: {
@ -79,6 +89,7 @@ export default class Learn extends LearnProps {
updateCurLearningElement() {
this.curLearningElement = this.learningSessionManager.getCurrentLearningSessionElementWithCardDetails();
this.updateRatingForCurrentLearningElement();
saveLearningSessionManagerDataToLocalStorage(this.learningSessionManager);
}
updateRatingForCurrentLearningElement() {
@ -95,13 +106,20 @@ export default class Learn extends LearnProps {
}
beforeMount() {
if (this.numberOfSelectedDecks === 0) {
this.$router.replace("/");
return;
const learningSessionManagerDataInLocalStorage = getLearningSessionManagerDataFromLocalStorage();
if (learningSessionManagerDataInLocalStorage) {
this.learningSessionManager = new FollowUpLearningSessionManager(
learningSessionManagerDataInLocalStorage
);
} else {
if (this.numberOfSelectedDecks === 0) {
this.$router.replace("/");
return;
}
this.learningSessionManager = new LearningSessionManager(
this.decks.filter(deck => deck.selected)
);
}
this.learningSessionManager = new LearningSessionManager(
this.decks.filter(deck => deck.selected)
);
this.updateCurLearningElement();
}
@ -115,20 +133,9 @@ export default class Learn extends LearnProps {
moveToNext() {
if (this.checkIfCardIsEndOfSession()) {
const bars = [];
for (let rating = 1; rating <= this.numberOfStarsInRating; rating++) {
bars.push({ name: `${rating}`, value: 0 });
}
for (const element of this.learningSessionManager.learningSession
.elements) {
if (element.rating?.r !== undefined) {
bars[this.mapRatingFrom100ToStars(element.rating.r) - 1].value += 1;
}
}
finishLearningDialog(this, bars);
this.finishSession();
}
this.learningSessionManager.moveToNextLearningSessionElement();
this.updateCurLearningElement();
}
get buttonNext(): { text: string; color: string } {
@ -147,7 +154,6 @@ export default class Learn extends LearnProps {
moveToPrev() {
this.learningSessionManager.moveToPrevLearningSessionElement();
this.updateCurLearningElement();
}
revealAnswer() {
@ -158,6 +164,7 @@ export default class Learn extends LearnProps {
if (programmatically) return;
const r = this.mapRatingFromStarsTo100(rating);
this.learningSessionManager.saveRatingForCurrentLearningSessionElement(r);
saveLearningSessionManagerDataToLocalStorage(this.learningSessionManager);
}
mapRatingFromStarsTo100(rating: number): number {
@ -169,6 +176,24 @@ export default class Learn extends LearnProps {
return (rating * (this.numberOfStarsInRating - 1)) / 100 + 1;
}
finishSession() {
finishLearningDialog(this, this.getBarsForFinishLearningDialog());
}
getBarsForFinishLearningDialog(): CustomDialogOptionsBarChartBar[] {
const bars = [];
for (let rating = 1; rating <= this.numberOfStarsInRating; rating++) {
bars.push({ name: `${rating}`, value: 0 });
}
for (const element of this.learningSessionManager.learningSession
.elements) {
if (element.rating?.r !== undefined) {
bars[this.mapRatingFrom100ToStars(element.rating.r) - 1].value += 1;
}
}
return bars;
}
updateVerticalCentering() {
for (const el of document.getElementsByClassName("max-height")) {
if (el.scrollHeight > el.clientHeight) {
@ -183,6 +208,7 @@ export default class Learn extends LearnProps {
}
updated() {
this.updateVerticalCentering();
this.updateCurLearningElement();
}
}
</script>

View file

@ -59,8 +59,8 @@ export function addDecksFromJSON(context: Context, fileContent: FFCFile) {
}
}
function showAddedDecksConfirmation(context: Context, addedDecksAndCards: addedDeckAndCards[]) {
const numberOfAddedCards = addedDecksAndCards.reduce(
function showAddedDecksConfirmation(context: Context, addedDeckAndCards: addedDeckAndCards[]) {
const numberOfAddedCards = addedDeckAndCards.reduce(
(total, deck) => total + deck.numberOfCards,
0
);
@ -72,7 +72,7 @@ function showAddedDecksConfirmation(context: Context, addedDecksAndCards: addedD
title: "Successfully Imported Decks",
message: "Following decks have been added:",
tableHead: { name: "Deck", value: "Number of Cards" },
table: addedDecksAndCards.map((deck) => {
table: addedDeckAndCards.map((deck) => {
return {
name: deck.name,
value: String(deck.numberOfCards),

View file

@ -0,0 +1,58 @@
import Vue from "vue";
import { Deck } from "@/types";
import VueRouter from "vue-router";
import {
getLearningSessionManagerDataFromLocalStorage,
clearLearningSessionManagerDataInLocalStorage,
} from "./learningSessionStorageHelper";
export default function continueCurrentLearningSessionIfPresent(
eventHub: Vue,
router: VueRouter,
decks: Deck[]
) {
const data = getLearningSessionManagerDataFromLocalStorage();
if (data) {
const options = {
title: `Continue Learning?`,
message:
`You didn't finish your last learning session. Do you want to resume learning where you stopped last session?
Your last session included the following decks: ` +
data.decks.reduce(
(str: string, deck: Deck, index: number) =>
str + (index > 0 ? ", " : "") + deck.name,
""
),
buttons: [
{
name: "Discard Session",
color: "grey",
callback: () => {
clearLearningSessionManagerDataInLocalStorage();
if (router.currentRoute.name !== "DeckSelection") {
router.replace("/");
}
},
},
{
name: "Resume",
color: "indigo",
callback: () => {
data.decks.forEach((deckFromLastSession: Deck) => {
const curDeck = decks.find(
(deckInUse) => deckInUse.id === deckFromLastSession.id
);
if (curDeck) {
curDeck.selected = true;
}
});
if (router.currentRoute.name !== "Learn") {
router.replace("learn");
}
},
},
],
};
eventHub.$emit("showCustomDialog", options);
}
}

View file

@ -5,7 +5,12 @@ import {
CustomDialogOptionsBarChartBar,
} from "../types";
export function finishLearningDialog(context: any, bars: CustomDialogOptionsBarChartBar[]) {
import { clearLearningSessionManagerDataInLocalStorage } from "./learningSessionStorageHelper";
export function finishLearningDialog(
context: any,
bars: CustomDialogOptionsBarChartBar[]
) {
const options = {
title: "Finish Learning?",
message:
@ -26,6 +31,7 @@ export function finishLearningDialog(context: any, bars: CustomDialogOptionsBarC
Event.QUIT_LEARNING,
QuitLearningReason.NO_MORE_CARDS
);
clearLearningSessionManagerDataInLocalStorage();
},
},
],

View file

@ -0,0 +1,9 @@
import LearningSessionManager from "./learningSessionManager";
export default class FollowUpLearningSessionManager extends LearningSessionManager {
constructor(data: LearningSessionManager) {
super(data.decks, data.numberOfRecentCardsToIgnoreWhenSelectingNextCard);
this.cardsToSelectFrom = data.cardsToSelectFrom;
this.learningSession = data.learningSession;
}
}

View file

@ -0,0 +1,51 @@
import LearningSessionManager from "./learningSessionManager";
import { set, get, remove } from "./localStorageHelper";
const LS_NAME_LEARNING_SESSION_MANAGER_DATA = "learningSessionManagerData";
export function saveLearningSessionManagerDataToLocalStorage(
learningSessionManager: LearningSessionManager
) {
set(
LS_NAME_LEARNING_SESSION_MANAGER_DATA,
JSON.stringify(learningSessionManager)
);
}
export function getLearningSessionManagerDataFromLocalStorage() {
try {
const learningSessionMangerData = JSON.parse(
get(LS_NAME_LEARNING_SESSION_MANAGER_DATA)
);
if (!checkIfDataIsLearningSessionManagerData(learningSessionMangerData)) {
throw new Error(
"Stored data is broken and can not be used to create a learning session manager"
);
}
return learningSessionMangerData;
} catch (error) {
return null;
}
}
export function clearLearningSessionManagerDataInLocalStorage() {
remove(LS_NAME_LEARNING_SESSION_MANAGER_DATA);
}
function checkIfDataIsLearningSessionManagerData(
learningSessionManager: LearningSessionManager
): boolean {
if (!learningSessionManager) return false;
for (const attribute of [
"decks",
"numberOfRecentCardsToIgnoreWhenSelectingNextCard",
"cardsToSelectFrom",
"learningSession",
]) {
if (!(attribute in learningSessionManager)) {
return false;
}
}
return true;
}

View file

@ -12,14 +12,18 @@ interface Context {
[x: string]: any;
}
function get(key: string): string {
export function get(key: string): string {
return localStorage.getItem(LOCAL_STORAGE_APP_CONTEXT + key) || "";
}
function set(key: string, value: string): void {
export function set(key: string, value: string): void {
localStorage.setItem(LOCAL_STORAGE_APP_CONTEXT + key, value);
}
export function remove(key: string): void {
localStorage.removeItem(LOCAL_STORAGE_APP_CONTEXT + key);
}
function clearAppData(): void {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i) || "";

View file

@ -1,4 +1,5 @@
import { Event, QuitLearningReason } from "../types";
import { clearLearningSessionManagerDataInLocalStorage } from "./learningSessionStorageHelper";
export function quitLearningDialog(context: any) {
context.$eventHub.$emit("showCustomDialog", {
@ -18,6 +19,7 @@ export function quitLearningDialog(context: any) {
Event.QUIT_LEARNING,
QuitLearningReason.USER_ACTION
);
clearLearningSessionManagerDataInLocalStorage();
},
},
],