Added create/join pages and refactored friend list
This commit is contained in:
parent
77f264b003
commit
c39796a40f
|
@ -1,4 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="io.flutter" />
|
||||
|
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,28 +1,13 @@
|
|||
# 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.
|
||||
analyzer:
|
||||
errors:
|
||||
library_private_types_in_public_api: ignore
|
||||
prefer_const_constructors: ignore
|
||||
use_build_context_synchronously: ignore
|
||||
use_key_in_widget_constructors: ignore
|
||||
use_super_parameters: ignore
|
||||
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
|
||||
rules:
|
||||
|
|
|
@ -5,10 +5,12 @@ import 'pages/login.dart';
|
|||
import 'pages/home.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
|
@ -49,7 +51,7 @@ class EntryPoint extends StatelessWidget {
|
|||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
_logger.d("Waiting for initial page resolution.");
|
||||
return Scaffold(
|
||||
return const Scaffold(
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
|
|
|
@ -19,8 +19,8 @@ class _HomePageState extends State<HomePage> {
|
|||
// Define the pages for each section
|
||||
final List<Widget> _pages = [
|
||||
LeaderboardPage(), // Use imported widget
|
||||
PlaceholderPageJoin(),//JoinMatchPage(), // Use imported widget
|
||||
PlaceholderPageCreate(),//CreateMatchPage(), // Use imported widget
|
||||
JoinMatchPage(), // Use imported widget
|
||||
CreateMatchPage(), // Use imported widget
|
||||
AddFriendPage(), // Use imported widget
|
||||
PlaceholderPage(),//ProfilePage(), // Use imported widget
|
||||
];
|
||||
|
|
|
@ -18,7 +18,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||
bool _isLogin = true;
|
||||
bool _isLoading = false;
|
||||
|
||||
final String baseUrl = ''; // Replace with your actual API base URL
|
||||
final String baseUrl = 'http://10.0.0.10:9134'; // Replace with your actual API base URL
|
||||
|
||||
Future<void> _handleAuth() async {
|
||||
final email = _emailController.text.trim();
|
||||
|
|
|
@ -1,17 +1,74 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class PlaceholderPageCreate extends StatelessWidget {
|
||||
final String description;
|
||||
class CreateMatchPage extends StatefulWidget {
|
||||
@override
|
||||
_CreateMatchPageState createState() => _CreateMatchPageState();
|
||||
}
|
||||
|
||||
const PlaceholderPageCreate({
|
||||
Key? key,
|
||||
this.description = 'This is a placeholder page. Work in progress!',
|
||||
}) : super(key: key);
|
||||
class _CreateMatchPageState extends State<CreateMatchPage> {
|
||||
String? _matchId;
|
||||
bool _isLoading = false;
|
||||
|
||||
final String _createMatchApiUrl = 'http://10.0.0.10:9134/creatematch'; // Replace with your API endpoint
|
||||
|
||||
// Method to create a match
|
||||
Future<void> _createMatch() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final String? token = prefs.getString('token');
|
||||
|
||||
if (token == null) {
|
||||
_showToast('No token found. Please login again.');
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(_createMatchApiUrl),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'token': token}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
setState(() {
|
||||
_matchId = data['match_id'].toString();
|
||||
});
|
||||
_showToast('Match created successfully!');
|
||||
} else {
|
||||
_showToast('Failed to create match.');
|
||||
}
|
||||
} catch (e) {
|
||||
_showToast('Error: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Show a Toast message (SnackBar in Flutter)
|
||||
void _showToast(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
||||
appBar: AppBar(
|
||||
title: Text('Create Match'),
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
|
@ -20,17 +77,30 @@ class PlaceholderPageCreate extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.construction,
|
||||
Icons.sports_tennis,
|
||||
size: 80,
|
||||
color: Colors.grey,
|
||||
color: Colors.blue,
|
||||
),
|
||||
SizedBox(height: 25),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
||||
'Create a Match',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
_isLoading
|
||||
? CircularProgressIndicator() // Show loading spinner
|
||||
: ElevatedButton(
|
||||
onPressed: _createMatch,
|
||||
child: Text('Create Match'),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
if (_matchId != null)
|
||||
Text(
|
||||
'Your Match ID: $_matchId',
|
||||
style: TextStyle(fontSize: 18, color: Colors.green),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -9,12 +9,12 @@ class AddFriendPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _AddFriendPageState extends State<AddFriendPage> {
|
||||
TextEditingController _friendUidController = TextEditingController();
|
||||
final TextEditingController _friendUidController = TextEditingController();
|
||||
List<dynamic> _friends = [];
|
||||
bool _isLoading = false;
|
||||
|
||||
final String _addFriendApiUrl = 'http://-/add_friend'; // Replace with your actual API endpoint
|
||||
final String _getFriendsApiUrl = 'http://-/get_friends'; // Replace with your actual API endpoint
|
||||
final String _addFriendApiUrl = 'http://10.0.0.10:9134/add_friend';
|
||||
final String _getFriendsApiUrl = 'http://10.0.0.10:9134/get_friends';
|
||||
|
||||
// Method to add a friend
|
||||
Future<void> _addFriend(String friendUid) async {
|
||||
|
@ -37,13 +37,12 @@ class _AddFriendPageState extends State<AddFriendPage> {
|
|||
|
||||
if (response.statusCode == 200) {
|
||||
_showToast('Friend added successfully!');
|
||||
_fetchFriends(); // Refresh the friends list after adding a friend
|
||||
_fetchFriends();
|
||||
} else {
|
||||
_showToast('Failed to add friend.');
|
||||
}
|
||||
}
|
||||
|
||||
// Method to fetch the list of friends
|
||||
Future<void> _fetchFriends() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
|
@ -80,7 +79,6 @@ class _AddFriendPageState extends State<AddFriendPage> {
|
|||
}
|
||||
}
|
||||
|
||||
// Show a Toast message (SnackBar in Flutter)
|
||||
void _showToast(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
|
@ -90,7 +88,7 @@ class _AddFriendPageState extends State<AddFriendPage> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchFriends(); // Fetch the friends when the page loads
|
||||
_fetchFriends();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,38 +1,207 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class PlaceholderPageJoin extends StatelessWidget {
|
||||
final String description;
|
||||
class JoinMatchPage extends StatefulWidget {
|
||||
@override
|
||||
_JoinMatchPageState createState() => _JoinMatchPageState();
|
||||
}
|
||||
|
||||
const PlaceholderPageJoin({
|
||||
Key? key,
|
||||
this.description = 'This is a placeholder page. Work in progress!',
|
||||
}) : super(key: key);
|
||||
class _JoinMatchPageState extends State<JoinMatchPage> {
|
||||
TextEditingController _matchIdController = TextEditingController();
|
||||
bool _isJoined = false;
|
||||
bool _isLoading = false;
|
||||
int _player1Score = 0;
|
||||
int _player2Score = 0;
|
||||
|
||||
final String _joinMatchApiUrl = 'http://10.0.0.10:9134/joinmatch';
|
||||
final String _endMatchApiUrl = 'http://10.0.0.10:9134/endmatch'; // Replace with your API endpoint
|
||||
|
||||
// Join Match Function
|
||||
Future<void> _joinMatch() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final String? token = prefs.getString('token');
|
||||
final String matchId = _matchIdController.text;
|
||||
|
||||
if (token == null) {
|
||||
_showToast('No token found. Please login again.');
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(_joinMatchApiUrl),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'token': token, 'match_id': int.parse(matchId)}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
setState(() {
|
||||
_isJoined = true;
|
||||
_player1Score = 0; // Reset scores for the new match
|
||||
_player2Score = 0;
|
||||
});
|
||||
_showToast('Joined match successfully!');
|
||||
} else {
|
||||
_showToast('Failed to join match.');
|
||||
}
|
||||
} catch (e) {
|
||||
_showToast('Error: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Increment/Decrement Player Scores
|
||||
void _updateScore(int player, int delta) {
|
||||
setState(() {
|
||||
if (player == 1) {
|
||||
_player1Score += delta;
|
||||
} else if (player == 2) {
|
||||
_player2Score += delta;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// End Match Function
|
||||
Future<void> _endMatch() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
});
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final String? token = prefs.getString('token');
|
||||
|
||||
if (token == null) {
|
||||
_showToast('No token found. Please login again.');
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(_endMatchApiUrl),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({
|
||||
'token': token,
|
||||
'player1_score': _player1Score,
|
||||
'player2_score': _player2Score,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
_showToast('Match ended successfully!');
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
_showToast('Failed to end match.');
|
||||
}
|
||||
} catch (e) {
|
||||
_showToast('Error: $e');
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _showToast(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(message)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.construction,
|
||||
size: 80,
|
||||
color: Colors.grey,
|
||||
appBar: AppBar(
|
||||
title: Text('Join Match'),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: _isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: _isJoined
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove),
|
||||
onPressed: () => _updateScore(1, -1),
|
||||
),
|
||||
Text(
|
||||
'Player 1 Score: $_player1Score',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => _updateScore(1, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove),
|
||||
onPressed: () => _updateScore(2, -1),
|
||||
),
|
||||
Text(
|
||||
'Player 2 Score: $_player2Score',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => _updateScore(2, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 32),
|
||||
ElevatedButton(
|
||||
onPressed: _endMatch,
|
||||
child: Text('End Match'),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
TextField(
|
||||
controller: _matchIdController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Enter Match ID',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
SizedBox(height: 25),
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_matchIdController.text.isNotEmpty) {
|
||||
_joinMatch();
|
||||
} else {
|
||||
_showToast('Please enter a Match ID.');
|
||||
}
|
||||
},
|
||||
child: Text('Join Match'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -11,7 +11,7 @@ class _LeaderboardPageState extends State<LeaderboardPage> {
|
|||
List<dynamic> _leaderboard = [];
|
||||
bool _isLoading = true;
|
||||
|
||||
final String _apiUrl = 'http://-/leaderboards';
|
||||
final String _apiUrl = 'http://10.0.0.10:9134/leaderboards';
|
||||
|
||||
Future<void> _fetchLeaderboard() async {
|
||||
setState(() {
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// 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:pingpongapp/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(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);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue