230 lines
7.8 KiB
Dart
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),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|