Merge pull request #28 from fancy-flashcard/limit-learning-session

Limit learning session
This commit is contained in:
Rene Fischer 2020-08-28 18:55:01 +02:00 committed by GitHub
commit 49e6778e17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 256 additions and 39 deletions

View file

@ -1,8 +1,8 @@
{
"name": "ffc",
"version": "2.1.0",
"version": "2.2.0",
"author": "Niko Lockenvitz & Rene-Pascal Fischer",
"license": "MIT",
"license": "GNU GPLv2",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",

View file

@ -10,7 +10,11 @@
:decks="decks"
:numberOfSelectedDecks="numberOfSelectedDecks"
></NavigationBar>
<router-view :decks="decks" :numberOfSelectedDecks="numberOfSelectedDecks" />
<router-view
:decks="decks"
:numberOfSelectedDecks="numberOfSelectedDecks"
:cardLimit="cardLimit"
/>
<v-snackbar app v-model="snackbar.snackbar" :timeout="snackbar.timeout">
{{ snackbar.text }}
<template v-slot:action="{ attrs }">
@ -60,8 +64,10 @@ const AppProps = Vue.extend({
})
export default class App extends AppProps {
propertiesToSyncWithLocalStorage = [
{ key: "decks", defaultValue: [] }
{ key: "decks", defaultValue: [] },
{ key: "cardLimit", defaultValue: "" }
] as SyncItem[];
cardLimit = "";
decks = [] as Deck[];
snackbar = {
text: "",
@ -96,7 +102,11 @@ export default class App extends AppProps {
mounted() {
readFromLocalStorage(this);
this.setSelectedStatusForAllDecks(false);
continueCurrentLearningSessionIfPresent(this.$eventHub, this.$router, this.decks);
continueCurrentLearningSessionIfPresent(
this.$eventHub,
this.$router,
this.decks
);
}
get numberOfSelectedDecks() {

View file

@ -1,5 +1,5 @@
<template>
<div class="settings">
<div>
<v-container fluid>
<v-row>
<ThirdPartyDeckCard />

View file

@ -8,7 +8,7 @@
<v-list-item-title v-text="deck.name"></v-list-item-title>
</v-list-item-content>
<v-list-item-icon
v-bind:class="{ hidden: numberOfSelectedDecks===0, visible: numberOfSelectedDecks>0 }"
:class="{ hidden: numberOfSelectedDecks===0, visible: numberOfSelectedDecks>0 }"
>
<v-icon v-if="deck.selected">mdi-check-box-outline</v-icon>
<v-icon v-else>mdi-checkbox-blank-outline</v-icon>

View file

@ -50,7 +50,8 @@ import {
const LearnProps = Vue.extend({
props: {
decks: { type: Array as () => Deck[] },
numberOfSelectedDecks: Number
numberOfSelectedDecks: Number,
cardLimit: String
}
});
@ -136,11 +137,15 @@ export default class Learn extends LearnProps {
}
checkIfCardIsEndOfSession(): boolean {
return (
this.learningSessionManager.learningSession.currentElementIndex ===
const endOfSession =
(this.learningSessionManager.learningSession.currentElementIndex ===
this.learningSessionManager.learningSession.elements.length - 1 &&
this.learningSessionManager.cardsToSelectFrom.length === 0
);
this.learningSessionManager.cardsToSelectFrom.length === 0) ||
(this.cardLimit === "0"
? false
: this.learningSessionManager.learningSession.currentElementIndex ===
parseInt(this.cardLimit) - 1);
return endOfSession;
}
moveToNext() {

View file

@ -0,0 +1,97 @@
<template>
<v-col cols="12" sm="12" md="6" lg="6" xl="6">
<v-card height="100%" raised>
<v-card-title>Card Limit</v-card-title>
<v-card-text>
<p class="paragraph">
Limit the number of cards that will be in each learning session.
<v-icon
size="1em"
@click="showHelpText = !showHelpText"
class="mx-1"
>mdi-help-circle-outline</v-icon>
</p>
<p
class="description"
v-show="showHelpText"
>If the given deck(s) has (have) less cards it will default to the number of cards in the given deck(s).</p>
<v-text-field
v-model="curCardLimit"
type="number"
min="1"
:label="label"
hide-details="auto"
outlined
></v-text-field>
</v-card-text>
<v-card-actions class="button-padding">
<v-spacer></v-spacer>
<v-btn color="red" @click="deactivatecardLimit" right>Deactivate Limit</v-btn>
</v-card-actions>
</v-card>
</v-col>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { Event } from "../../types";
const CardLimitProps = Vue.extend({
props: {
cardLimit: String
}
});
@Component
export default class CardLimit extends CardLimitProps {
noLimitString = "Currently no limit";
defaultLabel = "Card Limit";
showHelpText = false;
get label() {
return this.curCardLimit ? this.defaultLabel : this.noLimitString;
}
get curCardLimit() {
return this.cardLimit === "0" || !this.cardLimit ? null : this.cardLimit;
}
set curCardLimit(newValue) {
this.$eventHub.$emit(Event.UPDATE_CARD_LIMIT, newValue);
}
deactivatecardLimit() {
this.$eventHub.$emit(Event.UPDATE_CARD_LIMIT, "0");
}
}
</script>
<style scoped>
.button-padding {
padding: 16px;
}
.description {
align-items: center;
font-size: 0.875rem;
font-weight: 400;
color: rgba(255, 255, 255, 0.7);
}
p .v-icon {
color: inherit;
}
.paragraph {
display: flex;
}
/* Disable stepper in number input */
::v-deep input,
::v-deep input::-webkit-outer-spin-button,
::v-deep input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
-moz-appearance: textfield;
}
</style>

View file

@ -0,0 +1,42 @@
<template>
<v-col cols="12" sm="12" md="6" lg="6" xl="6">
<v-card height="100%" raised>
<v-card-title>Clear Local Storage</v-card-title>
<v-card-text>
<p>Delete all imported decks as well as your learning progess in the app.</p>
</v-card-text>
<div class="horizontal-spacer"></div>
<v-card-actions class="button-padding">
<v-spacer></v-spacer>
<v-btn color="red" @click="clearLocalStorage" right>Clear Local Storage</v-btn>
</v-card-actions>
</v-card>
</v-col>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import * as clearStorageDialogHelper from "../../helpers/clearStorageDialogHelper";
@Component
export default class ClearLocalStorage extends Vue {
clearLocalStorage() {
clearStorageDialogHelper.clearLocalStorageDialog(this);
}
}
</script>
<style scoped>
.button-padding {
padding: 16px;
}
.v-card {
display: flex;
flex-direction: column;
}
.horizontal-spacer {
flex-grow: 1;
}
</style>

View file

@ -0,0 +1,35 @@
<template>
<div>
<v-container fluid>
<v-row>
<CardLimit :cardLimit="cardLimit" />
<ClearLocalStorage />
</v-row>
</v-container>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import CardLimit from "./CardLimit.vue";
import ClearLocalStorage from "./ClearLocalStorage.vue";
const SettingProps = Vue.extend({
props: {
cardLimit: String
}
});
@Component({
components: {
CardLimit,
ClearLocalStorage
}
})
export default class Settings extends SettingProps {}
</script>
<style scoped>
</style>

View file

@ -0,0 +1,24 @@
import { Event } from "../types";
export function clearLocalStorageDialog(context: any) {
context.$eventHub.$emit("showCustomDialog", {
title: "Clear Storage?",
message:
"Do you really want to clear your local storage? Every deck and learning progress will be lost.",
buttons: [
{
name: "Cancel",
color: "grey",
},
{
name: "Clear Storage",
color: "orange darken-1",
callback: () => {
context.$eventHub.$emit(
Event.CLEAR_LOCAL_STORAGE
);
},
},
],
});
}

View file

@ -22,9 +22,12 @@ export function registerEventListenerForMainApp(context: any) {
context.$eventHub.$on(Event.ADD_DECKS_FROM_FILE, (fileContent: string) => {
addDecksFromFile(context, fileContent);
});
context.$eventHub.$on(Event.ADD_DECKS_FROM_JSON, (fileContent: FFCFile, url?: string) => {
addDecksFromJSON(context, fileContent, url);
});
context.$eventHub.$on(
Event.ADD_DECKS_FROM_JSON,
(fileContent: FFCFile, url?: string) => {
addDecksFromJSON(context, fileContent, url);
}
);
context.$eventHub.$on(Event.SNACKBAR_EVENT, (message: string) => {
showSnackbar(context, message);
});
@ -43,4 +46,7 @@ export function registerEventListenerForMainApp(context: any) {
}
context.$router.replace("/");
});
context.$eventHub.$on(Event.UPDATE_CARD_LIMIT, (newValue: string) => {
context.cardLimit = newValue;
});
}

View file

@ -1,4 +1,4 @@
import { showSnackbar } from './snackbarHelper';
import { showSnackbar } from "./snackbarHelper";
const LOCAL_STORAGE_APP_CONTEXT = "ffc_";
@ -25,9 +25,9 @@ export function remove(key: string): void {
}
function clearAppData(): void {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i) || "";
if (key.startsWith(LOCAL_STORAGE_APP_CONTEXT)) {
for (let i = localStorage.length - 1; i >= 0; i--) {
const key = localStorage.key(i);
if (key && key.startsWith(LOCAL_STORAGE_APP_CONTEXT)) {
localStorage.removeItem(key);
}
}

View file

@ -117,6 +117,7 @@ export enum Event {
DESELECT_ALL_DECKS = "deselectAllDecks",
SWIPE_LEFT_IN_LEARN = "swipeLeftInLearn",
SWIPE_RIGHT_IN_LEARN = "swipeRightInLearn",
UPDATE_CARD_LIMIT = "updateCardLimit",
}
export interface NavBarConfigItem {

View file

@ -1,6 +1,6 @@
<template>
<div class="deckselection">
<DeckSelection v-bind:decks="decks" v-bind:numberOfSelectedDecks="numberOfSelectedDecks"></DeckSelection>
<DeckSelection :decks="decks" :numberOfSelectedDecks="numberOfSelectedDecks"></DeckSelection>
</div>
</template>

View file

@ -4,6 +4,7 @@
:decks="decks"
:numberOfSelectedDecks="numberOfSelectedDecks"
:learningSession="learningSession"
:cardLimit="cardLimit"
/>
</div>
</template>
@ -20,7 +21,8 @@ const LearnProps = Vue.extend({
props: {
decks: { type: Array as () => Deck[] },
learningSession: { type: Object as () => LearningSession },
numberOfSelectedDecks: Number
numberOfSelectedDecks: Number,
cardLimit: String
}
});

View file

@ -1,14 +1,6 @@
<template>
<div class="settings">
<v-container fluid>
<v-row align="center" justify="center">
<v-col cols="10">
<span class="title">Settings</span>
<br />
<v-btn color="red" @click="clearLocalStorage" class="my-4">Clear Local Storage</v-btn>
</v-col>
</v-row>
</v-container>
<SettingsComponent :cardLimit="cardLimit" />
</div>
</template>
@ -16,18 +8,21 @@
import Vue from "vue";
import Component from "vue-class-component";
import { Event } from "../types";
import SettingsComponent from "../components/settings/Settings.vue";
@Component
export default class Settings extends Vue {
clearLocalStorage() {
this.$eventHub.$emit(Event.CLEAR_LOCAL_STORAGE);
const SettingProps = Vue.extend({
props: {
cardLimit: String
}
}
});
@Component({
components: {
SettingsComponent
}
})
export default class Settings extends SettingProps {}
</script>
<style scoped>
.settings {
text-align: center;
}
</style>