Files
Hirameki-SRS/lib/src/screens/settings_screen.dart
2025-11-01 07:50:21 +01:00

230 lines
7.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hirameki_srs/src/models/theme_model.dart';
import 'package:hirameki_srs/src/themes.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/deck_repository.dart';
import 'home_screen.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
final TextEditingController _apiKeyController = TextEditingController();
bool _playIncorrectSound = true;
bool _playCorrectSound = true;
bool _playNarrator = true;
@override
void dispose() {
_apiKeyController.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_loadSettings();
final repo = Provider.of<DeckRepository>(context, listen: false);
repo.loadApiKey().then((key) {
if (key != null) {
_apiKeyController.text = key;
}
});
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_playIncorrectSound = prefs.getBool('playIncorrectSound') ?? true;
_playCorrectSound = prefs.getBool('playCorrectSound') ?? true;
_playNarrator = prefs.getBool('playNarrator') ?? true;
});
}
Future<void> _saveApiKey() async {
final apiKey = _apiKeyController.text.trim();
if (apiKey.isEmpty) return;
final repo = Provider.of<DeckRepository>(context, listen: false);
await repo.setApiKey(apiKey);
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('API key saved!')));
Navigator.of(
context,
).pushReplacement(MaterialPageRoute(builder: (_) => const HomeScreen()));
}
}
@override
Widget build(BuildContext context) {
final themeModel = Provider.of<ThemeModel>(context);
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface,
appBar: AppBar(
title: const Text('Settings'),
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
foregroundColor: Theme.of(context).colorScheme.onSurface,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _apiKeyController,
obscureText: true,
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
decoration: InputDecoration(
labelText: 'WaniKani API Key',
labelStyle: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
filled: true,
fillColor: Theme.of(context).colorScheme.surfaceContainer,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(6),
borderSide: BorderSide(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _saveApiKey,
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
child: const Text('Save & Start Quiz'),
),
const SizedBox(height: 24),
SwitchListTile(
title: Text(
'Play incorrect sound',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
value: _playIncorrectSound,
onChanged: (value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('playIncorrectSound', value);
setState(() {
_playIncorrectSound = value;
});
},
activeThumbColor: Theme.of(context).colorScheme.primary,
inactiveThumbColor: Theme.of(
context,
).colorScheme.onSurfaceVariant,
tileColor: Theme.of(context).colorScheme.surfaceContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(height: 12),
SwitchListTile(
title: Text(
'Play correct sound',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
value: _playCorrectSound,
onChanged: (value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('playCorrectSound', value);
setState(() {
_playCorrectSound = value;
});
},
activeThumbColor: Theme.of(context).colorScheme.primary,
inactiveThumbColor: Theme.of(
context,
).colorScheme.onSurfaceVariant,
tileColor: Theme.of(context).colorScheme.surfaceContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(height: 12),
SwitchListTile(
title: Text(
'Play narrator (TTS)',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
value: _playNarrator,
onChanged: (value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('playNarrator', value);
setState(() {
_playNarrator = value;
});
},
activeThumbColor: Theme.of(context).colorScheme.primary,
inactiveThumbColor: Theme.of(
context,
).colorScheme.onSurfaceVariant,
tileColor: Theme.of(context).colorScheme.surfaceContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
const SizedBox(height: 12),
ListTile(
title: Text(
'Theme',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
trailing: DropdownButton<ThemeData>(
value: themeModel.currentTheme,
dropdownColor: Theme.of(context).colorScheme.surfaceContainer,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
items: [
DropdownMenuItem(
value: Themes.dark,
child: const Text('Dark'),
),
DropdownMenuItem(
value: Themes.light,
child: const Text('Light'),
),
DropdownMenuItem(
value: Themes.nier,
child: const Text('Nier'),
),
],
onChanged: (theme) {
if (theme != null) {
themeModel.setTheme(theme);
}
},
),
tileColor: Theme.of(context).colorScheme.surfaceContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
],
),
),
);
}
}