save current learning session and option to resume
Co-authored-by: Niko Lockenvitz <nl@nikolockenvitz.de>
This commit is contained in:
parent
fe7ccf62ba
commit
9ce6c20583
9 changed files with 184 additions and 28 deletions
|
@ -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() {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
|
|
58
src/helpers/continueLearningHelper.ts
Normal file
58
src/helpers/continueLearningHelper.ts
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
9
src/helpers/followUpLearningSessionManager.ts
Normal file
9
src/helpers/followUpLearningSessionManager.ts
Normal 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;
|
||||
}
|
||||
}
|
51
src/helpers/learningSessionStorageHelper.ts
Normal file
51
src/helpers/learningSessionStorageHelper.ts
Normal 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;
|
||||
}
|
|
@ -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) || "";
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue