Added rank view, minor match page refactor. bump version to 0.0.51
|
@ -67,9 +67,6 @@ class _CreateMatchPageState extends State<CreateMatchPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
|
||||||
title: Text('Create Match'),
|
|
||||||
),
|
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
|
|
@ -15,11 +15,9 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
int _player1Score = 0;
|
int _player1Score = 0;
|
||||||
int _player2Score = 0;
|
int _player2Score = 0;
|
||||||
|
String? _player1name;
|
||||||
|
String? _player2name;
|
||||||
String? _matchId;
|
String? _matchId;
|
||||||
bool _showJoinAsCheckbox = false;
|
|
||||||
bool _joinAsPlayer2 = false;
|
|
||||||
bool _joinAsPlayer3 = false;
|
|
||||||
bool _joinAsPlayer4 = false;
|
|
||||||
|
|
||||||
final String _joinMatchApiUrl = '$apiurl/joinmatch';
|
final String _joinMatchApiUrl = '$apiurl/joinmatch';
|
||||||
final String _endMatchApiUrl = '$apiurl/endmatch';
|
final String _endMatchApiUrl = '$apiurl/endmatch';
|
||||||
|
@ -49,8 +47,11 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
final responseData = json.decode(response.body);
|
||||||
setState(() {
|
setState(() {
|
||||||
_isJoined = true;
|
_isJoined = true;
|
||||||
|
_player1name = responseData['player1_name'];
|
||||||
|
_player2name = responseData['player2_name'];
|
||||||
_player1Score = 0;
|
_player1Score = 0;
|
||||||
_player2Score = 0;
|
_player2Score = 0;
|
||||||
_matchId = matchId;
|
_matchId = matchId;
|
||||||
|
@ -125,79 +126,115 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_matchIdController.addListener(() {
|
|
||||||
if (_matchIdController.text.contains(RegExp(r'[Dd]'))) {
|
|
||||||
setState(() {
|
|
||||||
_showJoinAsCheckbox = true;
|
|
||||||
});
|
|
||||||
_showToast('We\'re sorry, this feature isn\'t available yet');
|
|
||||||
} else {
|
|
||||||
setState(() {
|
|
||||||
_showJoinAsCheckbox = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
|
||||||
title: Text('Join Match'),
|
|
||||||
),
|
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? Center(child: CircularProgressIndicator())
|
? Center(child: CircularProgressIndicator())
|
||||||
: _isJoined
|
: _isJoined
|
||||||
? Column(
|
? Center(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
// Player 1
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
Text(
|
||||||
children: [
|
_player1name ?? 'Player 1',
|
||||||
IconButton(
|
style: TextStyle(
|
||||||
icon: Icon(Icons.remove),
|
fontSize: 18,
|
||||||
onPressed: () => _updateScore(1, -1),
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'Player 1 Score: $_player1Score',
|
SizedBox(height: 8),
|
||||||
style: TextStyle(fontSize: 20),
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.remove, color: Colors.white),
|
||||||
|
onPressed: () => _updateScore(1, -1),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: Colors.white, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'$_player1Score',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add, color: Colors.white),
|
||||||
|
onPressed: () => _updateScore(1, 1),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Divider(
|
||||||
|
color: Colors.white,
|
||||||
|
thickness: 2,
|
||||||
|
indent: 80,
|
||||||
|
endIndent: 80,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
// Player 2
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.remove, color: Colors.white),
|
||||||
|
onPressed: () => _updateScore(2, -1),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: Colors.white, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'$_player2Score',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.add, color: Colors.white),
|
||||||
|
onPressed: () => _updateScore(2, 1),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
_player2name ?? 'Player 2',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
IconButton(
|
),
|
||||||
icon: Icon(Icons.add),
|
SizedBox(height: 32),
|
||||||
onPressed: () => _updateScore(1, 1),
|
ElevatedButton(
|
||||||
),
|
onPressed: _endMatch,
|
||||||
],
|
child: Text('End Match'),
|
||||||
),
|
),
|
||||||
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(
|
: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
@ -222,40 +259,6 @@ class _JoinMatchPageState extends State<JoinMatchPage> {
|
||||||
},
|
},
|
||||||
child: Text('Join Match'),
|
child: Text('Join Match'),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
|
||||||
if (_showJoinAsCheckbox)
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
Text('Join as:'),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: Text('Player 2'),
|
|
||||||
value: _joinAsPlayer2,
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
_joinAsPlayer2 = value ?? false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: Text('Player 3'),
|
|
||||||
value: _joinAsPlayer3,
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
_joinAsPlayer3 = value ?? false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
CheckboxListTile(
|
|
||||||
title: Text('Player 4'),
|
|
||||||
value: _joinAsPlayer4,
|
|
||||||
onChanged: (bool? value) {
|
|
||||||
setState(() {
|
|
||||||
_joinAsPlayer4 = value ?? false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -74,6 +74,17 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getRankImage(int? elo) {
|
||||||
|
if (elo == null) return 'ranks/none.png';
|
||||||
|
if (elo > 1000) return 'ranks/u.png';
|
||||||
|
if (elo > 750) return 'ranks/s.png';
|
||||||
|
if (elo > 400) return 'ranks/a.png';
|
||||||
|
if (elo > 200) return 'ranks/b.png';
|
||||||
|
if (elo > 100) return 'ranks/c.png';
|
||||||
|
if (elo > 30) return 'ranks/d.png';
|
||||||
|
return 'ranks/none.png';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -88,7 +99,6 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||||
padding: EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// Profile Icon
|
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
backgroundColor: _generateRandomColor(),
|
backgroundColor: _generateRandomColor(),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -99,6 +109,7 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||||
),
|
),
|
||||||
radius: 40,
|
radius: 40,
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(width: 16),
|
SizedBox(width: 16),
|
||||||
// Profile Info
|
// Profile Info
|
||||||
Column(
|
Column(
|
||||||
|
@ -116,10 +127,15 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||||
Text('ELO: ${_elo ?? 'N/A'}'),
|
Text('ELO: ${_elo ?? 'N/A'}'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 25),
|
||||||
|
Image.asset(
|
||||||
|
getRankImage(_elo),
|
||||||
|
width: 137,
|
||||||
|
height: 137,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16),
|
|
||||||
// Recent Matches
|
// Recent Matches
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _matches.isEmpty
|
child: _matches.isEmpty
|
||||||
|
|
13
pubspec.yaml
|
@ -2,7 +2,7 @@ name: pingpongapp
|
||||||
description: "DTH Ping Pong Score tracking app"
|
description: "DTH Ping Pong Score tracking app"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.34+1
|
version: 0.0.51+2
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.4.3 <4.0.0'
|
sdk: '>=3.4.3 <4.0.0'
|
||||||
|
@ -17,6 +17,7 @@ dependencies:
|
||||||
package_info: ^2.0.2
|
package_info: ^2.0.2
|
||||||
font_awesome_flutter: ^10.8.0
|
font_awesome_flutter: ^10.8.0
|
||||||
url_launcher: ^6.3.1
|
url_launcher: ^6.3.1
|
||||||
|
fl_chart: ^0.70.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -26,8 +27,14 @@ flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
assets:
|
||||||
# - images/a_dot_burr.jpeg
|
- ranks/none.png
|
||||||
|
- ranks/A.png
|
||||||
|
- ranks/B.png
|
||||||
|
- ranks/C.png
|
||||||
|
- ranks/D.png
|
||||||
|
- ranks/S.png
|
||||||
|
- ranks/U.png
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
|
BIN
ranks/A.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
ranks/B.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
ranks/C.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
ranks/D.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
ranks/S.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
ranks/U.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
ranks/none.png
Normal file
After Width: | Height: | Size: 32 KiB |