RebreakVpnService.onStartCommand crashed with SecurityException because Android 16's validateForegroundServiceType rejects the implicit 2-arg startForeground(). Now passes FOREGROUND_SERVICE_TYPE_SPECIAL_USE explicitly (Google's documented best practice) and guards the call so a failed foreground promotion stops the service cleanly instead of crashing the app. Verified vs reported Galaxy A54 / Android 16 signature (97% of crash events, 1-user crash loop). Bundles pending working-tree work across native/marketing/locales/mac + graphify-out rebuild. gitignore: google-services.json + /screenshots/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
64 lines
3.6 KiB
TypeScript
64 lines
3.6 KiB
TypeScript
// Konstanten für den SOS-Screen: Chip-Sets, Atemphasen, Emotion-Regex.
|
|
|
|
export type ChipSet = 'start' | 'help' | 'after_breathing' | 'after_game' | 'overcome_check' | 'overcome_done' | 'none';
|
|
type Chip = { label: string; action: string };
|
|
|
|
export const CHIP_SETS: Record<ChipSet, Chip[]> = {
|
|
start: [
|
|
{ label: '😤 Wütend', action: 'feel:Ich bin gerade sehr wütend.' },
|
|
{ label: '😰 Ängstlich', action: 'feel:Ich bin ängstlich und nervös.' },
|
|
{ label: '😔 Traurig', action: 'feel:Ich bin traurig.' },
|
|
{ label: '😤 Gestresst', action: 'feel:Ich bin gerade gestresst.' },
|
|
{ label: '😶 Leer', action: 'feel:Ich fühle mich innerlich leer.' },
|
|
{ label: '🤔 Etwas anderes...', action: 'need_help' },
|
|
],
|
|
help: [
|
|
{ label: '🫁 Atemübung', action: 'breathing' },
|
|
{ label: '🎮 Spiel starten', action: 'game_picker' },
|
|
],
|
|
after_breathing: [
|
|
{ label: '😌 Besser', action: 'send_text:Ich fühle mich nach der Atemübung besser.' },
|
|
{ label: '🔄 Nochmal', action: 'breathing' },
|
|
{ label: '🎮 Spiel', action: 'game_picker' },
|
|
{ label: '❤️ Überwunden', action: 'overcome' },
|
|
],
|
|
after_game: [
|
|
{ label: '😌 Ruhiger', action: 'send_text:Das Spiel hat geholfen, ich bin ruhiger.' },
|
|
{ label: '🔄 Nochmal', action: 'game_picker' },
|
|
{ label: '❤️ Überwunden', action: 'overcome' },
|
|
],
|
|
overcome_check: [
|
|
{ label: '✅ Ja, ich habe es geschafft', action: 'overcome' },
|
|
{ label: '💪 Noch nicht ganz', action: 'send_text:Der Spielimpuls ist noch da, ich brauche noch Hilfe.' },
|
|
],
|
|
overcome_done: [
|
|
{ label: '✨ Erfolg teilen', action: 'share_success' },
|
|
{ label: '⭐ Diese Session bewerten', action: 'rate_session' },
|
|
{ label: '📊 Meine Statistik', action: 'show_stats' },
|
|
{ label: '✅ Fertig', action: 'close' },
|
|
],
|
|
none: [],
|
|
};
|
|
|
|
// ── Breathing guide ──────────────────────────────────────────────────────────
|
|
export type BreathPhase = 'inhale' | 'hold' | 'exhale';
|
|
export type BreathState = 'idle' | 'countdown' | 'active';
|
|
// speakLine bewusst durchgehend null — Phase-TTS würde Lyras laufende Audio abbrechen
|
|
// (User-Wahrnehmung: "Stimme ändert sich"). Visuelles Pulsieren + Countdown reicht.
|
|
export const BREATH_PHASES: { phase: BreathPhase; duration: number; label: string; color: string; speakLine: string | null }[] = [
|
|
{ phase: 'inhale', duration: 4, label: 'Einatmen', color: '#6366f1', speakLine: 'Einatmen' },
|
|
{ phase: 'hold', duration: 7, label: 'Halten', color: '#f97316', speakLine: 'Halten' },
|
|
{ phase: 'exhale', duration: 8, label: 'Ausatmen', color: '#16a34a', speakLine: 'Ausatmen' },
|
|
];
|
|
export const TOTAL_ROUNDS = 3;
|
|
|
|
export const EMPATHY_RE = /schwer|rückfall|traurig|schlimm|hoffnungslos|verloren|scham|schuld|verzweifelt/i;
|
|
export const HAPPY_RE = /toll|super|geschafft|stark|stolz|fantastisch|prima/i;
|
|
// Stärkere Feier (Meilenstein/Streak) als das alltägliche "happy".
|
|
export const JOY_RE = /glückwunsch|meilenstein|unglaublich|wahnsinn|grandios|großer schritt|so stolz auf dich|riesig stolz/i;
|
|
// Schwere Verlust-/Rückfall-/Scham-Sprache → spiegelndes Mitgefühl statt Winken.
|
|
// Hat in detectEmotion Vorrang vor EMPATHY_RE.
|
|
export const SAD_RE = /rückfällig|verspielt|am boden|versagt|schäme|so leid|es tut mir.{0,12}leid/i;
|
|
// Lyra braucht Klärung / stellt eine Rückfrage.
|
|
export const CONFUSION_RE = /meinst du|wie genau|was genau|verstehe ich.{0,15}richtig|kannst du.{0,15}(erklär|genauer)|nicht ganz sicher|magst du.{0,15}(erzähl|erklär)/i;
|