diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 854f2c8..0e24c20 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -17,11 +17,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.0.1
+ 1.1.0
CFBundleSignature
????
CFBundleVersion
- 2
+ 1
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/lib/views/app/TournamentList.dart b/lib/views/app/TournamentList.dart
index fd20b5f..2809146 100644
--- a/lib/views/app/TournamentList.dart
+++ b/lib/views/app/TournamentList.dart
@@ -14,7 +14,7 @@ import "package:ezra_companion/views/tournament/TournamentView.dart";
/// Make a request to Ezra and get a list of tournaments
/// TODO: Store the results of this locally, check for new tournaments every so often (every week?)
Future> fetchTournaments(http.Client client) async {
- final response = await client.get('https://www.ezratech.us/api/tournaments/search?appOptIn=true');
+ final response = await client.get('https://www.ezratech.us/api/tournaments/search');
if (response.statusCode == 200) {
// Use the compute function to run parseTournaments
diff --git a/lib/views/tournament/TournamentView.dart b/lib/views/tournament/TournamentView.dart
index 74edfe3..464ddb2 100644
--- a/lib/views/tournament/TournamentView.dart
+++ b/lib/views/tournament/TournamentView.dart
@@ -115,6 +115,7 @@ class _TournamentViewState extends State {
updateSubscriptionStatus: _updatePublicSubscriptionStatus
);
_tournamentResults = new TournamentResults(
+ fileStorage: _fileStorage,
tournamentInfo: widget.tournamentInfo
);
_tournamentSchedule = new TournamentSchedule(
@@ -179,8 +180,19 @@ class _TournamentViewState extends State {
// Build the widget
@override
Widget build(BuildContext context) {
- final double padding = _selectedIndex != 1 ? 15.0 : 0.0;
- final TextTheme textTheme = Theme.of(context).textTheme;
+ // Ignore the maps and results page for padding
+ double padding;
+ switch(_selectedIndex) {
+ case 1:
+ padding = 0.0;
+ break;
+ case 4:
+ padding = 5.0;
+ break;
+ default:
+ padding = 15.0;
+ }
+ final TextTheme textTheme = Theme.of(context).textTheme;
return FutureBuilder(
future: initializeTournament(),
diff --git a/lib/views/tournament/tabs/TournamentMap.dart b/lib/views/tournament/tabs/TournamentMap.dart
index 8fabaa3..ef14217 100644
--- a/lib/views/tournament/tabs/TournamentMap.dart
+++ b/lib/views/tournament/tabs/TournamentMap.dart
@@ -41,11 +41,26 @@ class TournamentMap extends StatelessWidget {
}
}
else {
- return Column(
- children: [
- Text('No map!'),
- Text('View more ${tournamentInfo.name}'),
- ],
+ TextStyle pageTextStyle = new TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.black87,
+ );
+ return Padding(
+ padding: new EdgeInsets.all(25.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ new Icon(Icons.map),
+ SizedBox(height: 30),
+ new Text(
+ "No map has been provided for this tournament; ask your organizers to upload one, then you'll see it here!",
+ style: pageTextStyle,
+ textAlign: TextAlign.center
+ ),
+ ]
+ )
);
}
}
diff --git a/lib/views/tournament/tabs/TournamentResults.dart b/lib/views/tournament/tabs/TournamentResults.dart
index 67c575e..f8579d4 100644
--- a/lib/views/tournament/tabs/TournamentResults.dart
+++ b/lib/views/tournament/tabs/TournamentResults.dart
@@ -1,41 +1,296 @@
+import 'package:async/async.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'dart:convert';
+
+import 'package:http/http.dart' as http;
// Consume the Ezra results API, allow people to view results on teams and events from here
// Class imports
import "package:ezra_companion/classes/TournamentListItem.dart";
-class TournamentResults extends StatelessWidget {
+class TournamentResults extends StatefulWidget {
+ final fileStorage;
final TournamentListItem tournamentInfo;
const TournamentResults({
Key key,
+ this.fileStorage,
this.tournamentInfo,
}) : super(key: key);
@override
- Widget build(BuildContext context) {
- TextStyle textStyle = new TextStyle(
- fontSize: 16.0,
- fontWeight: FontWeight.w600,
- color: Colors.black87,
- );
- return Padding(
- padding: new EdgeInsets.all(25.0),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- new Icon(Icons.stars),
- SizedBox(height: 30),
- new Text(
- "Results from this tournament will be available after the conclusion of the tournament. Check back here to see them when they've been released!",
- style: textStyle,
- textAlign: TextAlign.center
+ _TournamentResultsState createState() => _TournamentResultsState();
+}
+
+// https://stackoverflow.com/questions/51998995/invalid-arguments-illegal-argument-in-isolate-message-object-is-a-closure
+/// A function that converts a response body into a List
+List parseApiResponse(String responseBody) {
+ final decodedBody = json.decode(responseBody);
+ if (decodedBody is List && decodedBody.length > 0) {
+ return decodedBody;
+ }
+ else {
+ return [];
+ }
+}
+
+class _TournamentResultsState extends State {
+ final AsyncMemoizer _memoizer = AsyncMemoizer();
+
+ int _dropdownIndex;
+
+ List _eventNames;
+
+ TextStyle _rowTextStyle = new TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.black87,
+ );
+
+ void initState() {
+ _dropdownIndex = 0;
+ _eventNames = [];
+ }
+
+ List createTableRowsFromIndex(List data, int eventIndex) {
+ // Event data is not normally sorted from the API, this sorts it by place within the event
+ if (eventIndex < 998) {
+ data.sort((teamA, teamB) {
+ return teamA["name"].compareTo(teamB["name"]);
+ });
+ }
+ else {
+ data.sort((teamA, teamB) {
+ int teamAScore = teamA["finalScore"];
+ int teamBScore = teamB["finalScore"];
+ return teamAScore - teamBScore;
+ });
+ }
+
+ // Create a list of rows based on each team's performance in this event (or a final aspect)
+ List tableRows = List.from(data.map((team) {
+ String teamName = team["name"];
+ String teamPlace;
+
+ List teamEvents = team["events"];
+
+ // Sort each event by name (this is already done by Ezra, but sometimes it isn't perfect for some reason)
+ teamEvents.sort((eventA, eventB) {
+ return eventA["eventName"].compareTo(eventB["eventName"]);
+ });
+
+ // Determine where to look for information that will populate the current row
+ if (eventIndex == 998) {
+ // Final scores
+ teamPlace = "${team["finalScore"] != null ? team["finalScore"] : "N/A"}";
+ }
+ else if (eventIndex == 999) {
+ // Final places
+ teamPlace = "${team["finalPlace"] != null ? team["finalPlace"] : "N/A"}";
+ }
+ else {
+ // Regular event
+ Map currentEvent = teamEvents[eventIndex];
+ teamPlace = "${currentEvent["place"]}";
+ }
+
+ // Create a TableRow
+ return TableRow(
+ children: [
+ TableCell(
+ child: Padding(
+ padding: const EdgeInsets.all(9.0),
+ child: Center(
+ child: Text(
+ teamName,
+ style: _rowTextStyle,
+ textAlign: TextAlign.center,
+ )
+ )
+ ),
+ verticalAlignment: TableCellVerticalAlignment.middle,
+ ),
+ TableCell(
+ child: Padding(
+ padding: const EdgeInsets.all(9.0),
+ child: Center(
+ child: Text(
+ teamPlace,
+ style: _rowTextStyle,
+ textAlign: TextAlign.center,
+ )
+ )
+ ),
+ verticalAlignment: TableCellVerticalAlignment.middle,
+ ),
+ ],
+ );
+ }));
+
+ // Insert header rows for the table
+ tableRows.insert(
+ 0,
+ TableRow(
+ decoration: BoxDecoration(
+ color: Colors.red
+ ),
+ children: [
+ TableCell(
+ child: Padding(
+ padding: const EdgeInsets.all(9.0),
+ child: Center(
+ child: Text(
+ "Team Name",
+ style: TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ textAlign: TextAlign.center,
+ )
+ )
+ ),
+ verticalAlignment: TableCellVerticalAlignment.middle,
+ ),
+ TableCell(
+ child: Padding(
+ padding: const EdgeInsets.all(9.0),
+ child: Center(
+ child: Text(
+ "Score",
+ style: TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ ),
+ textAlign: TextAlign.center,
+ )
+ )
+ ),
+ verticalAlignment: TableCellVerticalAlignment.middle,
),
]
)
);
+ return tableRows;
+ }
+
+ // Get event names
+ List getDropdownChoices(List data) {
+ int eventIndex = 0;
+ List dropdownChoices = List.from(
+ data[0]["events"].map((currentEvent) {
+ DropdownMenuItem item = DropdownMenuItem(
+ child: Text(currentEvent["eventName"]),
+ value: eventIndex,
+ );
+ eventIndex++;
+ return item;
+ })
+ );
+ dropdownChoices.addAll([
+ DropdownMenuItem(
+ child: Text("Final Scores"),
+ value: 998
+ ),
+ DropdownMenuItem(
+ child: Text("Final Places"),
+ value: 999
+ )
+ ]);
+ return dropdownChoices;
+ }
+
+ Future get tournamentResults async {
+ List parsedTournamentResults = await this._memoizer.runOnce(() async {
+ // See if results have already been saved for this tournament
+ // If they have, pull them up
+ // If not, make a request for them
+ // If they are there, save them locally
+ // If they are not there, save nothing
+ http.Client client = http.Client();
+ http.Response resultsApiResponse = await client.get("https://www.ezratech.us/competition/${widget.tournamentInfo.key}/api/results");
+ if (resultsApiResponse.statusCode == 200) {
+ // Parse each event
+ final parsedResults = await compute(parseApiResponse, resultsApiResponse.body);
+
+ return parsedResults;
+ }
+ else {
+ print(resultsApiResponse.statusCode);
+ print(resultsApiResponse.toString());
+ }
+ });
+ return parsedTournamentResults;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: tournamentResults,
+ builder: (context, snapshot) {
+ if (snapshot.hasError) {
+ print(snapshot.error);
+ }
+ if (!snapshot.hasData) {
+ return Center(child: CircularProgressIndicator());
+ }
+ else {
+ if (snapshot.data is List && snapshot.data.length > 0) {
+ return SingleChildScrollView(
+ child: Column(
+ children: [
+ DropdownButton(
+ items: getDropdownChoices(snapshot.data),
+ onChanged: (dropdownChoice) {
+ if (dropdownChoice is int) {
+ setState(() {
+ _dropdownIndex = dropdownChoice;
+ });
+ }
+ },
+ value: _dropdownIndex,
+ ),
+ Table(
+ border: TableBorder.all(
+ color: Colors.black,
+ style: BorderStyle.solid,
+ width: 1.0
+ ),
+ children: createTableRowsFromIndex(snapshot.data, _dropdownIndex)
+ )
+ ],
+ )
+ );
+ }
+ else {
+ TextStyle _rowTextStyle = new TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.w600,
+ color: Colors.black87,
+ );
+ // no data
+ return Padding(
+ padding: new EdgeInsets.all(25.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ new Icon(Icons.stars),
+ SizedBox(height: 30),
+ new Text(
+ "Results from this tournament will be available after the conclusion of the tournament. Check back here to see them when they've been released!",
+ style: _rowTextStyle,
+ textAlign: TextAlign.center
+ ),
+ ]
+ )
+ );
+ }
+ }
+ }
+ );
}
}
diff --git a/pubspec.yaml b/pubspec.yaml
index fbc59db..500597a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,7 @@ description: Companion to Ezra Tech.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
-version: 1.0.1+2
+version: 1.1.0+3
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"