import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// Stores and retrieves all user-configurable app settings. class SettingsService extends ChangeNotifier { static const _keyBlurExplore = 'set_blur_explore'; static const _keyBlurReels = 'set_blur_reels'; static const _keyRequireLongPress = 'set_require_long_press'; static const _keyShowBreathGate = 'set_show_breath_gate'; static const _keyRequireWordChallenge = 'set_require_word_challenge'; static const _keyEnableTextSelection = 'set_enable_text_selection'; static const _keyEnabledTabs = 'set_enabled_tabs'; static const _keyShowInstaSettings = 'set_show_insta_settings'; static const _keyIsFirstRun = 'set_is_first_run'; // Focus / playback static const _keyBlockAutoplay = 'block_autoplay'; // Grayscale mode static const _keyGrayscaleEnabled = 'grayscale_enabled'; static const _keyGrayscaleScheduleEnabled = 'grayscale_schedule_enabled'; static const _keyGrayscaleScheduleTime = 'grayscale_schedule_time'; // Content filtering / UI hiding static const _keyHideSuggestedPosts = 'hide_suggested_posts'; static const _keyHideSponsoredPosts = 'hide_sponsored_posts'; static const _keyHideLikeCounts = 'hide_like_counts'; static const _keyHideFollowerCounts = 'hide_follower_counts'; static const _keyHideStoriesBar = 'hide_stories_bar'; static const _keyHideExploreTab = 'hide_explore_tab'; static const _keyHideReelsTab = 'hide_reels_tab'; static const _keyHideShopTab = 'hide_shop_tab'; // Complete section disabling / Minimal mode static const _keyDisableReelsEntirely = 'disable_reels_entirely'; static const _keyDisableExploreEntirely = 'disable_explore_entirely'; static const _keyMinimalModeEnabled = 'minimal_mode_enabled'; // Reels History static const _keyReelsHistoryEnabled = 'reels_history_enabled'; // Privacy keys static const _keySanitizeLinks = 'set_sanitize_links'; static const _keyNotifyDMs = 'set_notify_dms'; static const _keyNotifyActivity = 'set_notify_activity'; static const _keyNotifySessionEnd = 'set_notify_session_end'; SharedPreferences? _prefs; bool _blurExplore = true; bool _blurReels = false; bool _requireLongPress = true; bool _showBreathGate = true; bool _requireWordChallenge = true; bool _enableTextSelection = false; bool _showInstaSettings = true; bool _isDarkMode = true; // Default to dark as per existing app theme bool _blockAutoplay = true; bool _grayscaleEnabled = false; bool _grayscaleScheduleEnabled = false; String _grayscaleScheduleTime = '21:00'; // 9:00 PM default bool _hideSuggestedPosts = false; bool _hideSponsoredPosts = false; bool _hideLikeCounts = false; bool _hideFollowerCounts = false; bool _hideStoriesBar = false; bool _hideExploreTab = false; bool _hideReelsTab = false; bool _hideShopTab = false; bool _disableReelsEntirely = false; bool _disableExploreEntirely = false; bool _minimalModeEnabled = false; bool _reelsHistoryEnabled = true; // Privacy defaults - notifications OFF by default bool _sanitizeLinks = true; bool _notifyDMs = false; bool _notifyActivity = false; bool _notifySessionEnd = false; List _enabledTabs = [ 'Home', 'Search', 'Reels', 'Messages', 'Profile', ]; bool _isFirstRun = true; bool get blurExplore => _blurExplore; bool get blurReels => _blurReels; bool get requireLongPress => _requireLongPress; bool get showBreathGate => _showBreathGate; bool get requireWordChallenge => _requireWordChallenge; bool get enableTextSelection => _enableTextSelection; bool get showInstaSettings => _showInstaSettings; List get enabledTabs => _enabledTabs; bool get isFirstRun => _isFirstRun; bool get isDarkMode => _isDarkMode; bool get blockAutoplay => _blockAutoplay; bool get notifyDMs => _notifyDMs; bool get notifyActivity => _notifyActivity; bool get notifySessionEnd => _notifySessionEnd; bool get grayscaleEnabled => _grayscaleEnabled; bool get grayscaleScheduleEnabled => _grayscaleScheduleEnabled; String get grayscaleScheduleTime => _grayscaleScheduleTime; bool get hideSuggestedPosts => _hideSuggestedPosts; bool get hideSponsoredPosts => _hideSponsoredPosts; bool get hideLikeCounts => _hideLikeCounts; bool get hideFollowerCounts => _hideFollowerCounts; bool get hideStoriesBar => _hideStoriesBar; bool get hideExploreTab => _hideExploreTab; bool get hideReelsTab => _hideReelsTab; bool get hideShopTab => _hideShopTab; bool get disableReelsEntirely => _disableReelsEntirely; bool get disableExploreEntirely => _disableExploreEntirely; bool get minimalModeEnabled => _minimalModeEnabled; bool get reelsHistoryEnabled => _reelsHistoryEnabled; /// True if grayscale should currently be applied, considering the manual /// toggle and the optional schedule. bool get isGrayscaleActiveNow { if (_grayscaleEnabled) return true; if (!_grayscaleScheduleEnabled) return false; try { final parts = _grayscaleScheduleTime.split(':'); if (parts.length != 2) return false; final h = int.parse(parts[0]); final m = int.parse(parts[1]); final now = DateTime.now(); final currentMinutes = now.hour * 60 + now.minute; final startMinutes = h * 60 + m; // Active from the configured time until midnight. return currentMinutes >= startMinutes; } catch (_) { return false; } } // Privacy getters bool get sanitizeLinks => _sanitizeLinks; Future init() async { _prefs = await SharedPreferences.getInstance(); _blurExplore = _prefs!.getBool(_keyBlurExplore) ?? true; _blurReels = _prefs!.getBool(_keyBlurReels) ?? false; _requireLongPress = _prefs!.getBool(_keyRequireLongPress) ?? true; _showBreathGate = _prefs!.getBool(_keyShowBreathGate) ?? true; _requireWordChallenge = _prefs!.getBool(_keyRequireWordChallenge) ?? true; _enableTextSelection = _prefs!.getBool(_keyEnableTextSelection) ?? false; _showInstaSettings = _prefs!.getBool(_keyShowInstaSettings) ?? true; _blockAutoplay = _prefs!.getBool(_keyBlockAutoplay) ?? true; _grayscaleEnabled = _prefs!.getBool(_keyGrayscaleEnabled) ?? false; _grayscaleScheduleEnabled = _prefs!.getBool(_keyGrayscaleScheduleEnabled) ?? false; _grayscaleScheduleTime = _prefs!.getString(_keyGrayscaleScheduleTime) ?? '21:00'; _hideSuggestedPosts = _prefs!.getBool(_keyHideSuggestedPosts) ?? false; _hideSponsoredPosts = _prefs!.getBool(_keyHideSponsoredPosts) ?? false; _hideLikeCounts = _prefs!.getBool(_keyHideLikeCounts) ?? false; _hideFollowerCounts = _prefs!.getBool(_keyHideFollowerCounts) ?? false; _hideStoriesBar = _prefs!.getBool(_keyHideStoriesBar) ?? false; _hideExploreTab = _prefs!.getBool(_keyHideExploreTab) ?? false; _hideReelsTab = _prefs!.getBool(_keyHideReelsTab) ?? false; _hideShopTab = _prefs!.getBool(_keyHideShopTab) ?? false; _disableReelsEntirely = _prefs!.getBool(_keyDisableReelsEntirely) ?? false; _disableExploreEntirely = _prefs!.getBool(_keyDisableExploreEntirely) ?? false; _minimalModeEnabled = _prefs!.getBool(_keyMinimalModeEnabled) ?? false; _reelsHistoryEnabled = _prefs!.getBool(_keyReelsHistoryEnabled) ?? true; _sanitizeLinks = _prefs!.getBool(_keySanitizeLinks) ?? true; _notifyDMs = _prefs!.getBool(_keyNotifyDMs) ?? false; _notifyActivity = _prefs!.getBool(_keyNotifyActivity) ?? false; _notifySessionEnd = _prefs!.getBool(_keyNotifySessionEnd) ?? false; _enabledTabs = (_prefs!.getStringList(_keyEnabledTabs) ?? ['Home', 'Search', 'Reels', 'Messages', 'Profile']) ..remove('Create'); if (!_enabledTabs.contains('Messages') && _enabledTabs.length < 5) { // Migration: add Messages if missing _enabledTabs.insert(3, 'Messages'); } _isFirstRun = _prefs!.getBool(_keyIsFirstRun) ?? true; notifyListeners(); } Future setFirstRunCompleted() async { _isFirstRun = false; await _prefs?.setBool(_keyIsFirstRun, false); notifyListeners(); } Future setBlurExplore(bool v) async { _blurExplore = v; await _prefs?.setBool(_keyBlurExplore, v); notifyListeners(); } Future setBlurReels(bool v) async { _blurReels = v; await _prefs?.setBool(_keyBlurReels, v); notifyListeners(); } Future setRequireLongPress(bool v) async { _requireLongPress = v; await _prefs?.setBool(_keyRequireLongPress, v); notifyListeners(); } Future setShowBreathGate(bool v) async { _showBreathGate = v; await _prefs?.setBool(_keyShowBreathGate, v); notifyListeners(); } Future setRequireWordChallenge(bool v) async { _requireWordChallenge = v; await _prefs?.setBool(_keyRequireWordChallenge, v); notifyListeners(); } Future setEnableTextSelection(bool v) async { _enableTextSelection = v; await _prefs?.setBool(_keyEnableTextSelection, v); notifyListeners(); } Future setShowInstaSettings(bool v) async { _showInstaSettings = v; await _prefs?.setBool(_keyShowInstaSettings, v); notifyListeners(); } Future setBlockAutoplay(bool v) async { _blockAutoplay = v; await _prefs?.setBool(_keyBlockAutoplay, v); notifyListeners(); } Future setGrayscaleEnabled(bool v) async { _grayscaleEnabled = v; await _prefs?.setBool(_keyGrayscaleEnabled, v); notifyListeners(); } Future setGrayscaleScheduleEnabled(bool v) async { _grayscaleScheduleEnabled = v; await _prefs?.setBool(_keyGrayscaleScheduleEnabled, v); notifyListeners(); } Future setGrayscaleScheduleTime(String hhmm) async { _grayscaleScheduleTime = hhmm; await _prefs?.setString(_keyGrayscaleScheduleTime, hhmm); notifyListeners(); } Future setHideSuggestedPosts(bool v) async { _hideSuggestedPosts = v; await _prefs?.setBool(_keyHideSuggestedPosts, v); notifyListeners(); } Future setHideSponsoredPosts(bool v) async { _hideSponsoredPosts = v; await _prefs?.setBool(_keyHideSponsoredPosts, v); notifyListeners(); } Future setHideLikeCounts(bool v) async { _hideLikeCounts = v; await _prefs?.setBool(_keyHideLikeCounts, v); notifyListeners(); } Future setHideFollowerCounts(bool v) async { _hideFollowerCounts = v; await _prefs?.setBool(_keyHideFollowerCounts, v); notifyListeners(); } Future setHideStoriesBar(bool v) async { _hideStoriesBar = v; await _prefs?.setBool(_keyHideStoriesBar, v); notifyListeners(); } Future setHideExploreTab(bool v) async { _hideExploreTab = v; await _prefs?.setBool(_keyHideExploreTab, v); notifyListeners(); } Future setHideReelsTab(bool v) async { _hideReelsTab = v; await _prefs?.setBool(_keyHideReelsTab, v); notifyListeners(); } Future setHideShopTab(bool v) async { _hideShopTab = v; await _prefs?.setBool(_keyHideShopTab, v); notifyListeners(); } Future setDisableReelsEntirely(bool v) async { _disableReelsEntirely = v; await _prefs?.setBool(_keyDisableReelsEntirely, v); notifyListeners(); } Future setDisableExploreEntirely(bool v) async { _disableExploreEntirely = v; await _prefs?.setBool(_keyDisableExploreEntirely, v); notifyListeners(); } Future setMinimalModeEnabled(bool v) async { _minimalModeEnabled = v; await _prefs?.setBool(_keyMinimalModeEnabled, v); notifyListeners(); } Future setReelsHistoryEnabled(bool v) async { _reelsHistoryEnabled = v; await _prefs?.setBool(_keyReelsHistoryEnabled, v); notifyListeners(); } void setDarkMode(bool dark) { if (_isDarkMode != dark) { _isDarkMode = dark; notifyListeners(); } } Future setSanitizeLinks(bool v) async { _sanitizeLinks = v; await _prefs?.setBool(_keySanitizeLinks, v); notifyListeners(); } Future setNotifyDMs(bool v) async { _notifyDMs = v; await _prefs?.setBool(_keyNotifyDMs, v); notifyListeners(); } Future setNotifyActivity(bool v) async { _notifyActivity = v; await _prefs?.setBool(_keyNotifyActivity, v); notifyListeners(); } Future setNotifySessionEnd(bool v) async { _notifySessionEnd = v; await _prefs?.setBool(_keyNotifySessionEnd, v); notifyListeners(); } Future toggleTab(String tab) async { if (_enabledTabs.contains(tab)) { if (_enabledTabs.length > 1) { _enabledTabs.remove(tab); } } else { _enabledTabs.add(tab); } await _prefs?.setStringList(_keyEnabledTabs, _enabledTabs); notifyListeners(); } Future reorderTab(int oldIndex, int newIndex) async { if (newIndex > oldIndex) newIndex -= 1; final String item = _enabledTabs.removeAt(oldIndex); _enabledTabs.insert(newIndex, item); await _prefs?.setStringList(_keyEnabledTabs, _enabledTabs); notifyListeners(); } }