import 'dart:async'; import 'package:flutter/services.dart'; import '../state/app/modules/settings/bloc/settings_cubit.dart'; import '../storage/haptic_settings.dart'; import '../storage/settings.dart'; /// App-weite Haptik-Fassade. Liest die aktive Stufe aus einem in-memory Cache, /// der einmal an den SettingsCubit gebunden wird — damit sind die Aufrufe /// kontextfrei (egal ob aus Widget oder Util). /// /// Semantische Methoden statt roher Impacts, damit Call-Sites die Intention /// transportieren, nicht die Stärke. class Haptics { static HapticLevel _level = HapticLevel.full; static StreamSubscription? _sub; /// Einmal aus App-Root aufrufen, sobald der [SettingsCubit] verfügbar ist. static void bind(SettingsCubit cubit) { _level = cubit.state.hapticSettings.level; _sub?.cancel(); _sub = cubit.stream.listen((s) => _level = s.hapticSettings.level); } // --- reduced + full --- /// Long-Press, der ein Bottom-Sheet / Action-Menü öffnet. static void longPress() { if (_level == HapticLevel.off) return; HapticFeedback.mediumImpact(); } /// Bestätigen eines ConfirmDialogs (nicht das Abbrechen). static void confirm() { if (_level == HapticLevel.off) return; HapticFeedback.mediumImpact(); } /// Fehler einer Async-Aktion / Dialog-Fehler. static void error() { if (_level == HapticLevel.off) return; HapticFeedback.mediumImpact(); } /// Seltener Dopamin-Moment — z.B. erfolgreicher Login. static void heavyAccent() { if (_level == HapticLevel.off) return; HapticFeedback.heavyImpact(); } // --- nur full --- /// Erfolg einer Async-Aktion (Senden, Reagieren, Speichern, …). static void success() { if (_level != HapticLevel.full) return; HapticFeedback.lightImpact(); } /// Pull-to-Refresh ausgelöst. static void refresh() { if (_level != HapticLevel.full) return; HapticFeedback.selectionClick(); } /// Tab-Wechsel, Toggle-Switch, Clipboard-Copy — alles, was eine /// subtile Quittung verdient. static void selection() { if (_level != HapticLevel.full) return; HapticFeedback.selectionClick(); } }