import 'package:flutter/material.dart'; import 'package:kana_kit/kana_kit.dart'; import '../models/custom_kanji_item.dart'; import '../services/custom_deck_repository.dart'; class AddCardScreen extends StatefulWidget { const AddCardScreen({super.key}); @override State createState() => _AddCardScreenState(); } class _AddCardScreenState extends State { final _formKey = GlobalKey(); final _japaneseController = TextEditingController(); final _englishController = TextEditingController(); final _kanjiController = TextEditingController(); final _kanaKit = const KanaKit(); final _deckRepository = CustomDeckRepository(); bool _useInterval = false; late FocusNode _japaneseFocusNode; @override void initState() { super.initState(); _japaneseController.addListener(_convertToKana); _japaneseFocusNode = FocusNode(); _japaneseFocusNode.addListener(_onJapaneseFocusChange); } @override void dispose() { _japaneseController.removeListener(_convertToKana); _japaneseController.dispose(); _englishController.dispose(); _kanjiController.dispose(); _japaneseFocusNode.removeListener(_onJapaneseFocusChange); _japaneseFocusNode.dispose(); super.dispose(); } void _convertToKana() { final text = _japaneseController.text; final selection = _japaneseController.selection; final offset = selection.baseOffset; if ((offset > 1 && text[offset - 1] == 'n' && text[offset - 2] != 'n') || (offset == 1 && text[offset - 1] == 'n')) { return; } final converted = _kanaKit.toKana(text); if (converted != text) { _japaneseController.value = _japaneseController.value.copyWith( text: converted, selection: TextSelection.fromPosition( TextPosition(offset: converted.length), ), ); } } void _onJapaneseFocusChange() { if (!_japaneseFocusNode.hasFocus) { _forceNConversion(); } } void _forceNConversion() { final text = _japaneseController.text; if (text.isNotEmpty && text.endsWith('n') && _kanaKit.toKana(text) != text) { _japaneseController.text = _kanaKit.toKana(text); } } void _saveCard() { if (_formKey.currentState!.validate()) { final srsData = _useInterval ? SrsData( japaneseToEnglishNextReview: DateTime.now(), englishToJapaneseNextReview: DateTime.now(), listeningComprehensionNextReview: DateTime.now(), ) : SrsData(); final newItem = CustomKanjiItem( characters: _japaneseController.text, meaning: _englishController.text, kanji: _kanjiController.text.trim().isNotEmpty ? _kanjiController.text.trim() : null, useInterval: _useInterval, srsData: srsData, ); _deckRepository.addCard(newItem); Navigator.of(context).pop(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Add New Card')), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( children: [ TextFormField( controller: _japaneseController, focusNode: _japaneseFocusNode, decoration: const InputDecoration( labelText: 'Japanese (Kana)', hintText: 'Enter Japanese vocabulary or kanji', ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter a Japanese term'; } return null; }, ), const SizedBox(height: 16), TextFormField( controller: _kanjiController, decoration: const InputDecoration( labelText: 'Japanese (Kanji)', hintText: 'Enter the kanji (optional)', ), ), const SizedBox(height: 16), TextFormField( controller: _englishController, decoration: const InputDecoration( labelText: 'English', hintText: 'Enter the English meaning', ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter an English meaning'; } return null; }, ), const SizedBox(height: 16), SwitchListTile( title: const Text('Use Interval-based SRS'), value: _useInterval, onChanged: (value) { setState(() { _useInterval = value; }); }, ), const SizedBox(height: 32), ElevatedButton( onPressed: _saveCard, child: const Text('Save Card'), ), ], ), ), ), ); } }