import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; enum ScoutingView { match, pit } class NotesPage extends StatefulWidget { final String teamCode; final String eventCode; final String teamName; const NotesPage({ super.key, required this.teamCode, required this.teamName, required this.eventCode, }); @override State createState() => _NotesPageState(); } class _NotesPageState extends State { late SharedPreferences _prefs; ScoutingView _selectedView = ScoutingView.match; bool _isLoading = true; final _autonRundownController = TextEditingController(); final _botPositionController = TextEditingController(); final _generalObservationsController = TextEditingController(); final _driveTrainTypeController = TextEditingController(); bool _hasVision = false; double _climbLevel = 100.0; bool _trenchable = false; double _fuelCapacity = 0.0; @override void initState() { super.initState(); _loadNotes(); } @override void dispose() { _autonRundownController.dispose(); _botPositionController.dispose(); _driveTrainTypeController.dispose(); _generalObservationsController.dispose(); super.dispose(); } String _generateKey(String field) { return '${widget.teamCode}_${widget.eventCode}_$field'; } Future _loadNotes() async { _prefs = await SharedPreferences.getInstance(); _autonRundownController.text = _prefs.getString(_generateKey('autonRundown')) ?? ''; _botPositionController.text = _prefs.getString(_generateKey('botPosition')) ?? ''; _generalObservationsController.text = _prefs.getString(_generateKey('generalObservations')) ?? ''; _driveTrainTypeController.text = _prefs.getString(_generateKey('driveTrainType')) ?? ''; _hasVision = _prefs.getBool(_generateKey('hasVision')) ?? false; _climbLevel = _prefs.getDouble(_generateKey('climbLevel')) ?? 0.0; _trenchable = _prefs.getBool(_generateKey('trenchable')) ?? false; _fuelCapacity = _prefs.getDouble(_generateKey('fuelCapacity')) ?? 0.0; _autonRundownController.addListener(() => _saveString('autonRundown', _autonRundownController.text)); _botPositionController.addListener(() => _saveString('botPosition', _botPositionController.text)); _driveTrainTypeController.addListener(() => _saveString('driveTrainType', _driveTrainTypeController.text)); _generalObservationsController.addListener(() => _saveString('generalObservations', _generalObservationsController.text)); if (mounted) { setState(() { _isLoading = false; }); } } Future _saveString(String field, String value) async { await _prefs.setString(_generateKey(field), value); } Future _saveBool(String field, bool value) async { await _prefs.setBool(_generateKey(field), value); } Future _saveDouble(String field, double value) async { await _prefs.setDouble(_generateKey(field), value); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Notes'), ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : Column( children: [ Padding( padding: const EdgeInsets.only(top: 16.0), child: Text(widget.teamName, style: Theme.of(context).textTheme.titleLarge) ), Padding( padding: const EdgeInsets.all(16.0), child: SegmentedButton( segments: const [ ButtonSegment(value: ScoutingView.match, label: Text('Match Scouting')), ButtonSegment(value: ScoutingView.pit, label: Text('Pit Scouting')), ], selected: {_selectedView}, onSelectionChanged: (newSelection) { setState(() { _selectedView = newSelection.first; }); }, ), ), Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: _selectedView == ScoutingView.match ? _buildMatchScoutingView() : _buildPitScoutingView(), ), ), ], ), ); } Widget _buildMatchScoutingView() { return ListView( key: const ValueKey('match'), padding: const EdgeInsets.symmetric(horizontal: 16.0), children: [ Text('Match-Specific Observations', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), TextField( controller: _botPositionController, decoration: const InputDecoration( labelText: 'Bot Position / Role', hintText: 'e.g., Shooter, Defense, Collector', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), TextField( controller: _autonRundownController, decoration: const InputDecoration( labelText: 'Autonomous Rundown', hintText: 'Describe their auto', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), TextField( controller: _generalObservationsController, decoration: const InputDecoration( labelText: 'Observations', hintText: 'General observations', border: OutlineInputBorder(), ), ) ], ); } Widget _buildPitScoutingView() { return ListView( key: const ValueKey('pit'), padding: const EdgeInsets.symmetric(horizontal: 16.0), children: [ Text('Robot Technical Details', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), TextField( controller: _driveTrainTypeController, decoration: const InputDecoration( labelText: 'Drivetrain Type', hintText: 'e.g., Swerve, Tank', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), SwitchListTile( title: Text('Has Vision/AprilTags', style: Theme.of(context).textTheme.titleSmall), value: _hasVision, onChanged: (bool value) { setState(() { _hasVision = value; }); _saveBool('hasVision', value); }, ), SwitchListTile( title: Text('Can Go Under Trench', style: Theme.of(context).textTheme.titleSmall), value: _trenchable, onChanged: (bool value) { setState(() { _trenchable = value; }); _saveBool('trenchable', value); }, ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Max Climb Level - ${_climbLevel.round()}', style: Theme.of(context).textTheme.titleSmall), Slider( value: _climbLevel, min: 0, max: 3, divisions: 3, label: _climbLevel.round().toString(), onChanged: (double value) { setState(() { _climbLevel = value; }); }, onChangeEnd: (double value) { _saveDouble('climbLevel', value); }, ), ], ), ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Fuel Capacity - ${_fuelCapacity.round()}', style: Theme.of(context).textTheme.titleSmall), Slider( value: _fuelCapacity, min: 0, max: 50, divisions: 50, label: _fuelCapacity.round().toString(), onChanged: (double value) { setState(() { _fuelCapacity = value; }); }, onChangeEnd: (double value) { _saveDouble('fuelCapacity', value); }, ), ], ), ), ], ); } }