Thinking about adaptivity
This commit is contained in:
parent
1b9249f36b
commit
874d5a2e5c
|
@ -51,6 +51,7 @@ android {
|
|||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.dan63.tetra_stats"
|
||||
testApplicationId "com.dan63.tetra_stats.dev_build"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
|
|
|
@ -49,7 +49,7 @@ class Summaries {
|
|||
];
|
||||
league =
|
||||
TetraLeague.fromJson(json['league'], DateTime.now(), currentSeason, i);
|
||||
if (json['league']['past'].isNotEmpty)
|
||||
if (json['league']['past'] != null && json['league']['past'].isNotEmpty)
|
||||
for (var key in json['league']['past'].keys) {
|
||||
pastLeague[int.parse(key)] = TetraLeague.fromJson(
|
||||
json['league']['past'][key],
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/// Locales: 3
|
||||
/// Strings: 1818 (606 per locale)
|
||||
///
|
||||
/// Built on 2024-09-30 at 21:23 UTC
|
||||
/// Built on 2024-11-16 at 13:39 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
|
|
|
@ -59,7 +59,17 @@ ThemeData theme = ThemeData(
|
|||
expandedAlignment: Alignment.bottomCenter,
|
||||
),
|
||||
dropdownMenuTheme: DropdownMenuThemeData(textStyle: TextStyle(fontFamily: "Eurostile Round", fontSize: 18)),
|
||||
scaffoldBackgroundColor: Colors.black
|
||||
scaffoldBackgroundColor: Colors.black,
|
||||
tooltipTheme: TooltipThemeData(
|
||||
textStyle: TextStyle(color: Colors.white),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
border: Border.all(
|
||||
color: Colors.white
|
||||
),
|
||||
color: Colors.black,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
void main() async {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -118,7 +118,10 @@ class _DestinationSavedData extends State<DestinationSavedData> {
|
|||
child: Column(
|
||||
children: [
|
||||
Card(
|
||||
child: TabBar(tabs: [
|
||||
child: TabBar(
|
||||
labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28),
|
||||
labelColor: Theme.of(context).colorScheme.primary,
|
||||
tabs: [
|
||||
Tab(text: "S${currentSeason} TL States"),
|
||||
Tab(text: "S1 TL States"),
|
||||
Tab(text: "TL Records")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:tetra_stats/data_objects/cutoff_tetrio.dart';
|
||||
import 'package:tetra_stats/data_objects/news.dart';
|
||||
import 'package:tetra_stats/data_objects/p1nkl0bst3r.dart';
|
||||
|
@ -24,6 +25,7 @@ import 'package:tetra_stats/main.dart';
|
|||
|
||||
late Future<FetchResults> _data;
|
||||
TetrioPlayersLeaderboard? _everyone;
|
||||
int destination = 0;
|
||||
|
||||
Future<FetchResults> getData(String searchFor) async {
|
||||
TetrioPlayer player;
|
||||
|
@ -102,15 +104,23 @@ Map<Cards, String> cardsTitles = {
|
|||
late ScrollController controller;
|
||||
|
||||
class _MainState extends State<MainView> with TickerProviderStateMixin {
|
||||
int destination = 0;
|
||||
String _searchFor = "6098518e3d5155e6ec429cdc";
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
Timer _backgroundUpdate = Timer(const Duration(days: 365), (){});
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
teto.open();
|
||||
controller = ScrollController();
|
||||
changePlayer(_searchFor);
|
||||
|
||||
if (prefs.getBool("updateInBG") == true) {
|
||||
_backgroundUpdate = Timer(Duration(minutes: 5), () {
|
||||
changePlayer(_searchFor);
|
||||
});
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -139,47 +149,144 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
);
|
||||
}
|
||||
|
||||
NavigationDestination getMobileDestinationButton(IconData icon, String title){
|
||||
return NavigationDestination(
|
||||
icon: Tooltip(
|
||||
message: title,
|
||||
child: Icon(icon)
|
||||
),
|
||||
selectedIcon: Icon(icon),
|
||||
label: title,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
drawer: SearchDrawer(changePlayer: changePlayer, controller: _searchController),
|
||||
body: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
TweenAnimationBuilder(
|
||||
child: NavigationRail(
|
||||
leading: FloatingActionButton(
|
||||
elevation: 0,
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
trailing: IconButton(
|
||||
onPressed: () {
|
||||
// Add your onPressed code here!
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
destinations: [
|
||||
getDestinationButton(Icons.home, "Home"),
|
||||
getDestinationButton(Icons.data_thresholding_outlined, "Graphs"),
|
||||
getDestinationButton(Icons.leaderboard, "Leaderboards"),
|
||||
getDestinationButton(Icons.compress, "Cutoffs"),
|
||||
getDestinationButton(Icons.calculate, "Calc"),
|
||||
getDestinationButton(Icons.info_outline, "Information"),
|
||||
getDestinationButton(Icons.storage, "Saved Data"),
|
||||
getDestinationButton(Icons.settings, "Settings"),
|
||||
],
|
||||
selectedIndex: destination,
|
||||
onDestinationSelected: (value) {
|
||||
setState(() {
|
||||
destination = value;
|
||||
});
|
||||
},
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints){
|
||||
bool screenIsBig = constraints.maxWidth > 768.00;
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
drawer: SearchDrawer(changePlayer: changePlayer, controller: _searchController),
|
||||
endDrawer: DestinationsDrawer(changeDestination: (value) {setState(() {destination = value;});}),
|
||||
bottomNavigationBar: screenIsBig ? null : BottomAppBar(
|
||||
shape: const AutomaticNotchedShape(RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(0.0))), RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0)))),
|
||||
notchMargin: 2.0,
|
||||
height: 88,
|
||||
child: IconTheme(
|
||||
data: IconThemeData(color: Theme.of(context).colorScheme.primary),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
tooltip: 'Open navigation menu',
|
||||
icon: const Icon(Icons.menu),
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState!.openEndDrawer();
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SegmentedButton<CardMod>(
|
||||
showSelectedIcon: false,
|
||||
selected: <CardMod>{cardMod},
|
||||
segments: modeButtons[rightCard]!,
|
||||
onSelectionChanged: (p0) {
|
||||
setState(() {
|
||||
cardMod = p0.first;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
SegmentedButton<Cards>(
|
||||
showSelectedIcon: false,
|
||||
segments: <ButtonSegment<Cards>>[
|
||||
const ButtonSegment<Cards>(
|
||||
value: Cards.overview,
|
||||
tooltip: 'Overview',
|
||||
icon: Icon(Icons.calendar_view_day)),
|
||||
ButtonSegment<Cards>(
|
||||
value: Cards.tetraLeague,
|
||||
tooltip: 'Tetra League',
|
||||
icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
|
||||
ButtonSegment<Cards>(
|
||||
value: Cards.quickPlay,
|
||||
tooltip: 'Quick Play',
|
||||
icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
|
||||
ButtonSegment<Cards>(
|
||||
value: Cards.sprint,
|
||||
tooltip: '40 Lines',
|
||||
icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
|
||||
ButtonSegment<Cards>(
|
||||
value: Cards.blitz,
|
||||
tooltip: 'Blitz',
|
||||
icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
|
||||
],
|
||||
selected: <Cards>{rightCard},
|
||||
onSelectionChanged: (Set<Cards> newSelection) {
|
||||
setState(() {
|
||||
cardMod = CardMod.info;
|
||||
rightCard = newSelection.first;
|
||||
});})
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Fake "Open navigation menu" button\nHere only for symmetry',
|
||||
icon: const Icon(Icons.menu, color: Colors.transparent),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButtonLocation: screenIsBig ? null : FloatingActionButtonLocation.endDocked,
|
||||
floatingActionButton: screenIsBig ? null : FloatingActionButton(
|
||||
elevation: 0,
|
||||
onPressed: () {
|
||||
_scaffoldKey.currentState!.openDrawer();
|
||||
},
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (screenIsBig) TweenAnimationBuilder(
|
||||
child: NavigationRail(
|
||||
leading: FloatingActionButton(
|
||||
elevation: 0,
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
child: const Icon(Icons.search),
|
||||
),
|
||||
trailing: IconButton(
|
||||
tooltip: "Refresh data",
|
||||
onPressed: () {
|
||||
changePlayer(_searchFor);
|
||||
},
|
||||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
destinations: [
|
||||
getDestinationButton(Icons.home, "Home"),
|
||||
getDestinationButton(Icons.data_thresholding_outlined, "Graphs"),
|
||||
getDestinationButton(Icons.leaderboard, "Leaderboards"),
|
||||
getDestinationButton(Icons.compress, "Cutoffs"),
|
||||
getDestinationButton(Icons.calculate, "Calc"),
|
||||
getDestinationButton(Icons.info_outline, "Information"),
|
||||
getDestinationButton(Icons.storage, "Saved Data"),
|
||||
getDestinationButton(Icons.settings, "Settings"),
|
||||
],
|
||||
selectedIndex: destination,
|
||||
onDestinationSelected: (value) {
|
||||
setState(() {
|
||||
destination = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
duration: Durations.long4,
|
||||
tween: Tween<double>(begin: 0, end: 1),
|
||||
curve: Easing.standard,
|
||||
|
@ -189,23 +296,25 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
|
|||
child: Opacity(opacity: value, child: child),
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: switch (destination){
|
||||
0 => DestinationHome(searchFor: _searchFor, constraints: constraints, dataFuture: _data),
|
||||
1 => DestinationGraphs(searchFor: _searchFor, constraints: constraints),
|
||||
2 => DestinationLeaderboards(constraints: constraints),
|
||||
3 => DestinationCutoffs(constraints: constraints),
|
||||
4 => DestinationCalculator(constraints: constraints),
|
||||
5 => DestinationInfo(constraints: constraints),
|
||||
6 => DestinationSavedData(constraints: constraints),
|
||||
7 => DestinationSettings(constraints: constraints),
|
||||
_ => Text("Unknown destination $destination")
|
||||
},
|
||||
)
|
||||
]);
|
||||
},
|
||||
));
|
||||
),
|
||||
Expanded(
|
||||
child: switch (destination){
|
||||
0 => DestinationHome(searchFor: _searchFor, constraints: constraints, dataFuture: _data, noSidebar: !screenIsBig),
|
||||
1 => DestinationGraphs(searchFor: _searchFor, constraints: constraints),
|
||||
2 => DestinationLeaderboards(constraints: constraints),
|
||||
3 => DestinationCutoffs(constraints: constraints),
|
||||
4 => DestinationCalculator(constraints: constraints),
|
||||
5 => DestinationInfo(constraints: constraints),
|
||||
6 => DestinationSavedData(constraints: constraints),
|
||||
7 => DestinationSettings(constraints: constraints),
|
||||
_ => Text("Unknown destination $destination")
|
||||
},
|
||||
)
|
||||
]
|
||||
),
|
||||
));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,80 +331,178 @@ class _SearchDrawerState extends State<SearchDrawer> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Drawer(
|
||||
child: StreamBuilder(
|
||||
stream: teto.allPlayers,
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
case ConnectionState.done:
|
||||
case ConnectionState.active:
|
||||
final allPlayers = (snapshot.data != null)
|
||||
? snapshot.data as Map<String, String>
|
||||
: <String, String>{};
|
||||
allPlayers.remove(prefs.getString("playerID") ?? "6098518e3d5155e6ec429cdc"); // player from the home button will be delisted
|
||||
List<String> keys = allPlayers.keys.toList();
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool value){
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: SearchBar(
|
||||
controller: widget.controller,
|
||||
hintText: "Enter the username",
|
||||
hintStyle: const WidgetStatePropertyAll(TextStyle(color: Colors.grey)),
|
||||
trailing: [
|
||||
IconButton(onPressed: (){setState(() {
|
||||
widget.changePlayer(widget.controller.value.text);
|
||||
Navigator.of(context).pop();
|
||||
});}, icon: const Icon(Icons.search))
|
||||
],
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
widget.changePlayer(value);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
child: SafeArea(
|
||||
child: StreamBuilder(
|
||||
stream: teto.allPlayers,
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
case ConnectionState.done:
|
||||
case ConnectionState.active:
|
||||
final allPlayers = (snapshot.data != null)
|
||||
? snapshot.data as Map<String, String>
|
||||
: <String, String>{};
|
||||
allPlayers.remove(prefs.getString("playerID") ?? "6098518e3d5155e6ec429cdc"); // player from the home button will be delisted
|
||||
List<String> keys = allPlayers.keys.toList();
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool value){
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: SearchBar(
|
||||
controller: widget.controller,
|
||||
hintText: "Enter the username",
|
||||
hintStyle: const WidgetStatePropertyAll(TextStyle(color: Colors.grey)),
|
||||
trailing: [
|
||||
IconButton(onPressed: (){setState(() {
|
||||
widget.changePlayer(widget.controller.value.text);
|
||||
Navigator.of(context).pop();
|
||||
});}, icon: const Icon(Icons.search))
|
||||
],
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
widget.changePlayer(value);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.home),
|
||||
title: Text(prefs.getString("player") ?? "dan63"),
|
||||
onTap: () {
|
||||
widget.changePlayer(prefs.getString("playerID") ?? "6098518e3d5155e6ec429cdc");
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.home),
|
||||
title: Text(prefs.getString("player") ?? "dan63"),
|
||||
onTap: () {
|
||||
widget.changePlayer(prefs.getString("playerID") ?? "6098518e3d5155e6ec429cdc");
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Text("Tracked Players", style: Theme.of(context).textTheme.headlineLarge),
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
body: ListView.builder( // Builds list of tracked players.
|
||||
itemCount: allPlayers.length,
|
||||
itemBuilder: (context, index) {
|
||||
var i = allPlayers.length-1-index; // Last players in this map are most recent ones, they are gonna be shown at the top.
|
||||
return ListTile(
|
||||
title: Text(allPlayers[keys[i]]??keys[i]), // Takes last known username from list of states
|
||||
trailing: IconButton(onPressed: (){
|
||||
teto.deletePlayerToTrack(keys[i]);
|
||||
}, icon: Icon(Icons.delete, color: Colors.grey)),
|
||||
onTap: () {
|
||||
widget.changePlayer(keys[i]); // changes to chosen player
|
||||
Navigator.of(context).pop(); // and closes itself.
|
||||
},
|
||||
);
|
||||
})
|
||||
);
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: Text("Tracked Players", style: Theme.of(context).textTheme.headlineLarge),
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
body: ListView.builder( // Builds list of tracked players.
|
||||
itemCount: allPlayers.length,
|
||||
itemBuilder: (context, index) {
|
||||
var i = allPlayers.length-1-index; // Last players in this map are most recent ones, they are gonna be shown at the top.
|
||||
return ListTile(
|
||||
title: Text(allPlayers[keys[i]]??keys[i]), // Takes last known username from list of states
|
||||
trailing: IconButton(onPressed: (){
|
||||
teto.deletePlayerToTrack(keys[i]);
|
||||
}, icon: Icon(Icons.delete, color: Colors.grey)),
|
||||
onTap: () {
|
||||
widget.changePlayer(keys[i]); // changes to chosen player
|
||||
Navigator.of(context).pop(); // and closes itself.
|
||||
},
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DestinationsDrawer extends StatefulWidget{
|
||||
final Function changeDestination;
|
||||
|
||||
const DestinationsDrawer({super.key, required this.changeDestination});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DestinationsDrawerState();
|
||||
|
||||
}
|
||||
|
||||
class _DestinationsDrawerState extends State<DestinationsDrawer>{
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Drawer(
|
||||
child: NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool value){
|
||||
return [
|
||||
SliverToBoxAdapter(
|
||||
child: DrawerHeader(
|
||||
child: Text("Navigation menu", style: const TextStyle(color: Colors.white, fontSize: 25),
|
||||
)))
|
||||
];
|
||||
},
|
||||
body: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(Icons.home),
|
||||
title: Text("Home"),
|
||||
onTap: (){
|
||||
widget.changeDestination(0);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.data_thresholding_outlined),
|
||||
title: Text("Graphs"),
|
||||
onTap: (){
|
||||
widget.changeDestination(1);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.leaderboard),
|
||||
title: Text("Leaderboards"),
|
||||
onTap: (){
|
||||
widget.changeDestination(2);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.compress),
|
||||
title: Text("Cutoffs"),
|
||||
onTap: (){
|
||||
widget.changeDestination(3);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.calculate),
|
||||
title: Text("Calc"),
|
||||
onTap: (){
|
||||
widget.changeDestination(4);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.info_outline),
|
||||
title: Text("Information"),
|
||||
onTap: (){
|
||||
widget.changeDestination(5);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.storage),
|
||||
title: Text("Saved Data"),
|
||||
onTap: (){
|
||||
widget.changeDestination(6);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Icons.settings),
|
||||
title: Text("Settings"),
|
||||
onTap: (){
|
||||
widget.changeDestination(7);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:tetra_stats/data_objects/record_single.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/views/destination_home.dart';
|
||||
import 'package:tetra_stats/widgets/singleplayer_record.dart';
|
||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||
|
||||
|
@ -15,28 +16,28 @@ class SingleplayerRecordView extends StatelessWidget {
|
|||
//bool bigScreen = MediaQuery.of(context).size.width >= 368;
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
appBar: AppBar(
|
||||
title: Text("${
|
||||
switch (record.gamemode){
|
||||
"40l" => t.sprint,
|
||||
"blitz" => t.blitz,
|
||||
String() => "5000000 Blast",
|
||||
}
|
||||
} ${timestamp(record.timestamp)}"),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.startTop,
|
||||
floatingActionButton: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 0.0, 0.0),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
tooltip: 'Fuck go back',
|
||||
child: const Icon(Icons.arrow_back),
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SingleplayerRecord(record: record, hideTitle: true),
|
||||
// TODO: Insert replay link here
|
||||
]
|
||||
)
|
||||
],
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 768
|
||||
),
|
||||
child: switch (record.gamemode){
|
||||
"zenith" => ZenithCard(record, false),
|
||||
"zenithex" => ZenithCard(record, false),
|
||||
_ => SingleplayerRecord(record: record, hideTitle: true)
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/tetra_league.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/widgets/graphs.dart';
|
||||
import 'package:tetra_stats/widgets/nerd_stats_thingy.dart';
|
||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||
import 'package:tetra_stats/widgets/tl_thingy.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
@ -45,11 +47,19 @@ class StateState extends State<StateView> {
|
|||
//final t = Translations.of(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("State from ${timestamp(widget.state.timestamp)}"),
|
||||
title: Text("State from ${timestamp(widget.state.timestamp)}", style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28)),
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: SafeArea(
|
||||
child: TetraLeagueThingy(league: widget.state)
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
TetraLeagueThingy(league: widget.state),
|
||||
if (widget.state.nerdStats != null) NerdStatsThingy(nerdStats: widget.state.nerdStats!),
|
||||
if (widget.state.playstyle != null) Graphs(widget.state.apm!, widget.state.pps!, widget.state.vs!, widget.state.nerdStats!, widget.state.playstyle!)
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,128 @@ class NerdStatsThingy extends StatelessWidget{
|
|||
final NerdStats? oldNerdStats;
|
||||
final CutoffTetrio? averages;
|
||||
final PlayerLeaderboardPosition? lbPos;
|
||||
final double width;
|
||||
|
||||
const NerdStatsThingy({super.key, required this.nerdStats, this.oldNerdStats, this.averages, this.lbPos});
|
||||
const NerdStatsThingy({super.key, required this.nerdStats, this.oldNerdStats, this.averages, this.lbPos, this.width = double.infinity});
|
||||
|
||||
Widget big(){
|
||||
return SizedBox(
|
||||
height: 256.0,
|
||||
width: 256.0,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(1000),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(gradient: RadialGradient(colors: [Colors.black12.withAlpha(100), Colors.black], radius: 0.6)),
|
||||
child: SfRadialGauge(
|
||||
axes: [
|
||||
RadialAxis(
|
||||
startAngle: 190,
|
||||
endAngle: 350,
|
||||
showLabels: false,
|
||||
showTicks: true,
|
||||
radiusFactor: 1,
|
||||
centerY: 0.5,
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
ranges: [
|
||||
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
|
||||
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
|
||||
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
||||
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
||||
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
||||
],
|
||||
pointers: [
|
||||
NeedlePointer(
|
||||
value: nerdStats.app,
|
||||
enableAnimation: true,
|
||||
needleLength: 0.9,
|
||||
needleStartWidth: 2,
|
||||
needleEndWidth: 15,
|
||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
||||
],
|
||||
annotations: [
|
||||
GaugeAnnotation(widget: Container(child:
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: "Eurostile Round"),
|
||||
children: [
|
||||
const TextSpan(text: "APP\n"),
|
||||
TextSpan(text: f3.format(nerdStats.app), style: TextStyle(fontSize: 25, fontFamily: "Eurostile Round Extended", fontWeight: FontWeight.w100, color: getStatColor(nerdStats.app, averages?.nerdStats?.app, true))),
|
||||
if (lbPos != null) TextSpan(text: lbPos!.app!.position >= 1000 ? "\n${t.top} ${f2.format(lbPos!.app!.percentage*100)}%" : "\n№${lbPos!.app!.position}", style: TextStyle(color: getColorOfRank(lbPos!.app!.position))),
|
||||
if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.app - oldNerdStats!.app)}", style: TextStyle(color: getDifferenceColor(nerdStats.app - oldNerdStats!.app)))
|
||||
]
|
||||
))),
|
||||
angle: 270,positionFactor: 0.5
|
||||
)],
|
||||
),
|
||||
RadialAxis(
|
||||
startAngle: 20,
|
||||
endAngle: 160,
|
||||
isInversed: true,
|
||||
showLabels: false,
|
||||
showTicks: true,
|
||||
radiusFactor: 1,
|
||||
centerY: 0.5,
|
||||
minimum: 1.8,
|
||||
maximum: 2.4,
|
||||
ranges: [
|
||||
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
|
||||
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
|
||||
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
||||
],
|
||||
pointers: [
|
||||
NeedlePointer(
|
||||
value: nerdStats.vsapm,
|
||||
enableAnimation: true,
|
||||
needleLength: 0.9,
|
||||
needleStartWidth: 2,
|
||||
needleEndWidth: 15,
|
||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
||||
],
|
||||
annotations: [
|
||||
GaugeAnnotation(widget: Container(child:
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: "Eurostile Round"),
|
||||
children: [
|
||||
const TextSpan(text: "VS/APM\n"),
|
||||
TextSpan(text: f3.format(nerdStats.vsapm), style: TextStyle(fontSize: 25, fontFamily: "Eurostile Round Extended", fontWeight: FontWeight.w100, color: getStatColor(nerdStats.vsapm, averages?.nerdStats?.vsapm, true))),
|
||||
if (lbPos != null) TextSpan(text: lbPos!.vsapm!.position >= 1000 ? "\n${t.top} ${f2.format(lbPos!.vsapm!.percentage*100)}%" : "\n№${lbPos!.vsapm!.position}", style: TextStyle(color: getColorOfRank(lbPos!.vsapm!.position))),
|
||||
if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.vsapm - oldNerdStats!.vsapm)}", style: TextStyle(color: getDifferenceColor(nerdStats.vsapm - oldNerdStats!.vsapm))),
|
||||
]
|
||||
))),
|
||||
angle: 90,positionFactor: 0.5
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget manySmalls(){
|
||||
return Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 10.0,
|
||||
runSpacing: 10.0,
|
||||
runAlignment: WrapAlignment.start,
|
||||
children: [
|
||||
GaugetThingy(value: nerdStats.dss, oldValue: oldNerdStats?.dss, min: 0, max: 1.0, tickInterval: .2, label: "DS/S", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.dss, lbPos: lbPos?.dss),
|
||||
GaugetThingy(value: nerdStats.dsp, oldValue: oldNerdStats?.dsp, min: 0, max: 1.0, tickInterval: .2, label: "DS/P", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.dsp, lbPos: lbPos?.dsp),
|
||||
GaugetThingy(value: nerdStats.appdsp, oldValue: oldNerdStats?.appdsp, min: 0, max: 1.2, tickInterval: .2, label: "APP+DS/P", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.appdsp, lbPos: lbPos?.appdsp),
|
||||
GaugetThingy(value: nerdStats.cheese, oldValue: oldNerdStats?.cheese, min: -80, max: 80, tickInterval: 40, label: "Cheese", sideSize: 128.0, fractionDigits: 2, moreIsBetter: false, lbPos: lbPos?.cheese),
|
||||
GaugetThingy(value: nerdStats.gbe, oldValue: oldNerdStats?.gbe, min: 0, max: 1.0, tickInterval: .2, label: "GbE", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.gbe, lbPos: lbPos?.gbe),
|
||||
GaugetThingy(value: nerdStats.nyaapp, oldValue: oldNerdStats?.nyaapp, min: 0, max: 1.2, tickInterval: .2, label: "wAPP", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.nyaapp, lbPos: lbPos?.nyaapp),
|
||||
GaugetThingy(value: nerdStats.area, oldValue: oldNerdStats?.area, min: 0, max: 1000, tickInterval: 100, label: "Area", sideSize: 128.0, fractionDigits: 1, moreIsBetter: true, avgValue: averages?.nerdStats?.area, lbPos: lbPos?.area),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -23,126 +143,20 @@ class NerdStatsThingy extends StatelessWidget{
|
|||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0),
|
||||
child: Row(
|
||||
child: width > 600 ? Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 256.0,
|
||||
width: 256.0,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(1000),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(gradient: RadialGradient(colors: [Colors.black12.withAlpha(100), Colors.black], radius: 0.6)),
|
||||
child: SfRadialGauge(
|
||||
axes: [
|
||||
RadialAxis(
|
||||
startAngle: 190,
|
||||
endAngle: 350,
|
||||
showLabels: false,
|
||||
showTicks: true,
|
||||
radiusFactor: 1,
|
||||
centerY: 0.5,
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
ranges: [
|
||||
GaugeRange(startValue: 0, endValue: 0.2, color: Colors.red),
|
||||
GaugeRange(startValue: 0.2, endValue: 0.4, color: Colors.yellow),
|
||||
GaugeRange(startValue: 0.4, endValue: 0.6, color: Colors.green),
|
||||
GaugeRange(startValue: 0.6, endValue: 0.8, color: Colors.blue),
|
||||
GaugeRange(startValue: 0.8, endValue: 1, color: Colors.purple),
|
||||
],
|
||||
pointers: [
|
||||
NeedlePointer(
|
||||
value: nerdStats.app,
|
||||
enableAnimation: true,
|
||||
needleLength: 0.9,
|
||||
needleStartWidth: 2,
|
||||
needleEndWidth: 15,
|
||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
||||
],
|
||||
annotations: [
|
||||
GaugeAnnotation(widget: Container(child:
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: "Eurostile Round"),
|
||||
children: [
|
||||
const TextSpan(text: "APP\n"),
|
||||
TextSpan(text: f3.format(nerdStats.app), style: TextStyle(fontSize: 25, fontFamily: "Eurostile Round Extended", fontWeight: FontWeight.w100, color: getStatColor(nerdStats.app, averages?.nerdStats?.app, true))),
|
||||
if (lbPos != null) TextSpan(text: lbPos!.app!.position >= 1000 ? "\n${t.top} ${f2.format(lbPos!.app!.percentage*100)}%" : "\n№${lbPos!.app!.position}", style: TextStyle(color: getColorOfRank(lbPos!.app!.position))),
|
||||
if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.app - oldNerdStats!.app)}", style: TextStyle(color: getDifferenceColor(nerdStats.app - oldNerdStats!.app)))
|
||||
]
|
||||
))),
|
||||
angle: 270,positionFactor: 0.5
|
||||
)],
|
||||
),
|
||||
RadialAxis(
|
||||
startAngle: 20,
|
||||
endAngle: 160,
|
||||
isInversed: true,
|
||||
showLabels: false,
|
||||
showTicks: true,
|
||||
radiusFactor: 1,
|
||||
centerY: 0.5,
|
||||
minimum: 1.8,
|
||||
maximum: 2.4,
|
||||
ranges: [
|
||||
GaugeRange(startValue: 1.8, endValue: 2.0, color: Colors.green),
|
||||
GaugeRange(startValue: 2.0, endValue: 2.2, color: Colors.blue),
|
||||
GaugeRange(startValue: 2.2, endValue: 2.4, color: Colors.purple),
|
||||
],
|
||||
pointers: [
|
||||
NeedlePointer(
|
||||
value: nerdStats.vsapm,
|
||||
enableAnimation: true,
|
||||
needleLength: 0.9,
|
||||
needleStartWidth: 2,
|
||||
needleEndWidth: 15,
|
||||
knobStyle: const KnobStyle(color: Colors.transparent),
|
||||
gradient: const LinearGradient(colors: [Colors.transparent, Colors.white], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.5, 1]),)
|
||||
],
|
||||
annotations: [
|
||||
GaugeAnnotation(widget: Container(child:
|
||||
RichText(
|
||||
textAlign: TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: "Eurostile Round"),
|
||||
children: [
|
||||
const TextSpan(text: "VS/APM\n"),
|
||||
TextSpan(text: f3.format(nerdStats.vsapm), style: TextStyle(fontSize: 25, fontFamily: "Eurostile Round Extended", fontWeight: FontWeight.w100, color: getStatColor(nerdStats.vsapm, averages?.nerdStats?.vsapm, true))),
|
||||
if (lbPos != null) TextSpan(text: lbPos!.vsapm!.position >= 1000 ? "\n${t.top} ${f2.format(lbPos!.vsapm!.percentage*100)}%" : "\n№${lbPos!.vsapm!.position}", style: TextStyle(color: getColorOfRank(lbPos!.vsapm!.position))),
|
||||
if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.vsapm - oldNerdStats!.vsapm)}", style: TextStyle(color: getDifferenceColor(nerdStats.vsapm - oldNerdStats!.vsapm))),
|
||||
]
|
||||
))),
|
||||
angle: 90,positionFactor: 0.5
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 10.0,
|
||||
runSpacing: 10.0,
|
||||
runAlignment: WrapAlignment.start,
|
||||
children: [
|
||||
GaugetThingy(value: nerdStats.dss, oldValue: oldNerdStats?.dss, min: 0, max: 1.0, tickInterval: .2, label: "DS/S", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.dss, lbPos: lbPos?.dss),
|
||||
GaugetThingy(value: nerdStats.dsp, oldValue: oldNerdStats?.dsp, min: 0, max: 1.0, tickInterval: .2, label: "DS/P", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.dsp, lbPos: lbPos?.dsp),
|
||||
GaugetThingy(value: nerdStats.appdsp, oldValue: oldNerdStats?.appdsp, min: 0, max: 1.2, tickInterval: .2, label: "APP+DS/P", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.appdsp, lbPos: lbPos?.appdsp),
|
||||
GaugetThingy(value: nerdStats.cheese, oldValue: oldNerdStats?.cheese, min: -80, max: 80, tickInterval: 40, label: "Cheese", sideSize: 128.0, fractionDigits: 2, moreIsBetter: false, lbPos: lbPos?.cheese),
|
||||
GaugetThingy(value: nerdStats.gbe, oldValue: oldNerdStats?.gbe, min: 0, max: 1.0, tickInterval: .2, label: "GbE", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.gbe, lbPos: lbPos?.gbe),
|
||||
GaugetThingy(value: nerdStats.nyaapp, oldValue: oldNerdStats?.nyaapp, min: 0, max: 1.2, tickInterval: .2, label: "wAPP", sideSize: 128.0, fractionDigits: 3, moreIsBetter: true, avgValue: averages?.nerdStats?.nyaapp, lbPos: lbPos?.nyaapp),
|
||||
GaugetThingy(value: nerdStats.area, oldValue: oldNerdStats?.area, min: 0, max: 1000, tickInterval: 100, label: "Area", sideSize: 128.0, fractionDigits: 1, moreIsBetter: true, avgValue: averages?.nerdStats?.area, lbPos: lbPos?.area),
|
||||
],
|
||||
),
|
||||
)
|
||||
big(),
|
||||
Expanded(child: manySmalls())
|
||||
]
|
||||
) : Center(
|
||||
child: Column(
|
||||
children: [
|
||||
big(),
|
||||
manySmalls()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:tetra_stats/data_objects/record_single.dart';
|
||||
import 'package:tetra_stats/data_objects/singleplayer_stream.dart';
|
||||
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/utils/colors_functions.dart';
|
||||
import 'package:tetra_stats/utils/numers_formats.dart';
|
||||
import 'package:tetra_stats/utils/open_in_browser.dart';
|
||||
import 'package:tetra_stats/utils/relative_timestamps.dart';
|
||||
import 'package:tetra_stats/utils/text_shadow.dart';
|
||||
import 'package:tetra_stats/views/singleplayer_record_view.dart';
|
||||
import 'package:tetra_stats/widgets/finesse_thingy.dart';
|
||||
import 'package:tetra_stats/widgets/lineclears_thingy.dart';
|
||||
import 'package:tetra_stats/widgets/sp_trailing_stats.dart';
|
||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||
import 'package:tetra_stats/widgets/text_timestamp.dart';
|
||||
import 'package:tetra_stats/views/destination_home.dart';
|
||||
|
||||
class SingleplayerRecord extends StatelessWidget {
|
||||
final RecordSingle? record;
|
||||
final SingleplayerStream? stream;
|
||||
final String? rank;
|
||||
final bool hideTitle;
|
||||
|
||||
/// Widget that displays data from [record]
|
||||
const SingleplayerRecord({super.key, required this.record, this.stream, this.rank, this.hideTitle = false});
|
||||
const SingleplayerRecord({super.key, required this.record, this.rank, this.hideTitle = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -42,114 +29,6 @@ class SingleplayerRecord extends StatelessWidget {
|
|||
blitzBetterThanClosestAverage = record!.stats.score > closestAverageBlitz.value;
|
||||
}
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
bool bigScreen = constraints.maxWidth > 768;
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (record!.gamemode == "40l") Padding(padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageSprint.key}.png", height: 96)
|
||||
),
|
||||
if (record!.gamemode == "blitz") Padding(padding: const EdgeInsets.only(right: 8.0),
|
||||
child: Image.asset("res/tetrio_tl_alpha_ranks/${closestAverageBlitz.key}.png", height: 96)
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (record!.gamemode == "40l" && !hideTitle) Text(t.sprint, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
||||
if (record!.gamemode == "blitz" && !hideTitle) Text(t.blitz, style: const TextStyle(height: 0.1, fontFamily: "Eurostile Round Extended", fontSize: 18)),
|
||||
RichText(text: TextSpan(
|
||||
text: record!.gamemode == "40l" ? get40lTime(record!.stats.finalTime.inMicroseconds) : NumberFormat.decimalPattern().format(record!.stats.score),
|
||||
style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 36 : 32, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
),
|
||||
),
|
||||
RichText(text: TextSpan(
|
||||
text: "",
|
||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||
children: [
|
||||
if (record!.gamemode == "40l" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.stats.finalTime, sprintAverages[rank]!), verdict: sprintBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
||||
color: sprintBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
||||
))
|
||||
else if (record!.gamemode == "40l" && (rank == null || rank == "z" || rank != "x+")) TextSpan(text: "${t.verdictGeneral(n: readableTimeDifference(record!.stats.finalTime, closestAverageSprint.value), verdict: sprintBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageSprint.key.toUpperCase())}\n", style: TextStyle(
|
||||
color: sprintBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
||||
))
|
||||
else if (record!.gamemode == "blitz" && (rank != null && rank != "z")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.stats.score, blitzAverages[rank]!), verdict: blitzBetterThanRankAverage??false ? t.verdictBetter : t.verdictWorse, rank: rank!.toUpperCase())}\n", style: TextStyle(
|
||||
color: blitzBetterThanRankAverage??false ? Colors.greenAccent : Colors.redAccent
|
||||
))
|
||||
else if (record!.gamemode == "blitz" && (rank == null || rank == "z" || rank != "x+")) TextSpan(text: "${t.verdictGeneral(n: readableIntDifference(record!.stats.score, closestAverageBlitz.value), verdict: blitzBetterThanClosestAverage ? t.verdictBetter : t.verdictWorse, rank: closestAverageBlitz.key.toUpperCase())}\n", style: TextStyle(
|
||||
color: blitzBetterThanClosestAverage ? Colors.greenAccent : Colors.redAccent
|
||||
)),
|
||||
if (record!.rank != -1) TextSpan(text: "№${record!.rank}", style: TextStyle(color: getColorOfRank(record!.rank))),
|
||||
if (record!.rank != -1) const TextSpan(text: " • "),
|
||||
TextSpan(text: timestamp(record!.timestamp)),
|
||||
]
|
||||
),
|
||||
)
|
||||
],),
|
||||
],
|
||||
),
|
||||
if (record!.gamemode == "40l") Wrap(
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
spacing: 20,
|
||||
children: [ // TODO: replace
|
||||
StatCellNum(playerStat: record!.stats.piecesPlaced, playerStatLabel: t.statCellNum.pieces, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||
StatCellNum(playerStat: record!.stats.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||
StatCellNum(playerStat: record!.stats.kpp, playerStatLabel: t.statCellNum.kpp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||
],
|
||||
),
|
||||
if (record!.gamemode == "blitz") Wrap(
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
spacing: 20,
|
||||
children: [
|
||||
StatCellNum(playerStat: record!.stats.level, playerStatLabel: t.statCellNum.level, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||
StatCellNum(playerStat: record!.stats.pps, playerStatLabel: t.statCellNum.pps, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true, smallDecimal: false),
|
||||
StatCellNum(playerStat: record!.stats.spp, playerStatLabel: t.statCellNum.spp, fractionDigits: 2, isScreenBig: bigScreen, higherIsBetter: true)
|
||||
],
|
||||
),
|
||||
FinesseThingy(record?.stats.finesse, record?.stats.finessePercentage),
|
||||
LineclearsThingy(record!.stats.clears, record!.stats.lines, record!.stats.holds, record!.stats.tSpins),
|
||||
if (record!.gamemode == "40l") Text("${record!.stats.inputs} KP • ${f2.format(record!.stats.kps)} KPS"),
|
||||
if (record!.gamemode == "blitz") Text("${record!.stats.piecesPlaced} P • ${record!.stats.inputs} KP • ${f2.format(record!.stats.kpp)} KPP • ${f2.format(record!.stats.kps)} KPS"),
|
||||
if (record != null) Wrap(
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
spacing: 20,
|
||||
children: [
|
||||
TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${record!.replayId}"));}, child: Text(t.openSPreplay)),
|
||||
TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${record!.replayId}"));}, child: Text(t.downloadSPreplay)),
|
||||
],
|
||||
),
|
||||
if (stream != null && stream!.records.length > 1) for(int i = 1; i < stream!.records.length; i++) ListTile(
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: stream!.records[i]))),
|
||||
leading: Text("#${i+1}",
|
||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 28, shadows: textShadow, height: 0.9)
|
||||
),
|
||||
title: Text(
|
||||
switch (stream!.records[i].gamemode){
|
||||
"40l" => get40lTime(stream!.records[i].stats.finalTime.inMicroseconds),
|
||||
"blitz" => t.blitzScore(p: NumberFormat.decimalPattern().format(stream!.records[i].stats.score)),
|
||||
"5mblast" => get40lTime(stream!.records[i].stats.finalTime.inMicroseconds),
|
||||
String() => "huh",
|
||||
},
|
||||
style: Theme.of(context).textTheme.displayLarge),
|
||||
subtitle: Text(timestamp(stream!.records[i].timestamp), style: const TextStyle(color: Colors.grey, height: 0.85)),
|
||||
trailing: SpTrailingStats(stream!.records[i], stream!.records[i].gamemode)
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
return RecordCard(record, [], record!.gamemode == "40l" ? sprintBetterThanRankAverage : blitzBetterThanRankAverage, record!.gamemode == "40l" ? closestAverageSprint : closestAverageBlitz, record!.gamemode == "40l" ? sprintBetterThanClosestAverage : blitzBetterThanClosestAverage, rank);
|
||||
}
|
||||
}
|
|
@ -40,9 +40,10 @@ class TLRatingThingy extends StatelessWidget{
|
|||
? Image.asset("res/icons/kagari.png", height: 128) // Btw why she wearing Kazamatsuri high school uniform?
|
||||
: Image.asset("res/tetrio_tl_alpha_ranks/${tlData.rank}.png", height: 128),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: bigScreen ? CrossAxisAlignment.start : CrossAxisAlignment.center,
|
||||
children: [
|
||||
RichText(
|
||||
textAlign: bigScreen ? TextAlign.start : TextAlign.center,
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 20, color: Colors.white, height: 0.9),
|
||||
children: (tlData.gamesPlayed > 9) ? switch(prefs.getInt("ratingMode")){
|
||||
|
@ -125,7 +126,7 @@ class TLRatingThingy extends StatelessWidget{
|
|||
],
|
||||
),
|
||||
if (showPositions == true) RichText(
|
||||
textAlign: TextAlign.start,
|
||||
textAlign: bigScreen ? TextAlign.start : TextAlign.center,
|
||||
text: TextSpan(
|
||||
text: "",
|
||||
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
|
||||
|
|
|
@ -17,8 +17,35 @@ class TetraLeagueThingy extends StatelessWidget{
|
|||
final Cutoffs? cutoffs;
|
||||
final CutoffTetrio? averages;
|
||||
final PlayerLeaderboardPosition? lbPos;
|
||||
final double width;
|
||||
|
||||
const TetraLeagueThingy({super.key, required this.league, this.toCompare, this.cutoffs, this.averages, this.lbPos});
|
||||
const TetraLeagueThingy({super.key, required this.league, this.toCompare, this.cutoffs, this.averages, this.lbPos, this.width = double.infinity});
|
||||
|
||||
List<TableRow> secondColumn(){
|
||||
return [
|
||||
TableRow(children: [
|
||||
//Text("APM: ", style: TextStyle(fontSize: 21)),
|
||||
Text(intf.format(league.gamesPlayed), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Games", style: TextStyle(fontSize: 21)),
|
||||
if (toCompare != null) Text(" (${comparef2.format(league.gamesPlayed-toCompare!.gamesPlayed)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
if (lbPos != null) Text(lbPos?.gamesPlayed != null ? (lbPos!.gamesPlayed!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesPlayed!.percentage*100)}%)" : " (№ ${lbPos!.gamesPlayed!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesPlayed != null ? getColorOfRank(lbPos!.gamesPlayed!.position) : null))
|
||||
]),
|
||||
TableRow(children: [
|
||||
//Text("PPS: ", style: TextStyle(fontSize: 21)),
|
||||
Text(intf.format(league.gamesWon), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Won", style: TextStyle(fontSize: 21)),
|
||||
if (toCompare != null) Text(" (${comparef2.format(league.gamesWon-toCompare!.gamesWon)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
if (lbPos != null) Text(lbPos?.gamesWon != null ? (lbPos!.gamesWon!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesWon!.percentage*100)}%)" : " (№ ${lbPos!.gamesWon!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesWon != null ? getColorOfRank(lbPos!.gamesWon!.position) : null))
|
||||
]),
|
||||
TableRow(children: [
|
||||
//Text("VS: ", style: TextStyle(fontSize: 21)),
|
||||
Tooltip(child: Text("${league.gxe.isNegative ? "---" : f3.format(league.gxe)}", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "${f2.format(league.s1tr)} S1 TR"),
|
||||
Tooltip(child: Text(" GXE", style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "Glixare"),
|
||||
if (toCompare != null) Text(" (${comparef.format(league.gxe-toCompare!.gxe)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.gxe-toCompare!.gxe))),
|
||||
if (lbPos != null) Text(lbPos?.glixare != null ? (lbPos!.glixare!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.glixare!.percentage*100)}%)" : " (№ ${lbPos!.glixare!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.glixare != null ? getColorOfRank(lbPos!.glixare!.position) : null))
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -37,8 +64,6 @@ class TetraLeagueThingy extends StatelessWidget{
|
|||
nextRankGlickoCutoff: cutoffs != null ? (league.rank != "z" ? league.rank == "x+" : league.percentileRank == "x+") ? 25000 : cutoffs!.glicko[ranks.elementAtOrNull(ranks.indexOf(league.rank != "z" ? league.rank : league.percentileRank)+1)] : null,
|
||||
),
|
||||
Row(
|
||||
// spacing: 25.0,
|
||||
// alignment: WrapAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
|
@ -65,41 +90,26 @@ class TetraLeagueThingy extends StatelessWidget{
|
|||
Text(" VS", style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)),
|
||||
if (toCompare != null) Text(" (${comparef2.format(league.vs!-toCompare!.vs!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.vs!-toCompare!.vs!))),
|
||||
if (lbPos != null) Text(lbPos?.vs != null ? (lbPos!.vs!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.vs!.percentage*100)}%)" : " (№ ${lbPos!.vs!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.vs != null ? getColorOfRank(lbPos!.vs!.position) : null))
|
||||
])
|
||||
]),
|
||||
if (width <= 600) TableRow(children: [
|
||||
Text(!league.winrate.isNegative ? percentage.format(league.winrate) : "---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: !league.winrate.isNegative ? Colors.white : Colors.grey)),
|
||||
Text(" WR", style: TextStyle(fontSize: 21, color: !league.winrate.isNegative ? Colors.white : Colors.grey)),
|
||||
if (toCompare != null) Text(" (${comparef2.format((league.winrate-toCompare!.winrate)*100)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.winrate-toCompare!.winrate))),
|
||||
if (lbPos != null) Text(lbPos?.winrate != null ? (lbPos!.winrate!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.winrate!.percentage*100)}%)" : " (№ ${lbPos!.winrate!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.winrate != null ? getColorOfRank(lbPos!.winrate!.position) : null))
|
||||
]),
|
||||
if (width <= 400) ...secondColumn()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GaugetThingy(value: league.winrate, min: 0, max: 1, tickInterval: 0.25, label: "Winrate", sideSize: 128, fractionDigits: 2, moreIsBetter: true, oldValue: toCompare?.winrate, percentileFormat: true, lbPos: lbPos?.winrate),
|
||||
Expanded(
|
||||
if (width > 600) GaugetThingy(value: league.winrate, min: 0, max: 1, tickInterval: 0.25, label: "Winrate", sideSize: 128, fractionDigits: 2, moreIsBetter: true, oldValue: toCompare?.winrate, percentileFormat: true, lbPos: lbPos?.winrate),
|
||||
if (width > 400) Expanded(
|
||||
child: Center(
|
||||
child: Table(
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
defaultColumnWidth:const IntrinsicColumnWidth(),
|
||||
children: [
|
||||
TableRow(children: [
|
||||
//Text("APM: ", style: TextStyle(fontSize: 21)),
|
||||
Text(intf.format(league.gamesPlayed), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Games", style: TextStyle(fontSize: 21)),
|
||||
if (toCompare != null) Text(" (${comparef2.format(league.gamesPlayed-toCompare!.gamesPlayed)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
if (lbPos != null) Text(lbPos?.gamesPlayed != null ? (lbPos!.gamesPlayed!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesPlayed!.percentage*100)}%)" : " (№ ${lbPos!.gamesPlayed!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesPlayed != null ? getColorOfRank(lbPos!.gamesPlayed!.position) : null))
|
||||
]),
|
||||
TableRow(children: [
|
||||
//Text("PPS: ", style: TextStyle(fontSize: 21)),
|
||||
Text(intf.format(league.gamesWon), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Won", style: TextStyle(fontSize: 21)),
|
||||
if (toCompare != null) Text(" (${comparef2.format(league.gamesWon-toCompare!.gamesWon)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
if (lbPos != null) Text(lbPos?.gamesWon != null ? (lbPos!.gamesWon!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.gamesWon!.percentage*100)}%)" : " (№ ${lbPos!.gamesWon!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.gamesWon != null ? getColorOfRank(lbPos!.gamesWon!.position) : null))
|
||||
]),
|
||||
TableRow(children: [
|
||||
//Text("VS: ", style: TextStyle(fontSize: 21)),
|
||||
Tooltip(child: Text("${league.gxe.isNegative ? "---" : f3.format(league.gxe)}", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "${f2.format(league.s1tr)} S1 TR"),
|
||||
Tooltip(child: Text(" GXE", style: TextStyle(fontSize: 21, color: league.gxe.isNegative ? Colors.grey : Colors.white)), message: "Glixare"),
|
||||
if (toCompare != null) Text(" (${comparef.format(league.gxe-toCompare!.gxe)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.gxe-toCompare!.gxe))),
|
||||
if (lbPos != null) Text(lbPos?.glixare != null ? (lbPos!.glixare!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.glixare!.percentage*100)}%)" : " (№ ${lbPos!.glixare!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.glixare != null ? getColorOfRank(lbPos!.glixare!.position) : null))
|
||||
]),
|
||||
],
|
||||
children: secondColumn(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -9,8 +9,51 @@ import 'package:tetra_stats/widgets/text_timestamp.dart';
|
|||
class ZenithThingy extends StatelessWidget{
|
||||
final RecordSingle? zenith;
|
||||
final bool old;
|
||||
final double width;
|
||||
|
||||
const ZenithThingy({super.key, required this.zenith, this.old = false});
|
||||
const ZenithThingy({super.key, required this.zenith, this.old = false, this.width = double.infinity});
|
||||
|
||||
List<TableRow> secondColumn(){
|
||||
return [
|
||||
TableRow(children: [
|
||||
Text(intf.format(zenith!.stats.kills), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" KO's", style: TextStyle(fontSize: 21))
|
||||
]),
|
||||
TableRow(children: [
|
||||
Text(zenith!.stats.topBtB.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" B2B", style: TextStyle(fontSize: 21))
|
||||
]),
|
||||
TableRow(children: [
|
||||
Text(zenith!.stats.garbage.maxspike_nomult.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Top spike", style: TextStyle(fontSize: 21))
|
||||
]),
|
||||
if (width <= 600) TableRow(children: [
|
||||
Text(f2.format(zenith!.stats.zenith!.peakrank), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Peak CSP", style: TextStyle(fontSize: 21)),
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
List<TableRow> noRecordSecondColumn(){
|
||||
return [
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" KO's", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
]),
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" B2B", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
]),
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" Top spike", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
]),
|
||||
if (width <= 600) TableRow(children: [
|
||||
Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
const Text(" Peak CSP", style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -68,30 +111,22 @@ class ZenithThingy extends StatelessWidget{
|
|||
TableRow(children: [
|
||||
Text(f2.format(zenith!.aggregateStats.vs), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" VS", style: TextStyle(fontSize: 21)),
|
||||
])
|
||||
]),
|
||||
if (width <= 600) TableRow(children: [
|
||||
Text(f2.format(zenith!.stats.cps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" CSP", style: TextStyle(fontSize: 21)),
|
||||
]),
|
||||
if (width <= 400) ...secondColumn().reversed
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GaugetThingy(value: zenith!.stats.cps, min: 0, max: 12, tickInterval: 3, label: "Climb\nSpeed", subString: "Peak: ${f2.format(zenith!.stats.zenith!.peakrank)}", sideSize: 128, fractionDigits: 2, moreIsBetter: true),
|
||||
Expanded(
|
||||
if (width > 600) GaugetThingy(value: zenith!.stats.cps, min: 0, max: 12, tickInterval: 3, label: "Climb\nSpeed", subString: "Peak: ${f2.format(zenith!.stats.zenith!.peakrank)}", sideSize: 128, fractionDigits: 2, moreIsBetter: true),
|
||||
if (width > 400) Expanded(
|
||||
child: Center(
|
||||
child: Table(
|
||||
defaultColumnWidth:const IntrinsicColumnWidth(),
|
||||
children: [
|
||||
TableRow(children: [
|
||||
Text(intf.format(zenith!.stats.kills), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" KO's", style: TextStyle(fontSize: 21))
|
||||
]),
|
||||
TableRow(children: [
|
||||
Text(zenith!.stats.topBtB.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" B2B", style: TextStyle(fontSize: 21))
|
||||
]),
|
||||
TableRow(children: [
|
||||
Text(zenith!.stats.garbage.maxspike_nomult.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
|
||||
const Text(" Top spike", style: TextStyle(fontSize: 21))
|
||||
])
|
||||
],
|
||||
children: secondColumn(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -114,30 +149,21 @@ class ZenithThingy extends StatelessWidget{
|
|||
const TableRow(children: [
|
||||
Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" VS", style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
]),
|
||||
if (width <= 600) TableRow(children: [
|
||||
Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
const Text(" CSP", style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
])
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GaugetThingy(value: null, min: 0, max: 12, tickInterval: 3, label: "Climb\nSpeed", subString: "Peak: ---", sideSize: 128, fractionDigits: 0, moreIsBetter: true),
|
||||
Expanded(
|
||||
if (width > 600) GaugetThingy(value: null, min: 0, max: 12, tickInterval: 3, label: "Climb\nSpeed", subString: "Peak: ---", sideSize: 128, fractionDigits: 0, moreIsBetter: true),
|
||||
if (width > 400) Expanded(
|
||||
child: Center(
|
||||
child: Table(
|
||||
defaultColumnWidth: IntrinsicColumnWidth(),
|
||||
children: [
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" KO's", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
]),
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" B2B", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
]),
|
||||
const TableRow(children: [
|
||||
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
|
||||
Text(" Top spike", style: TextStyle(fontSize: 21, color: Colors.grey))
|
||||
])
|
||||
],
|
||||
children: noRecordSecondColumn(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
16
pubspec.lock
16
pubspec.lock
|
@ -278,6 +278,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.1"
|
||||
flutter_layout_grid:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_layout_grid
|
||||
sha256: "88b4f8484a0874962e27c47733ad256aeb26acc694a9f029edbef771d301885a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -645,6 +653,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -43,6 +43,7 @@ dependencies:
|
|||
window_manager: ^0.3.7
|
||||
flutter_markdown: ^0.6.18
|
||||
flutter_colorpicker: ^1.0.3
|
||||
flutter_layout_grid: ^2.0.0
|
||||
go_router: ^13.0.0
|
||||
syncfusion_flutter_charts: ^24.2.9
|
||||
|
||||
|
|
Loading…
Reference in New Issue