Leaderboard sorting + some UI reworks

This commit is contained in:
dan63047 2023-09-03 01:48:50 +03:00
parent dbe875150f
commit 2b2b9ff7d5
10 changed files with 286 additions and 252 deletions

View File

@ -67,6 +67,35 @@ enum Stats {
openerMinusInfDS openerMinusInfDS
} }
const Map<Stats, String> chartsShortTitles = {
Stats.tr: "TR",
Stats.glicko: "Glicko",
Stats.rd: "RD",
Stats.gp: "GP",
Stats.gw: "GW",
Stats.wr: "WR%",
Stats.apm: "APM",
Stats.pps: "PPS",
Stats.vs: "VS",
Stats.app: "APP",
Stats.dss: "DS/S",
Stats.dsp: "DS/P",
Stats.appdsp: "APP + DS/P",
Stats.vsapm: "VS/APM",
Stats.cheese: "Cheese",
Stats.gbe: "GbE",
Stats.nyaapp: "wAPP",
Stats.area: "Area",
Stats.eTR: "eTR",
Stats.acceTR: "±eTR",
Stats.opener: "Opener",
Stats.plonk: "Plonk",
Stats.infDS: "Inf. DS",
Stats.stride: "Stride",
Stats.stridemMinusPlonk: "Stride - Plonk",
Stats.openerMinusInfDS: "Opener - Inf. DS"
};
const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:418 const Map<String, Color> rankColors = { // thanks osk for const rankColors at https://ch.tetr.io/res/js/base.js:418
'x': Color(0xFFFF45FF), 'x': Color(0xFFFF45FF),
'u': Color(0xFFFF3813), 'u': Color(0xFFFF3813),
@ -1009,10 +1038,21 @@ class TetrioPlayersLeaderboard {
TetrioPlayersLeaderboard(this.type, this.leaderboard); TetrioPlayersLeaderboard(this.type, this.leaderboard);
List<num> getStatRanking(List<TetrioPlayerFromLeaderboard> leaderboard, Stats stat){ List<TetrioPlayerFromLeaderboard> getStatRanking(List<TetrioPlayerFromLeaderboard> leaderboard, Stats stat, {bool reversed = false, String country = ""}){
var lb = leaderboard.map((e) => e.getStatByEnum(stat)).toList(); List<TetrioPlayerFromLeaderboard> lb = List.from(leaderboard);
lb.sort(); if (country.isNotEmpty){
return lb.reversed.toList(); lb.removeWhere((element) => element.country != country);
}
lb.sort(((a, b) {
if (a.getStatByEnum(stat) > b.getStatByEnum(stat)){
return reversed ? 1 : -1;
}else if (a.getStatByEnum(stat) == b.getStatByEnum(stat)){
return 0;
}else{
return reversed ? -1 : 1;
}
}));
return lb;
} }
List<dynamic> getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible List<dynamic> getAverageOfRank(String rank){ // i tried to refactor it and that's was terrible
@ -1689,7 +1729,7 @@ class TetrioPlayerFromLeaderboard {
username = json['username']; username = json['username'];
role = json['role']; role = json['role'];
xp = json['xp'].toDouble(); xp = json['xp'].toDouble();
country = json['country ']; country = json['country'];
supporter = json['supporter']; supporter = json['supporter'];
verified = json['verified']; verified = json['verified'];
timestamp = ts; timestamp = ts;
@ -1722,7 +1762,7 @@ class TetrioPlayerFromLeaderboard {
case Stats.gw: case Stats.gw:
return gamesWon; return gamesWon;
case Stats.wr: case Stats.wr:
return winrate; return winrate*100;
case Stats.apm: case Stats.apm:
return apm; return apm;
case Stats.pps: case Stats.pps:

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 2 /// Locales: 2
/// Strings: 898 (449 per locale) /// Strings: 906 (453 per locale)
/// ///
/// Built on 2023-08-21 at 09:52 UTC /// Built on 2023-09-02 at 21:37 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -251,10 +251,13 @@ class _StringsEn implements BaseTranslations<AppLocale, _StringsEn> {
String get calcViewNoValues => 'Enter values to calculate the stats'; String get calcViewNoValues => 'Enter values to calculate the stats';
String get rankAveragesViewTitle => 'Ranks cutoff and average stats'; String get rankAveragesViewTitle => 'Ranks cutoff and average stats';
String get averages => 'Averages'; String get averages => 'Averages';
String get lbViewZeroEntrys => 'Empty list. Looks like something is wrong...'; String get lbViewZeroEntrys => 'Empty list';
String get lbViewOneEntry => 'There is only one player... What?'; String get lbViewOneEntry => 'There is only one player';
String lbViewManyEntrys({required Object numberOfPlayers}) => 'There are ${numberOfPlayers}.'; String lbViewManyEntrys({required Object numberOfPlayers}) => 'There are ${numberOfPlayers}';
String get everyoneAverages => 'Values for leaderboard'; String get everyoneAverages => 'Values for leaderboard';
String get sortBy => 'Sort by';
String get reversed => 'Reversed';
String get country => 'Country';
String rankAverages({required Object rank}) => 'Values for ${rank} rank'; String rankAverages({required Object rank}) => 'Values for ${rank} rank';
String players({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, String players({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: '${n} players', zero: '${n} players',
@ -290,6 +293,7 @@ class _StringsEn implements BaseTranslations<AppLocale, _StringsEn> {
late final _StringsPopupActionsEn popupActions = _StringsPopupActionsEn._(_root); late final _StringsPopupActionsEn popupActions = _StringsPopupActionsEn._(_root);
late final _StringsErrorsEn errors = _StringsErrorsEn._(_root); late final _StringsErrorsEn errors = _StringsErrorsEn._(_root);
Map<String, String> get countries => { Map<String, String> get countries => {
'': 'Not selected',
'AF': 'Afghanistan', 'AF': 'Afghanistan',
'AX': 'Åland Islands', 'AX': 'Åland Islands',
'AL': 'Albania', 'AL': 'Albania',
@ -775,10 +779,13 @@ class _StringsRu implements _StringsEn {
@override String get calcViewNoValues => 'Введите значения, чтобы посчитать статистику'; @override String get calcViewNoValues => 'Введите значения, чтобы посчитать статистику';
@override String get rankAveragesViewTitle => 'Требования рангов и средние значения'; @override String get rankAveragesViewTitle => 'Требования рангов и средние значения';
@override String get averages => 'Средние значения'; @override String get averages => 'Средние значения';
@override String get lbViewZeroEntrys => 'Рейтинговая таблица пуста. Похоже, что-то здесь не так...'; @override String get lbViewZeroEntrys => 'Рейтинговая таблица пуста';
@override String get lbViewOneEntry => 'В рейтинговой таблице всего один игрок... Чего?'; @override String get lbViewOneEntry => 'В рейтинговой таблице всего один игрок';
@override String lbViewManyEntrys({required Object numberOfPlayers}) => 'В рейтинговой таблице находится ${numberOfPlayers}.'; @override String lbViewManyEntrys({required Object numberOfPlayers}) => 'В рейтинговой таблице находится ${numberOfPlayers}';
@override String get everyoneAverages => 'Значения таблицы'; @override String get everyoneAverages => 'Значения таблицы';
@override String get sortBy => 'Cортировать по';
@override String get reversed => 'Наоборот';
@override String get country => 'Страна';
@override String rankAverages({required Object rank}) => 'Значения для ${rank} ранга'; @override String rankAverages({required Object rank}) => 'Значения для ${rank} ранга';
@override String players({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n, @override String players({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
zero: '${n} игроков', zero: '${n} игроков',
@ -814,6 +821,7 @@ class _StringsRu implements _StringsEn {
@override late final _StringsPopupActionsRu popupActions = _StringsPopupActionsRu._(_root); @override late final _StringsPopupActionsRu popupActions = _StringsPopupActionsRu._(_root);
@override late final _StringsErrorsRu errors = _StringsErrorsRu._(_root); @override late final _StringsErrorsRu errors = _StringsErrorsRu._(_root);
@override Map<String, String> get countries => { @override Map<String, String> get countries => {
'': 'Не выбрана',
'AF': 'Афганистан', 'AF': 'Афганистан',
'AX': 'Аландские острова', 'AX': 'Аландские острова',
'AL': 'Албания', 'AL': 'Албания',
@ -1278,10 +1286,13 @@ extension on _StringsEn {
case 'calcViewNoValues': return 'Enter values to calculate the stats'; case 'calcViewNoValues': return 'Enter values to calculate the stats';
case 'rankAveragesViewTitle': return 'Ranks cutoff and average stats'; case 'rankAveragesViewTitle': return 'Ranks cutoff and average stats';
case 'averages': return 'Averages'; case 'averages': return 'Averages';
case 'lbViewZeroEntrys': return 'Empty list. Looks like something is wrong...'; case 'lbViewZeroEntrys': return 'Empty list';
case 'lbViewOneEntry': return 'There is only one player... What?'; case 'lbViewOneEntry': return 'There is only one player';
case 'lbViewManyEntrys': return ({required Object numberOfPlayers}) => 'There are ${numberOfPlayers}.'; case 'lbViewManyEntrys': return ({required Object numberOfPlayers}) => 'There are ${numberOfPlayers}';
case 'everyoneAverages': return 'Values for leaderboard'; case 'everyoneAverages': return 'Values for leaderboard';
case 'sortBy': return 'Sort by';
case 'reversed': return 'Reversed';
case 'country': return 'Country';
case 'rankAverages': return ({required Object rank}) => 'Values for ${rank} rank'; case 'rankAverages': return ({required Object rank}) => 'Values for ${rank} rank';
case 'players': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, case 'players': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: '${n} players', zero: '${n} players',
@ -1372,6 +1383,7 @@ extension on _StringsEn {
case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}'; case 'errors.connection': return ({required Object code, required Object message}) => 'Some issue with connection: ${code} ${message}';
case 'errors.noSuchUser': return 'No such user'; case 'errors.noSuchUser': return 'No such user';
case 'errors.socketException': return ({required Object host, required Object message}) => 'Can\'t connect with ${host}: ${message}'; case 'errors.socketException': return ({required Object host, required Object message}) => 'Can\'t connect with ${host}: ${message}';
case 'countries.': return 'Not selected';
case 'countries.AF': return 'Afghanistan'; case 'countries.AF': return 'Afghanistan';
case 'countries.AX': return 'Åland Islands'; case 'countries.AX': return 'Åland Islands';
case 'countries.AL': return 'Albania'; case 'countries.AL': return 'Albania';
@ -1737,10 +1749,13 @@ extension on _StringsRu {
case 'calcViewNoValues': return 'Введите значения, чтобы посчитать статистику'; case 'calcViewNoValues': return 'Введите значения, чтобы посчитать статистику';
case 'rankAveragesViewTitle': return 'Требования рангов и средние значения'; case 'rankAveragesViewTitle': return 'Требования рангов и средние значения';
case 'averages': return 'Средние значения'; case 'averages': return 'Средние значения';
case 'lbViewZeroEntrys': return 'Рейтинговая таблица пуста. Похоже, что-то здесь не так...'; case 'lbViewZeroEntrys': return 'Рейтинговая таблица пуста';
case 'lbViewOneEntry': return 'В рейтинговой таблице всего один игрок... Чего?'; case 'lbViewOneEntry': return 'В рейтинговой таблице всего один игрок';
case 'lbViewManyEntrys': return ({required Object numberOfPlayers}) => 'В рейтинговой таблице находится ${numberOfPlayers}.'; case 'lbViewManyEntrys': return ({required Object numberOfPlayers}) => 'В рейтинговой таблице находится ${numberOfPlayers}';
case 'everyoneAverages': return 'Значения таблицы'; case 'everyoneAverages': return 'Значения таблицы';
case 'sortBy': return 'Cортировать по';
case 'reversed': return 'Наоборот';
case 'country': return 'Страна';
case 'rankAverages': return ({required Object rank}) => 'Значения для ${rank} ранга'; case 'rankAverages': return ({required Object rank}) => 'Значения для ${rank} ранга';
case 'players': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n, case 'players': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('ru'))(n,
zero: '${n} игроков', zero: '${n} игроков',
@ -1831,6 +1846,7 @@ extension on _StringsRu {
case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}'; case 'errors.connection': return ({required Object code, required Object message}) => 'Проблема с подключением: ${code} ${message}';
case 'errors.noSuchUser': return 'Нет такого пользователя'; case 'errors.noSuchUser': return 'Нет такого пользователя';
case 'errors.socketException': return ({required Object host, required Object message}) => 'Невозможно подключиться к ${host}: ${message}'; case 'errors.socketException': return ({required Object host, required Object message}) => 'Невозможно подключиться к ${host}: ${message}';
case 'countries.': return 'Не выбрана';
case 'countries.AF': return 'Афганистан'; case 'countries.AF': return 'Афганистан';
case 'countries.AX': return 'Аландские острова'; case 'countries.AX': return 'Аландские острова';
case 'countries.AL': return 'Албания'; case 'countries.AL': return 'Албания';

View File

@ -10,6 +10,7 @@ double? vs;
NerdStats? nerdStats; NerdStats? nerdStats;
EstTr? estTr; EstTr? estTr;
Playstyle? playstyle; Playstyle? playstyle;
final NumberFormat f2 = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2);
class CalcView extends StatefulWidget { class CalcView extends StatefulWidget {
const CalcView({Key? key}) : super(key: key); const CalcView({Key? key}) : super(key: key);
@ -129,10 +130,10 @@ class CalcState extends State<CalcView> {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 48), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 300, height: 310,
width: 300, width: 310,
child: RadarChart( child: RadarChart(
RadarChartData( RadarChartData(
radarShape: RadarShape.polygon, radarShape: RadarShape.polygon,
@ -154,21 +155,21 @@ class CalcState extends State<CalcView> {
angle: angle, angle: angle,
); );
case 2: case 2:
return RadarChartTitle(text: 'VS', angle: angle); return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'APP', angle: angle + 180); return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05);
case 4: case 4:
return RadarChartTitle(text: 'DS/S', angle: angle + 180); return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05);
case 5: case 5:
return RadarChartTitle(text: 'DS/P', angle: angle + 180); return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 6: case 6:
return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180); return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 7: case 7:
return RadarChartTitle(text: 'VS/APM', angle: angle + 180); return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05);
case 8: case 8:
return RadarChartTitle(text: 'Cheese', angle: angle); return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05);
case 9: case 9:
return RadarChartTitle(text: 'Gb Eff.', angle: angle); return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }
@ -212,34 +213,30 @@ class CalcState extends State<CalcView> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 48), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 300, height: 310,
width: 300, width: 310,
child: RadarChart( child: RadarChart(
RadarChartData( RadarChartData(
radarShape: RadarShape.polygon, radarShape: RadarShape.polygon,
tickCount: 4, tickCount: 4,
ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10),
radarBorderData: const BorderSide(color: Colors.transparent, width: 1), radarBorderData: const BorderSide(color: Colors.transparent, width: 1),
gridBorderData: const BorderSide(color: Colors.white24, width: 1), gridBorderData: const BorderSide(color: Colors.white24, width: 1),
tickBorderData: const BorderSide(color: Colors.transparent, width: 1), tickBorderData: const BorderSide(color: Colors.transparent, width: 1),
titleTextStyle: const TextStyle(height: 1.1),
radarTouchData: RadarTouchData(),
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle( return RadarChartTitle(text: 'Opener\n${f2.format(playstyle!.opener)}', angle: 0, positionPercentageOffset: 0.05);
text: 'Opener',
angle: angle,
);
case 1: case 1:
return RadarChartTitle( return RadarChartTitle(text: 'Stride\n${f2.format(playstyle!.stride)}', angle: 0, positionPercentageOffset: 0.05);
text: 'Stride',
angle: angle,
);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds', angle: angle + 180); return RadarChartTitle(text: 'Inf Ds\n${f2.format(playstyle!.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk', angle: angle); return RadarChartTitle(text: 'Plonk\n${f2.format(playstyle!.plonk)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -620,49 +620,51 @@ class CompareState extends State<CompareView> {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
children: [ children: [
Padding( Padding(
padding: padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
const EdgeInsets.fromLTRB(20, 20, 20, 20), child: SizedBox(
child: SizedBox( height: 310,
height: 300, width: 310,
width: 300, child: RadarChart(
child: RadarChart( RadarChartData(
RadarChartData( radarShape: RadarShape.polygon,
radarShape: RadarShape.polygon, tickCount: 4,
tickCount: 4, ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10),
ticksTextStyle: const TextStyle( radarBorderData: const BorderSide(color: Colors.transparent, width: 1),
color: Colors.transparent, gridBorderData: const BorderSide(color: Colors.white24, width: 1),
fontSize: 10), tickBorderData: const BorderSide(color: Colors.transparent, width: 1),
radarBorderData: const BorderSide( getTitle: (index, angle) {
color: Colors.transparent, width: 1), switch (index) {
gridBorderData: const BorderSide( case 0:
color: Colors.white24, width: 1), return RadarChartTitle(
tickBorderData: const BorderSide( text: 'APM',
color: Colors.transparent, width: 1), angle: angle,
getTitle: (index, angle) { positionPercentageOffset: 0.05
switch (index) { );
case 0: case 1:
return RadarChartTitle(text: 'APM', angle: angle); return RadarChartTitle(
case 1: text: 'PPS',
return RadarChartTitle(text: 'PPS', angle: angle); angle: angle,
case 2: positionPercentageOffset: 0.05
return RadarChartTitle(text: 'VS', angle: angle); );
case 3: case 2:
return RadarChartTitle(text: 'APP', angle: angle + 180); return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05);
case 4: case 3:
return RadarChartTitle(text: 'DS/S', angle: angle + 180); return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05);
case 5: case 4:
return RadarChartTitle(text: 'DS/P', angle: angle + 180); return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05);
case 6: case 5:
return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180); return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 7: case 6:
return RadarChartTitle(text: 'VS/APM', angle: angle + 180); return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 8: case 7:
return RadarChartTitle(text: 'Cheese', angle: angle); return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05);
case 9: case 8:
return RadarChartTitle(text: 'Gb Eff.', angle: angle); return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05);
default: case 9:
return const RadarChartTitle(text: ''); return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05);
} default:
return const RadarChartTitle(text: '');
}
}, },
dataSets: [ dataSets: [
RadarDataSet( RadarDataSet(
@ -721,34 +723,30 @@ class CompareState extends State<CompareView> {
), ),
), ),
Padding( Padding(
padding: padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
const EdgeInsets.fromLTRB(20, 20, 20, 20), child: SizedBox(
child: SizedBox( height: 310,
height: 300, width: 310,
width: 300, child: RadarChart(
child: RadarChart( RadarChartData(
RadarChartData( radarShape: RadarShape.polygon,
radarShape: RadarShape.polygon, tickCount: 4,
tickCount: 4, ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10),
ticksTextStyle: const TextStyle( radarBorderData: const BorderSide(color: Colors.transparent, width: 1),
color: Colors.transparent, gridBorderData: const BorderSide(color: Colors.white24, width: 1),
fontSize: 10), tickBorderData: const BorderSide(color: Colors.transparent, width: 1),
radarBorderData: const BorderSide( titleTextStyle: const TextStyle(height: 1.1),
color: Colors.transparent, width: 1), radarTouchData: RadarTouchData(),
gridBorderData: const BorderSide(
color: Colors.white24, width: 1),
tickBorderData: const BorderSide(
color: Colors.transparent, width: 1),
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: 'Opener',angle: angle); return RadarChartTitle(text: 'Opener',angle: angle, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: 'Stride', angle: angle); return RadarChartTitle(text: 'Stride', angle: angle, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds', angle: angle + 180); return RadarChartTitle(text: 'Inf Ds', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk', angle: angle); return RadarChartTitle(text: 'Plonk', angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }
@ -849,7 +847,7 @@ class CompareState extends State<CompareView> {
) )
], ],
) )
] : [Text(t.compareViewNoValues(avgR: "\$avdR"))], // This is so fucked up holy shit ] : [Text(t.compareViewNoValues(avgR: "\$avgR"))], // This is so fucked up holy shit
) )
), ),
), ),

View File

@ -23,7 +23,7 @@ String _titleNickname = "dan63047";
final TetrioService teto = TetrioService(); final TetrioService teto = TetrioService();
late SharedPreferences prefs; late SharedPreferences prefs;
var chartsData = <DropdownMenuItem<List<FlSpot>>>[]; var chartsData = <DropdownMenuItem<List<FlSpot>>>[];
List chartsShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"]; List historyShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"];
int chartsIndex = 0; int chartsIndex = 0;
const allowedHeightForPlayerIdInPixels = 40.0; const allowedHeightForPlayerIdInPixels = 40.0;
const allowedHeightForPlayerBioInPixels = 30.0; const allowedHeightForPlayerBioInPixels = 30.0;
@ -508,12 +508,18 @@ class _TLRecords extends StatelessWidget {
fontSize: 28,)), fontSize: 28,)),
title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"),
subtitle: Text(dateFormat.format(value.timestamp)), subtitle: Text(dateFormat.format(value.timestamp)),
trailing: Column(mainAxisAlignment: MainAxisAlignment.center, trailing: Table(defaultColumnWidth: IntrinsicColumnWidth(),
defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
columnWidths: {
0: FixedColumnWidth(50),
2: FixedColumnWidth(50),
},
children: [ children: [
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary)} APM", style: const TextStyle(height: 1.1)), TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: const TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" APM", textAlign: TextAlign.right, style: const TextStyle(height: 1.1))]),
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary)} PPS", style: const TextStyle(height: 1.1)), TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: const TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" PPS", textAlign: TextAlign.right, style: const TextStyle(height: 1.1))]),
Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra)} VS", style: const TextStyle(height: 1.1)), TableRow(children: [Text(f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" :", style: const TextStyle(height: 1.1)), Text(f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra), textAlign: TextAlign.right, style: const TextStyle(height: 1.1)), const Text(" VS", textAlign: TextAlign.right, style: const TextStyle(height: 1.1))]),
]), ],),
onTap: (){Navigator.push( onTap: (){Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -546,7 +552,7 @@ class _History extends StatelessWidget{
update(); update();
} }
), ),
if(chartsData[chartsIndex].value!.length > 1) _HistoryChartThigy(data: chartsData[chartsIndex].value!, title: "ss", yAxisTitle: chartsShortTitles[chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),) if(chartsData[chartsIndex].value!.length > 1) _HistoryChartThigy(data: chartsData[chartsIndex].value!, title: "ss", yAxisTitle: historyShortTitles[chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),)
else Center(child: Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))) else Center(child: Text(t.notEnoughData, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))
], ],
), ),

View File

@ -6,39 +6,9 @@ import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/views/main_view.dart' show MainView, f4, f2; import 'package:tetra_stats/views/main_view.dart' show MainView, f4, f2;
const List chartsShortTitles = [ var chartsShortTitlesDropdowns = <DropdownMenuItem>[for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value),)];
"TR", Stats chartsX = Stats.tr;
"Glicko", Stats chartsY = Stats.apm;
"RD",
"GP",
"GW",
"WR%",
"APM",
"PPS",
"VS",
"APP",
"DS/S",
"DS/P",
"APP + DS/P",
"VS/APM",
"Cheese",
"GbE",
"wAPP",
"Area",
"eTR",
"±eTR",
"Opener",
"Plonk",
"Inf. DS",
"Stride",
"Stride - Plonk",
"Opener - Inf. DS"
];
var chartsShortTitlesDropdowns = <DropdownMenuItem>[for (String e in chartsShortTitles) DropdownMenuItem(value: e,child: Text(e),)];
int chartsIndexX = 0;
int chartsIndexY = 6;
//final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms();
double pfpHeight = 128;
class RankView extends StatefulWidget { class RankView extends StatefulWidget {
final List rank; final List rank;
@ -154,9 +124,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
child: Text(t.currentAxis(axis: "X"), style: const TextStyle(fontSize: 22))), child: Text(t.currentAxis(axis: "X"), style: const TextStyle(fontSize: 22))),
DropdownButton( DropdownButton(
items: chartsShortTitlesDropdowns, items: chartsShortTitlesDropdowns,
value: chartsShortTitlesDropdowns[chartsIndexX].value, value: chartsX,
onChanged: (value) { onChanged: (value) {
chartsIndexX = chartsShortTitlesDropdowns.indexWhere((element) => element.value == value); chartsX = value;
_justUpdate(); _justUpdate();
} }
), ),
@ -174,9 +144,9 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
), ),
DropdownButton( DropdownButton(
items: chartsShortTitlesDropdowns, items: chartsShortTitlesDropdowns,
value: chartsShortTitlesDropdowns[chartsIndexY].value, value: chartsY,
onChanged: (value) { onChanged: (value) {
chartsIndexY = chartsShortTitlesDropdowns.indexWhere((element) => element.value == value); chartsY = value;
_justUpdate(); _justUpdate();
} }
), ),
@ -195,11 +165,11 @@ class RankState extends State<RankView> with SingleTickerProviderStateMixin {
: const EdgeInsets.fromLTRB(0, 40, 16, 48), : const EdgeInsets.fromLTRB(0, 40, 16, 48),
child: ScatterChart( child: ScatterChart(
ScatterChartData( ScatterChartData(
scatterSpots: [ for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"]) _MyScatterSpot(takeStat(entry, chartsShortTitles[chartsIndexX]), takeStat(entry, chartsShortTitles[chartsIndexY]), entry.userId, entry.username, color: rankColors[entry.rank])], scatterSpots: [ for (TetrioPlayerFromLeaderboard entry in widget.rank[1]["entries"]) _MyScatterSpot(entry.getStatByEnum(chartsX) as double, entry.getStatByEnum(chartsY) as double, entry.userId, entry.username, color: rankColors[entry.rank])],
scatterTouchData: ScatterTouchData(touchTooltipData: ScatterTouchTooltipData( scatterTouchData: ScatterTouchData(touchTooltipData: ScatterTouchTooltipData(
fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpot) { fitInsideHorizontally: true, fitInsideVertically: true, getTooltipItems: (touchedSpot) {
touchedSpot as _MyScatterSpot; touchedSpot as _MyScatterSpot;
return ScatterTooltipItem("${touchedSpot.nickname}\n", textStyle: const TextStyle(fontFamily: "Eurostile Round Extended"), children: [TextSpan(text: "${f4.format(touchedSpot.x)} ${chartsShortTitles[chartsIndexX]}\n${f4.format(touchedSpot.y)} ${chartsShortTitles[chartsIndexY]}", style: const TextStyle(fontFamily: "Eurostile Round"))]); return ScatterTooltipItem("${touchedSpot.nickname}\n", textStyle: const TextStyle(fontFamily: "Eurostile Round Extended"), children: [TextSpan(text: "${f4.format(touchedSpot.x)} ${chartsShortTitles[chartsX]}\n${f4.format(touchedSpot.y)} ${chartsShortTitles[chartsY]}", style: const TextStyle(fontFamily: "Eurostile Round"))]);
}), }),
touchCallback:(event, response) { touchCallback:(event, response) {
if (event.runtimeType == FlTapDownEvent && response?.touchedSpot?.spot != null){ if (event.runtimeType == FlTapDownEvent && response?.touchedSpot?.spot != null){
@ -956,66 +926,6 @@ class _ListEntry extends StatelessWidget {
); );
} }
} }
double takeStat(TetrioPlayerFromLeaderboard entry, String stat) {
switch (stat) {
case "TR":
return entry.rating;
case "Glicko":
return entry.glicko;
case "RD":
return entry.rd;
case "GP":
return entry.gamesPlayed.toDouble();
case "GW":
return entry.gamesWon.toDouble();
case "WR%":
return entry.winrate*100;
case "APM":
return entry.apm;
case "PPS":
return entry.pps;
case "VS":
return entry.vs;
case "APP":
return entry.nerdStats.app;
case "DS/S":
return entry.nerdStats.dss;
case "DS/P":
return entry.nerdStats.dsp;
case "APP + DS/P":
return entry.nerdStats.appdsp;
case "VS/APM":
return entry.nerdStats.vsapm;
case "Cheese":
return entry.nerdStats.cheese;
case "GbE":
return entry.nerdStats.gbe;
case "wAPP":
return entry.nerdStats.nyaapp;
case "Area":
return entry.nerdStats.area;
case "eTR":
return entry.estTr.esttr;
case "±eTR":
return entry.esttracc;
case "Opener":
return entry.playstyle.opener;
case "Plonk":
return entry.playstyle.plonk;
case "Inf. DS":
return entry.playstyle.infds;
case "Stride":
return entry.playstyle.stride;
case "Stride - Plonk":
return entry.playstyle.stride - entry.playstyle.plonk;
case "Opener - Inf. DS":
return entry.playstyle.opener - entry.playstyle.infds;
default:
throw ArgumentError.value(stat, "Incorrect stat", "We don't have that stat");
}
}
class _MyScatterSpot extends ScatterSpot{ class _MyScatterSpot extends ScatterSpot{
String id; String id;
String nickname; String nickname;

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/services/tetrio_crud.dart'; import 'package:tetra_stats/services/tetrio_crud.dart';
import 'package:tetra_stats/views/main_view.dart'; import 'package:tetra_stats/views/main_view.dart';
@ -7,6 +8,11 @@ import 'package:tetra_stats/views/rank_averages_view.dart';
import 'package:tetra_stats/views/ranks_averages_view.dart'; import 'package:tetra_stats/views/ranks_averages_view.dart';
final TetrioService teto = TetrioService(); final TetrioService teto = TetrioService();
List<DropdownMenuItem> itemStats = [for (MapEntry e in chartsShortTitles.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
Stats sortBy = Stats.tr;
bool reversed = false;
List<DropdownMenuItem> itemCountries = [for (MapEntry e in t.countries.entries) DropdownMenuItem(value: e.key, child: Text(e.value))];
String country = "";
class TLLeaderboardView extends StatefulWidget { class TLLeaderboardView extends StatefulWidget {
const TLLeaderboardView({Key? key}) : super(key: key); const TLLeaderboardView({Key? key}) : super(key: key);
@ -51,7 +57,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
case ConnectionState.active: case ConnectionState.active:
return const Center(child: Text('Fetching...')); return const Center(child: Text('Fetching...'));
case ConnectionState.done: case ConnectionState.done:
final allPlayers = snapshot.data?.leaderboard; final allPlayers = snapshot.data?.getStatRanking(snapshot.data!.leaderboard, sortBy, reversed: reversed, country: country);
return NestedScrollView( return NestedScrollView(
headerSliverBuilder: (context, value) { headerSliverBuilder: (context, value) {
String howManyPlayers(int numberOfPlayers) => Intl.plural( String howManyPlayers(int numberOfPlayers) => Intl.plural(
@ -87,6 +93,61 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
style: const TextStyle(fontSize: 25))) style: const TextStyle(fontSize: 25)))
],) ],)
)), )),
SliverToBoxAdapter(child: Padding(
padding: const EdgeInsets.only(left: 16),
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 16,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text("${t.sortBy}: ",
style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton(items: itemStats, value: sortBy, onChanged: ((value) {
sortBy = value;
setState(() {});
}),),
],
),
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text("${t.reversed}: ",
style: const TextStyle(color: Colors.white, fontSize: 25)),
Padding(
padding: const EdgeInsets.fromLTRB(0, 5.5, 0, 7.5),
child: Checkbox(value: reversed,
checkColor: Colors.black,
onChanged: ((value) {
reversed = value!;
setState(() {});
}),),
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text("${t.country}: ",
style: const TextStyle(color: Colors.white, fontSize: 25)),
DropdownButton(items: itemCountries, value: country, onChanged: ((value) {
country = value;
setState(() {});
}),),
],
),
],
),
),),
const SliverToBoxAdapter(child: Divider()) const SliverToBoxAdapter(child: Divider())
]; ];
}, },
@ -98,7 +159,7 @@ class TLLeaderboardState extends State<TLLeaderboardView> {
leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null), leading: Text((index+1).toString(), style: bigScreen ? const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28) : null),
title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")), title: Text(allPlayers[index].username, style: const TextStyle(fontFamily: "Eurostile Round Extended")),
subtitle: Text( subtitle: Text(
"${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM"), sortBy == Stats.tr ? "${f2.format(allPlayers[index].apm)} APM, ${f2.format(allPlayers[index].pps)} PPS, ${f2.format(allPlayers[index].vs)} VS, ${f2.format(allPlayers[index].nerdStats.app)} APP, ${f2.format(allPlayers[index].nerdStats.vsapm)} VS/APM" : "${f4.format(allPlayers[index].getStatByEnum(sortBy))} ${chartsShortTitles[sortBy]}"),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@ -69,7 +69,8 @@ class TLThingy extends StatelessWidget {
maximum: tl.prevAt.toDouble(), maximum: tl.prevAt.toDouble(),
interval: tl.prevAt.toDouble() - tl.nextAt.toDouble(), interval: tl.prevAt.toDouble() - tl.nextAt.toDouble(),
ranges: [LinearGaugeRange(startValue: tl.standing.toDouble() <= tl.prevAt.toDouble() ? tl.standing.toDouble() : tl.prevAt.toDouble(), endValue: tl.prevAt.toDouble(), color: Colors.cyanAccent,)], ranges: [LinearGaugeRange(startValue: tl.standing.toDouble() <= tl.prevAt.toDouble() ? tl.standing.toDouble() : tl.prevAt.toDouble(), endValue: tl.prevAt.toDouble(), color: Colors.cyanAccent,)],
//barPointers: [LinearBarPointer(value: 80)], markerPointers: [LinearShapePointer(value: tl.standing.toDouble() <= tl.prevAt.toDouble() ? tl.standing.toDouble() : tl.prevAt.toDouble(), position: LinearElementPosition.inside, shapeType: LinearShapePointerType.triangle, color: Colors.white, height: 20),
LinearWidgetPointer(offset: 4, position: LinearElementPosition.outside, value: tl.standing.toDouble() <= tl.prevAt.toDouble() ? tl.standing.toDouble() : tl.prevAt.toDouble(), child: Text(NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 0).format(tl.standing)))],
isAxisInversed: true, isAxisInversed: true,
isMirrored: true, isMirrored: true,
showTicks: true, showTicks: true,
@ -97,7 +98,6 @@ class TLThingy extends StatelessWidget {
if (tl.apm != null) StatCellNum(playerStat: tl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.apm, higherIsBetter: true, oldPlayerStat: oldTl?.apm), if (tl.apm != null) StatCellNum(playerStat: tl.apm!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.apm, higherIsBetter: true, oldPlayerStat: oldTl?.apm),
if (tl.pps != null) StatCellNum(playerStat: tl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.pps, higherIsBetter: true, oldPlayerStat: oldTl?.pps), if (tl.pps != null) StatCellNum(playerStat: tl.pps!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.pps, higherIsBetter: true, oldPlayerStat: oldTl?.pps),
if (tl.vs != null) StatCellNum(playerStat: tl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.vs, higherIsBetter: true, oldPlayerStat: oldTl?.vs), if (tl.vs != null) StatCellNum(playerStat: tl.vs!, isScreenBig: bigScreen, fractionDigits: 2, playerStatLabel: t.statCellNum.vs, higherIsBetter: true, oldPlayerStat: oldTl?.vs),
if (tl.standing > 0) StatCellNum(playerStat: tl.standing, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.lbp, higherIsBetter: false, oldPlayerStat: oldTl?.standing),
if (tl.standingLocal > 0) StatCellNum(playerStat: tl.standingLocal, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.lbpc, higherIsBetter: false, oldPlayerStat: oldTl?.standingLocal), if (tl.standingLocal > 0) StatCellNum(playerStat: tl.standingLocal, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.lbpc, higherIsBetter: false, oldPlayerStat: oldTl?.standingLocal),
StatCellNum(playerStat: tl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesPlayed, higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed), StatCellNum(playerStat: tl.gamesPlayed, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesPlayed, higherIsBetter: true, oldPlayerStat: oldTl?.gamesPlayed),
StatCellNum(playerStat: tl.gamesWon, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesWonTL, higherIsBetter: true, oldPlayerStat: oldTl?.gamesWon), StatCellNum(playerStat: tl.gamesWon, isScreenBig: bigScreen, playerStatLabel: t.statCellNum.gamesWonTL, higherIsBetter: true, oldPlayerStat: oldTl?.gamesWon),
@ -352,10 +352,10 @@ class TLThingy extends StatelessWidget {
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 48), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 300, height: 310,
width: 300, width: 310,
child: RadarChart( child: RadarChart(
RadarChartData( RadarChartData(
radarShape: RadarShape.polygon, radarShape: RadarShape.polygon,
@ -377,21 +377,21 @@ class TLThingy extends StatelessWidget {
angle: angle, angle: angle,
); );
case 2: case 2:
return RadarChartTitle(text: 'VS', angle: angle); return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'APP', angle: angle + 180); return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05);
case 4: case 4:
return RadarChartTitle(text: 'DS/S', angle: angle + 180); return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05);
case 5: case 5:
return RadarChartTitle(text: 'DS/P', angle: angle + 180); return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 6: case 6:
return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180); return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05);
case 7: case 7:
return RadarChartTitle(text: 'VS/APM', angle: angle + 180); return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05);
case 8: case 8:
return RadarChartTitle(text: 'Cheese', angle: angle); return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05);
case 9: case 9:
return RadarChartTitle(text: 'Gb Eff.', angle: angle); return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }
@ -435,34 +435,30 @@ class TLThingy extends StatelessWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 48), padding: const EdgeInsets.fromLTRB(18, 0, 18, 44),
child: SizedBox( child: SizedBox(
height: 300, height: 310,
width: 300, width: 310,
child: RadarChart( child: RadarChart(
RadarChartData( RadarChartData(
radarShape: RadarShape.polygon, radarShape: RadarShape.polygon,
tickCount: 4, tickCount: 4,
ticksTextStyle: const TextStyle(color: Colors.transparent, fontSize: 10), ticksTextStyle: const TextStyle(color: Colors.white24, fontSize: 10),
radarBorderData: const BorderSide(color: Colors.transparent, width: 1), radarBorderData: const BorderSide(color: Colors.transparent, width: 1),
gridBorderData: const BorderSide(color: Colors.white24, width: 1), gridBorderData: const BorderSide(color: Colors.white24, width: 1),
tickBorderData: const BorderSide(color: Colors.transparent, width: 1), tickBorderData: const BorderSide(color: Colors.transparent, width: 1),
titleTextStyle: const TextStyle(height: 1.1),
radarTouchData: RadarTouchData(),
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle( return RadarChartTitle(text: 'Opener\n${f2.format(tl.playstyle!.opener)}', angle: 0, positionPercentageOffset: 0.05);
text: 'Opener',
angle: angle,
);
case 1: case 1:
return RadarChartTitle( return RadarChartTitle(text: 'Stride\n${f2.format(tl.playstyle!.stride)}', angle: 0, positionPercentageOffset: 0.05);
text: 'Stride',
angle: angle,
);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds', angle: angle + 180); return RadarChartTitle(text: 'Inf Ds\n${f2.format(tl.playstyle!.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk', angle: angle); return RadarChartTitle(text: 'Plonk\n${f2.format(tl.playstyle!.plonk)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -100,10 +100,13 @@
"calcViewNoValues": "Enter values to calculate the stats", "calcViewNoValues": "Enter values to calculate the stats",
"rankAveragesViewTitle": "Ranks cutoff and average stats", "rankAveragesViewTitle": "Ranks cutoff and average stats",
"averages": "Averages", "averages": "Averages",
"lbViewZeroEntrys": "Empty list. Looks like something is wrong...", "lbViewZeroEntrys": "Empty list",
"lbViewOneEntry": "There is only one player... What?", "lbViewOneEntry": "There is only one player",
"lbViewManyEntrys": "There are ${numberOfPlayers}.", "lbViewManyEntrys": "There are ${numberOfPlayers}",
"everyoneAverages": "Values for leaderboard", "everyoneAverages": "Values for leaderboard",
"sortBy": "Sort by",
"reversed": "Reversed",
"country": "Country",
"rankAverages": "Values for $rank rank", "rankAverages": "Values for $rank rank",
"players":{ "players":{
"zero": "$n players", "zero": "$n players",
@ -205,6 +208,8 @@
"socketException": "Can't connect with ${host}: ${message}" "socketException": "Can't connect with ${host}: ${message}"
}, },
"countries(map)": { "countries(map)": {
"": "Not selected",
"AF": "Afghanistan", "AF": "Afghanistan",
"AX": "\u00c5land Islands", "AX": "\u00c5land Islands",
"AL": "Albania", "AL": "Albania",

View File

@ -100,10 +100,13 @@
"calcViewNoValues": "Введите значения, чтобы посчитать статистику", "calcViewNoValues": "Введите значения, чтобы посчитать статистику",
"rankAveragesViewTitle": "Требования рангов и средние значения", "rankAveragesViewTitle": "Требования рангов и средние значения",
"averages": "Средние значения", "averages": "Средние значения",
"lbViewZeroEntrys": "Рейтинговая таблица пуста. Похоже, что-то здесь не так...", "lbViewZeroEntrys": "Рейтинговая таблица пуста",
"lbViewOneEntry": "В рейтинговой таблице всего один игрок... Чего?", "lbViewOneEntry": "В рейтинговой таблице всего один игрок",
"lbViewManyEntrys": "В рейтинговой таблице находится ${numberOfPlayers}.", "lbViewManyEntrys": "В рейтинговой таблице находится ${numberOfPlayers}",
"everyoneAverages": "Значения таблицы", "everyoneAverages": "Значения таблицы",
"sortBy": "Cортировать по",
"reversed": "Наоборот",
"country": "Страна",
"rankAverages": "Значения для $rank ранга", "rankAverages": "Значения для $rank ранга",
"players":{ "players":{
"zero": "$n игроков", "zero": "$n игроков",
@ -205,6 +208,8 @@
"socketException": "Невозможно подключиться к ${host}: ${message}" "socketException": "Невозможно подключиться к ${host}: ${message}"
}, },
"countries(map)": { "countries(map)": {
"": "Не выбрана",
"AF": "Афганистан", "AF": "Афганистан",
"AX": "Аландские острова", "AX": "Аландские острова",
"AL": "Албания", "AL": "Албания",