diff --git a/client/lib/widgets/codeinput_page.dart b/client/lib/widgets/codeinput_page.dart index a319e3f..9db1721 100644 --- a/client/lib/widgets/codeinput_page.dart +++ b/client/lib/widgets/codeinput_page.dart @@ -72,7 +72,7 @@ Widget codeInputPage( if (response.statusCode == 200) { Map srlResponse = jsonDecode(response.body); if (srlResponse['success'] == true) { - updatePlayerId(srlResponse['player']['id']); + updatePlayerId(output); updatePlayerName(srlResponse['player']['name']); controller.nextPage( duration: const Duration(milliseconds: 300), diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..24476c5 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/frontend/.metadata b/frontend/.metadata new file mode 100644 index 0000000..5b0941d --- /dev/null +++ b/frontend/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "12fccda598477eddd19f93040a1dba24f915b9be" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 12fccda598477eddd19f93040a1dba24f915b9be + base_revision: 12fccda598477eddd19f93040a1dba24f915b9be + - platform: web + create_revision: 12fccda598477eddd19f93040a1dba24f915b9be + base_revision: 12fccda598477eddd19f93040a1dba24f915b9be + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..03d619c --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,16 @@ +# frontend + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/analysis_options.yaml b/frontend/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/frontend/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/assets/images/enei_logo.svg b/frontend/assets/images/enei_logo.svg new file mode 100644 index 0000000..df47f53 --- /dev/null +++ b/frontend/assets/images/enei_logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/assets/images/glua_logo.svg b/frontend/assets/images/glua_logo.svg new file mode 100644 index 0000000..0327519 --- /dev/null +++ b/frontend/assets/images/glua_logo.svg @@ -0,0 +1,107 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/frontend/lib/logic/requester.dart b/frontend/lib/logic/requester.dart new file mode 100644 index 0000000..e35b12a --- /dev/null +++ b/frontend/lib/logic/requester.dart @@ -0,0 +1,11 @@ +import 'package:http/http.dart' as http; + +const String baseUrl = "http://localhost:3000"; + +Future getLeaderboard() async { + try { + return await http.get(Uri.parse('$baseUrl/tournament/players')); + } catch (e) { + return http.Response('{"error": "Could not connect to server"}', 500); + } +} diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart new file mode 100644 index 0000000..f924493 --- /dev/null +++ b/frontend/lib/main.dart @@ -0,0 +1,141 @@ +import 'dart:async'; +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:frontend/logic/requester.dart'; +import 'package:frontend/widgets/leaderboard.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: const MyHomePage(title: 'Super Tux Leaderboard'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + late Timer _timer; + List leaderboardEntries = []; + + @override + void initState() { + super.initState(); + _timer = Timer.periodic( + const Duration(milliseconds: 2500), + (timer) async { + final http.Response response = await getLeaderboard(); + + if (response.statusCode == 200) { + Map srlResponse = jsonDecode(response.body); + if (srlResponse['success'] == true) { + List newEntries = []; + + // Sort the players by levelsCompleted in descending order + List sortedPlayers = List.from(srlResponse['players']); + sortedPlayers.sort( + (a, b) => b['levelsCompleted'].compareTo(a['levelsCompleted'])); + + // Slice the list to get the first 10 players + var topPlayers = sortedPlayers.length > 10 + ? sortedPlayers.sublist(0, 10) + : sortedPlayers; + + for (var player in topPlayers) { + var estado = + player['endedTournament'] ? "Terminado" : "Em progreso"; + newEntries.add( + DataRow( + cells: [ + DataCell(Text(player['name'])), + DataCell( + Text('${player['levelsCompleted'].toString()}/23')), + DataCell(Text(estado)), + DataCell(Text(player['nextLevel'])), + ], + ), + ); + } + setState(() { + leaderboardEntries = newEntries; + }); + } else { + // Handle the error here. For now, just print it + print('Failed to load leaderboard: ${srlResponse['error']}'); + } + } else { + // Handle the error here. For now, just print it + print('Failed to load leaderboard: ${response.statusCode}'); + } + }, + ); + } + + @override + void dispose() { + _timer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Column( + children: [ + Container( + width: 600, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + "/images/enei_logo.svg", + fit: BoxFit.contain, + height: 100, + ), + SvgPicture.asset( + "/images/glua_logo.svg", + fit: BoxFit.contain, + height: 70, + ), + ], + ), + ), + const SizedBox( + height: 20, + ), + Leaderboard( + entries: leaderboardEntries, + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/leaderboard.dart b/frontend/lib/widgets/leaderboard.dart new file mode 100644 index 0000000..06e2f63 --- /dev/null +++ b/frontend/lib/widgets/leaderboard.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class Leaderboard extends StatelessWidget { + const Leaderboard({Key? key, required this.entries}) : super(key: key); + + final List entries; + + @override + Widget build(BuildContext context) { + return DataTable( + columns: const [ + // Nome do jogador + DataColumn( + label: Text('Nome do Jogador', + style: TextStyle(fontWeight: FontWeight.bold))), + // Mostra o tempo de jogo + DataColumn( + label: + Text('Níveis', style: TextStyle(fontWeight: FontWeight.bold))), + // n_nivel/n_total ou terminado se n_nivel = n_total + DataColumn( + label: + Text('Estado', style: TextStyle(fontWeight: FontWeight.bold))), + // Mostra o próximo nível ou -------------- se n_nivel = n_total + DataColumn( + label: Text('Próximo Nível', + style: TextStyle(fontWeight: FontWeight.bold))), + ], + rows: entries, + ); + } +} diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock new file mode 100644 index 0000000..9908702 --- /dev/null +++ b/frontend/pubspec.lock @@ -0,0 +1,253 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.dev" + source: hosted + version: "1.17.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "9ac1967e2f72a08af11b05b39167920f90d043cf67163d13a544a358c8f31afa" + url: "https://pub.dev" + source: hosted + version: "0.22.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" + source: hosted + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_drawing: + dependency: transitive + description: + name: path_drawing + sha256: "3bdd251dae9ffaef944450b73f168610db7e968e7b20daf0c3907f8b4aafc8a2" + url: "https://pub.dev" + source: hosted + version: "0.5.1+1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: ee5c47c1058ad66b4a41746ec3996af9593d0858872807bcd64ac118f0700337 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" + xml: + dependency: transitive + description: + name: xml + sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a" + url: "https://pub.dev" + source: hosted + version: "5.4.1" +sdks: + dart: ">=3.1.2 <4.0.0" + flutter: ">=1.24.0-7.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml new file mode 100644 index 0000000..116ef01 --- /dev/null +++ b/frontend/pubspec.yaml @@ -0,0 +1,21 @@ +name: frontend +description: A new Flutter project. +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: '>=3.1.2 <4.0.0' +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.2 + http: ^1.1.0 + flutter_svg: ^0.22.0 +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 +flutter: + uses-material-design: true + assets: + - assets/images/ \ No newline at end of file diff --git a/frontend/test/widget_test.dart b/frontend/test/widget_test.dart new file mode 100644 index 0000000..812c978 --- /dev/null +++ b/frontend/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:frontend/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/frontend/web/favicon.png b/frontend/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/frontend/web/favicon.png differ diff --git a/frontend/web/icons/Icon-192.png b/frontend/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/frontend/web/icons/Icon-192.png differ diff --git a/frontend/web/icons/Icon-512.png b/frontend/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/frontend/web/icons/Icon-512.png differ diff --git a/frontend/web/icons/Icon-maskable-192.png b/frontend/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/frontend/web/icons/Icon-maskable-192.png differ diff --git a/frontend/web/icons/Icon-maskable-512.png b/frontend/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/frontend/web/icons/Icon-maskable-512.png differ diff --git a/frontend/web/index.html b/frontend/web/index.html new file mode 100644 index 0000000..fa4f09a --- /dev/null +++ b/frontend/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + frontend + + + + + + + + + + diff --git a/frontend/web/manifest.json b/frontend/web/manifest.json new file mode 100644 index 0000000..409f4c9 --- /dev/null +++ b/frontend/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "frontend", + "short_name": "frontend", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}