chahinebrini ac605dce33 feat(onboarding,diga): TTS auto-play preference + 90 more DiGA test codes
## 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>
2026-05-17 22:39:18 +02:00

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);
},
}));