Spaces:
Build error
Build error
/* | |
Right Vote - A web app for election prediction and manifesto comparison with machine learning and NLP. | |
Nilakna Warushavithana, September 2024 | |
*/ | |
import 'package:flutter/material.dart'; | |
import 'dart:ui'; | |
import 'package:http/http.dart' as http; | |
import 'dart:convert'; | |
import 'package:pie_chart/pie_chart.dart'; | |
class CompareScreenGenerator extends StatefulWidget { | |
final bool scrollToComparison; | |
const CompareScreenGenerator({super.key, this.scrollToComparison = false}); | |
_CompareScreenState createState() => _CompareScreenState(); | |
} | |
class _CompareScreenState extends State<CompareScreenGenerator> { | |
final List<Map<String, dynamic>> _comparisonData = [ | |
{ | |
"Anura": { | |
"Economy": "Pro-market policies", | |
"Healthcare": "Universal healthcare", | |
"Education": "Increase funding for schools", | |
}, | |
}, | |
{ | |
"Sajith": { | |
"Economy": "Regulation-focused", | |
"Healthcare": "Private healthcare", | |
"Education": "Voucher system", | |
}, | |
}, | |
{ | |
"Ranil": { | |
"Economy": "2-Regulation-focused", | |
"Healthcare": "2-Private healthcare", | |
"Education": "2 -Voucher system", | |
}, | |
}, | |
]; | |
late var _comparisonCategories = | |
_comparisonData[0].values.toList()[0].keys.toList(); | |
late var _comparisonNames = [ | |
_comparisonData[0], | |
_comparisonData[1], | |
_comparisonData[2] | |
].map((e) => e.keys.toList()[0]).toList(); | |
late var _comparisonContent = [ | |
_comparisonData[0].values.toList()[0].values.toList(), | |
_comparisonData[1].values.toList()[0].values.toList(), | |
_comparisonData[2].values.toList()[0].values.toList(), | |
]; | |
final _comparisonBetter = [ | |
["Candidate1", "Candidate2", "Candidate1"], | |
["Candidate2", "Candidate1", "Candidate2"], | |
]; | |
/*the following functions are used for larger group of candidates, to compare two at a time. | |
current app shows all major 3 candidates side by side*/ | |
// String? _selectedCandidate1; | |
// String? _selectedCandidate2; | |
final String apiUrl = | |
'YOUR_FIREBASE_FUNCTION_URL_HERE'; // Replace with your Firebase function URL | |
final String apiUrl_winpredict = | |
'YOUR_FIREBASE_FUNCTION_URL_HERE'; // Replace with your Firebase function URL | |
double anuraWinPercentage = 39.57; | |
double ranilWinPercentage = 21.36; | |
double sajithWinPercentage = 32.12; | |
bool isLoading = true; | |
// final ScrollController _scrollController = ScrollController(); | |
// final GlobalKey comparisonKey = GlobalKey(); | |
void initState() { | |
super.initState(); | |
// _selectedCandidate1 = _comparisonNames[0]; | |
// _selectedCandidate2 = _comparisonNames[1]; | |
// _fetchWinPrediction(); //for a real time win prediction | |
// _fetchComparisonData( | |
// ["Candidate1", "Candidate2"]); // Pass candidate IDs or names | |
// Scroll to the comparison area if the parameter is true | |
// WidgetsBinding.instance.addPostFrameCallback((_) { | |
// if (widget.scrollToComparison) { | |
// _scrollToComparison(); | |
// } | |
// }); | |
} | |
// @override | |
// void dispose() { | |
// _scrollController.dispose(); | |
// super.dispose(); | |
// } | |
// Future<void> _fetchWinPrediction() async { | |
// try { | |
// final response = await http.get(Uri.parse(apiUrl + '/win-prediction')); | |
// if (response.statusCode == 200) { | |
// final Map<String, dynamic> responseData = json.decode(response.body); | |
// setState(() { | |
// anuraWinPercentage = responseData['anura'] ?? 0.0; | |
// ranilWinPercentage = responseData['ranil'] ?? 0.0; | |
// sajithWinPercentage = responseData['sajith'] ?? 0.0; | |
// isLoading = false; | |
// }); | |
// } else { | |
// print('Error fetching prediction: ${response.statusCode}'); | |
// } | |
// } catch (error) { | |
// print('Network error: $error'); | |
// } | |
// } | |
void _fetchComparisonData(List<String> candidates) async { | |
try { | |
final response = await http.post( | |
Uri.parse(apiUrl + '/compare'), | |
headers: {'Content-Type': 'application/json'}, | |
body: jsonEncode({"candidates": candidates}), | |
); | |
if (response.statusCode == 200) { | |
final Map<String, dynamic> responseData = json.decode(response.body); | |
setState(() { | |
_comparisonData.clear(); | |
_comparisonData.addAll(responseData['comparison']); | |
_updateComparisonInfo(); | |
}); | |
} else { | |
// Handle error | |
print('Error fetching data: ${response.statusCode}'); | |
} | |
} catch (error) { | |
// Handle network error | |
print('Network error: $error'); | |
} | |
} | |
void _updateComparisonInfo() { | |
// Update the categories and candidate names based on the new comparison data | |
_comparisonCategories = _comparisonData[0].values.toList()[0].keys.toList(); | |
_comparisonNames = [_comparisonData[0], _comparisonData[1]] | |
.map((e) => e.keys.toList()[0]) | |
.toList(); | |
_comparisonContent = [ | |
_comparisonData[0].values.toList()[0].values.toList(), | |
_comparisonData[1].values.toList()[0].values.toList() | |
]; | |
} | |
// void _scrollToComparison() { | |
// _scrollController.animateTo( | |
// _scrollController.position.maxScrollExtent, // Scroll to the end | |
// duration: Duration(seconds: 1), | |
// curve: Curves.easeInOut, | |
// ); | |
// } | |
final _themeTopics = <List>[ | |
[ | |
'Public and Micro Finance', | |
'Industries', | |
'Technology', | |
'Legal Reform', | |
'Housing and Construction', | |
'Trade, Business, and SMEs', | |
'Public Administration' | |
], | |
[ | |
'Industries', | |
'Housing and Construction', | |
'Technology', | |
'Land', | |
'Transportation', | |
'Power and Energy', | |
'Justice System', | |
'Science and Research', | |
'Mass Media', | |
'Public and Micro Finance', | |
'Water Supply', | |
'Ports and Shipping', | |
'Environmental Conservation and Mitigating Pollution', | |
'Urban Development', | |
'Legal Reform', | |
'Aviation', | |
'Labour Welfare and Regulation', | |
'Disaster Management', | |
'Public Administration' | |
], | |
[ | |
'Child Development and Women\'s Affairs', | |
'Labour Welfare and Regulation', | |
'Community Support', | |
'Public and Micro Finance', | |
'Healthcare', | |
'Transportation', | |
'National Security', | |
'Housing and Construction', | |
'Foreign Affairs', | |
'Public Administration', | |
'Justice System', | |
'Urban Development' | |
], | |
[ | |
'Sports Affairs', | |
'Cultural and Religious Affairs', | |
'Environmental Conservation and Mitigating Pollution', | |
'Public and Micro Finance', | |
'Foreign Employment', | |
'Parliament, Provincial Councils and Local Government', | |
'Mass Media', | |
'Foreign Affairs', | |
'Primary and Secondary Education', | |
'Public Administration', | |
'Water Supply', | |
'Trade, Business, and SMEs', | |
'Healthcare', | |
'SOE Reform' | |
], | |
[ | |
'Livestock', | |
'Plantation Industries', | |
'Fisheries and Aquatic Resources', | |
'Trade, Business, and SMEs', | |
'Traditional and Modern Agriculture', | |
'Technology', | |
'Water Supply', | |
'Labour Welfare and Regulation', | |
'Public and Micro Finance', | |
'Land' | |
], | |
[ | |
'SOE Reform', | |
'Parliament, Provincial Councils and Local Government', | |
'Public Administration', | |
'Land', | |
'Public and Micro Finance', | |
'Technology', | |
'Youth Affairs and Skills', | |
'Legal Reform', | |
'Foreign Affairs', | |
'Power and Energy' | |
], | |
[ | |
'Public and Micro Finance', | |
'Tourism', | |
'Economic and Investment Zones', | |
'Trade, Business, and SMEs' | |
], | |
[ | |
'Legal Reform', | |
'Justice System', | |
'National Security', | |
'Legal Enforcement', | |
'Police', | |
'Power and Energy', | |
'Parliament, Provincial Councils and Local Government', | |
'Cultural and Religious Affairs', | |
'Child Development and Women\'s Affairs', | |
'Healthcare', | |
'Rehabilitation and Prisons Reform' | |
], | |
[ | |
'Public Administration', | |
'Labour Welfare and Regulation', | |
'Youth Affairs and Skills', | |
'Foreign Employment', | |
'Child Development and Women\'s Affairs', | |
'Community Support' | |
], | |
[ | |
'Vocational Development', | |
'Higher Education', | |
'Primary and Secondary Education', | |
'Youth Affairs and Skills', | |
'Child Development and Women\'s Affairs', | |
'Labour Welfare and Regulation', | |
'Healthcare', | |
'Technology', | |
'Mass Media', | |
'Science and Research' | |
], | |
[ | |
'Vocational Development', | |
'Higher Education', | |
'Primary and Secondary Education', | |
'Youth Affairs and Skills', | |
'Child Development and Women\'s Affairs', | |
'Labour Welfare and Regulation', | |
'Healthcare', | |
'Technology', | |
'Mass Media', | |
' Science and Research' | |
], | |
[ | |
'Legal Enforcement', | |
'Justice System', | |
'Public Administration', | |
'Legal Reform', | |
'Public and Micro Finance' | |
], | |
[ | |
'Healthcare', | |
'Medical Staff and Hospitals', | |
'Medicine', | |
'Indigenous Medicine', | |
'Child Development and Women\'s Affairs' | |
], | |
['Public and Micro Finance', 'Public Administration'], | |
[ | |
'Legal Enforcement', | |
'Cultural and Religious Affairs', | |
'Land', | |
'Community Support' | |
], | |
]; | |
Widget _buildComparisonTable() { | |
if (_comparisonData.isEmpty) { | |
return Center(child: CircularProgressIndicator()); | |
} | |
return SingleChildScrollView( | |
scrollDirection: Axis.horizontal, | |
child: DataTable( | |
columns: [ | |
DataColumn( | |
label: Text( | |
'Theme', | |
style: TextStyle(fontWeight: FontWeight.bold), | |
)), | |
DataColumn( | |
label: Text(_comparisonNames[0] + ' \%', | |
style: TextStyle(fontWeight: FontWeight.bold))), | |
DataColumn( | |
label: Text(_comparisonNames[1] + ' \%', | |
style: TextStyle(fontWeight: FontWeight.bold))), | |
DataColumn( | |
label: Text(_comparisonNames[2] + ' \%', | |
style: TextStyle(fontWeight: FontWeight.bold))), | |
DataColumn( | |
label: Text('Focused Areas', | |
style: TextStyle(fontWeight: FontWeight.bold))), | |
], | |
rows: List<DataRow>.generate( | |
(_themes.length), | |
(index) => DataRow(cells: [ | |
DataCell(Text(_themes[index])), | |
DataCell(Text(_scoresAnura[index].toString().toString())), | |
DataCell(Text(_scoresSajith[index].toString())), | |
DataCell(Text(_scoresRanil[index].toString())), | |
DataCell(Text(_themeTopics[index].toString())), | |
// DataCell(Text(_comparisonCategories[index])), | |
// DataCell(Text(_comparisonContent[0][index])), | |
// DataCell(Text(_comparisonContent[1][index])), | |
// DataCell(Text(_comparisonContent[2][index])), | |
// DataCell(Text(_comparisonBetter[0][index])), | |
])), | |
)); | |
} | |
Widget _firstVoteChart() { | |
//remove hardcode these to get actual data | |
double othersWinPercentage = | |
100 - (anuraWinPercentage + ranilWinPercentage + sajithWinPercentage); | |
Map<String, double> dataMap = { | |
"Anura": anuraWinPercentage, | |
"Sajith": sajithWinPercentage, | |
"Ranil": ranilWinPercentage, | |
"Others": othersWinPercentage, | |
}; | |
final colorList = <Color>[ | |
Colors.pinkAccent, | |
Colors.green, | |
Colors.yellow, | |
Colors.grey, | |
]; | |
return SizedBox( | |
height: 200, // Set height for the pie chart | |
child: PieChart( | |
dataMap: dataMap, | |
// animationDuration: Duration(milliseconds: 800), | |
chartLegendSpacing: 32, | |
// chartRadius: MediaQuery.of(context).size.width / 4, | |
colorList: colorList, | |
initialAngleInDegree: -90, | |
chartType: ChartType.disc, | |
ringStrokeWidth: 32, | |
// centerText: "1st Vote", | |
legendOptions: const LegendOptions( | |
// showLegendsInRow: true, | |
legendPosition: LegendPosition.right, | |
showLegends: true, | |
legendShape: BoxShape.circle, | |
// legendTextStyle: TextStyle( | |
// fontWeight: FontWeight.bold, | |
// ), | |
), | |
chartValuesOptions: const ChartValuesOptions( | |
showChartValueBackground: true, | |
showChartValues: true, | |
showChartValuesInPercentage: false, | |
showChartValuesOutside: false, | |
), | |
)); | |
} | |
Widget _secondVotesChart() { | |
//remove hardcode these to get actual data | |
double othersWinPercentage = | |
100 - (anuraWinPercentage + ranilWinPercentage + sajithWinPercentage); | |
Map<String, double> dataMap = { | |
"Anura": 44.27, // put the actual value here | |
"Sajith": 39.59, | |
// "Ranil": ranils, | |
"Others": othersWinPercentage, | |
}; | |
final colorList = <Color>[ | |
Colors.pinkAccent, | |
// Colors.yellow, | |
Colors.green, | |
Colors.grey, | |
]; | |
return SizedBox( | |
height: 200, // Set height for the pie chart | |
child: PieChart( | |
dataMap: dataMap, | |
// animationDuration: Duration(milliseconds: 800), | |
chartLegendSpacing: 32, | |
// chartRadius: MediaQuery.of(context).size.width / 4, | |
colorList: colorList, | |
initialAngleInDegree: -90, | |
chartType: ChartType.disc, | |
ringStrokeWidth: 32, | |
// centerText: "1st + 2nd vote", | |
legendOptions: const LegendOptions( | |
// showLegendsInRow: true, | |
legendPosition: LegendPosition.right, | |
showLegends: true, | |
legendShape: BoxShape.circle, | |
legendTextStyle: TextStyle( | |
fontWeight: FontWeight.bold, | |
// backgroundColor: Colors.white, | |
), | |
), | |
chartValuesOptions: const ChartValuesOptions( | |
showChartValueBackground: true, | |
showChartValues: true, | |
showChartValuesInPercentage: false, | |
showChartValuesOutside: false, | |
), | |
)); | |
} | |
// the following function is used for larger group of candidates, to compare two at a time. | |
// Widget _selectCandidateButton() { | |
// return Row( | |
// mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
// children: [ | |
// DropdownButton<String>( | |
// value: _selectedCandidate1, | |
// items: _comparisonNames | |
// .map((e) => DropdownMenuItem( | |
// child: Text(e), | |
// value: e, | |
// )) | |
// .toList(), | |
// onChanged: (value) { | |
// setState(() { | |
// _selectedCandidate1 = value; | |
// _fetchComparisonData([value!, _selectedCandidate2!]); | |
// }); | |
// }, | |
// ), | |
// DropdownButton<String>( | |
// value: _selectedCandidate2, | |
// items: _comparisonNames | |
// .map((e) => DropdownMenuItem( | |
// child: Text(e), | |
// value: e, | |
// )) | |
// .toList(), | |
// onChanged: (value) { | |
// setState(() { | |
// _selectedCandidate2 = value; | |
// _fetchComparisonData([_selectedCandidate1!, value!]); | |
// }); | |
// }, | |
// ), | |
// ], | |
// ); | |
// } | |
Widget _buildTeamInfo() { | |
return Container( | |
width: double.infinity, | |
color: Colors.lightBlue[50], | |
child: Column( | |
children: [ | |
SizedBox(height: 50.0), | |
Text('Developed by LLMinators', style: TextStyle(fontSize: 16)), | |
SizedBox(height: 16.0), | |
Text( | |
'#TeamLLMinators #AIChallenge #IEEEChallengeSphere #MachineLearning', | |
textAlign: TextAlign.center), | |
SizedBox(height: 16.0), | |
Text( | |
'This app is created for educational purposes only.', | |
textAlign: TextAlign.center, | |
), | |
SizedBox(height: 50.0), | |
], | |
), | |
); | |
} | |
Widget _firstVoteBox() { | |
return Container( | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(20), | |
color: const Color.fromRGBO(255, 255, 255, 0.4), | |
), | |
padding: EdgeInsets.all(16.0), | |
child: Column( | |
children: [ | |
_firstVoteChart(), | |
Text( | |
'Based on First Vote', | |
style: TextStyle( | |
fontSize: 16.0, | |
// fontWeight: FontWeight.bold | |
color: Colors.black, | |
), | |
) | |
], | |
), | |
); | |
} | |
Widget _secondVoteBox() { | |
return Container( | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(20), | |
color: const Color.fromRGBO(255, 255, 255, 0.4), | |
), | |
padding: EdgeInsets.all(16.0), | |
child: Column( | |
children: [ | |
_secondVotesChart(), | |
Text( | |
'Based on First and Second Votes', | |
style: TextStyle( | |
fontSize: 16.0, | |
// fontWeight: FontWeight.bold | |
color: Colors.black, | |
), | |
) | |
], | |
), | |
); | |
} | |
Widget _comparisonTableBox() { | |
return Container( | |
width: double.infinity, | |
padding: EdgeInsets.all(20.0), | |
margin: EdgeInsets.all(20.0), | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(20), | |
color: const Color.fromRGBO(225, 245, 254, 0.75), | |
), | |
alignment: Alignment.center, | |
child: Column(children: [_buildComparisonTable()]), | |
); | |
} | |
Widget _comparisonScoreBox() { | |
return Container( | |
width: double.infinity, | |
padding: EdgeInsets.all(20.0), | |
margin: EdgeInsets.all(20.0), | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(20), | |
color: const Color.fromRGBO(225, 245, 254, 0.75), | |
), | |
alignment: Alignment.center, | |
child: Row( | |
children: <Widget>[ | |
Expanded( | |
flex: 5, | |
child: _comparisonScoreChart(), | |
), | |
Expanded( | |
flex: 5, | |
child: Column( | |
children: [ | |
_selectThemes(), | |
SizedBox(height: 16.0), | |
Text( | |
'The Manifesto Comparator scores each candidate based on the volume of policies they offer within key themes, helping you see who aligns with your priorities'), | |
], | |
), | |
), | |
], | |
), | |
); | |
} | |
final _themes = [ | |
'Taxation', | |
'Infrastructure', | |
'Social Protection', | |
'Supplementary', | |
'Agricultural', | |
'Governance', | |
'Economic Growth', | |
'Law and Order', | |
'Labour', | |
'Education', | |
'Trade and export', | |
'Corruption', | |
'Health', | |
'IMF Programme', | |
'Reconciliation', | |
]; | |
List<int> _selectedIndexes = []; | |
var _comparisonScore = <double>[10, 10, 10]; | |
final _scoresAnura = <double>[ | |
26, | |
79, | |
51, | |
65, | |
70, | |
28, | |
64, | |
55, | |
36, | |
50, | |
67, | |
39, | |
71, | |
40, | |
0 | |
]; | |
final _scoresSajith = <double>[ | |
74, | |
16, | |
33, | |
19, | |
20, | |
52, | |
14, | |
35, | |
50, | |
27, | |
25, | |
57, | |
21, | |
40, | |
17 | |
]; | |
final _scoresRanil = <double>[ | |
0, | |
5, | |
16, | |
16, | |
10, | |
20, | |
22, | |
10, | |
14, | |
23, | |
8, | |
4, | |
8, | |
20, | |
83 | |
]; | |
void _onThemeSelected(int index) { | |
setState(() { | |
// If already selected, remove from the list, otherwise add | |
if (_selectedIndexes.contains(index)) { | |
_selectedIndexes.remove(index); | |
} else { | |
_selectedIndexes.add(index); | |
} | |
_updateComparisonScore(); | |
}); | |
} | |
void _updateComparisonScore() { | |
double sumAnura = 0; | |
double sumSajith = 0; | |
double sumRanil = 0; | |
// Calculate the sum of scores for selected indexes for each candidate | |
for (int index in _selectedIndexes) { | |
sumAnura += _scoresAnura[index]; | |
sumSajith += _scoresSajith[index]; | |
sumRanil += _scoresRanil[index]; | |
} | |
// get percentage values | |
double totalScore = sumAnura + sumSajith + sumRanil; | |
double percentageAnura = | |
totalScore != 0 ? (sumAnura / totalScore) * 100 : 0; | |
double percentageSajith = | |
totalScore != 0 ? (sumSajith / totalScore) * 100 : 0; | |
double percentageRanil = | |
totalScore != 0 ? (sumRanil / totalScore) * 100 : 0; | |
// Update _comparisonScore list | |
_comparisonScore = [percentageAnura, percentageSajith, percentageRanil]; | |
} | |
Widget _selectThemes() { | |
return Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Wrap( | |
spacing: 8.0, // space between buttons | |
runSpacing: 8.0, // space between rows | |
children: List.generate(_themes.length, (index) { | |
return ChoiceChip( | |
label: Text(_themes[index]), | |
selected: _selectedIndexes.contains(index), | |
onSelected: (bool selected) { | |
_onThemeSelected(index); | |
}, | |
); | |
}), | |
), | |
); | |
} | |
_comparisonScoreChart() { | |
Map<String, double> dataMap = { | |
"Anura": _comparisonScore[0], // put the actual value here | |
"Sajith": _comparisonScore[1], | |
"Ranil": _comparisonScore[2], | |
}; | |
final colorList = <Color>[ | |
Colors.pinkAccent, | |
// Colors.yellow, | |
Colors.green, | |
Colors.yellow, | |
]; | |
return SizedBox( | |
height: 200, // Set height for the pie chart | |
child: PieChart( | |
dataMap: dataMap, | |
// animationDuration: Duration(milliseconds: 800), | |
chartLegendSpacing: 32, | |
// chartRadius: MediaQuery.of(context).size.width / 4, | |
colorList: colorList, | |
initialAngleInDegree: -90, | |
chartType: ChartType.disc, | |
ringStrokeWidth: 32, | |
legendOptions: const LegendOptions( | |
// showLegendsInRow: true, | |
legendPosition: LegendPosition.right, | |
showLegends: true, | |
legendShape: BoxShape.circle, | |
legendTextStyle: TextStyle( | |
fontWeight: FontWeight.bold, | |
// backgroundColor: Colors.white, | |
), | |
), | |
chartValuesOptions: const ChartValuesOptions( | |
showChartValueBackground: true, | |
showChartValues: true, | |
showChartValuesInPercentage: false, | |
showChartValuesOutside: false, | |
), | |
)); | |
} | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Stack(fit: StackFit.expand, children: <Widget>[ | |
Image.asset( | |
"assets/bgimg.jpg", // Ensure this path is correct | |
fit: BoxFit.cover, | |
), | |
BackdropFilter( | |
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6), | |
child: Container( | |
color: Colors.black.withOpacity(0), | |
), | |
), | |
SingleChildScrollView( | |
// controller: _scrollController, // Scroll controller for scrolling to the comparison area. removed because of the change in design | |
child: Padding( | |
padding: const EdgeInsets.all(0), | |
child: Column( | |
// mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
SizedBox(height: 25.0), | |
Text( | |
'Win Prediction', | |
style: TextStyle( | |
fontSize: 20, | |
fontWeight: FontWeight.bold, | |
color: Colors.white, | |
), | |
), | |
SizedBox(height: 20.0), | |
Row( | |
children: [_firstVoteBox(), _secondVoteBox()], | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly), | |
SizedBox(height: 25.0), | |
Text( | |
'Manifesto Comparison', | |
style: TextStyle( | |
fontSize: 20, | |
fontWeight: FontWeight.bold, | |
color: Colors.white), | |
), | |
SizedBox(height: 16.0), // Add some spacing | |
_comparisonScoreBox(), | |
// _selectCandidateButton(), /// to choose candidates from if manifestos trained for all the candidates | |
// SizedBox(height: 16.0), | |
_comparisonTableBox(), | |
SizedBox(height: 100.0), | |
_buildTeamInfo(), | |
], | |
), | |
), | |
), | |
]), | |
); | |
} | |
} | |