Daily Practice per section: mixed drills, stricter unlock, tick-and-skip one-tap
- One-tap mode no longer shows the answer when you're right: a green tick flashes and it skips straight to the next question. Wrong answers still show the full correction and now wait for an explicit Next tap. - Every tab (Prepositions, Articles, Possessives, Pronouns) gets its own pinned Daily Practice card. Sessions mix questions from every lesson in the tab via a shuffle-bag over lesson ids. - Daily Practice is locked until every lesson in its section has been passed (one full round at 70%); the locked card shows x/y progress. - Finishing a daily session offers 'Continue: <section> Daily Practice' cycling to the next tab with an unlocked daily, with play again and back to menu as secondary options.
This commit is contained in:
+26
-4
@@ -237,25 +237,29 @@ export const LEVELS = [
|
||||
{id:5, tab:'article', name:'Genitiv', desc:'trotz, während, wegen, statt...', cases:['genitive'], preps:PREPS_BY_CASE.genitive, type:'article', artType:'definite'},
|
||||
{id:6, tab:'article', name:'Alles gemischt', desc:'All prepositions, definite articles', cases:['accusative','dative','genitive'], preps:[...SENTENCE_ACC_PREPS,...PREPS_BY_CASE.dative,...PREPS_BY_CASE.genitive,...PREPS_BY_CASE.wechsel], type:'article', artType:'definite', mixed:true},
|
||||
{id:7, tab:'article', name:'ein-Wörter', desc:'Everything with ein/eine/einem...', cases:['accusative','dative','genitive'], preps:[...SENTENCE_ACC_PREPS,...PREPS_BY_CASE.dative,...PREPS_BY_CASE.genitive,...PREPS_BY_CASE.wechsel], type:'article', artType:'indefinite', mixed:true},
|
||||
// Daily Practice pseudo-levels (one per tab): a one-tap drill that mixes
|
||||
// questions from every lesson in the tab. Rendered pinned at the top of each
|
||||
// tab by App.jsx (not inline in the level list) and locked until every
|
||||
// lesson in the tab has been passed.
|
||||
{id:7.5, tab:'article', name:'Daily Practice', desc:'Every article lesson, mixed · one-tap', daily:true},
|
||||
|
||||
{id:8, tab:'prep', name:'Häufige Präpositionen', desc:'16 most common prepositions', preps:COMMON_PREPS, type:'prep'},
|
||||
{id:9, tab:'prep', name:'Seltene Präpositionen', desc:'15 less common prepositions', preps:RARE_PREPS, type:'prep'},
|
||||
{id:10, tab:'prep', name:'Alle Präpositionen', desc:'All 31 prepositions mixed', preps:ALL_PREPS, type:'prep'},
|
||||
// Daily Practice: unlocked once "Alle Präpositionen" is completed. Drills all
|
||||
// 31 prepositions and defaults to one-tap mode. Rendered pinned at the top of
|
||||
// the Prepositions tab by App.jsx, not inline in the level list.
|
||||
{id:10.5, tab:'prep', name:'Daily Practice', desc:'All 31 prepositions · one-tap daily drill', preps:ALL_PREPS, type:'prep', daily:true},
|
||||
{id:10.5, tab:'prep', name:'Daily Practice', desc:'Every preposition lesson, mixed · one-tap', daily:true},
|
||||
{id:18, tab:'prep', name:'Wechsel im Kontext', desc:'Real sentences: Akkusativ or Dativ?', preps:PREPS_BY_CASE.wechsel, type:'wechselContext'},
|
||||
{id:19, tab:'prep', name:'Kontraktionen', desc:'Contractions: am, ins, zum, beim…', type:'contraction'},
|
||||
|
||||
{id:11, tab:'poss', name:'Häufige Possessive', desc:'mein · dein · sein — Akkusativ & Dativ', possessives:['mein','dein','sein'], cases:['accusative','dative'], type:'poss'},
|
||||
{id:12, tab:'poss', name:'Schwierige Possessive', desc:'ihr · unser · euer — Akkusativ & Dativ', possessives:['ihr','unser','euer'], cases:['accusative','dative'], type:'poss'},
|
||||
{id:13, tab:'poss', name:'Alle gemischt', desc:'mein, dein, sein, ihr, unser, euer — incl. Genitiv', possessives:['mein','dein','sein','ihr','unser','euer'], cases:['accusative','dative','genitive'], type:'poss'},
|
||||
{id:13.5, tab:'poss', name:'Daily Practice', desc:'Every possessive lesson, mixed · one-tap', daily:true},
|
||||
|
||||
{id:14, tab:'pronoun', name:'Singular Pronomen', desc:'mich, mir, dich, dir…', pronouns:SG_PRONOUN_KEYS, cases:['accusative','dative'], type:'pronoun'},
|
||||
{id:15, tab:'pronoun', name:'Plural Pronomen', desc:'uns, euch, ihnen…', pronouns:PL_PRONOUN_KEYS, cases:['accusative','dative'], type:'pronoun'},
|
||||
{id:16, tab:'pronoun', name:'Sie (formal)', desc:'Formal Sie — singular and plural', pronouns:FORMAL_PRONOUN_KEYS, cases:['accusative','dative'], type:'pronoun'},
|
||||
{id:17, tab:'pronoun', name:'Alle gemischt', desc:'All 10 pronouns, Akkusativ & Dativ', pronouns:ALL_PRONOUN_KEYS, cases:['accusative','dative'], type:'pronoun'},
|
||||
{id:17.5, tab:'pronoun', name:'Daily Practice', desc:'Every pronoun lesson, mixed · one-tap', daily:true},
|
||||
];
|
||||
|
||||
// Contractions (preposition + article). pref:true = preferred even in writing.
|
||||
@@ -440,7 +444,25 @@ export function newState() {
|
||||
}
|
||||
|
||||
// A practice session: one shuffle-bag + anti-repeat memory per round.
|
||||
// Daily levels mix questions from every lesson in their tab: a shuffle-bag
|
||||
// deals the lesson ids so no lesson repeats back-to-back, and each lesson
|
||||
// keeps its own state (their bag pools differ, so they can't share one).
|
||||
export function createSession(levelId) {
|
||||
const lv = LEVELS.find(l => l.id === levelId);
|
||||
if (lv?.daily) {
|
||||
const lessonIds = LEVELS.filter(l => l.tab === lv.tab && !l.daily).map(l => l.id);
|
||||
const meta = newState();
|
||||
const states = {};
|
||||
return {
|
||||
next: () => {
|
||||
const id = drawBag(meta, 'lvl', lessonIds, meta.last.lvl);
|
||||
meta.last.lvl = id;
|
||||
if (!states[id]) states[id] = newState();
|
||||
return gen(id, states[id]);
|
||||
},
|
||||
state: meta,
|
||||
};
|
||||
}
|
||||
const state = newState();
|
||||
return { next: () => gen(levelId, state), state };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user