## TTS Auto-Play Preference User-Request: wenn Voice einmal aktiviert, soll Lyra auf jeder Slide automatisch sprechen — nicht jede Slide extra antippen. - stores/lyraVoice.ts: zustand-store mit AsyncStorage-Persistence (@rebreak/lyraVoiceEnabled). Default OFF. - LyraBubble auto-plays on text-change wenn enabled - Audio-Button toggled die Preference + stoppt current playback - Visuell: Button ist orange-filled wenn voice ON, ghost-bordered wenn OFF - Icon: volume-mute-outline (OFF) / volume-medium / hourglass / stop - Cleanup beim Unmount (stopLyraSpeech) + bei text-change Initialisiert via init() in app/_layout.tsx (analog language/theme/appLock). Locale-keys: audio_play → "Stimme einschalten", neu audio_disable → "Stimme ausschalten" in 4 Sprachen. ## DiGA Test Codes 011-100 Aktuell 10 Codes (REBREAK-TEST-001..010), aber 100 Android-Tester kommen morgen onboarding. Migration 20260518_extend_diga_test_codes seeded 90 zusätzliche Codes via generate_series(11, 100) + LPAD-Padding. - Label: 'test_batch_2026-05-android' für Auditbarkeit (vs '...2026-05' für die ersten 10) - grants_plan: 'legend' wie die ersten 10 - ON CONFLICT DO NOTHING — idempotent Distribution-Pattern: Tester N kriegt Code REBREAK-TEST-<NNN-padded>. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
52 lines
1.3 KiB
TypeScript
52 lines
1.3 KiB
TypeScript
import { create } from 'zustand';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
|
/**
|
|
* Persistente User-Preference für Lyra-TTS-Auto-Play.
|
|
*
|
|
* Default OFF — User aktiviert einmal in der Welcome-Slide via Audio-Button,
|
|
* danach playt Lyra auf jeder Slide automatisch. Erneutes Tappen disabled
|
|
* + stoppt aktuelles Playback.
|
|
*
|
|
* Persistence: AsyncStorage @rebreak/lyraVoiceEnabled. Init beim App-Start
|
|
* via `init()` (analog zu language/theme/appLock-Stores).
|
|
*/
|
|
|
|
const STORAGE_KEY = '@rebreak/lyraVoiceEnabled';
|
|
|
|
type LyraVoiceState = {
|
|
enabled: boolean;
|
|
ready: boolean;
|
|
init: () => Promise<void>;
|
|
setEnabled: (enabled: boolean) => Promise<void>;
|
|
toggle: () => Promise<void>;
|
|
};
|
|
|
|
export const useLyraVoiceStore = create<LyraVoiceState>((set, get) => ({
|
|
enabled: false,
|
|
ready: false,
|
|
|
|
init: async () => {
|
|
try {
|
|
const stored = await AsyncStorage.getItem(STORAGE_KEY);
|
|
set({ enabled: stored === '1', ready: true });
|
|
} catch {
|
|
set({ enabled: false, ready: true });
|
|
}
|
|
},
|
|
|
|
setEnabled: async (enabled: boolean) => {
|
|
set({ enabled });
|
|
try {
|
|
await AsyncStorage.setItem(STORAGE_KEY, enabled ? '1' : '0');
|
|
} catch {
|
|
// ignore — in-memory state ist wichtiger
|
|
}
|
|
},
|
|
|
|
toggle: async () => {
|
|
const next = !get().enabled;
|
|
await get().setEnabled(next);
|
|
},
|
|
}));
|