Changed questions, added export.
This commit is contained in:
parent
a83bf0d533
commit
78618aed9a
8 changed files with 277 additions and 173 deletions
|
|
@ -26,4 +26,5 @@
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
String proxyURL = "https://laserscouter.halfheart.net/";
|
String proxyURL = "https://laserproxy.halfheart.net/";
|
||||||
|
|
||||||
class TeamSearchResult {
|
class TeamSearchResult {
|
||||||
final List<String> eventNames;
|
final List<String> eventNames;
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,9 @@ final ThemeData laserTheme = ThemeData(
|
||||||
|
|
||||||
sliderTheme: SliderThemeData(
|
sliderTheme: SliderThemeData(
|
||||||
activeTrackColor: const Color(0xFF00245D),
|
activeTrackColor: const Color(0xFF00245D),
|
||||||
thumbColor: const Color(0xFF00245D),
|
thumbColor: const Color(0xFFFFFFFF),
|
||||||
inactiveTrackColor: Colors.grey.shade800,
|
inactiveTrackColor: Colors.grey.shade800,
|
||||||
|
valueIndicatorColor: Colors.white
|
||||||
),
|
),
|
||||||
|
|
||||||
checkboxTheme: CheckboxThemeData(
|
checkboxTheme: CheckboxThemeData(
|
||||||
|
|
@ -101,7 +102,7 @@ final ThemeData laserTheme = ThemeData(
|
||||||
switchTheme: SwitchThemeData(
|
switchTheme: SwitchThemeData(
|
||||||
thumbColor: WidgetStateProperty.resolveWith((states) {
|
thumbColor: WidgetStateProperty.resolveWith((states) {
|
||||||
if (states.contains(WidgetState.selected)) {
|
if (states.contains(WidgetState.selected)) {
|
||||||
return const Color(0xFF00245D);
|
return const Color(0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
enum ScoutingView { match, pit }
|
||||||
|
|
||||||
class NotesPage extends StatefulWidget {
|
class NotesPage extends StatefulWidget {
|
||||||
final String teamCode;
|
final String teamCode;
|
||||||
final String eventCode;
|
final String eventCode;
|
||||||
|
|
@ -18,10 +20,19 @@ class NotesPage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NotesPageState extends State<NotesPage> {
|
class _NotesPageState extends State<NotesPage> {
|
||||||
final TextEditingController _checkboxes = TextEditingController();
|
late SharedPreferences _prefs;
|
||||||
final TextEditingController _controller2 = TextEditingController();
|
ScoutingView _selectedView = ScoutingView.match;
|
||||||
final TextEditingController _switchvalue = TextEditingController();
|
bool _isLoading = true;
|
||||||
double _slidervalue = 0.0;
|
|
||||||
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -31,40 +42,50 @@ class _NotesPageState extends State<NotesPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_saveNotes();
|
_autonRundownController.dispose();
|
||||||
_checkboxes.dispose();
|
_botPositionController.dispose();
|
||||||
_controller2.dispose();
|
_driveTrainTypeController.dispose();
|
||||||
_switchvalue.dispose();
|
_generalObservationsController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _generateKey(String field) {
|
||||||
|
return '${widget.teamCode}_${widget.eventCode}_$field';
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _loadNotes() async {
|
Future<void> _loadNotes() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
_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) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_checkboxes.text =
|
_isLoading = false;
|
||||||
prefs.getString('${widget.teamCode}_${widget.eventCode}_note1') ?? '';
|
|
||||||
_controller2.text =
|
|
||||||
prefs.getString('${widget.teamCode}_${widget.eventCode}_note2') ?? '';
|
|
||||||
_switchvalue.text =
|
|
||||||
prefs.getString('${widget.teamCode}_${widget.eventCode}_note3') ?? '';
|
|
||||||
_slidervalue = double.tryParse(prefs
|
|
||||||
.getString('${widget.teamCode}_${widget.eventCode}_note4') ??
|
|
||||||
'0.0') ?? 0.0;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _saveNotes() async {
|
Future<void> _saveString(String field, String value) async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
await _prefs.setString(_generateKey(field), value);
|
||||||
await prefs.setString(
|
}
|
||||||
'${widget.teamCode}_${widget.eventCode}_note1', _checkboxes.text);
|
|
||||||
await prefs.setString(
|
Future<void> _saveBool(String field, bool value) async {
|
||||||
'${widget.teamCode}_${widget.eventCode}_note2', _controller2.text);
|
await _prefs.setBool(_generateKey(field), value);
|
||||||
await prefs.setString(
|
}
|
||||||
'${widget.teamCode}_${widget.eventCode}_note3', _switchvalue.text);
|
|
||||||
await prefs.setString(
|
Future<void> _saveDouble(String field, double value) async {
|
||||||
'${widget.teamCode}_${widget.eventCode}_note4', _slidervalue.toString());
|
await _prefs.setDouble(_generateKey(field), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -73,108 +94,166 @@ class _NotesPageState extends State<NotesPage> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Notes'),
|
title: Text('Notes'),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: _isLoading
|
||||||
padding: const EdgeInsets.all(16.0),
|
? const Center(child: CircularProgressIndicator())
|
||||||
child: ListView(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(widget.teamName, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center),
|
Padding(
|
||||||
Text('Bot Starting Position',
|
padding: const EdgeInsets.only(top: 16.0),
|
||||||
style: Theme.of(context).textTheme.titleMedium),
|
child: Text(widget.teamName, style: Theme.of(context).textTheme.titleLarge)
|
||||||
CheckboxListTile(
|
),
|
||||||
title: const Text('Left'),
|
Padding(
|
||||||
value: _checkboxes.text.contains('Left'),
|
padding: const EdgeInsets.all(16.0),
|
||||||
onChanged: (bool? value) {
|
child: SegmentedButton<ScoutingView>(
|
||||||
|
segments: const [
|
||||||
|
ButtonSegment(value: ScoutingView.match, label: Text('Match Scouting')),
|
||||||
|
ButtonSegment(value: ScoutingView.pit, label: Text('Pit Scouting')),
|
||||||
|
],
|
||||||
|
selected: {_selectedView},
|
||||||
|
onSelectionChanged: (newSelection) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (value == true) {
|
_selectedView = newSelection.first;
|
||||||
_checkboxes.text += 'Left ';
|
|
||||||
} else {
|
|
||||||
_checkboxes.text =
|
|
||||||
_checkboxes.text.replaceAll('Left ', '');
|
|
||||||
}
|
|
||||||
_saveNotes();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
CheckboxListTile(
|
),
|
||||||
title: const Text('Mid'),
|
Expanded(
|
||||||
value: _checkboxes.text.contains('Mid'),
|
child: AnimatedSwitcher(
|
||||||
onChanged: (bool? value) {
|
duration: const Duration(milliseconds: 300),
|
||||||
setState(() {
|
child: _selectedView == ScoutingView.match
|
||||||
if (value == true) {
|
? _buildMatchScoutingView()
|
||||||
_checkboxes.text += 'Mid ';
|
: _buildPitScoutingView(),
|
||||||
} else {
|
|
||||||
_checkboxes.text = _checkboxes.text.replaceAll('Mid ', '');
|
|
||||||
}
|
|
||||||
_saveNotes();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
CheckboxListTile(
|
),
|
||||||
title: const Text('Right'),
|
],
|
||||||
value: _checkboxes.text.contains('Right'),
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
if (value == true) {
|
|
||||||
_checkboxes.text += 'Right ';
|
|
||||||
} else {
|
|
||||||
_checkboxes.text =
|
|
||||||
_checkboxes.text.replaceAll('Right ', '');
|
|
||||||
}
|
|
||||||
_saveNotes();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
TextField(
|
|
||||||
controller: _controller2,
|
|
||||||
decoration: const InputDecoration(labelText: 'Auton Rundown'),
|
|
||||||
maxLines: null,
|
|
||||||
keyboardType: TextInputType.multiline,
|
|
||||||
onChanged: (text) => _saveNotes(),
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: const Text('Can Score Algae'),
|
|
||||||
value: _switchvalue.text.contains('Can Score Algae'),
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
_switchvalue.text =
|
|
||||||
value == true ? 'Can Score Algae' : '';
|
|
||||||
_saveNotes();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: const Text('Cannot Score Algae'),
|
|
||||||
value: _switchvalue.text.contains('Cannot Score Algae'),
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
_switchvalue.text =
|
|
||||||
value == true ? 'Cannot Score Algae' : '';
|
|
||||||
_saveNotes();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
Text('Coral Level', style: Theme.of(context).textTheme.titleMedium),
|
|
||||||
Slider(
|
|
||||||
value: _slidervalue,
|
|
||||||
onChanged: (double value) {
|
|
||||||
setState(() {
|
|
||||||
_slidervalue = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onChangeEnd: (double value) {
|
|
||||||
_saveNotes();
|
|
||||||
},
|
|
||||||
min: 0,
|
|
||||||
max: 3,
|
|
||||||
divisions: 3,
|
|
||||||
label: _slidervalue.round().toString(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
controller: _urlController,
|
controller: _urlController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'URL',
|
labelText: 'URL',
|
||||||
hintText: 'https://laserscouter.halfheart.net/',
|
hintText: 'https://laserproxy.halfheart.net/',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Color.fromARGB(255, 19, 81, 179)),
|
borderSide: BorderSide(color: Color.fromARGB(255, 19, 81, 179)),
|
||||||
|
|
@ -64,7 +64,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
),
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
proxyURL = "https://laserscouter.halfheart.net/";
|
proxyURL = "https://laserproxy.halfheart.net/";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
proxyURL = value;
|
proxyURL = value;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:laserscouter/core/api.dart';
|
import 'package:laserscouter/core/api.dart';
|
||||||
|
import 'notespage.dart';
|
||||||
|
import 'package:to_csv/to_csv.dart' as csv_export;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:to_csv/to_csv.dart' as exportcsv;
|
|
||||||
import 'notespage.dart'; // Import the new notes page file
|
|
||||||
|
|
||||||
class TeamPicker extends StatefulWidget {
|
class TeamPicker extends StatefulWidget {
|
||||||
final String eventCode;
|
final String eventCode;
|
||||||
|
|
@ -22,16 +23,67 @@ class _TeamPickerState extends State<TeamPicker> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// Call the new async method to fetch teams
|
|
||||||
_fetchTeams();
|
_fetchTeams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _exportData() async {
|
||||||
|
List<String> header = [];
|
||||||
|
header.add('Team Number');
|
||||||
|
header.add('Drivetrain Type');
|
||||||
|
header.add('Has Vision');
|
||||||
|
header.add('Climb Level');
|
||||||
|
header.add('Trenchable');
|
||||||
|
header.add('Fuel Capacity');
|
||||||
|
header.add('Bot Position');
|
||||||
|
header.add('Auton Rundown');
|
||||||
|
header.add('General Observations');
|
||||||
|
|
||||||
|
List<List<String>> data = [];
|
||||||
|
for (int i = 0; i < teamCodes.length; i++) {
|
||||||
|
String generateKey(String field) {
|
||||||
|
return '${teamCodes[i]}_${widget.eventCode}_$field';
|
||||||
|
}
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
String? autonRundown = prefs.getString(generateKey('autonRundown'));
|
||||||
|
String? botPosition = prefs.getString(generateKey('botPosition'));
|
||||||
|
String? generalObservations = prefs.getString(generateKey('generalObservations'));
|
||||||
|
String? driveTrainType = prefs.getString(generateKey('driveTrainType'));
|
||||||
|
String? hasVision = prefs.getBool(generateKey('hasVision')).toString();
|
||||||
|
String? climbLevel = prefs.getDouble(generateKey('climbLevel')).toString();
|
||||||
|
String? trenchable = prefs.getBool(generateKey('trenchable')).toString();
|
||||||
|
String? fuelCapacity = prefs.getDouble(generateKey('fuelCapacity')).toString();
|
||||||
|
|
||||||
|
if (hasVision == 'null') {
|
||||||
|
hasVision = '';
|
||||||
|
}
|
||||||
|
if (climbLevel == 'null') {
|
||||||
|
climbLevel = '';
|
||||||
|
}
|
||||||
|
if (trenchable == 'null') {
|
||||||
|
trenchable = '';
|
||||||
|
}
|
||||||
|
if (fuelCapacity == 'null') {
|
||||||
|
fuelCapacity = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> teamData = [];
|
||||||
|
teamData.add(teamCodes[i]);
|
||||||
|
teamData.add(driveTrainType ?? '');
|
||||||
|
teamData.add(hasVision);
|
||||||
|
teamData.add(climbLevel);
|
||||||
|
teamData.add(trenchable);
|
||||||
|
teamData.add(fuelCapacity);
|
||||||
|
teamData.add(botPosition ?? '');
|
||||||
|
teamData.add(autonRundown ?? '');
|
||||||
|
teamData.add(generalObservations ?? '');
|
||||||
|
data.add(teamData);
|
||||||
|
}
|
||||||
|
csv_export.myCSV(header, data, setHeadersInFirstRow: true, emptyRowsConfig: {1: 1}, fileName: 'laserscouter_${widget.eventCode}.csv');
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _fetchTeams() async {
|
Future<void> _fetchTeams() async {
|
||||||
try {
|
try {
|
||||||
// Await the result from the refactored API function
|
|
||||||
final EventSearchResult result = await eventSearch(widget.eventCode);
|
final EventSearchResult result = await eventSearch(widget.eventCode);
|
||||||
|
|
||||||
// Check if the widget is still mounted before updating state
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
teamNames = result.teamNames;
|
teamNames = result.teamNames;
|
||||||
|
|
@ -40,7 +92,6 @@ class _TeamPickerState extends State<TeamPicker> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// If an error occurs, update the state to show an error message
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessage = "Failed to load teams. Please try again.";
|
errorMessage = "Failed to load teams. Please try again.";
|
||||||
|
|
@ -50,46 +101,17 @@ class _TeamPickerState extends State<TeamPicker> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> makeCSV() async {
|
|
||||||
List<String> header = [
|
|
||||||
'Team Number',
|
|
||||||
'Bot Position',
|
|
||||||
'Auton Rundown',
|
|
||||||
'Can Score Algae',
|
|
||||||
'Coral Level'
|
|
||||||
];
|
|
||||||
List<List<String>> dataLists = [header];
|
|
||||||
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
for (int i = 0; i < teamCodes.length; i++) {
|
|
||||||
List<String> data = [];
|
|
||||||
data.add(teamCodes[i]);
|
|
||||||
String botPosition = prefs.getString('${teamCodes[i]}_${widget.eventCode}_note1') ?? '';
|
|
||||||
String autonRundown = prefs.getString('${teamCodes[i]}_${widget.eventCode}_note2') ?? '';
|
|
||||||
String canScoreAlgae = prefs.getString('${teamCodes[i]}_${widget.eventCode}_note3') ?? '';
|
|
||||||
String coralLevel = prefs.getString('${teamCodes[i]}_${widget.eventCode}_note4') ?? '0.0';
|
|
||||||
data.add(botPosition.trim());
|
|
||||||
data.add(autonRundown);
|
|
||||||
data.add(canScoreAlgae);
|
|
||||||
data.add(coralLevel);
|
|
||||||
dataLists.add(data);
|
|
||||||
}
|
|
||||||
exportcsv.myCSV(header, dataLists, fileName: '${widget.eventCode}-scouting-data');
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Teams'),
|
title: const Text('Teams'),
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.share),
|
|
||||||
onPressed: isLoading || teamCodes.isEmpty ? null : makeCSV,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
body: _buildBody(),
|
body: _buildBody(),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: _exportData,
|
||||||
|
child: const Icon(Icons.share),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,4 +162,4 @@ class _TeamPickerState extends State<TeamPicker> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.6"
|
version: "0.15.6"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||||
|
|
@ -372,10 +372,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: objective_c
|
name: objective_c
|
||||||
sha256: "9922a1ad59ac5afb154cc948aa6ded01987a75003651d0a2866afc23f4da624e"
|
sha256: "7fd0c4d8ac8980011753b9bdaed2bf15111365924cdeeeaeb596214ea2b03537"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.2.3"
|
version: "9.2.4"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ dependencies:
|
||||||
to_csv: ^6.0.1
|
to_csv: ^6.0.1
|
||||||
flutter_launcher_icons: ^0.14.4
|
flutter_launcher_icons: ^0.14.4
|
||||||
rename_app: ^1.6.5
|
rename_app: ^1.6.5
|
||||||
|
http: ^1.6.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue