mirror of
https://github.com/Ujwal223/FocusGram.git
synced 2026-06-05 05:08:05 +02:00
Progress SAve- downloader,blur,ghost mode(Partially) works
This commit is contained in:
@@ -2,14 +2,18 @@ import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'notification_service.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 _keyTapToUnblur = 'set_tap_to_unblur';
|
||||
static const _keyRequireLongPress = 'set_require_long_press';
|
||||
static const _keyShowBreathGate = 'set_show_breath_gate';
|
||||
static const _keyRequireWordChallenge = 'set_require_word_challenge';
|
||||
static const _keyRequireLongPress = 'set_require_long_press';
|
||||
static const _keyBreathGateSeconds = 'breath_gate_seconds';
|
||||
static const _keyWordChallengeCount = 'word_challenge_count';
|
||||
static const _keyEnableTextSelection = 'set_enable_text_selection';
|
||||
static const _keyEnabledTabs = 'set_enabled_tabs';
|
||||
static const _keyShowInstaSettings = 'set_show_insta_settings';
|
||||
@@ -18,23 +22,42 @@ class SettingsService extends ChangeNotifier {
|
||||
// Focus / playback
|
||||
static const _keyBlockAutoplay = 'block_autoplay';
|
||||
|
||||
// Extras (Phase 2)
|
||||
static const _keyVideoDownloadEnabled = 'video_download_enabled';
|
||||
static const _keyHideSuggestedPosts = 'hide_suggested_posts';
|
||||
|
||||
// ── FocusGram v2 overlay toggles ─────────────────────────────────────────
|
||||
static const _keyV2GhostModeEnabled = 'v2_ghost_mode_enabled';
|
||||
static const _keyV2AdBlockerDomEnabled = 'v2_adblock_dom_enabled';
|
||||
static const _keyV2ContentHiderEnabled = 'v2_content_hider_enabled';
|
||||
|
||||
// Content hider flags (consumed by v2/content_hider.js via prefs keys)
|
||||
static const _keyContentStories = 'content_stories';
|
||||
static const _keyContentPosts = 'content_posts';
|
||||
static const _keyContentReels = 'content_reels';
|
||||
static const _keyContentSuggested = 'content_suggested';
|
||||
|
||||
// Grayscale mode - now supports multiple schedules
|
||||
static const _keyGrayscaleEnabled = 'grayscale_enabled';
|
||||
static const _keyGrayscaleSchedules = 'grayscale_schedules';
|
||||
|
||||
// Content filtering / UI hiding
|
||||
static const _keyHideSponsoredPosts = 'hide_sponsored_posts';
|
||||
static const _keyHideLikeCounts = 'hide_like_counts';
|
||||
static const _keyHideFollowerCounts = 'hide_follower_counts';
|
||||
static const _keyHideShopTab = 'hide_shop_tab';
|
||||
|
||||
// Minimal mode
|
||||
static const _keyMinimalModeEnabled = 'minimal_mode_enabled';
|
||||
|
||||
|
||||
// Minimal mode state tracking for smart restore
|
||||
static const _keyMinimalModePrevDisableReels = 'minimal_mode_prev_disable_reels';
|
||||
static const _keyMinimalModePrevDisableExplore = 'minimal_mode_prev_disable_explore';
|
||||
static const _keyMinimalModePrevBlurExplore = 'minimal_mode_prev_blur_explore';
|
||||
static const _keyMinimalModePrevDisableReels =
|
||||
'minimal_mode_prev_disable_reels';
|
||||
static const _keyMinimalModePrevDisableExplore =
|
||||
'minimal_mode_prev_disable_explore';
|
||||
static const _keyMinimalModePrevBlurExplore =
|
||||
'minimal_mode_prev_blur_explore';
|
||||
static const _keyMinimalModePrevBlockHomeFeedScroll =
|
||||
'minimal_mode_prev_block_home_feed_scroll';
|
||||
|
||||
// Reels History
|
||||
static const _keyReelsHistoryEnabled = 'reels_history_enabled';
|
||||
@@ -46,6 +69,14 @@ class SettingsService extends ChangeNotifier {
|
||||
static const _keyNotifySessionEnd = 'set_notify_session_end';
|
||||
static const _keyNotifyPersistent = 'set_notify_persistent';
|
||||
|
||||
// Focus mode settings
|
||||
static const _keyGhostMode = 'ghost_mode';
|
||||
static const _keyNoAds = 'no_ads';
|
||||
static const _keyNoStories = 'no_stories';
|
||||
static const _keyNoReels = 'no_reels';
|
||||
static const _keyNoAutoplay = 'no_autoplay';
|
||||
static const _keyNoDMs = 'no_dms';
|
||||
|
||||
SharedPreferences? _prefs;
|
||||
|
||||
bool _blurExplore = true;
|
||||
@@ -54,19 +85,33 @@ class SettingsService extends ChangeNotifier {
|
||||
bool _requireLongPress = true;
|
||||
bool _showBreathGate = true;
|
||||
bool _requireWordChallenge = true;
|
||||
int _breathGateSeconds = 10;
|
||||
int _wordChallengeCount = 30;
|
||||
bool _enableTextSelection = false;
|
||||
bool _showInstaSettings = true;
|
||||
bool _isDarkMode = true; // Default to dark as per existing app theme
|
||||
|
||||
bool _blockAutoplay = true;
|
||||
|
||||
bool _videoDownloadEnabled = false;
|
||||
bool _hideSuggestedPosts = false;
|
||||
|
||||
// ── FocusGram v2 overlay toggles ─────────────────────────────────────────
|
||||
bool _v2GhostModeEnabled = false;
|
||||
bool _v2AdBlockerDomEnabled = false;
|
||||
bool _v2ContentHiderEnabled = false;
|
||||
|
||||
// Content hider flags (consumed by v2/content_hider.js via prefs keys)
|
||||
bool _contentStories = false;
|
||||
bool _contentPosts = false;
|
||||
bool _contentReels = false;
|
||||
bool _contentSuggested = false;
|
||||
|
||||
// Grayscale mode - now supports multiple schedules
|
||||
bool _grayscaleEnabled = false;
|
||||
|
||||
// Grayscale schedules - list of {enabled, startTime, endTime}
|
||||
// startTime and endTime are in format "HH:MM"
|
||||
List<Map<String, dynamic>> _grayscaleSchedules = [];
|
||||
|
||||
bool _hideSponsoredPosts = false;
|
||||
// Content filtering / UI hiding
|
||||
bool _hideLikeCounts = false;
|
||||
bool _hideFollowerCounts = false;
|
||||
bool _hideShopTab = false;
|
||||
@@ -74,12 +119,14 @@ class SettingsService extends ChangeNotifier {
|
||||
// These are now controlled internally by minimal mode
|
||||
bool _disableReelsEntirely = false;
|
||||
bool _disableExploreEntirely = false;
|
||||
bool _blockHomeFeedScroll = false;
|
||||
bool _minimalModeEnabled = false;
|
||||
|
||||
// Tracking for smart restore
|
||||
bool _prevDisableReels = false;
|
||||
bool _prevDisableExplore = false;
|
||||
bool _prevBlurExplore = false;
|
||||
bool _prevBlockHomeFeedScroll = false;
|
||||
|
||||
bool _reelsHistoryEnabled = true;
|
||||
|
||||
@@ -90,6 +137,14 @@ class SettingsService extends ChangeNotifier {
|
||||
bool _notifySessionEnd = false;
|
||||
bool _notifyPersistent = false;
|
||||
|
||||
// Focus mode settings
|
||||
bool _ghostMode = false;
|
||||
bool _noAds = false;
|
||||
bool _noStories = false;
|
||||
bool _noReels = false;
|
||||
bool _noAutoplay = false;
|
||||
bool _noDMs = false;
|
||||
|
||||
List<String> _enabledTabs = [
|
||||
'Home',
|
||||
'Search',
|
||||
@@ -105,12 +160,28 @@ class SettingsService extends ChangeNotifier {
|
||||
bool get requireLongPress => _requireLongPress;
|
||||
bool get showBreathGate => _showBreathGate;
|
||||
bool get requireWordChallenge => _requireWordChallenge;
|
||||
int get breathGateSeconds => _breathGateSeconds;
|
||||
int get wordChallengeCount => _wordChallengeCount;
|
||||
bool get enableTextSelection => _enableTextSelection;
|
||||
bool get showInstaSettings => _showInstaSettings;
|
||||
List<String> get enabledTabs => _enabledTabs;
|
||||
bool get isFirstRun => _isFirstRun;
|
||||
bool get isDarkMode => _isDarkMode;
|
||||
bool get blockAutoplay => _blockAutoplay;
|
||||
|
||||
// Extras (Phase 2)
|
||||
bool get videoDownloadEnabled => _videoDownloadEnabled;
|
||||
bool get hideSuggestedPosts => _hideSuggestedPosts;
|
||||
|
||||
// ── FocusGram v2 overlay toggles ─────────────────────────────────────────
|
||||
bool get v2GhostModeEnabled => _v2GhostModeEnabled;
|
||||
bool get v2AdBlockerDomEnabled => _v2AdBlockerDomEnabled;
|
||||
bool get v2ContentHiderEnabled => _v2ContentHiderEnabled;
|
||||
|
||||
bool get contentStories => _contentStories;
|
||||
bool get contentPosts => _contentPosts;
|
||||
bool get contentReels => _contentReels;
|
||||
bool get contentSuggested => _contentSuggested;
|
||||
bool get notifyDMs => _notifyDMs;
|
||||
bool get notifyActivity => _notifyActivity;
|
||||
bool get notifySessionEnd => _notifySessionEnd;
|
||||
@@ -119,14 +190,22 @@ class SettingsService extends ChangeNotifier {
|
||||
bool get grayscaleEnabled => _grayscaleEnabled;
|
||||
List<Map<String, dynamic>> get grayscaleSchedules => _grayscaleSchedules;
|
||||
|
||||
bool get hideSponsoredPosts => _hideSponsoredPosts;
|
||||
bool get hideLikeCounts => _hideLikeCounts;
|
||||
bool get hideFollowerCounts => _hideFollowerCounts;
|
||||
bool get hideShopTab => _hideShopTab;
|
||||
|
||||
// Focus mode settings
|
||||
bool get ghostMode => _ghostMode;
|
||||
bool get noAds => _noAds;
|
||||
bool get noStories => _noStories;
|
||||
bool get noReels => _noReels;
|
||||
bool get noAutoplay => _noAutoplay;
|
||||
bool get noDMs => _noDMs;
|
||||
|
||||
// These are now controlled by minimal mode only
|
||||
bool get disableReelsEntirely => _minimalModeEnabled ? true : _disableReelsEntirely;
|
||||
bool get disableExploreEntirely => _minimalModeEnabled ? true : _disableExploreEntirely;
|
||||
bool get disableReelsEntirely => _disableReelsEntirely;
|
||||
bool get disableExploreEntirely => _disableExploreEntirely;
|
||||
bool get blockHomeFeedScroll => _blockHomeFeedScroll;
|
||||
bool get minimalModeEnabled => _minimalModeEnabled;
|
||||
|
||||
bool get reelsHistoryEnabled => _reelsHistoryEnabled;
|
||||
@@ -136,22 +215,23 @@ class SettingsService extends ChangeNotifier {
|
||||
bool get isGrayscaleActiveNow {
|
||||
if (_grayscaleEnabled) return true;
|
||||
if (_grayscaleSchedules.isEmpty) return false;
|
||||
|
||||
|
||||
final now = DateTime.now();
|
||||
final currentMinutes = now.hour * 60 + now.minute;
|
||||
|
||||
|
||||
for (final schedule in _grayscaleSchedules) {
|
||||
if (schedule['enabled'] != true) continue;
|
||||
|
||||
|
||||
try {
|
||||
final startParts = (schedule['startTime'] as String).split(':');
|
||||
final endParts = (schedule['endTime'] as String).split(':');
|
||||
|
||||
|
||||
if (startParts.length != 2 || endParts.length != 2) continue;
|
||||
|
||||
final startMinutes = int.parse(startParts[0]) * 60 + int.parse(startParts[1]);
|
||||
|
||||
final startMinutes =
|
||||
int.parse(startParts[0]) * 60 + int.parse(startParts[1]);
|
||||
final endMinutes = int.parse(endParts[0]) * 60 + int.parse(endParts[1]);
|
||||
|
||||
|
||||
// Handle overnight schedules (e.g., 21:00 to 06:00)
|
||||
if (endMinutes < startMinutes) {
|
||||
// Overnight: active if current time is >= start OR < end
|
||||
@@ -182,43 +262,80 @@ class SettingsService extends ChangeNotifier {
|
||||
_requireLongPress = _prefs!.getBool(_keyRequireLongPress) ?? true;
|
||||
_showBreathGate = _prefs!.getBool(_keyShowBreathGate) ?? true;
|
||||
_requireWordChallenge = _prefs!.getBool(_keyRequireWordChallenge) ?? true;
|
||||
_breathGateSeconds = (_prefs!.getInt(_keyBreathGateSeconds) ?? 10)
|
||||
.clamp(3, 60)
|
||||
.toInt();
|
||||
_wordChallengeCount = _normaliseWordChallengeCount(
|
||||
_prefs!.getInt(_keyWordChallengeCount) ?? 30,
|
||||
);
|
||||
_enableTextSelection = _prefs!.getBool(_keyEnableTextSelection) ?? false;
|
||||
_showInstaSettings = _prefs!.getBool(_keyShowInstaSettings) ?? true;
|
||||
_blockAutoplay = _prefs!.getBool(_keyBlockAutoplay) ?? true;
|
||||
|
||||
_grayscaleEnabled = _prefs!.getBool(_keyGrayscaleEnabled) ?? false;
|
||||
|
||||
// Extras (Phase 2) - defaults OFF for safety/non-invasive behavior
|
||||
_videoDownloadEnabled = _prefs!.getBool(_keyVideoDownloadEnabled) ?? false;
|
||||
_hideSuggestedPosts = _prefs!.getBool(_keyHideSuggestedPosts) ?? false;
|
||||
|
||||
// ── FocusGram v2 overlay toggles ─────────────────────────────────────────
|
||||
_v2GhostModeEnabled = _prefs!.getBool(_keyV2GhostModeEnabled) ?? false;
|
||||
_v2AdBlockerDomEnabled =
|
||||
_prefs!.getBool(_keyV2AdBlockerDomEnabled) ?? false;
|
||||
_v2ContentHiderEnabled =
|
||||
_prefs!.getBool(_keyV2ContentHiderEnabled) ?? false;
|
||||
|
||||
_contentStories = _prefs!.getBool(_keyContentStories) ?? false;
|
||||
_contentPosts = _prefs!.getBool(_keyContentPosts) ?? false;
|
||||
_contentReels = _prefs!.getBool(_keyContentReels) ?? false;
|
||||
_contentSuggested = _prefs!.getBool(_keyContentSuggested) ?? false;
|
||||
_hideSuggestedPosts = _prefs!.getBool(_keyHideSuggestedPosts) ?? false;
|
||||
|
||||
// Load grayscale schedules
|
||||
final schedulesJson = _prefs!.getString(_keyGrayscaleSchedules);
|
||||
if (schedulesJson != null) {
|
||||
try {
|
||||
_grayscaleSchedules = List<Map<String, dynamic>>.from(
|
||||
(jsonDecode(schedulesJson) as List).map((e) => Map<String, dynamic>.from(e))
|
||||
(jsonDecode(schedulesJson) as List).map(
|
||||
(e) => Map<String, dynamic>.from(e),
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
_grayscaleSchedules = [];
|
||||
}
|
||||
}
|
||||
|
||||
_hideSponsoredPosts = _prefs!.getBool(_keyHideSponsoredPosts) ?? false;
|
||||
_hideLikeCounts = _prefs!.getBool(_keyHideLikeCounts) ?? false;
|
||||
_hideFollowerCounts = _prefs!.getBool(_keyHideFollowerCounts) ?? false;
|
||||
_hideShopTab = _prefs!.getBool(_keyHideShopTab) ?? false;
|
||||
|
||||
// Load minimal mode
|
||||
_minimalModeEnabled = _prefs!.getBool(_keyMinimalModeEnabled) ?? false;
|
||||
|
||||
|
||||
// Load previous states for smart restore
|
||||
_prevDisableReels = _prefs!.getBool(_keyMinimalModePrevDisableReels) ?? false;
|
||||
_prevDisableExplore = _prefs!.getBool(_keyMinimalModePrevDisableExplore) ?? false;
|
||||
_prevDisableReels =
|
||||
_prefs!.getBool(_keyMinimalModePrevDisableReels) ?? false;
|
||||
_prevDisableExplore =
|
||||
_prefs!.getBool(_keyMinimalModePrevDisableExplore) ?? false;
|
||||
_prevBlurExplore = _prefs!.getBool(_keyMinimalModePrevBlurExplore) ?? false;
|
||||
_prevBlockHomeFeedScroll =
|
||||
_prefs!.getBool(_keyMinimalModePrevBlockHomeFeedScroll) ?? false;
|
||||
|
||||
// These are now internal states, not user-facing settings
|
||||
_disableReelsEntirely = _prefs!.getBool('internal_disable_reels_entirely') ?? false;
|
||||
_disableExploreEntirely = _prefs!.getBool('internal_disable_explore_entirely') ?? false;
|
||||
_disableReelsEntirely =
|
||||
_prefs!.getBool('internal_disable_reels_entirely') ?? false;
|
||||
_disableExploreEntirely =
|
||||
_prefs!.getBool('internal_disable_explore_entirely') ?? false;
|
||||
_blockHomeFeedScroll =
|
||||
_prefs!.getBool('internal_block_home_feed_scroll') ?? false;
|
||||
|
||||
_reelsHistoryEnabled = _prefs!.getBool(_keyReelsHistoryEnabled) ?? true;
|
||||
|
||||
// Focus mode settings
|
||||
_ghostMode = _prefs!.getBool(_keyGhostMode) ?? false;
|
||||
_noAds = _prefs!.getBool(_keyNoAds) ?? false;
|
||||
_noStories = _prefs!.getBool(_keyNoStories) ?? false;
|
||||
_noReels = _prefs!.getBool(_keyNoReels) ?? false;
|
||||
_noAutoplay = _prefs!.getBool(_keyNoAutoplay) ?? false;
|
||||
_noDMs = _prefs!.getBool(_keyNoDMs) ?? false;
|
||||
|
||||
_sanitizeLinks = _prefs!.getBool(_keySanitizeLinks) ?? true;
|
||||
_notifyDMs = _prefs!.getBool(_keyNotifyDMs) ?? false;
|
||||
_notifyActivity = _prefs!.getBool(_keyNotifyActivity) ?? false;
|
||||
@@ -245,12 +362,12 @@ class SettingsService extends ChangeNotifier {
|
||||
|
||||
Future<void> setBlurExplore(bool v) async {
|
||||
_blurExplore = v;
|
||||
// Sync blur explore with blur reels - enabling one enables the other
|
||||
if (v && !_blurReels) {
|
||||
_blurReels = true;
|
||||
await _prefs?.setBool(_keyBlurReels, true);
|
||||
}
|
||||
await _prefs?.setBool(_keyBlurExplore, v);
|
||||
|
||||
if (_minimalModeEnabled) {
|
||||
await _checkAndAutoDisableMinimalMode();
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -289,6 +406,30 @@ class SettingsService extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setBreathGateSeconds(int seconds) async {
|
||||
_breathGateSeconds = seconds.clamp(3, 60).toInt();
|
||||
await _prefs?.setInt(_keyBreathGateSeconds, _breathGateSeconds);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setWordChallengeCount(int count) async {
|
||||
_wordChallengeCount = _normaliseWordChallengeCount(count);
|
||||
await _prefs?.setInt(_keyWordChallengeCount, _wordChallengeCount);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
int resolvedWordChallengeCount() {
|
||||
if (_wordChallengeCount != 0) return _wordChallengeCount;
|
||||
final now = DateTime.now().microsecondsSinceEpoch;
|
||||
return 10 + (now % 26);
|
||||
}
|
||||
|
||||
static int _normaliseWordChallengeCount(int count) {
|
||||
if (count == 0) return 0;
|
||||
const allowed = [20, 25, 30, 35];
|
||||
return allowed.contains(count) ? count : 30;
|
||||
}
|
||||
|
||||
Future<void> setEnableTextSelection(bool v) async {
|
||||
_enableTextSelection = v;
|
||||
await _prefs?.setBool(_keyEnableTextSelection, v);
|
||||
@@ -307,13 +448,29 @@ class SettingsService extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// ── Extras (Phase 2) ──────────────────────────────────────────────────────
|
||||
|
||||
Future<void> setVideoDownloadEnabled(bool v) async {
|
||||
_videoDownloadEnabled = v;
|
||||
await _prefs?.setBool(_keyVideoDownloadEnabled, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setHideSuggestedPosts(bool v) async {
|
||||
_hideSuggestedPosts = v;
|
||||
await _prefs?.setBool(_keyHideSuggestedPosts, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setGrayscaleEnabled(bool v) async {
|
||||
_grayscaleEnabled = v;
|
||||
await _prefs?.setBool(_keyGrayscaleEnabled, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setGrayscaleSchedules(List<Map<String, dynamic>> schedules) async {
|
||||
Future<void> setGrayscaleSchedules(
|
||||
List<Map<String, dynamic>> schedules,
|
||||
) async {
|
||||
_grayscaleSchedules = schedules;
|
||||
await _prefs?.setString(_keyGrayscaleSchedules, jsonEncode(schedules));
|
||||
notifyListeners();
|
||||
@@ -321,14 +478,23 @@ class SettingsService extends ChangeNotifier {
|
||||
|
||||
Future<void> addGrayscaleSchedule(Map<String, dynamic> schedule) async {
|
||||
_grayscaleSchedules.add(schedule);
|
||||
await _prefs?.setString(_keyGrayscaleSchedules, jsonEncode(_grayscaleSchedules));
|
||||
await _prefs?.setString(
|
||||
_keyGrayscaleSchedules,
|
||||
jsonEncode(_grayscaleSchedules),
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> updateGrayscaleSchedule(int index, Map<String, dynamic> schedule) async {
|
||||
Future<void> updateGrayscaleSchedule(
|
||||
int index,
|
||||
Map<String, dynamic> schedule,
|
||||
) async {
|
||||
if (index >= 0 && index < _grayscaleSchedules.length) {
|
||||
_grayscaleSchedules[index] = schedule;
|
||||
await _prefs?.setString(_keyGrayscaleSchedules, jsonEncode(_grayscaleSchedules));
|
||||
await _prefs?.setString(
|
||||
_keyGrayscaleSchedules,
|
||||
jsonEncode(_grayscaleSchedules),
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
@@ -336,20 +502,76 @@ class SettingsService extends ChangeNotifier {
|
||||
Future<void> removeGrayscaleSchedule(int index) async {
|
||||
if (index >= 0 && index < _grayscaleSchedules.length) {
|
||||
_grayscaleSchedules.removeAt(index);
|
||||
await _prefs?.setString(_keyGrayscaleSchedules, jsonEncode(_grayscaleSchedules));
|
||||
await _prefs?.setString(
|
||||
_keyGrayscaleSchedules,
|
||||
jsonEncode(_grayscaleSchedules),
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setHideSponsoredPosts(bool v) async {
|
||||
_hideSponsoredPosts = v;
|
||||
await _prefs?.setBool(_keyHideSponsoredPosts, v);
|
||||
Future<void> setHideShopTab(bool v) async {
|
||||
_hideShopTab = v;
|
||||
await _prefs?.setBool(_keyHideShopTab, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setHideLikeCounts(bool v) async {
|
||||
_hideLikeCounts = v;
|
||||
await _prefs?.setBool(_keyHideLikeCounts, v);
|
||||
// ── FocusGram v2 overlay setters ──────────────────────────────────────────
|
||||
Future<void> setV2GhostModeEnabled(bool v) async {
|
||||
_v2GhostModeEnabled = v;
|
||||
await _prefs?.setBool(_keyV2GhostModeEnabled, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setV2AdBlockerDomEnabled(bool v) async {
|
||||
_v2AdBlockerDomEnabled = v;
|
||||
await _prefs?.setBool(_keyV2AdBlockerDomEnabled, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setV2ContentHiderEnabled(bool v) async {
|
||||
_v2ContentHiderEnabled = v;
|
||||
await _prefs?.setBool(_keyV2ContentHiderEnabled, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setContentStoriesEnabled(bool v) async {
|
||||
if (v && !_v2ContentHiderEnabled) {
|
||||
_v2ContentHiderEnabled = true;
|
||||
await _prefs?.setBool(_keyV2ContentHiderEnabled, true);
|
||||
}
|
||||
_contentStories = v;
|
||||
await _prefs?.setBool(_keyContentStories, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setContentPostsEnabled(bool v) async {
|
||||
if (v && !_v2ContentHiderEnabled) {
|
||||
_v2ContentHiderEnabled = true;
|
||||
await _prefs?.setBool(_keyV2ContentHiderEnabled, true);
|
||||
}
|
||||
_contentPosts = v;
|
||||
await _prefs?.setBool(_keyContentPosts, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setContentReelsEnabled(bool v) async {
|
||||
if (v && !_v2ContentHiderEnabled) {
|
||||
_v2ContentHiderEnabled = true;
|
||||
await _prefs?.setBool(_keyV2ContentHiderEnabled, true);
|
||||
}
|
||||
_contentReels = v;
|
||||
await _prefs?.setBool(_keyContentReels, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setContentSuggestedEnabled(bool v) async {
|
||||
if (v && !_v2ContentHiderEnabled) {
|
||||
_v2ContentHiderEnabled = true;
|
||||
await _prefs?.setBool(_keyV2ContentHiderEnabled, true);
|
||||
}
|
||||
_contentSuggested = v;
|
||||
await _prefs?.setBool(_keyContentSuggested, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -359,62 +581,138 @@ class SettingsService extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setHideShopTab(bool v) async {
|
||||
_hideShopTab = v;
|
||||
await _prefs?.setBool(_keyHideShopTab, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Setter for internal disable reels state (used by minimal mode submenu)
|
||||
/// Auto-disables minimal mode if all features are turned off
|
||||
Future<void> setDisableReelsEntirelyInternal(bool v) async {
|
||||
_disableReelsEntirely = v;
|
||||
await _prefs?.setBool('internal_disable_reels_entirely', v);
|
||||
|
||||
// Check if minimal mode should auto-disable
|
||||
await _checkAndAutoDisableMinimalMode();
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Setter for internal disable explore state (used by minimal mode submenu)
|
||||
/// Auto-disables minimal mode if all features are turned off
|
||||
Future<void> setDisableExploreEntirelyInternal(bool v) async {
|
||||
_disableExploreEntirely = v;
|
||||
await _prefs?.setBool('internal_disable_explore_entirely', v);
|
||||
|
||||
// Check if minimal mode should auto-disable
|
||||
await _checkAndAutoDisableMinimalMode();
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Setter for home feed scroll blocking state (used by minimal mode submenu).
|
||||
Future<void> setBlockHomeFeedScrollInternal(bool v) async {
|
||||
_blockHomeFeedScroll = v;
|
||||
await _prefs?.setBool('internal_block_home_feed_scroll', v);
|
||||
|
||||
await _checkAndAutoDisableMinimalMode();
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Helper: Auto-disable minimal mode if all its features are disabled
|
||||
/// This ensures minimal mode auto-turns-off when user disables all sub-features
|
||||
///
|
||||
/// NOTE: We must check the RAW state variables here, NOT the public getters
|
||||
/// (disableReelsEntirely/disableExploreEntirely), because those getters
|
||||
/// unconditionally return true when _minimalModeEnabled is true, which would
|
||||
/// make the "all disabled" condition impossible to reach.
|
||||
Future<void> _checkAndAutoDisableMinimalMode() async {
|
||||
if (!_minimalModeEnabled) return;
|
||||
|
||||
// Check the RAW saved state, not the getters
|
||||
final rawReels =
|
||||
_prefs?.getBool('internal_disable_reels_entirely') ??
|
||||
_disableReelsEntirely;
|
||||
final rawExplore =
|
||||
_prefs?.getBool('internal_disable_explore_entirely') ??
|
||||
_disableExploreEntirely;
|
||||
|
||||
final rawHomeFeedScroll =
|
||||
_prefs?.getBool('internal_block_home_feed_scroll') ??
|
||||
_blockHomeFeedScroll;
|
||||
|
||||
final allDisabled =
|
||||
!rawReels && !rawExplore && !rawHomeFeedScroll && !_blurExplore;
|
||||
|
||||
if (allDisabled) {
|
||||
_minimalModeEnabled = false;
|
||||
await _prefs?.setBool(_keyMinimalModeEnabled, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Smart minimal mode toggle with state preservation
|
||||
Future<void> setMinimalModeEnabled(bool v) async {
|
||||
if (v) {
|
||||
// Turning ON - save current states BEFORE enabling minimal mode
|
||||
// ── Turning ON ──────────────────────────────────────────────────────────
|
||||
// Save current pre-minimal-mode states so we can restore them later
|
||||
_prevDisableReels = _disableReelsEntirely;
|
||||
_prevDisableExplore = _disableExploreEntirely;
|
||||
_prevBlurExplore = _blurExplore;
|
||||
|
||||
_prevBlockHomeFeedScroll = _blockHomeFeedScroll;
|
||||
|
||||
await _prefs?.setBool(_keyMinimalModePrevDisableReels, _prevDisableReels);
|
||||
await _prefs?.setBool(_keyMinimalModePrevDisableExplore, _prevDisableExplore);
|
||||
await _prefs?.setBool(
|
||||
_keyMinimalModePrevDisableExplore,
|
||||
_prevDisableExplore,
|
||||
);
|
||||
await _prefs?.setBool(_keyMinimalModePrevBlurExplore, _prevBlurExplore);
|
||||
|
||||
// Enable all minimal mode settings
|
||||
await _prefs?.setBool(
|
||||
_keyMinimalModePrevBlockHomeFeedScroll,
|
||||
_prevBlockHomeFeedScroll,
|
||||
);
|
||||
|
||||
_minimalModeEnabled = true;
|
||||
_disableReelsEntirely = true;
|
||||
_disableExploreEntirely = true;
|
||||
_blurExplore = true;
|
||||
|
||||
_blockHomeFeedScroll = true;
|
||||
_blurExplore = true; // blurExplore is controlled by minimal mode while ON
|
||||
|
||||
await _prefs?.setBool(_keyMinimalModeEnabled, true);
|
||||
await _prefs?.setBool('internal_disable_reels_entirely', true);
|
||||
await _prefs?.setBool('internal_disable_explore_entirely', true);
|
||||
await _prefs?.setBool('internal_block_home_feed_scroll', true);
|
||||
await _prefs?.setBool(_keyBlurExplore, true);
|
||||
} else {
|
||||
// Turning OFF - restore to PREVIOUS states (before minimal mode was turned on)
|
||||
// ── Turning OFF ─────────────────────────────────────────────────────────
|
||||
// Restore states that were saved BEFORE minimal mode was enabled.
|
||||
// _prevDisableReels/Explore were saved at the moment minimal mode turned ON.
|
||||
_minimalModeEnabled = false;
|
||||
|
||||
// Simply restore to the states that were saved BEFORE minimal mode was enabled
|
||||
_disableReelsEntirely = _prevDisableReels;
|
||||
_disableExploreEntirely = _prevDisableExplore;
|
||||
_blockHomeFeedScroll = _prevBlockHomeFeedScroll;
|
||||
// For blurExplore: use _prevBlurExplore if it was saved, otherwise fall back
|
||||
// to the saved prefs value (covers the case where no prev was saved).
|
||||
_blurExplore = _prevBlurExplore;
|
||||
|
||||
// Save the restored states
|
||||
|
||||
await _prefs?.setBool(_keyMinimalModeEnabled, false);
|
||||
await _prefs?.setBool('internal_disable_reels_entirely', _disableReelsEntirely);
|
||||
await _prefs?.setBool('internal_disable_explore_entirely', _disableExploreEntirely);
|
||||
await _prefs?.setBool(
|
||||
'internal_disable_reels_entirely',
|
||||
_disableReelsEntirely,
|
||||
);
|
||||
await _prefs?.setBool(
|
||||
'internal_disable_explore_entirely',
|
||||
_disableExploreEntirely,
|
||||
);
|
||||
await _prefs?.setBool(
|
||||
'internal_block_home_feed_scroll',
|
||||
_blockHomeFeedScroll,
|
||||
);
|
||||
await _prefs?.setBool(_keyBlurExplore, _blurExplore);
|
||||
|
||||
// After restoring, check whether the user had ALL minimal features OFF
|
||||
// already — if so, minimal mode should stay off (no-op).
|
||||
if (!_disableReelsEntirely &&
|
||||
!_disableExploreEntirely &&
|
||||
!_blockHomeFeedScroll &&
|
||||
!_blurExplore) {
|
||||
// All features are off — minimal mode correctly stays off. No action needed.
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -441,24 +739,69 @@ class SettingsService extends ChangeNotifier {
|
||||
Future<void> setNotifyDMs(bool v) async {
|
||||
_notifyDMs = v;
|
||||
await _prefs?.setBool(_keyNotifyDMs, v);
|
||||
if (v) await NotificationService().requestPermissionsNow();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNotifyActivity(bool v) async {
|
||||
_notifyActivity = v;
|
||||
await _prefs?.setBool(_keyNotifyActivity, v);
|
||||
if (v) await NotificationService().requestPermissionsNow();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNotifySessionEnd(bool v) async {
|
||||
_notifySessionEnd = v;
|
||||
await _prefs?.setBool(_keyNotifySessionEnd, v);
|
||||
if (v) await NotificationService().requestPermissionsNow();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNotifyPersistent(bool v) async {
|
||||
_notifyPersistent = v;
|
||||
await _prefs?.setBool(_keyNotifyPersistent, v);
|
||||
if (v) {
|
||||
await NotificationService().requestPermissionsNow();
|
||||
} else {
|
||||
await NotificationService().cancelPersistentNotification(id: 5001);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// ── Focus mode settings ──────────────────────────────────────────────────────
|
||||
Future<void> setGhostMode(bool v) async {
|
||||
_ghostMode = v;
|
||||
await _prefs?.setBool(_keyGhostMode, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNoAds(bool v) async {
|
||||
_noAds = v;
|
||||
await _prefs?.setBool(_keyNoAds, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNoStories(bool v) async {
|
||||
_noStories = v;
|
||||
await _prefs?.setBool(_keyNoStories, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNoReels(bool v) async {
|
||||
_noReels = v;
|
||||
await _prefs?.setBool(_keyNoReels, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNoAutoplay(bool v) async {
|
||||
_noAutoplay = v;
|
||||
await _prefs?.setBool(_keyNoAutoplay, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setNoDMs(bool v) async {
|
||||
_noDMs = v;
|
||||
await _prefs?.setBool(_keyNoDMs, v);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user