feat: settings screen, haptic toggle, rain/lightning toggles, review docs

This commit is contained in:
esefxdz committed 2026-08-06 23:08:26 +03:00
1 parent 56ea53e73b
commit 04ec8ac5d1
11 files changed
+318 -3

No files matched your search

@@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:revoltvpn/logic/app_colors.dart';
// ── lib/screens/settings/in_settings/haptic.dart ────────────────────────────
// Toggle for light haptic feedback on successful connect/disconnect.
//
// Top-level bool (hapticEnabled) is read synchronously by connect_button.dart —
// no await, no SharedPreferences lookup on every tap. The tile loads the
// persisted value once and keeps the global in sync on every toggle.
//
// SharedPreferences key: haptic_feedback_enabled (default: false — off).
// lib/components/connect_button.dart reads this directly. Keep it exported.
bool hapticEnabled = false;
class HapticFeedbackTile extends StatefulWidget {
const HapticFeedbackTile({super.key});
@override
State<HapticFeedbackTile> createState() => _HapticFeedbackTileState();
}
class _HapticFeedbackTileState extends State<HapticFeedbackTile> {
bool _on = false;
@override
void initState() {
super.initState();
_load();
}
// Loads persisted state and syncs the top-level bool.
Future<void> _load() async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getBool('haptic_feedback_enabled') ?? false;
hapticEnabled = value;
if (mounted) setState(() => _on = value);
}
// Writes to SharedPreferences AND updates the live bool so the connect
// button sees the change immediately — no restart needed.
Future<void> _toggle(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('haptic_feedback_enabled', value);
hapticEnabled = value;
setState(() => _on = value);
}
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text(
'Haptic feedback',
style: TextStyle(color: AppColors.textWhite, fontSize: 15),
),
value: _on,
onChanged: _toggle,
activeTrackColor: AppColors.accent.withAlpha(80),
activeThumbColor: AppColors.accent,
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
);
}
}
@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:revoltvpn/logic/app_colors.dart';
// ── lib/screens/settings/in_settings/lightning.dart ─────────────────────────
// Toggle for the lightning strike overlay on the main screen.
//
// Same architecture as haptic.dart: exports a top-level bool read synchronously
// by lib/components/lightning.dart. Default: true (lightning is on — opt-out).
// lib/components/lightning.dart reads this in its build method.
bool lightningEnabled = true;
class LightningToggleTile extends StatefulWidget {
const LightningToggleTile({super.key});
@override
State<LightningToggleTile> createState() => _LightningToggleTileState();
}
class _LightningToggleTileState extends State<LightningToggleTile> {
bool _on = true;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getBool('lightning_effect_enabled') ?? true;
lightningEnabled = value;
if (mounted) setState(() => _on = value);
}
Future<void> _toggle(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('lightning_effect_enabled', value);
lightningEnabled = value;
setState(() => _on = value);
}
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text(
'Lightning effect',
style: TextStyle(color: AppColors.textWhite, fontSize: 15),
),
value: _on,
onChanged: _toggle,
activeTrackColor: AppColors.accent.withAlpha(80),
activeThumbColor: AppColors.accent,
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
);
}
}
@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:revoltvpn/logic/app_colors.dart';
// ── lib/screens/settings/in_settings/rain.dart ──────────────────────────────
// Toggle for the animated rain overlay on the main screen.
//
// Same architecture as haptic.dart: exports a top-level bool read synchronously
// by lib/components/rain.dart. Default: true (rain is on — opt-out).
// lib/components/rain.dart reads this in its build method.
bool rainEnabled = true;
class RainToggleTile extends StatefulWidget {
const RainToggleTile({super.key});
@override
State<RainToggleTile> createState() => _RainToggleTileState();
}
class _RainToggleTileState extends State<RainToggleTile> {
bool _on = true;
@override
void initState() {
super.initState();
_load();
}
Future<void> _load() async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getBool('rain_effect_enabled') ?? true;
rainEnabled = value;
if (mounted) setState(() => _on = value);
}
Future<void> _toggle(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('rain_effect_enabled', value);
rainEnabled = value;
setState(() => _on = value);
}
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text(
'Rain effect',
style: TextStyle(color: AppColors.textWhite, fontSize: 15),
),
value: _on,
onChanged: _toggle,
activeTrackColor: AppColors.accent.withAlpha(80),
activeThumbColor: AppColors.accent,
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
);
}
}