feat: settings screen, haptic toggle, rain/lightning toggles, review docs
This commit is contained in:
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:revoltvpn/logic/app_colors.dart';
|
||||
import 'package:revoltvpn/screens/settings/in_settings/haptic.dart';
|
||||
import 'package:revoltvpn/screens/settings/in_settings/rain.dart';
|
||||
import 'package:revoltvpn/screens/settings/in_settings/lightning.dart';
|
||||
|
||||
// ── lib/screens/settings/settings_screen.dart ────────────────────────────────
|
||||
// Settings shell — full-screen page reached from the sidebar.
|
||||
//
|
||||
// Folder layout:
|
||||
// lib/screens/settings/ ← this folder: settings family
|
||||
// settings_screen.dart ← shell: Scaffold + AppBar + ListView (this file)
|
||||
// *_tile.dart ← one file per setting feature (add below)
|
||||
// lib/components/sidebar_contents/
|
||||
// settings.dart ← thin sidebar row that navigates here
|
||||
//
|
||||
// To add a setting:
|
||||
// 1. Create a new file in this folder, e.g. appearance_tile.dart
|
||||
// 2. Import it below
|
||||
// 3. Append it to the children list
|
||||
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
const SettingsScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.bgDeep,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColors.bgSurface,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: AppColors.textWhite),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
title: const Text(
|
||||
'Settings',
|
||||
style: TextStyle(
|
||||
color: AppColors.textWhite,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
children: const [
|
||||
HapticFeedbackTile(),
|
||||
RainToggleTile(),
|
||||
LightningToggleTile(),
|
||||
// ── Add setting tiles here ────────────────────────────────────────
|
||||
// Each tile imports from its own file in this folder.
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user