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 _botPositionController = TextEditingController(); final _generalObservationsController = TextEditingController(); final _autonRundownController = TextEditingController(); final _intakePositionController = TextEditingController(); final _scoreMechanisimController = TextEditingController(); double _fuelPerCycle = 0; bool _canDriveUnderTrench = false; bool _canDriveOverBump = false; double _climbLevel = 0.0; double _fuelCapacity = 0.0; bool _canGiveToHumanPlayer = false; double _cycleTime = 0.0; @override void initState() { super.initState(); _loadNotes(); } @override void dispose() { _autonRundownController.dispose(); _botPositionController.dispose(); _generalObservationsController.dispose(); _intakePositionController.dispose(); _scoreMechanisimController.dispose(); super.dispose(); } String _generateKey(String field) { return '${widget.teamCode}_${widget.eventCode}_$field'; } Future _loadNotes() async { SharedPreferences prefs = await SharedPreferences.getInstance(); _botPositionController.text = prefs.getString(_generateKey('botPosition')) ?? ''; _botPositionController.addListener(() => _saveString('botPosition', _botPositionController.text)); _generalObservationsController.text = prefs.getString(_generateKey('generalObservations')) ?? ''; _generalObservationsController.addListener(() => _saveString('generalObservations', _generalObservationsController.text)); _autonRundownController.text = prefs.getString(_generateKey('autonRundown')) ?? ''; _autonRundownController.addListener(() => _saveString('autonRundown', _autonRundownController.text)); _intakePositionController.text = prefs.getString(_generateKey('intakePosition')) ?? ''; _intakePositionController.addListener(() => _saveString('intakePosition', _intakePositionController.text)); _scoreMechanisimController.text = prefs.getString(_generateKey('scoreMechanism')) ?? ''; _scoreMechanisimController.addListener(() => _saveString('scoreMechanism', _scoreMechanisimController.text)); _fuelPerCycle = prefs.getDouble(_generateKey('fuelPerCycle')) ?? 0.0; _canDriveUnderTrench = prefs.getBool(_generateKey('canDriveUnderTrench')) ?? false; _canDriveOverBump = prefs.getBool(_generateKey('canDriveOverBump')) ?? false; _climbLevel = prefs.getDouble(_generateKey('climbLevel')) ?? 0.0; _fuelCapacity = prefs.getDouble(_generateKey('fuelCapacity')) ?? 0.0; _canGiveToHumanPlayer = prefs.getBool(_generateKey('canGiveToHumanPlayer')) ?? false; _cycleTime = prefs.getDouble(_generateKey('cycleTime')) ?? 0.0; 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()) : SafeArea( child: 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: _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: _autonRundownController, decoration: const InputDecoration( labelText: 'Autonomous Rundown', hintText: 'Describe their auto', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), SwitchListTile( title: Text('Can Drive Over Bump', style: Theme.of(context).textTheme.titleSmall), value: _canDriveOverBump, onChanged: (bool value) { setState(() { _canDriveOverBump = value; }); _saveBool('canDriveOverBump', value); }, ), SwitchListTile( title: Text('Can Go Under Trench', style: Theme.of(context).textTheme.titleSmall), value: _canDriveUnderTrench, onChanged: (bool value) { setState(() { _canDriveUnderTrench = value; }); _saveBool('canDriveUnderTrench', value); }, ), SwitchListTile( title: Text('Can Give Fuel To Human Player', style: Theme.of(context).textTheme.titleSmall), value: _canGiveToHumanPlayer, onChanged: (bool value) { setState(() { _canGiveToHumanPlayer = value; }); _saveBool('canGiveToHumanPlayer', 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); }, ), ], ), ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Fuel Per Cycle - ${_fuelPerCycle.round()}', style: Theme.of(context).textTheme.titleSmall), Slider( value: _fuelPerCycle, min: 0, max: _fuelCapacity, divisions: 50, label: _fuelPerCycle.round().toString(), onChanged: (double value) { setState(() { _fuelPerCycle = value; }); }, onChangeEnd: (double value) { _saveDouble('fuelPerCycle', value); }, ), ], ), ), const SizedBox(height: 16), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Cycle Time - ${_cycleTime.round()}', style: Theme.of(context).textTheme.titleSmall), Slider( value: _cycleTime, min: 0, max: _cycleTime, divisions: 50, label: _cycleTime.round().toString(), onChanged: (double value) { setState(() { _cycleTime = value; }); }, onChangeEnd: (double value) { _saveDouble('cycleTime', value); }, ), ], ), ), ], ); } }