Yeah I'm definitely getting somewhere,
but i need to think about that tab controller
|
@ -44,6 +44,8 @@ class TetrioPlayer {
|
||||||
required this.username,
|
required this.username,
|
||||||
required this.role,
|
required this.role,
|
||||||
required this.state,
|
required this.state,
|
||||||
|
this.avatarRevision,
|
||||||
|
this.bannerRevision,
|
||||||
this.registrationTime,
|
this.registrationTime,
|
||||||
required this.badges,
|
required this.badges,
|
||||||
this.bio,
|
this.bio,
|
||||||
|
@ -55,11 +57,14 @@ class TetrioPlayer {
|
||||||
required this.xp,
|
required this.xp,
|
||||||
required this.supporterTier,
|
required this.supporterTier,
|
||||||
required this.verified,
|
required this.verified,
|
||||||
|
this.badstanding,
|
||||||
|
this.bot,
|
||||||
required this.connections,
|
required this.connections,
|
||||||
required this.tlSeason1,
|
required this.tlSeason1,
|
||||||
required this.sprint,
|
required this.sprint,
|
||||||
required this.blitz,
|
required this.blitz,
|
||||||
this.zen,
|
this.zen,
|
||||||
|
this.distinguishment,
|
||||||
});
|
});
|
||||||
|
|
||||||
double get level =>
|
double get level =>
|
||||||
|
@ -94,6 +99,7 @@ class TetrioPlayer {
|
||||||
? Distinguishment.fromJson(json['distinguishment'])
|
? Distinguishment.fromJson(json['distinguishment'])
|
||||||
: null;
|
: null;
|
||||||
friendCount = json['friend_count'] != null ? json['friend_count'] : 0;
|
friendCount = json['friend_count'] != null ? json['friend_count'] : 0;
|
||||||
|
badstanding = json['badstanding'] != null ? json['badstanding'] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getRecords() async {
|
Future<void> getRecords() async {
|
||||||
|
@ -139,6 +145,8 @@ class TetrioPlayer {
|
||||||
data['bio'] = bio;
|
data['bio'] = bio;
|
||||||
data['connections'] = connections.toJson();
|
data['connections'] = connections.toJson();
|
||||||
data['friend_count'] = friendCount;
|
data['friend_count'] = friendCount;
|
||||||
|
data['badstanding'] = badstanding;
|
||||||
|
data['bot'] = bot;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,6 +571,8 @@ class TetraLeagueAlpha {
|
||||||
this.vs,
|
this.vs,
|
||||||
this.records});
|
this.records});
|
||||||
|
|
||||||
|
double get winrate => gamesWon / gamesPlayed;
|
||||||
|
|
||||||
TetraLeagueAlpha.fromJson(Map<String, dynamic> json) {
|
TetraLeagueAlpha.fromJson(Map<String, dynamic> json) {
|
||||||
gamesPlayed = json['gamesplayed'];
|
gamesPlayed = json['gamesplayed'];
|
||||||
gamesWon = json['gameswon'];
|
gamesWon = json['gameswon'];
|
||||||
|
@ -586,6 +596,9 @@ class TetraLeagueAlpha {
|
||||||
}
|
}
|
||||||
|
|
||||||
double? get app => apm! / (pps! * 60);
|
double? get app => apm! / (pps! * 60);
|
||||||
|
double? get vsapm => vs! / apm!;
|
||||||
|
double? get dss => (vs! / 100) - (apm! / 60);
|
||||||
|
double? get dsp => ((vs! / 100) - (apm! / 60)) / pps!;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
|
|
@ -7,6 +7,9 @@ void main() {
|
||||||
databaseFactory = databaseFactoryFfi;
|
databaseFactory = databaseFactoryFfi;
|
||||||
runApp(MaterialApp(
|
runApp(MaterialApp(
|
||||||
home: MainView(),
|
home: MainView(),
|
||||||
theme: ThemeData(fontFamily: 'Eurostile Round'),
|
theme: ThemeData(
|
||||||
|
fontFamily: 'Eurostile Round',
|
||||||
|
colorScheme: ColorScheme.dark(),
|
||||||
|
scaffoldBackgroundColor: Colors.black),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ class MainView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<TetrioPlayer> fetchTetrioPlayer(String user) async {
|
Future<TetrioPlayer> fetchTetrioPlayer(String user) async {
|
||||||
var url = Uri.https('ch.tetr.io', 'api/users/$user');
|
var url = Uri.https('ch.tetr.io', 'api/users/${user.toLowerCase()}');
|
||||||
final response = await http.get(url);
|
final response = await http.get(url);
|
||||||
// final response = await http.get(Uri.parse('https://ch.tetr.io/'));
|
// final response = await http.get(Uri.parse('https://ch.tetr.io/'));
|
||||||
|
|
||||||
|
@ -63,11 +63,7 @@ class _MainViewState extends State<MainView> {
|
||||||
|
|
||||||
Widget _searchTextField() {
|
Widget _searchTextField() {
|
||||||
return TextField(
|
return TextField(
|
||||||
decoration: const InputDecoration(
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
|
||||||
borderSide: BorderSide(color: Colors.white))),
|
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
|
||||||
shadows: <Shadow>[
|
shadows: <Shadow>[
|
||||||
Shadow(
|
Shadow(
|
||||||
offset: Offset(0.0, 0.0),
|
offset: Offset(0.0, 0.0),
|
||||||
|
@ -92,7 +88,6 @@ class _MainViewState extends State<MainView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
drawer: NavDrawer(),
|
drawer: NavDrawer(),
|
||||||
backgroundColor: Colors.black,
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: !_searchBoolean
|
title: !_searchBoolean
|
||||||
? Text(
|
? Text(
|
||||||
|
@ -163,18 +158,20 @@ class _MainViewState extends State<MainView> {
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
children: [
|
children: [
|
||||||
_UserThingy(player: snapshot.data!),
|
_UserThingy(player: snapshot.data!),
|
||||||
|
_PlayerTabSection(context, snapshot.data!)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Text('${snapshot.error}',
|
return Center(
|
||||||
|
child: Text('${snapshot.error}',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
color: Colors.white,
|
fontSize: 42)));
|
||||||
fontSize: 42));
|
|
||||||
}
|
}
|
||||||
|
return const Center(
|
||||||
// By default, show a loading spinner.
|
child: CircularProgressIndicator(
|
||||||
return const CircularProgressIndicator();
|
color: Colors.white,
|
||||||
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -282,6 +279,9 @@ class _UserThingy extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
|
bool bigScreen = constraints.maxWidth > 768;
|
||||||
|
double bannerHeight = bigScreen ? 240 : 120;
|
||||||
|
double pfpHeight = bigScreen ? 64 : 32;
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Flex(
|
Flex(
|
||||||
|
@ -296,20 +296,31 @@ class _UserThingy extends StatelessWidget {
|
||||||
Image.network(
|
Image.network(
|
||||||
"https://tetr.io/user-content/banners/${player.userId}.jpg?rv=${player.bannerRevision}",
|
"https://tetr.io/user-content/banners/${player.userId}.jpg?rv=${player.bannerRevision}",
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
height: 240,
|
height: bannerHeight,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.fromLTRB(
|
padding: EdgeInsets.fromLTRB(
|
||||||
0, player.bannerRevision != null ? 170 : 64, 0, 0),
|
0,
|
||||||
|
player.bannerRevision != null
|
||||||
|
? bannerHeight / 1.4
|
||||||
|
: pfpHeight,
|
||||||
|
0,
|
||||||
|
0),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(1000),
|
borderRadius: BorderRadius.circular(1000),
|
||||||
child: Image.network(
|
child: player.role == "banned"
|
||||||
|
? Image.asset(
|
||||||
|
"res/avatars/tetrio_banned.png",
|
||||||
|
fit: BoxFit.fitHeight,
|
||||||
|
height: 128,
|
||||||
|
)
|
||||||
|
: Image.network(
|
||||||
"https://tetr.io/user-content/avatars/${player.userId}.jpg?rv=${player.avatarRevision}",
|
"https://tetr.io/user-content/avatars/${player.userId}.jpg?rv=${player.avatarRevision}",
|
||||||
fit: BoxFit.fitHeight,
|
fit: BoxFit.fitHeight,
|
||||||
height: 128,
|
height: 128,
|
||||||
errorBuilder: (context, error, stackTrace) =>
|
errorBuilder: (context, error, stackTrace) =>
|
||||||
Image.network(
|
Image.asset(
|
||||||
"https://tetr.io/res/avatar.png",
|
"res/avatars/tetrio_anon.png",
|
||||||
fit: BoxFit.fitHeight,
|
fit: BoxFit.fitHeight,
|
||||||
height: 128,
|
height: 128,
|
||||||
),
|
),
|
||||||
|
@ -322,15 +333,13 @@ class _UserThingy extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(player.username,
|
Text(player.username,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
color: Colors.white,
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
fontSize: 42)),
|
|
||||||
Text(
|
Text(
|
||||||
player.userId,
|
player.userId,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round Condensed",
|
fontFamily: "Eurostile Round Condensed",
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 14),
|
fontSize: 14),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -348,7 +357,8 @@ class _UserThingy extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
_StatCellNum(
|
_StatCellNum(
|
||||||
playerStat: player.level,
|
playerStat: player.level,
|
||||||
playerStatLabel: "Level",
|
playerStatLabel: "XP Level",
|
||||||
|
isScreenBig: bigScreen,
|
||||||
snackBar:
|
snackBar:
|
||||||
"${player.xp.floor().toString()} XP, ${((player.level - player.level.floor()) * 100).toStringAsFixed(2)} % until next level",
|
"${player.xp.floor().toString()} XP, ${((player.level - player.level.floor()) * 100).toStringAsFixed(2)} % until next level",
|
||||||
),
|
),
|
||||||
|
@ -356,32 +366,85 @@ class _UserThingy extends StatelessWidget {
|
||||||
_StatCellNum(
|
_StatCellNum(
|
||||||
playerStat: (player.gameTime.inSeconds / 3600),
|
playerStat: (player.gameTime.inSeconds / 3600),
|
||||||
playerStatLabel: "Hours\nPlayed",
|
playerStatLabel: "Hours\nPlayed",
|
||||||
|
isScreenBig: bigScreen,
|
||||||
snackBar: player.gameTime.toString(),
|
snackBar: player.gameTime.toString(),
|
||||||
),
|
),
|
||||||
if (player.gamesPlayed >= 0)
|
if (player.gamesPlayed >= 0)
|
||||||
_StatCellNum(
|
_StatCellNum(
|
||||||
playerStat: player.gamesPlayed,
|
playerStat: player.gamesPlayed,
|
||||||
playerStatLabel: "Games\nPlayed"),
|
isScreenBig: bigScreen,
|
||||||
|
playerStatLabel: "Online\nGames"),
|
||||||
if (player.gamesWon >= 0)
|
if (player.gamesWon >= 0)
|
||||||
_StatCellNum(
|
_StatCellNum(
|
||||||
playerStat: player.gamesWon,
|
playerStat: player.gamesWon,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
playerStatLabel: "Games\nWon"),
|
playerStatLabel: "Games\nWon"),
|
||||||
if (player.friendCount > 0)
|
if (player.friendCount > 0)
|
||||||
_StatCellNum(
|
_StatCellNum(
|
||||||
playerStat: player.friendCount,
|
playerStat: player.friendCount,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
playerStatLabel: "Friends"),
|
playerStatLabel: "Friends"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Text(
|
: Text(
|
||||||
"BANNED",
|
"BANNED",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.w900,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
fontSize: 60,
|
fontSize: bigScreen ? 60 : 45,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (player.badstanding != null)
|
||||||
|
player.badstanding!
|
||||||
|
? Text(
|
||||||
|
"BAD STANDING",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
color: Colors.red,
|
||||||
|
fontSize: bigScreen ? 60 : 45,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Text(
|
||||||
|
"Was in bad standing long time ago",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (player.country != null)
|
||||||
|
Text("${player.country?.toUpperCase()} • ",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: "Eurostile Round",
|
||||||
|
fontSize: 16,
|
||||||
|
)),
|
||||||
|
Text(
|
||||||
|
"${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${player.registrationTime}'}",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: "Eurostile Round",
|
||||||
|
fontSize: 16,
|
||||||
|
)),
|
||||||
|
const Text(" • ",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round",
|
||||||
|
fontSize: 16,
|
||||||
|
)),
|
||||||
|
Text(
|
||||||
|
player.supporterTier == 0
|
||||||
|
? "Not a supporter"
|
||||||
|
: "Supporter tier ${player.supporterTier}",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: "Eurostile Round",
|
||||||
|
fontSize: 16,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
Wrap(
|
Wrap(
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
alignment: WrapAlignment.center,
|
alignment: WrapAlignment.center,
|
||||||
|
@ -389,12 +452,54 @@ class _UserThingy extends StatelessWidget {
|
||||||
crossAxisAlignment: WrapCrossAlignment.start,
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
for (var badge in player.badges)
|
||||||
"${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${player.registrationTime}'}",
|
IconButton(
|
||||||
|
onPressed: () => showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
badge.label,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round",
|
fontFamily: "Eurostile Round Extended"),
|
||||||
color: Colors.white,
|
),
|
||||||
fontSize: 16,
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
crossAxisAlignment:
|
||||||
|
WrapCrossAlignment.center,
|
||||||
|
spacing: 25,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
"res/tetrio_badges/${badge.badgeId}.png"),
|
||||||
|
Text(badge.ts != null
|
||||||
|
? "Obtained ${badge.ts}"
|
||||||
|
: "That badge was assigned manualy by TETR.IO admins"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: const Text('OK'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
tooltip: badge.label,
|
||||||
|
icon: Image.asset(
|
||||||
|
"res/tetrio_badges/${badge.badgeId}.png",
|
||||||
|
height: 64,
|
||||||
|
width: 64,
|
||||||
))
|
))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -406,25 +511,29 @@ class _UserThingy extends StatelessWidget {
|
||||||
|
|
||||||
class _StatCellNum extends StatelessWidget {
|
class _StatCellNum extends StatelessWidget {
|
||||||
const _StatCellNum(
|
const _StatCellNum(
|
||||||
{super.key,
|
{required this.playerStat,
|
||||||
required this.playerStat,
|
|
||||||
required this.playerStatLabel,
|
required this.playerStatLabel,
|
||||||
this.snackBar});
|
required this.isScreenBig,
|
||||||
|
this.snackBar,
|
||||||
|
this.fractionDigits});
|
||||||
|
|
||||||
final num playerStat;
|
final num playerStat;
|
||||||
final String playerStatLabel;
|
final String playerStatLabel;
|
||||||
|
final bool isScreenBig;
|
||||||
final String? snackBar;
|
final String? snackBar;
|
||||||
|
final int? fractionDigits;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
playerStat.floor().toString(),
|
fractionDigits != null
|
||||||
style: const TextStyle(
|
? playerStat.toStringAsFixed(fractionDigits!)
|
||||||
|
: playerStat.floor().toString(),
|
||||||
|
style: TextStyle(
|
||||||
fontFamily: "Eurostile Round Extended",
|
fontFamily: "Eurostile Round Extended",
|
||||||
color: Colors.white,
|
fontSize: isScreenBig ? 32 : 24,
|
||||||
fontSize: 32,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
snackBar == null
|
snackBar == null
|
||||||
|
@ -433,7 +542,6 @@ class _StatCellNum extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round",
|
fontFamily: "Eurostile Round",
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -447,7 +555,6 @@ class _StatCellNum extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: "Eurostile Round",
|
fontFamily: "Eurostile Round",
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
|
@ -455,3 +562,204 @@ class _StatCellNum extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _PlayerTabSection(BuildContext context, TetrioPlayer player) {
|
||||||
|
bool bigScreen = MediaQuery.of(context).size.width > 768;
|
||||||
|
return DefaultTabController(
|
||||||
|
length: 4,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
child: TabBar(tabs: [
|
||||||
|
Tab(text: "Tetra League"),
|
||||||
|
Tab(text: "40 Lines"),
|
||||||
|
Tab(text: "Blitz"),
|
||||||
|
Tab(text: "Other"),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
//Add this to give height
|
||||||
|
height: MediaQuery.of(context).size.height,
|
||||||
|
child: TabBarView(children: [
|
||||||
|
Container(
|
||||||
|
child: Column(
|
||||||
|
children: (player.tlSeason1.gamesPlayed > 0)
|
||||||
|
? [
|
||||||
|
Text("Tetra League",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
if (player.tlSeason1.gamesPlayed >= 10)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
"res/tetrio_tl_alpha_ranks/${player.tlSeason1.rank}.png",
|
||||||
|
height: bigScreen ? 128 : 64,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${player.tlSeason1.rating.toStringAsFixed(2)} TR",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily:
|
||||||
|
"Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
Text(
|
||||||
|
"Top ${(player.tlSeason1.percentile * 100).toStringAsFixed(2)}% • Top Rank: ${player.tlSeason1.bestRank.toUpperCase()} • Glicko: ${player.tlSeason1.glicko?.toStringAsFixed(2)}±${player.tlSeason1.rd?.toStringAsFixed(2)}${player.tlSeason1.decaying ? ' • Decaying' : ''}")
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"${10 - player.tlSeason1.gamesPlayed} games until being ranked",
|
||||||
|
softWrap: true,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
)),
|
||||||
|
//Text("Top ${(player.tlSeason1.percentile * 100).toStringAsFixed(2)}% • Glicko: ${player.tlSeason1.glicko?.toStringAsFixed(2)}±${player.tlSeason1.rd?.toStringAsFixed(2)}${player.tlSeason1.decaying ? ' • Decaying' : ''}")
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
||||||
|
child: Wrap(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 25,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
children: [
|
||||||
|
if (player.tlSeason1.apm != null)
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.apm!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 2,
|
||||||
|
playerStatLabel: "Attack\nPer Minute"),
|
||||||
|
if (player.tlSeason1.pps != null)
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.pps!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 2,
|
||||||
|
playerStatLabel: "Pieces\nPer Second"),
|
||||||
|
if (player.tlSeason1.apm != null)
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.vs!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 2,
|
||||||
|
playerStatLabel: "Versus\nScore"),
|
||||||
|
if (player.tlSeason1.standing > 0)
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.standing,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
playerStatLabel: "Leaderboard\nplacement"),
|
||||||
|
if (player.tlSeason1.standingLocal > 0)
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.standingLocal,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
playerStatLabel: "Country LB\nplacement"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.gamesPlayed,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
playerStatLabel: "Games\nplayed"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.gamesWon,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
playerStatLabel: "Games\nwon"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.winrate * 100,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 2,
|
||||||
|
playerStatLabel: "Winrate\nprecentage"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (player.tlSeason1.apm != null &&
|
||||||
|
player.tlSeason1.pps != null &&
|
||||||
|
player.tlSeason1.apm != null)
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text("Nerd Stats",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.fromLTRB(0, 16, 0, 48),
|
||||||
|
child: Wrap(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 25,
|
||||||
|
crossAxisAlignment:
|
||||||
|
WrapCrossAlignment.start,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
children: [
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.app!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 3,
|
||||||
|
playerStatLabel: "Attack\nPer Piece"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.vsapm!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 3,
|
||||||
|
playerStatLabel: "VS/APM"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.dss!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 3,
|
||||||
|
playerStatLabel:
|
||||||
|
"Downstack\nPer Second"),
|
||||||
|
_StatCellNum(
|
||||||
|
playerStat: player.tlSeason1.dsp!,
|
||||||
|
isScreenBig: bigScreen,
|
||||||
|
fractionDigits: 3,
|
||||||
|
playerStatLabel:
|
||||||
|
"Downstack\nPer Piece"),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
Text("That user never played Tetra League",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Text("40 Lines",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Text("Blitz",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Text("Other info",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: "Eurostile Round Extended",
|
||||||
|
fontSize: bigScreen ? 42 : 28)),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
123
pubspec.yaml
|
@ -1,8 +1,6 @@
|
||||||
name: tetra_stats
|
name: tetra_stats
|
||||||
description: Track your and other player stats in TETR.IO
|
description: Track your and other player stats in TETR.IO
|
||||||
# The following line prevents the package from being accidentally published to
|
publish_to: 'none'
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
|
||||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
# The following defines the version and build number for your application.
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
# A version number is three numbers separated by dots, like 1.2.43
|
||||||
|
@ -31,10 +29,6 @@ dependencies:
|
||||||
http:
|
http:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
sqflite: ^2.2.8+2
|
sqflite: ^2.2.8+2
|
||||||
sqflite_common_ffi: any
|
sqflite_common_ffi: any
|
||||||
|
@ -44,55 +38,94 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
|
||||||
# package. See that file for information about deactivating specific lint
|
|
||||||
# rules and activating additional ones.
|
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
|
||||||
|
|
||||||
# The following section is specific to Flutter packages.
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
||||||
# The following line ensures that the Material Icons font is
|
|
||||||
# included with your application, so that you can use the icons in
|
|
||||||
# the material Icons class.
|
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
|
- res/avatars/tetrio_anon.png
|
||||||
|
- res/avatars/tetrio_banned.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/x.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/u.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/ss.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/s+.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/s.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/s-.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/a+.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/a.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/a-.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/b+.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/b.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/b-.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/c+.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/c.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/c-.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/d+.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/d.png
|
||||||
|
- res/tetrio_tl_alpha_ranks/z.png
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
- res/tetrio_badges/5mblast_1.png
|
||||||
# assets:
|
- res/tetrio_badges/5mblast_10.png
|
||||||
# - images/a_dot_burr.jpeg
|
- res/tetrio_badges/5mblast_100.png
|
||||||
# - images/a_dot_ham.jpeg
|
- res/tetrio_badges/5mblast_1000.png
|
||||||
|
- res/tetrio_badges/20tsd.png
|
||||||
|
- res/tetrio_badges/100player.png
|
||||||
|
- res/tetrio_badges/allclear.png
|
||||||
|
- res/tetrio_badges/bugbounty.png
|
||||||
|
- res/tetrio_badges/cometopen_1.png
|
||||||
|
- res/tetrio_badges/cometopen_2.png
|
||||||
|
- res/tetrio_badges/cometopen_3.png
|
||||||
|
- res/tetrio_badges/early-supporter.png
|
||||||
|
- res/tetrio_badges/founder.png
|
||||||
|
- res/tetrio_badges/galactic2x2_1.png
|
||||||
|
- res/tetrio_badges/ggc_2.png
|
||||||
|
- res/tetrio_badges/heart.png
|
||||||
|
- res/tetrio_badges/hnprism_1.png
|
||||||
|
- res/tetrio_badges/hnprism_2.png
|
||||||
|
- res/tetrio_badges/ift_1.png
|
||||||
|
- res/tetrio_badges/ift_2.png
|
||||||
|
- res/tetrio_badges/ift_3.png
|
||||||
|
- res/tetrio_badges/infdev.png
|
||||||
|
- res/tetrio_badges/kod_by_founder.png
|
||||||
|
- res/tetrio_badges/kod_founder.png
|
||||||
|
- res/tetrio_badges/leaderboard1.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_1.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_2.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_3.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_superlobby.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_superlobby2.png
|
||||||
|
- res/tetrio_badges/mmc_tabi_superlobby3.png
|
||||||
|
- res/tetrio_badges/redgevo_2.png
|
||||||
|
- res/tetrio_badges/redgevo_3.png
|
||||||
|
- res/tetrio_badges/rengervl_1.png
|
||||||
|
- res/tetrio_badges/rengervl_2.png
|
||||||
|
- res/tetrio_badges/rengervl_3.png
|
||||||
|
- res/tetrio_badges/sakurablend_1.png
|
||||||
|
- res/tetrio_badges/scuncapped_1.png
|
||||||
|
- res/tetrio_badges/scuncapped_2.png
|
||||||
|
- res/tetrio_badges/secretgrade.png
|
||||||
|
- res/tetrio_badges/sfu_raccoon_1.png
|
||||||
|
- res/tetrio_badges/superlobby.png
|
||||||
|
- res/tetrio_badges/superlobby2.png
|
||||||
|
- res/tetrio_badges/tawshdsl_uncapped.png
|
||||||
|
- res/tetrio_badges/tawsignite_expert.png
|
||||||
|
- res/tetrio_badges/tawslg.png
|
||||||
|
- res/tetrio_badges/tetralympic_masters.png
|
||||||
|
- res/tetrio_badges/ttsdtc_1.png
|
||||||
|
- res/tetrio_badges/ttsdtc_2.png
|
||||||
|
- res/tetrio_badges/ttsdtc_3.png
|
||||||
|
- res/tetrio_badges/underdog_predict.png
|
||||||
|
- res/tetrio_badges/wpl_1.png
|
||||||
|
- res/tetrio_badges/wplc_1.png
|
||||||
|
- res/tetrio_badges/wplc_2.png
|
||||||
|
- res/tetrio_badges/wplc_3.png
|
||||||
|
- res/tetrio_badges/wplc_participation.png
|
||||||
|
|
||||||
# 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
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||||
|
|
||||||
# For details regarding adding assets from package dependencies, see
|
# For details regarding adding assets from package dependencies, see
|
||||||
# https://flutter.dev/assets-and-images/#from-packages
|
# https://flutter.dev/assets-and-images/#from-packages
|
||||||
|
|
||||||
# To add custom fonts to your application, add a fonts section here,
|
|
||||||
# in this "flutter" section. Each entry in this list should have a
|
|
||||||
# "family" key with the font family name, and a "fonts" key with a
|
|
||||||
# list giving the asset and other descriptors for the font. For
|
|
||||||
# example:
|
|
||||||
# fonts:
|
|
||||||
# - family: Schyler
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/Schyler-Regular.ttf
|
|
||||||
# - asset: fonts/Schyler-Italic.ttf
|
|
||||||
# style: italic
|
|
||||||
# - family: Trajan Pro
|
|
||||||
# fonts:
|
|
||||||
# - asset: fonts/TrajanPro.ttf
|
|
||||||
# - asset: fonts/TrajanPro_Bold.ttf
|
|
||||||
# weight: 700
|
|
||||||
#
|
|
||||||
# For details regarding fonts from package dependencies,
|
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: Eurostile Round
|
- family: Eurostile Round
|
||||||
fonts:
|
fonts:
|
||||||
|
|
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 1.5 KiB |