i18n fully done, time to translate

This commit is contained in:
dan63047 2024-12-02 23:45:15 +03:00
parent 04bf77c91a
commit d60406304f
28 changed files with 602 additions and 539 deletions

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 1 /// Locales: 1
/// Strings: 690 /// Strings: 756
/// ///
/// Built on 2024-11-28 at 20:31 UTC /// Built on 2024-12-02 at 19:52 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -198,15 +198,24 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String obtainDate({required Object date}) => 'Obtained ${date}'; String obtainDate({required Object date}) => 'Obtained ${date}';
String get assignedManualy => 'That badge was assigned manualy by TETR.IO admins'; String get assignedManualy => 'That badge was assigned manualy by TETR.IO admins';
String get distinguishment => 'Distinguishment'; String get distinguishment => 'Distinguishment';
String get bigRedBanned => 'BANNED'; String get banned => 'Banned';
String get normalBanned => 'Banned'; String get bannedSubtext => 'Bans are placed when TETR.IO rules or terms of service are broken';
String get bigRedBadStanding => 'BAD STANDING'; String get badStanding => 'Bad standing';
String get badStandingSubtext => 'One or more recent bans on record';
String get botAccount => 'Bot account';
String botAccountSubtext({required Object botMaintainers}) => 'Operated by ${botMaintainers}';
String get copiedToClipboard => 'Copied to clipboard!'; String get copiedToClipboard => 'Copied to clipboard!';
String get bio => 'Bio'; String get bio => 'Bio';
String get news => 'News'; String get news => 'News';
late final _StringsMatchResultEn matchResult = _StringsMatchResultEn._(_root);
late final _StringsDistinguishmentsEn distinguishments = _StringsDistinguishmentsEn._(_root);
late final _StringsNewsEntrysEn newsEntrys = _StringsNewsEntrysEn._(_root);
late final _StringsNewsPartsEn newsParts = _StringsNewsPartsEn._(_root); late final _StringsNewsPartsEn newsParts = _StringsNewsPartsEn._(_root);
String get copyUserID => 'Click to copy user ID'; String get copyUserID => 'Click to copy user ID';
String get searchHint => 'Username or ID'; String get searchHint => 'Username or ID';
String get navMenu => 'Navigation menu';
String get navMenuTooltip => 'Open navigation menu';
String get refresh => 'Refresh data';
String get searchButton => 'Search'; String get searchButton => 'Search';
String get trackedPlayers => 'Tracked Players'; String get trackedPlayers => 'Tracked Players';
String get standing => 'Standing'; String get standing => 'Standing';
@ -222,14 +231,17 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
late final _StringsFilterModaleEn filterModale = _StringsFilterModaleEn._(_root); late final _StringsFilterModaleEn filterModale = _StringsFilterModaleEn._(_root);
late final _StringsCutoffsDestinationEn cutoffsDestination = _StringsCutoffsDestinationEn._(_root); late final _StringsCutoffsDestinationEn cutoffsDestination = _StringsCutoffsDestinationEn._(_root);
late final _StringsRankViewEn rankView = _StringsRankViewEn._(_root); late final _StringsRankViewEn rankView = _StringsRankViewEn._(_root);
late final _StringsStateViewEn stateView = _StringsStateViewEn._(_root);
late final _StringsTlMatchViewEn tlMatchView = _StringsTlMatchViewEn._(_root); late final _StringsTlMatchViewEn tlMatchView = _StringsTlMatchViewEn._(_root);
late final _StringsCalcDestinationEn calcDestination = _StringsCalcDestinationEn._(_root); late final _StringsCalcDestinationEn calcDestination = _StringsCalcDestinationEn._(_root);
late final _StringsInfoDestinationEn infoDestination = _StringsInfoDestinationEn._(_root); late final _StringsInfoDestinationEn infoDestination = _StringsInfoDestinationEn._(_root);
late final _StringsLeaderboardsDestinationEn leaderboardsDestination = _StringsLeaderboardsDestinationEn._(_root); late final _StringsLeaderboardsDestinationEn leaderboardsDestination = _StringsLeaderboardsDestinationEn._(_root);
late final _StringsSavedDataDestinationEn savedDataDestination = _StringsSavedDataDestinationEn._(_root);
late final _StringsSettingsDestinationEn settingsDestination = _StringsSettingsDestinationEn._(_root); late final _StringsSettingsDestinationEn settingsDestination = _StringsSettingsDestinationEn._(_root);
late final _StringsHomeNavigationEn homeNavigation = _StringsHomeNavigationEn._(_root); late final _StringsHomeNavigationEn homeNavigation = _StringsHomeNavigationEn._(_root);
late final _StringsGraphsNavigationEn graphsNavigation = _StringsGraphsNavigationEn._(_root); late final _StringsGraphsNavigationEn graphsNavigation = _StringsGraphsNavigationEn._(_root);
late final _StringsCalcNavigationEn calcNavigation = _StringsCalcNavigationEn._(_root); late final _StringsCalcNavigationEn calcNavigation = _StringsCalcNavigationEn._(_root);
late final _StringsFirstTimeViewEn firstTimeView = _StringsFirstTimeViewEn._(_root);
late final _StringsAboutViewEn aboutView = _StringsAboutViewEn._(_root); late final _StringsAboutViewEn aboutView = _StringsAboutViewEn._(_root);
late final _StringsStatsEn stats = _StringsStatsEn._(_root); late final _StringsStatsEn stats = _StringsStatsEn._(_root);
Map<String, String> get countries => { Map<String, String> get countries => {
@ -536,6 +548,45 @@ class _StringsGametimeEn {
String breakdown({required Object years, required Object months, required Object days, required Object minutes, required Object seconds}) => 'It\'s ${years} years,\nor ${months} months,\nor ${days} days,\nor ${minutes} minutes\nor ${seconds} seconds'; String breakdown({required Object years, required Object months, required Object days, required Object minutes, required Object seconds}) => 'It\'s ${years} years,\nor ${months} months,\nor ${days} days,\nor ${minutes} minutes\nor ${seconds} seconds';
} }
// Path: matchResult
class _StringsMatchResultEn {
_StringsMatchResultEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get victory => 'Victory';
String get defeat => 'Defeat';
String get tie => 'Tie';
String get dqvictory => 'Opponent was DQ\'ed';
String get dqdefeat => 'Disqualified';
String get nocontest => 'No Contest';
String get nullified => 'Nullified';
}
// Path: distinguishments
class _StringsDistinguishmentsEn {
_StringsDistinguishmentsEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get noHeader => 'Header is missing';
String get noFooter => 'Footer is missing';
String get twc => 'TETR.IO World Champion';
String twcYear({required Object year}) => '${year} TETR.IO World Championship';
}
// Path: newsEntrys
class _StringsNewsEntrysEn {
_StringsNewsEntrysEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String leaderboard({required Object rank, required Object gametype}) => 'Got № ${rank} on ${gametype}';
}
// Path: newsParts // Path: newsParts
class _StringsNewsPartsEn { class _StringsNewsPartsEn {
_StringsNewsPartsEn._(this._root); _StringsNewsPartsEn._(this._root);
@ -689,6 +740,7 @@ class _StringsRankViewEn {
String get trRange => 'TR Range'; String get trRange => 'TR Range';
String get supposedToBe => 'Supposed to be'; String get supposedToBe => 'Supposed to be';
String gap({required Object value}) => '${value} gap'; String gap({required Object value}) => '${value} gap';
String trGap({required Object value}) => '${value} TR gap';
String get deflationGap => 'Deflation gap'; String get deflationGap => 'Deflation gap';
String get inflationGap => 'Inflation gap'; String get inflationGap => 'Inflation gap';
String get LBposRange => 'LB pos range'; String get LBposRange => 'LB pos range';
@ -701,6 +753,16 @@ class _StringsRankViewEn {
String get maximums => 'Maximums'; String get maximums => 'Maximums';
} }
// Path: stateView
class _StringsStateViewEn {
_StringsStateViewEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String title({required Object date}) => 'State from ${date}';
}
// Path: tlMatchView // Path: tlMatchView
class _StringsTlMatchViewEn { class _StringsTlMatchViewEn {
_StringsTlMatchViewEn._(this._root); _StringsTlMatchViewEn._(this._root);
@ -782,6 +844,19 @@ class _StringsLeaderboardsDestinationEn {
String get fullTLnote => 'Heavy, but allows you to sort players by their stats and filter them by ranks'; String get fullTLnote => 'Heavy, but allows you to sort players by their stats and filter them by ranks';
} }
// Path: savedDataDestination
class _StringsSavedDataDestinationEn {
_StringsSavedDataDestinationEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get title => 'Saved Data';
String get tip => 'Select nickname on the left to see data assosiated with it';
String seasonTLstates({required Object s}) => 'S${s} TL States';
String get TLrecords => 'TL Records';
}
// Path: settingsDestination // Path: settingsDestination
class _StringsSettingsDestinationEn { class _StringsSettingsDestinationEn {
_StringsSettingsDestinationEn._(this._root); _StringsSettingsDestinationEn._(this._root);
@ -790,11 +865,49 @@ class _StringsSettingsDestinationEn {
// Translations // Translations
String get title => 'Settings'; String get title => 'Settings';
String get timestamps => 'Timestamps'; String get general => 'General';
String get timestampsDescription => 'You can choose, in which way timestamps shows time'; String get customization => 'Custonization';
String get database => 'Local database';
String get checking => 'Checking...';
String get enterToSubmit => 'Press Enter to submit';
String get account => 'Your account in TETR.IO';
String get accountDescription => 'Stats of that player will be loaded initially right after launching this app. By default it loads my (dan63) stats. To change that, enter your nickname here.';
String get done => 'Done!';
String get noSuchAccount => 'No such account';
String get language => 'Language';
String languageDescription({required Object languages}) => 'Tetra Stats was translated on ${languages}. By default, app will pick your system one or English, if locale of your system isn\'t avaliable.';
String languages({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: 'zero languages',
one: '${n} language',
two: '${n} languages',
few: '${n} languages',
many: '${n} languages',
other: '${n} languages',
);
String get updateInTheBackground => 'Update data in the background';
String get updateInTheBackgroundDescription => 'If on, Tetra Stats will attempt to retrieve new info once cache expires. Usually that happen every 5 minutes';
String get compareStats => 'Compare TL stats with rank averages';
String get compareStatsDescription => 'If on, Tetra Stats will provide additional metrics, which allow you to compare yourself with average player on your rank. The way you\'ll see it — stats will be highlited with corresponding color, hover over them with cursor for more info.';
String get showPosition => 'Show position on leaderboard by stats';
String get showPositionDescription => 'This can take some time (and traffic) to load, but will allow you to see your position on the leaderboard, sorted by a stat';
String get accentColor => 'Accent color';
String get accentColorDescription => 'That color is seen across this app and usually highlites interactive UI elements.';
String get accentColorModale => 'Pick an accent color';
String get timestamps => 'Timestamps format';
String timestampsDescriptionPart1({required Object d}) => 'You can choose, in which way timestamps shows time. By default, they show time in GMT timezone, formatted according to chosen locale, example: ${d}.';
String timestampsDescriptionPart2({required Object y, required Object r}) => 'There is also:\n• Locale formatted in your timezone: ${y}\n• Relative timestamp: ${r}';
String get timestampsAbsoluteGMT => 'Absolute (GMT)'; String get timestampsAbsoluteGMT => 'Absolute (GMT)';
String get timestampsAbsoluteLocalTime => 'Absolute (Your timezone)'; String get timestampsAbsoluteLocalTime => 'Absolute (Your timezone)';
String get timestampsRelative => 'Relative'; String get timestampsRelative => 'Relative';
String get sheetbotLikeGraphs => 'Sheetbot-like behavior for radar graphs';
String get sheetbotLikeGraphsDescription => 'Altough it was considered by me, that the way graphs work in SheetBot is not very correct, some people were confused to see, that -0.5 stride dosen\'t look the way it looks on SheetBot graph. Hence, he we are: if this toggle is on, points on the graphs can appear on the opposite half of the graph if value is negative.';
String get oskKagariGimmick => 'Osk-Kagari gimmick';
String get oskKagariGimmickDescription => 'If on, instead of osk\'s rank, :kagari: will be rendered.';
String get bytesOfDataStored => 'of data stored';
String get TLrecordsSaved => 'Tetra League records saved';
String get TLplayerstatesSaved => 'Tetra League playerstates saved';
String get fixButton => 'Fix';
String get compressButton => 'Compress';
String get exportDB => 'Export local database'; String get exportDB => 'Export local database';
String get desktopExportAlertTitle => 'Desktop export'; String get desktopExportAlertTitle => 'Desktop export';
String get desktopExportText => 'It seems like you using this app on desktop. Check your documents folder, you should find "TetraStats.db". Copy it somewhere'; String get desktopExportText => 'It seems like you using this app on desktop. Check your documents folder, you should find "TetraStats.db". Copy it somewhere';
@ -845,6 +958,19 @@ class _StringsCalcNavigationEn {
String get damage => 'Damage Calculator'; String get damage => 'Damage Calculator';
} }
// Path: firstTimeView
class _StringsFirstTimeViewEn {
_StringsFirstTimeViewEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get welcome => 'Welcome to Tetra Stats';
String get description => 'Service, that allows you to keep track of various statistics for TETR.IO';
String get nicknameQuestion => 'What\'s your nickname?';
String get inpuntHint => 'Type it here... (3-16 symbols)';
}
// Path: aboutView // Path: aboutView
class _StringsAboutViewEn { class _StringsAboutViewEn {
_StringsAboutViewEn._(this._root); _StringsAboutViewEn._(this._root);
@ -926,6 +1052,7 @@ class _StringsStatsEn {
String get piecesWithPerfectFinesse => 'Placed with perfect finesse'; String get piecesWithPerfectFinesse => 'Placed with perfect finesse';
String get score => 'Score'; String get score => 'Score';
String get lines => 'Lines'; String get lines => 'Lines';
String get linesShort => 'L';
String get pcs => 'Perfect Clears'; String get pcs => 'Perfect Clears';
String get holds => 'Holds'; String get holds => 'Holds';
String get spike => 'Top Spike'; String get spike => 'Top Spike';
@ -937,6 +1064,7 @@ class _StringsStatsEn {
String get sent => 'Sent'; String get sent => 'Sent';
String get received => 'Received'; String get received => 'Received';
String get placement => 'Placement'; String get placement => 'Placement';
String get peak => 'peak';
String qpWithMods({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, String qpWithMods({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
one: 'With 1 mod', one: 'With 1 mod',
two: 'With ${n} mods', two: 'With ${n} mods',
@ -1571,12 +1699,27 @@ extension on Translations {
case 'obtainDate': return ({required Object date}) => 'Obtained ${date}'; case 'obtainDate': return ({required Object date}) => 'Obtained ${date}';
case 'assignedManualy': return 'That badge was assigned manualy by TETR.IO admins'; case 'assignedManualy': return 'That badge was assigned manualy by TETR.IO admins';
case 'distinguishment': return 'Distinguishment'; case 'distinguishment': return 'Distinguishment';
case 'bigRedBanned': return 'BANNED'; case 'banned': return 'Banned';
case 'normalBanned': return 'Banned'; case 'bannedSubtext': return 'Bans are placed when TETR.IO rules or terms of service are broken';
case 'bigRedBadStanding': return 'BAD STANDING'; case 'badStanding': return 'Bad standing';
case 'badStandingSubtext': return 'One or more recent bans on record';
case 'botAccount': return 'Bot account';
case 'botAccountSubtext': return ({required Object botMaintainers}) => 'Operated by ${botMaintainers}';
case 'copiedToClipboard': return 'Copied to clipboard!'; case 'copiedToClipboard': return 'Copied to clipboard!';
case 'bio': return 'Bio'; case 'bio': return 'Bio';
case 'news': return 'News'; case 'news': return 'News';
case 'matchResult.victory': return 'Victory';
case 'matchResult.defeat': return 'Defeat';
case 'matchResult.tie': return 'Tie';
case 'matchResult.dqvictory': return 'Opponent was DQ\'ed';
case 'matchResult.dqdefeat': return 'Disqualified';
case 'matchResult.nocontest': return 'No Contest';
case 'matchResult.nullified': return 'Nullified';
case 'distinguishments.noHeader': return 'Header is missing';
case 'distinguishments.noFooter': return 'Footer is missing';
case 'distinguishments.twc': return 'TETR.IO World Champion';
case 'distinguishments.twcYear': return ({required Object year}) => '${year} TETR.IO World Championship';
case 'newsEntrys.leaderboard': return ({required Object rank, required Object gametype}) => 'Got № ${rank} on ${gametype}';
case 'newsParts.leaderboardStart': return 'Got '; case 'newsParts.leaderboardStart': return 'Got ';
case 'newsParts.leaderboardMiddle': return 'on '; case 'newsParts.leaderboardMiddle': return 'on ';
case 'newsParts.personalbest': return 'Got a new PB in '; case 'newsParts.personalbest': return 'Got a new PB in ';
@ -1592,6 +1735,9 @@ extension on Translations {
case 'newsParts.unknownNews': return ({required Object type}) => 'Unknown news of type ${type}'; case 'newsParts.unknownNews': return ({required Object type}) => 'Unknown news of type ${type}';
case 'copyUserID': return 'Click to copy user ID'; case 'copyUserID': return 'Click to copy user ID';
case 'searchHint': return 'Username or ID'; case 'searchHint': return 'Username or ID';
case 'navMenu': return 'Navigation menu';
case 'navMenuTooltip': return 'Open navigation menu';
case 'refresh': return 'Refresh data';
case 'searchButton': return 'Search'; case 'searchButton': return 'Search';
case 'trackedPlayers': return 'Tracked Players'; case 'trackedPlayers': return 'Tracked Players';
case 'standing': return 'Standing'; case 'standing': return 'Standing';
@ -1670,6 +1816,7 @@ extension on Translations {
case 'rankView.trRange': return 'TR Range'; case 'rankView.trRange': return 'TR Range';
case 'rankView.supposedToBe': return 'Supposed to be'; case 'rankView.supposedToBe': return 'Supposed to be';
case 'rankView.gap': return ({required Object value}) => '${value} gap'; case 'rankView.gap': return ({required Object value}) => '${value} gap';
case 'rankView.trGap': return ({required Object value}) => '${value} TR gap';
case 'rankView.deflationGap': return 'Deflation gap'; case 'rankView.deflationGap': return 'Deflation gap';
case 'rankView.inflationGap': return 'Inflation gap'; case 'rankView.inflationGap': return 'Inflation gap';
case 'rankView.LBposRange': return 'LB pos range'; case 'rankView.LBposRange': return 'LB pos range';
@ -1680,6 +1827,7 @@ extension on Translations {
case 'rankView.avgNerdStats': return 'Average Nerd Stats'; case 'rankView.avgNerdStats': return 'Average Nerd Stats';
case 'rankView.minimums': return 'Minimums'; case 'rankView.minimums': return 'Minimums';
case 'rankView.maximums': return 'Maximums'; case 'rankView.maximums': return 'Maximums';
case 'stateView.title': return ({required Object date}) => 'State from ${date}';
case 'tlMatchView.match': return 'Match'; case 'tlMatchView.match': return 'Match';
case 'tlMatchView.vs': return 'vs'; case 'tlMatchView.vs': return 'vs';
case 'tlMatchView.winner': return 'Winner'; case 'tlMatchView.winner': return 'Winner';
@ -1725,12 +1873,54 @@ extension on Translations {
case 'leaderboardsDestination.fullTL': return 'Tetra League (Current Season, full one)'; case 'leaderboardsDestination.fullTL': return 'Tetra League (Current Season, full one)';
case 'leaderboardsDestination.ar': return 'Acievement Points'; case 'leaderboardsDestination.ar': return 'Acievement Points';
case 'leaderboardsDestination.fullTLnote': return 'Heavy, but allows you to sort players by their stats and filter them by ranks'; case 'leaderboardsDestination.fullTLnote': return 'Heavy, but allows you to sort players by their stats and filter them by ranks';
case 'savedDataDestination.title': return 'Saved Data';
case 'savedDataDestination.tip': return 'Select nickname on the left to see data assosiated with it';
case 'savedDataDestination.seasonTLstates': return ({required Object s}) => 'S${s} TL States';
case 'savedDataDestination.TLrecords': return 'TL Records';
case 'settingsDestination.title': return 'Settings'; case 'settingsDestination.title': return 'Settings';
case 'settingsDestination.timestamps': return 'Timestamps'; case 'settingsDestination.general': return 'General';
case 'settingsDestination.timestampsDescription': return 'You can choose, in which way timestamps shows time'; case 'settingsDestination.customization': return 'Custonization';
case 'settingsDestination.database': return 'Local database';
case 'settingsDestination.checking': return 'Checking...';
case 'settingsDestination.enterToSubmit': return 'Press Enter to submit';
case 'settingsDestination.account': return 'Your account in TETR.IO';
case 'settingsDestination.accountDescription': return 'Stats of that player will be loaded initially right after launching this app. By default it loads my (dan63) stats. To change that, enter your nickname here.';
case 'settingsDestination.done': return 'Done!';
case 'settingsDestination.noSuchAccount': return 'No such account';
case 'settingsDestination.language': return 'Language';
case 'settingsDestination.languageDescription': return ({required Object languages}) => 'Tetra Stats was translated on ${languages}. By default, app will pick your system one or English, if locale of your system isn\'t avaliable.';
case 'settingsDestination.languages': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
zero: 'zero languages',
one: '${n} language',
two: '${n} languages',
few: '${n} languages',
many: '${n} languages',
other: '${n} languages',
);
case 'settingsDestination.updateInTheBackground': return 'Update data in the background';
case 'settingsDestination.updateInTheBackgroundDescription': return 'If on, Tetra Stats will attempt to retrieve new info once cache expires. Usually that happen every 5 minutes';
case 'settingsDestination.compareStats': return 'Compare TL stats with rank averages';
case 'settingsDestination.compareStatsDescription': return 'If on, Tetra Stats will provide additional metrics, which allow you to compare yourself with average player on your rank. The way you\'ll see it — stats will be highlited with corresponding color, hover over them with cursor for more info.';
case 'settingsDestination.showPosition': return 'Show position on leaderboard by stats';
case 'settingsDestination.showPositionDescription': return 'This can take some time (and traffic) to load, but will allow you to see your position on the leaderboard, sorted by a stat';
case 'settingsDestination.accentColor': return 'Accent color';
case 'settingsDestination.accentColorDescription': return 'That color is seen across this app and usually highlites interactive UI elements.';
case 'settingsDestination.accentColorModale': return 'Pick an accent color';
case 'settingsDestination.timestamps': return 'Timestamps format';
case 'settingsDestination.timestampsDescriptionPart1': return ({required Object d}) => 'You can choose, in which way timestamps shows time. By default, they show time in GMT timezone, formatted according to chosen locale, example: ${d}.';
case 'settingsDestination.timestampsDescriptionPart2': return ({required Object y, required Object r}) => 'There is also:\n• Locale formatted in your timezone: ${y}\n• Relative timestamp: ${r}';
case 'settingsDestination.timestampsAbsoluteGMT': return 'Absolute (GMT)'; case 'settingsDestination.timestampsAbsoluteGMT': return 'Absolute (GMT)';
case 'settingsDestination.timestampsAbsoluteLocalTime': return 'Absolute (Your timezone)'; case 'settingsDestination.timestampsAbsoluteLocalTime': return 'Absolute (Your timezone)';
case 'settingsDestination.timestampsRelative': return 'Relative'; case 'settingsDestination.timestampsRelative': return 'Relative';
case 'settingsDestination.sheetbotLikeGraphs': return 'Sheetbot-like behavior for radar graphs';
case 'settingsDestination.sheetbotLikeGraphsDescription': return 'Altough it was considered by me, that the way graphs work in SheetBot is not very correct, some people were confused to see, that -0.5 stride dosen\'t look the way it looks on SheetBot graph. Hence, he we are: if this toggle is on, points on the graphs can appear on the opposite half of the graph if value is negative.';
case 'settingsDestination.oskKagariGimmick': return 'Osk-Kagari gimmick';
case 'settingsDestination.oskKagariGimmickDescription': return 'If on, instead of osk\'s rank, :kagari: will be rendered.';
case 'settingsDestination.bytesOfDataStored': return 'of data stored';
case 'settingsDestination.TLrecordsSaved': return 'Tetra League records saved';
case 'settingsDestination.TLplayerstatesSaved': return 'Tetra League playerstates saved';
case 'settingsDestination.fixButton': return 'Fix';
case 'settingsDestination.compressButton': return 'Compress';
case 'settingsDestination.exportDB': return 'Export local database'; case 'settingsDestination.exportDB': return 'Export local database';
case 'settingsDestination.desktopExportAlertTitle': return 'Desktop export'; case 'settingsDestination.desktopExportAlertTitle': return 'Desktop export';
case 'settingsDestination.desktopExportText': return 'It seems like you using this app on desktop. Check your documents folder, you should find "TetraStats.db". Copy it somewhere'; case 'settingsDestination.desktopExportText': return 'It seems like you using this app on desktop. Check your documents folder, you should find "TetraStats.db". Copy it somewhere';
@ -1752,6 +1942,10 @@ extension on Translations {
case 'graphsNavigation.cutoffs': return 'Cutoffs History'; case 'graphsNavigation.cutoffs': return 'Cutoffs History';
case 'calcNavigation.stats': return 'Stats Calculator'; case 'calcNavigation.stats': return 'Stats Calculator';
case 'calcNavigation.damage': return 'Damage Calculator'; case 'calcNavigation.damage': return 'Damage Calculator';
case 'firstTimeView.welcome': return 'Welcome to Tetra Stats';
case 'firstTimeView.description': return 'Service, that allows you to keep track of various statistics for TETR.IO';
case 'firstTimeView.nicknameQuestion': return 'What\'s your nickname?';
case 'firstTimeView.inpuntHint': return 'Type it here... (3-16 symbols)';
case 'aboutView.title': return 'About Tetra Stats'; case 'aboutView.title': return 'About Tetra Stats';
case 'aboutView.about': return 'Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with "Track" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity.'; case 'aboutView.about': return 'Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with "Track" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity.';
case 'aboutView.appVersion': return 'App Version'; case 'aboutView.appVersion': return 'App Version';
@ -1862,6 +2056,7 @@ extension on Translations {
case 'stats.piecesWithPerfectFinesse': return 'Placed with perfect finesse'; case 'stats.piecesWithPerfectFinesse': return 'Placed with perfect finesse';
case 'stats.score': return 'Score'; case 'stats.score': return 'Score';
case 'stats.lines': return 'Lines'; case 'stats.lines': return 'Lines';
case 'stats.linesShort': return 'L';
case 'stats.pcs': return 'Perfect Clears'; case 'stats.pcs': return 'Perfect Clears';
case 'stats.holds': return 'Holds'; case 'stats.holds': return 'Holds';
case 'stats.spike': return 'Top Spike'; case 'stats.spike': return 'Top Spike';
@ -1873,6 +2068,7 @@ extension on Translations {
case 'stats.sent': return 'Sent'; case 'stats.sent': return 'Sent';
case 'stats.received': return 'Received'; case 'stats.received': return 'Received';
case 'stats.placement': return 'Placement'; case 'stats.placement': return 'Placement';
case 'stats.peak': return 'peak';
case 'stats.qpWithMods': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n, case 'stats.qpWithMods': return ({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
one: 'With 1 mod', one: 'With 1 mod',
two: 'With ${n} mods', two: 'With ${n} mods',

View File

@ -1277,25 +1277,25 @@ class _DestinationHomeState extends State<DestinationHome> with SingleTickerProv
SegmentedButton<Cards>( SegmentedButton<Cards>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<Cards>>[ segments: <ButtonSegment<Cards>>[
const ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.overview, value: Cards.overview,
//label: Text('Overview'), tooltip: t.homeNavigation.overview,
icon: Icon(Icons.calendar_view_day)), icon: Icon(Icons.calendar_view_day)),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.tetraLeague, value: Cards.tetraLeague,
//label: Text('Tetra League'), tooltip: t.gamemodes["league"],
icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.quickPlay, value: Cards.quickPlay,
//label: Text('Quick Play'), tooltip: t.gamemodes["zenith"],
icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.sprint, value: Cards.sprint,
//label: Text('40 Lines'), tooltip: t.gamemodes["40l"],
icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.blitz, value: Cards.blitz,
//label: Text('Blitz'), tooltip: t.gamemodes["blitz"],
icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
], ],
selected: <Cards>{rightCard}, selected: <Cards>{rightCard},

View File

@ -31,11 +31,11 @@ class _DestinationSavedData extends State<DestinationSavedData> {
Widget getTetraLeagueListTile(TetraLeague data){ Widget getTetraLeagueListTile(TetraLeague data){
return ListTile( return ListTile(
title: Text("${timestamp(data.timestamp)}"), title: Text("${timestamp(data.timestamp)}"),
subtitle: Text("${data.apm != null ? f2.format(data.apm) : "-.--"} APM, ${data.pps != null ? f2.format(data.pps) : "-.--"} PPS, ${data.vs != null ? f2.format(data.vs) : "-.--"} VS, ${intf.format(data.gamesPlayed)} games", style: TextStyle(color: Colors.grey)), subtitle: Text("${data.apm != null ? f2.format(data.apm) : "-.--"} ${t.stats.apm.short}, ${data.pps != null ? f2.format(data.pps) : "-.--"} ${t.stats.pps.short}, ${data.vs != null ? f2.format(data.vs) : "-.--"} ${t.stats.vs.short}, ${intf.format(data.gamesPlayed)} ${t.stats.gp.short}", style: TextStyle(color: Colors.grey)),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text("${data.tr != -1.00 ? f2.format(data.tr) : "-.--"} TR", style: TextStyle(fontSize: 28)), Text("${data.tr != -1.00 ? f2.format(data.tr) : "-.--"} ${t.stats.tr.short}", style: TextStyle(fontSize: 28)),
Image.asset("res/tetrio_tl_alpha_ranks/${data.rank}.png", height: 36) Image.asset("res/tetrio_tl_alpha_ranks/${data.rank}.png", height: 36)
], ],
), ),
@ -82,9 +82,9 @@ class _DestinationSavedData extends State<DestinationSavedData> {
labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28), labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28),
labelColor: Theme.of(context).colorScheme.primary, labelColor: Theme.of(context).colorScheme.primary,
tabs: [ tabs: [
Tab(text: "S${currentSeason} TL States"), Tab(text: t.savedDataDestination.seasonTLstates(s: currentSeason)),
Tab(text: "S1 TL States"), Tab(text: t.savedDataDestination.seasonTLstates(s: 1)),
Tab(text: "TL Records") Tab(text: t.savedDataDestination.TLrecords)
]), ]),
), ),
SizedBox( SizedBox(
@ -117,7 +117,7 @@ class _DestinationSavedData extends State<DestinationSavedData> {
} }
} }
) : ) :
InfoThingy("Select nickname on the left to see data assosiated with it") InfoThingy(t.savedDataDestination.tip)
); );
} }
@ -145,7 +145,7 @@ class _DestinationSavedData extends State<DestinationSavedData> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Spacer(), Spacer(),
Text("Saved Data", style: Theme.of(context).textTheme.headlineMedium), Text(t.savedDataDestination.title, style: Theme.of(context).textTheme.headlineMedium),
Spacer() Spacer()
], ],
), ),

View File

@ -25,21 +25,22 @@ class DestinationSettings extends StatefulWidget{
} }
enum SettingsCardMod{ enum SettingsCardMod{
general("General"), general,
customization("Custonization"), customization,
database("Local database"); database
const SettingsCardMod(this.title);
final String title;
} }
Map<SettingsCardMod, String> settingsCardTitles = {
SettingsCardMod.general: t.settingsDestination.general,
SettingsCardMod.customization: t.settingsDestination.customization,
SettingsCardMod.database: t.settingsDestination.database
};
const EdgeInsets descriptionPadding = EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 8.0); const EdgeInsets descriptionPadding = EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 8.0);
class _DestinationSettings extends State<DestinationSettings> with SingleTickerProviderStateMixin { class _DestinationSettings extends State<DestinationSettings> with SingleTickerProviderStateMixin {
SettingsCardMod mod = SettingsCardMod.general; SettingsCardMod mod = SettingsCardMod.general;
List<DropdownMenuItem<AppLocale>> locales = <DropdownMenuItem<AppLocale>>[]; List<DropdownMenuItem<AppLocale>> locales = <DropdownMenuItem<AppLocale>>[];
String defaultNickname = "Checking..."; String defaultNickname = t.settingsDestination.checking;
String defaultID = ""; String defaultID = "";
Color pickerColor = Colors.cyanAccent; Color pickerColor = Colors.cyanAccent;
Color currentColor = Colors.cyanAccent; Color currentColor = Colors.cyanAccent;
@ -55,7 +56,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
late Animation _badDefaultNicknameAnim; late Animation _badDefaultNicknameAnim;
late Animation _defaultNicknameAnim = _goodDefaultNicknameAnim; late Animation _defaultNicknameAnim = _goodDefaultNicknameAnim;
double helperTextOpacity = 0; double helperTextOpacity = 0;
String helperText = "Press Enter to submit"; String helperText = t.settingsDestination.enterToSubmit;
@override @override
void initState() { void initState() {
@ -76,7 +77,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
curve: Easing.emphasizedAccelerate, curve: Easing.emphasizedAccelerate,
//reverseCurve: Cubic(0,.99,.99,1.01) //reverseCurve: Cubic(0,.99,.99,1.01)
))..addStatusListener((status) { ))..addStatusListener((status) {
if (status.index == 3) setState((){helperText = "Press Enter to submit"; helperTextOpacity = 0;}); if (status.index == 3) setState((){helperText = t.settingsDestination.enterToSubmit; helperTextOpacity = 0;});
}); });
_badDefaultNicknameAnim = new ColorTween( _badDefaultNicknameAnim = new ColorTween(
begin: Colors.redAccent, begin: Colors.redAccent,
@ -86,7 +87,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
curve: Easing.emphasizedAccelerate, curve: Easing.emphasizedAccelerate,
//reverseCurve: Cubic(0,.99,.99,1.01) //reverseCurve: Cubic(0,.99,.99,1.01)
))..addStatusListener((status) { ))..addStatusListener((status) {
if (status.index == 3) setState((){helperText = "Press Enter to submit"; helperTextOpacity = 0;}); if (status.index == 3) setState((){helperText = t.settingsDestination.enterToSubmit; helperTextOpacity = 0;});
}); });
_getPreferences(); _getPreferences();
super.initState(); super.initState();
@ -147,7 +148,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Column( child: Column(
children: [ children: [
Text(SettingsCardMod.general.title, style: Theme.of(context).textTheme.titleLarge), Text(t.settingsDestination.general, style: Theme.of(context).textTheme.titleLarge),
], ],
), ),
)), )),
@ -157,13 +158,13 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Your account in TETR.IO", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.account, style: Theme.of(context).textTheme.displayLarge),
trailing: SizedBox(width: 150.0, child: AnimatedBuilder( trailing: SizedBox(width: 150.0, child: AnimatedBuilder(
animation: _defaultNicknameAnim, animation: _defaultNicknameAnim,
builder: (context, child) { builder: (context, child) {
return Focus( return Focus(
onFocusChange: (value) { onFocusChange: (value) {
setState((){helperTextOpacity = ((value || helperText != "Press Enter to submit")) ? 1 : 0;}); setState((){helperTextOpacity = ((value || helperText != t.settingsDestination.enterToSubmit)) ? 1 : 0;});
}, },
child: TextField( child: TextField(
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -177,11 +178,11 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
), ),
), ),
onSubmitted: (value) { onSubmitted: (value) {
helperText = "Checking..."; helperText = t.settingsDestination.checking;
_setDefaultNickname(value).then((v) { _setDefaultNickname(value).then((v) {
_defaultNicknameAnim = v ? _goodDefaultNicknameAnim : _badDefaultNicknameAnim; _defaultNicknameAnim = v ? _goodDefaultNicknameAnim : _badDefaultNicknameAnim;
_defaultNicknameAnimController.forward(from: 0); _defaultNicknameAnimController.forward(from: 0);
setState((){ helperText = v ? "Done!" : "Fuck";}); setState((){ helperText = v ? t.settingsDestination.done : t.settingsDestination.noSuchAccount;});
}); });
}, },
), ),
@ -192,7 +193,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("Stats of that player will be loaded initially right after launching this app. By default it loads my (dan63) stats. To change that, enter your nickname here."), child: Text(t.settingsDestination.accountDescription),
) )
], ],
), ),
@ -219,7 +220,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("Tetra Stats was translated on ${locales.length} languages. By default, app will pick your system one or English, if locale of your system isn't avaliable."), child: Text(t.settingsDestination.languageDescription(languages: t.settingsDestination.languages(n: locales.length))),
) )
], ],
), ),
@ -229,7 +230,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Update data in the background", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.updateInTheBackground, style: Theme.of(context).textTheme.displayLarge),
trailing: Switch(value: updateInBG, onChanged: (bool value){ trailing: Switch(value: updateInBG, onChanged: (bool value){
prefs.setBool("updateInBG", value); prefs.setBool("updateInBG", value);
setState(() { setState(() {
@ -240,7 +241,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("If on, Tetra Stats will attempt to retrieve new info once cache expires. Usually that happen every 5 minutes"), child: Text(t.settingsDestination.updateInTheBackgroundDescription),
) )
], ],
), ),
@ -250,7 +251,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Compare TL stats with rank averages", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.compareStats, style: Theme.of(context).textTheme.displayLarge),
trailing: Switch(value: showAverages, onChanged: (bool value){ trailing: Switch(value: showAverages, onChanged: (bool value){
prefs.setBool("showAverages", value); prefs.setBool("showAverages", value);
setState(() { setState(() {
@ -261,7 +262,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("If on, Tetra Stats will provide additional metrics, which allow you to compare yourself with average player on your rank. The way you'll see it — stats will be highlited with corresponding color, hover over them with cursor for more info."), child: Text(t.settingsDestination.compareStatsDescription),
) )
], ],
), ),
@ -272,7 +273,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Show position on leaderboard by stats", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.showPosition, style: Theme.of(context).textTheme.displayLarge),
trailing: Switch(value: showPositions, onChanged: (bool value){ trailing: Switch(value: showPositions, onChanged: (bool value){
prefs.setBool("showPositions", value); prefs.setBool("showPositions", value);
setState(() { setState(() {
@ -283,7 +284,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("This can take some time (and traffic) to load, but will allow you to see your position on the leaderboard, sorted by a stat"), child: Text(t.settingsDestination.showPositionDescription),
) )
], ],
), ),
@ -300,7 +301,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Column( child: Column(
children: [ children: [
Text(SettingsCardMod.customization.title, style: Theme.of(context).textTheme.titleLarge), Text(t.settingsDestination.customization, style: Theme.of(context).textTheme.titleLarge),
], ],
), ),
)), )),
@ -310,13 +311,13 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Accent color", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.accentColor, style: Theme.of(context).textTheme.displayLarge),
trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary), width: 25, height: 25), trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary), width: 25, height: 25),
onTap: () { onTap: () {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: const Text('Pick an accent color'), title: Text(t.settingsDestination.accentColorModale),
content: SingleChildScrollView( content: SingleChildScrollView(
child: ColorPicker( child: ColorPicker(
pickerColor: pickerColor, pickerColor: pickerColor,
@ -325,7 +326,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
), ),
actions: <Widget>[ actions: <Widget>[
ElevatedButton( ElevatedButton(
child: const Text('Set'), child: Text(t.actions.apply),
onPressed: () { onPressed: () {
setState(() { setState(() {
context.findAncestorStateOfType<MyAppState>()?.setAccentColor(pickerColor); context.findAncestorStateOfType<MyAppState>()?.setAccentColor(pickerColor);
@ -340,7 +341,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("That color is seen across this app and usually highlites interactive UI elements."), child: Text(t.settingsDestination.accentColorDescription),
) )
], ],
), ),
@ -351,7 +352,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ListTile( ListTile(
title: Text("Timestamps format", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.timestamps, style: Theme.of(context).textTheme.displayLarge),
trailing: DropdownButton( trailing: DropdownButton(
value: timestampMode, value: timestampMode,
items: <DropdownMenuItem>[ items: <DropdownMenuItem>[
@ -370,11 +371,11 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("You can choose, in which way timestamps shows time. By default, they show time in GMT timezone, formatted according to chosen locale, example: ${DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms().format(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19))}."), child: Text(t.settingsDestination.timestampsDescriptionPart1(d: DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms().format(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19)))),
), ),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("There is also:\n• Locale formatted in your timezone: ${DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms().format(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19).toLocal())}\n• Relative timestamp: ${relativeDateTime(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19))}"), child: Text(t.settingsDestination.timestampsDescriptionPart2(y: DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode).add_Hms().format(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19).toLocal()), r: relativeDateTime(DateTime.utc(2023, DateTime.july, 20, 21, 03, 19)))),
) )
], ],
), ),
@ -384,7 +385,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Sheetbot-like behavior for radar graphs", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.sheetbotLikeGraphs, style: Theme.of(context).textTheme.displayLarge),
trailing: Switch(value: sheetbotRadarGraphs, onChanged: (bool value){ trailing: Switch(value: sheetbotRadarGraphs, onChanged: (bool value){
prefs.setBool("sheetbotRadarGraphs", value); prefs.setBool("sheetbotRadarGraphs", value);
setState(() { setState(() {
@ -395,7 +396,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("Altough it was considered by me, that the way graphs work in SheetBot is not very correct, some people were confused to see, that -0.5 stride dosen't look the way it looks on SheetBot graph. Hence, he we are: if this toggle is on, points on the graphs can appear on the opposite half of the graph if value is negative."), child: Text(t.settingsDestination.sheetbotLikeGraphsDescription),
) )
], ],
), ),
@ -405,7 +406,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text("Osk-Kagari gimmick", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.oskKagariGimmick, style: Theme.of(context).textTheme.displayLarge),
trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){ trailing: Switch(value: oskKagariGimmick, onChanged: (bool value){
prefs.setBool("oskKagariGimmick", value); prefs.setBool("oskKagariGimmick", value);
setState(() { setState(() {
@ -416,7 +417,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Divider(), Divider(),
Padding( Padding(
padding: descriptionPadding, padding: descriptionPadding,
child: Text("If on, instead of osk's rank, :kagari: will be rendered."), child: Text(t.settingsDestination.oskKagariGimmickDescription),
) )
], ],
), ),
@ -431,7 +432,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
Card( Card(
child: Center(child: Column( child: Center(child: Column(
children: [ children: [
Text(SettingsCardMod.database.title, style: Theme.of(context).textTheme.titleLarge), Text(t.settingsDestination.database, style: Theme.of(context).textTheme.titleLarge),
Divider(), Divider(),
FutureBuilder<(int, int, int)>(future: teto.getDatabaseData(), FutureBuilder<(int, int, int)>(future: teto.getDatabaseData(),
builder: (context, snapshot) { builder: (context, snapshot) {
@ -447,11 +448,11 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
style: TextStyle(fontFamily: "Eurostile Round", color: Colors.white), style: TextStyle(fontFamily: "Eurostile Round", color: Colors.white),
children: [ children: [
TextSpan(text: "${bytesToSize(snapshot.data!.$1)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)), TextSpan(text: "${bytesToSize(snapshot.data!.$1)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
TextSpan(text: "of data stored\n"), TextSpan(text: "${t.settingsDestination.bytesOfDataStored}\n"),
TextSpan(text: "${intf.format(snapshot.data!.$2)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)), TextSpan(text: "${intf.format(snapshot.data!.$2)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
TextSpan(text: "Tetra League records saved\n"), TextSpan(text: "${t.settingsDestination.TLrecordsSaved}\n"),
TextSpan(text: "${intf.format(snapshot.data!.$3)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)), TextSpan(text: "${intf.format(snapshot.data!.$3)} ", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)),
TextSpan(text: "Tetra League playerstates saved"), TextSpan(text: t.settingsDestination.TLplayerstatesSaved),
] ]
) )
); );
@ -469,7 +470,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: (){teto.removeDuplicatesFromTLMatches().then((_) => setState((){}));}, onPressed: (){teto.removeDuplicatesFromTLMatches().then((_) => setState((){}));},
icon: const Icon(Icons.build), icon: const Icon(Icons.build),
label: Text("Fix"), label: Text(t.settingsDestination.fixButton),
style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.only(bottomLeft: Radius.circular(12.0))))) style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.only(bottomLeft: Radius.circular(12.0)))))
) )
), ),
@ -477,7 +478,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: (){teto.compressDB().then((_) => setState((){}));}, onPressed: (){teto.compressDB().then((_) => setState((){}));},
icon: const Icon(Icons.compress), icon: const Icon(Icons.compress),
label: Text("Compress"), label: Text(t.settingsDestination.compressButton),
style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.only(bottomRight: Radius.circular(12.0))))) style: const ButtonStyle(shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.only(bottomRight: Radius.circular(12.0)))))
) )
) )
@ -488,7 +489,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
), ),
Card( Card(
child: ListTile( child: ListTile(
title: Text("Export Database", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.exportDB, style: Theme.of(context).textTheme.displayLarge),
onTap: () { onTap: () {
if (kIsWeb){ if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb)));
@ -543,7 +544,7 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
), ),
Card( Card(
child: ListTile( child: ListTile(
title: Text("Import Database", style: Theme.of(context).textTheme.displayLarge), title: Text(t.settingsDestination.importDB, style: Theme.of(context).textTheme.displayLarge),
onTap: (){ onTap: (){
if (kIsWeb){ if (kIsWeb){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb))); ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t.snackBarMessages.notForWeb)));
@ -639,14 +640,14 @@ class _DestinationSettings extends State<DestinationSettings> with SingleTickerP
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Spacer(), Spacer(),
Text("Settings", style: Theme.of(context).textTheme.headlineMedium), Text(t.settingsDestination.title, style: Theme.of(context).textTheme.headlineMedium),
Spacer() Spacer()
], ],
), ),
), ),
for (SettingsCardMod m in SettingsCardMod.values) Card( for (SettingsCardMod m in SettingsCardMod.values) Card(
child: ListTile( child: ListTile(
title: Text(m.title), title: Text(settingsCardTitles[m]!),
trailing: Icon(Icons.arrow_right, color: mod == m ? Colors.white : Colors.grey), trailing: Icon(Icons.arrow_right, color: mod == m ? Colors.white : Colors.grey),
onTap: () { onTap: () {
setState(() { setState(() {

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/gen/strings.g.dart';
class FirstTimeView extends StatefulWidget { class FirstTimeView extends StatefulWidget {
/// The very first view, that user see when he launch this programm. /// The very first view, that user see when he launch this programm.
@ -44,8 +45,8 @@ class _FirstTimeState extends State<FirstTimeView> with SingleTickerProviderStat
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text("Welcome to Tetra Stats", style: Theme.of(context).textTheme.titleLarge), Text(t.firstTimeView.welcome, style: Theme.of(context).textTheme.titleLarge),
Text("Service, that allows you to keep track of various statistics for TETR.IO"), Text(t.firstTimeView.description),
Padding( Padding(
padding: const EdgeInsets.only(top: 24.0), padding: const EdgeInsets.only(top: 24.0),
child: Card( child: Card(
@ -54,13 +55,13 @@ class _FirstTimeState extends State<FirstTimeView> with SingleTickerProviderStat
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text("What's your nickname?", style: Theme.of(context).textTheme.titleSmall), Text(t.firstTimeView.nicknameQuestion, style: Theme.of(context).textTheme.titleSmall),
Padding( Padding(
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: SizedBox(width: 400.0, child: TextField( child: SizedBox(width: 400.0, child: TextField(
maxLength: 16, maxLength: 16,
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Type it here... (3-16 symbols)", hintText: t.firstTimeView.inpuntHint,
counter: const Offstage() counter: const Offstage()
), ),
)), )),

View File

@ -30,8 +30,8 @@ int destination = 0;
// TODO: Redesign some widgets, so they could look nice on mobile view // TODO: Redesign some widgets, so they could look nice on mobile view
// - stats below TL progress bar & similar parts in other widgets // - stats below TL progress bar & similar parts in other widgets
// - APP and VS/APM gadget // - APP and VS/APM gadget
// - Badges widget needs some kind of scroll arrows for desktop mode (How is this related to this todo???) // - different design for radar graphs
// - i should put tooltips everywhere
Future<FetchResults> getData(String searchFor) async { Future<FetchResults> getData(String searchFor) async {
TetrioPlayer player; TetrioPlayer player;
try{ try{
@ -53,7 +53,7 @@ Future<FetchResults> getData(String searchFor) async {
teto.fetchSummaries(player.userId), teto.fetchSummaries(player.userId),
teto.fetchNews(player.userId), teto.fetchNews(player.userId),
teto.fetchCutoffsBeanserver(), teto.fetchCutoffsBeanserver(),
if (prefs.getBool("showAverages") == true) teto.fetchCutoffsTetrio() if (prefs.getBool("showAverages") ?? true) teto.fetchCutoffsTetrio()
]); ]);
summaries = requests[0]; summaries = requests[0];
@ -185,25 +185,25 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
SegmentedButton<Cards>( SegmentedButton<Cards>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<Cards>>[ segments: <ButtonSegment<Cards>>[
const ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.overview, value: Cards.overview,
tooltip: 'Overview', tooltip: t.homeNavigation.overview,
icon: Icon(Icons.calendar_view_day)), icon: Icon(Icons.calendar_view_day)),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.tetraLeague, value: Cards.tetraLeague,
tooltip: 'Tetra League', tooltip: t.gamemodes["league"],
icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/league.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.quickPlay, value: Cards.quickPlay,
tooltip: 'Quick Play', tooltip: t.gamemodes["zenith"],
icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/qp.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.sprint, value: Cards.sprint,
tooltip: '40 Lines', tooltip: t.gamemodes["40l"],
icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/40l.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
ButtonSegment<Cards>( ButtonSegment<Cards>(
value: Cards.blitz, value: Cards.blitz,
tooltip: 'Blitz', tooltip: t.gamemodes["blitz"],
icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))), icon: SvgPicture.asset("res/icons/blitz.svg", height: 16, colorFilter: ColorFilter.mode(theme.colorScheme.primary, BlendMode.modulate))),
], ],
selected: <Cards>{rightCard}, selected: <Cards>{rightCard},
@ -217,15 +217,15 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
1 => SegmentedButton<Graph>( 1 => SegmentedButton<Graph>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<Graph>>[ segments: <ButtonSegment<Graph>>[
const ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.history, value: Graph.history,
label: Text('Player History')), label: Text(t.graphsNavigation.history)),
ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.leagueState, value: Graph.leagueState,
label: Text('League State')), label: Text(t.graphsNavigation.league)),
ButtonSegment<Graph>( ButtonSegment<Graph>(
value: Graph.leagueCutoffs, value: Graph.leagueCutoffs,
label: Text('League Cutoffs'), label: Text(t.graphsNavigation.cutoffs),
), ),
], ],
selected: <Graph>{graph}, selected: <Graph>{graph},
@ -243,13 +243,13 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
4 => SegmentedButton<CalcCards>( 4 => SegmentedButton<CalcCards>(
showSelectedIcon: false, showSelectedIcon: false,
segments: <ButtonSegment<CalcCards>>[ segments: <ButtonSegment<CalcCards>>[
const ButtonSegment<CalcCards>( ButtonSegment<CalcCards>(
value: CalcCards.calc, value: CalcCards.calc,
label: Text('Stats Calculator'), label: Text(t.calcNavigation.stats),
), ),
ButtonSegment<CalcCards>( ButtonSegment<CalcCards>(
value: CalcCards.damage, value: CalcCards.damage,
label: Text('Damage Calculator'), label: Text(t.calcNavigation.damage),
), ),
], ],
selected: <CalcCards>{calcCard}, selected: <CalcCards>{calcCard},
@ -279,7 +279,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
IconButton( IconButton(
tooltip: 'Open navigation menu', tooltip: t.navMenuTooltip,
icon: const Icon(Icons.menu), icon: const Icon(Icons.menu),
onPressed: () { onPressed: () {
_scaffoldKey.currentState!.openEndDrawer(); _scaffoldKey.currentState!.openEndDrawer();
@ -319,21 +319,21 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
child: const Icon(Icons.search), child: const Icon(Icons.search),
), ),
trailing: IconButton( trailing: IconButton(
tooltip: "Refresh data", tooltip: t.refresh,
onPressed: () { onPressed: () {
changePlayer(_searchFor); changePlayer(_searchFor);
}, },
icon: const Icon(Icons.refresh), icon: const Icon(Icons.refresh),
), ),
destinations: [ destinations: [
getDestinationButton(Icons.home, "Home"), getDestinationButton(Icons.home, t.destinations.home),
getDestinationButton(Icons.data_thresholding_outlined, "Graphs"), getDestinationButton(Icons.data_thresholding_outlined, t.destinations.graphs),
getDestinationButton(Icons.leaderboard, "Leaderboards"), getDestinationButton(Icons.leaderboard, t.destinations.leaderboards),
getDestinationButton(Icons.compress, "Cutoffs"), getDestinationButton(Icons.compress, t.destinations.cutoffs),
getDestinationButton(Icons.calculate, "Calc"), getDestinationButton(Icons.calculate, t.destinations.calc),
getDestinationButton(Icons.info_outline, "Information"), getDestinationButton(Icons.info_outline, t.destinations.info),
getDestinationButton(Icons.storage, "Saved Data"), getDestinationButton(Icons.storage, t.destinations.data),
getDestinationButton(Icons.settings, "Settings"), getDestinationButton(Icons.settings, t.destinations.settings),
], ],
selectedIndex: destination, selectedIndex: destination,
onDestinationSelected: (value) { onDestinationSelected: (value) {
@ -406,7 +406,7 @@ class _SearchDrawerState extends State<SearchDrawer> {
SliverToBoxAdapter( SliverToBoxAdapter(
child: SearchBar( child: SearchBar(
controller: widget.controller, controller: widget.controller,
hintText: "Username or ID", hintText: t.searchHint,
hintStyle: const WidgetStatePropertyAll(TextStyle(color: Colors.grey)), hintStyle: const WidgetStatePropertyAll(TextStyle(color: Colors.grey)),
trailing: [ trailing: [
IconButton(onPressed: (){setState(() { IconButton(onPressed: (){setState(() {
@ -439,7 +439,7 @@ class _SearchDrawerState extends State<SearchDrawer> {
SliverToBoxAdapter( SliverToBoxAdapter(
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: Text("Tracked Players", style: Theme.of(context).textTheme.headlineLarge), child: Text(t.trackedPlayers, style: Theme.of(context).textTheme.headlineLarge),
), ),
) )
]; ];
@ -487,7 +487,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
return [ return [
SliverToBoxAdapter( SliverToBoxAdapter(
child: DrawerHeader( child: DrawerHeader(
child: Text("Navigation menu", style: const TextStyle(color: Colors.white, fontSize: 25), child: Text(t.navMenu, style: const TextStyle(color: Colors.white, fontSize: 25),
))) )))
]; ];
}, },
@ -495,7 +495,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
children: [ children: [
ListTile( ListTile(
leading: Icon(Icons.home), leading: Icon(Icons.home),
title: Text("Home"), title: Text(t.destinations.home),
onTap: (){ onTap: (){
widget.changeDestination(0); widget.changeDestination(0);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -503,7 +503,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.data_thresholding_outlined), leading: Icon(Icons.data_thresholding_outlined),
title: Text("Graphs"), title: Text(t.destinations.graphs),
onTap: (){ onTap: (){
widget.changeDestination(1); widget.changeDestination(1);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -511,7 +511,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.leaderboard), leading: Icon(Icons.leaderboard),
title: Text("Leaderboards"), title: Text(t.destinations.leaderboards),
onTap: (){ onTap: (){
widget.changeDestination(2); widget.changeDestination(2);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -519,7 +519,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.compress), leading: Icon(Icons.compress),
title: Text("Cutoffs"), title: Text(t.destinations.cutoffs),
onTap: (){ onTap: (){
widget.changeDestination(3); widget.changeDestination(3);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -527,7 +527,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.calculate), leading: Icon(Icons.calculate),
title: Text("Calc"), title: Text(t.destinations.calc),
onTap: (){ onTap: (){
widget.changeDestination(4); widget.changeDestination(4);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -535,7 +535,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.info_outline), leading: Icon(Icons.info_outline),
title: Text("Information"), title: Text(t.destinations.info),
onTap: (){ onTap: (){
widget.changeDestination(5); widget.changeDestination(5);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -543,7 +543,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.storage), leading: Icon(Icons.storage),
title: Text("Saved Data"), title: Text(t.destinations.data),
onTap: (){ onTap: (){
widget.changeDestination(6); widget.changeDestination(6);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -551,7 +551,7 @@ class _DestinationsDrawerState extends State<DestinationsDrawer>{
), ),
ListTile( ListTile(
leading: Icon(Icons.settings), leading: Icon(Icons.settings),
title: Text("Settings"), title: Text(t.destinations.settings),
onTap: (){ onTap: (){
widget.changeDestination(7); widget.changeDestination(7);
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@ -131,34 +131,34 @@ class _RankState extends State<RankView> {
child: Card( child: Card(
child: Column( child: Column(
children: [ children: [
Text(shortNames ? "" : "Cheese Index", style: TextStyle(fontSize: 28, color: Colors.transparent)), Text(shortNames ? "" : t.stats.cheese.full, style: TextStyle(fontSize: 28, color: Colors.transparent)),
Divider(), Divider(),
RankViewEntry(shortNames ? "TR" : "Tetra Rating", null, null), RankViewEntry(shortNames ? t.stats.tr.short : t.stats.tr.full, null, null),
RankViewEntry("Glicko", null, null, differentBG: true), RankViewEntry(t.stats.glicko.full, null, null, differentBG: true),
RankViewEntry("RD", null, null), RankViewEntry(shortNames ? t.stats.rd.short : t.stats.rd.full, null, null),
RankViewEntry("Glixare", null, null, differentBG: true), RankViewEntry(t.stats.glixare.full, null, null, differentBG: true),
RankViewEntry("S1 TR", null, null), RankViewEntry(t.stats.s1tr.short, null, null),
RankViewEntry(shortNames ? "GP" : "Games Played", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.gp.short : t.stats.gp.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "GW" : "Games Won", null, null), RankViewEntry(shortNames ? t.stats.gw.short : t.stats.gw.full, null, null),
RankViewEntry(shortNames ? "WR" : "Winrate", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.winrate.short : t.stats.winrate.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "APM" : "Attack Per Minute", null, null), RankViewEntry(shortNames ? t.stats.apm.short : t.stats.apm.full, null, null),
RankViewEntry(shortNames ? "PPS" : "Pieces Per Second", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.pps.short : t.stats.pps.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "VS" : "Versus Score", null, null), RankViewEntry(shortNames ? t.stats.vs.short : t.stats.vs.full, null, null),
RankViewEntry(shortNames ? "APP" : "Attack Per Piece", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.app.short : t.stats.app.full, null, null, differentBG: true),
RankViewEntry("VS / APM", null, null), RankViewEntry(t.stats.vsapm.full, null, null),
RankViewEntry(shortNames ? "DS/P" : "Downstack Per Second", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.dss.short : t.stats.dss.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "DS/S" : "Downstack Per Piece", null, null), RankViewEntry(shortNames ? t.stats.dsp.short : t.stats.dsp.full, null, null),
RankViewEntry("APP + DS/P", null, null, differentBG: true), RankViewEntry(t.stats.appdsp.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "Cheese" : "Cheese Index", null, null), RankViewEntry(shortNames ? t.stats.cheese.short : t.stats.cheese.full, null, null),
RankViewEntry(shortNames ? "GbE" : "Garbage Efficiency", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.gbe.short : t.stats.gbe.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "wAPP" : "Weighted APP", null, null), RankViewEntry(shortNames ? t.stats.nyaapp.short : t.stats.nyaapp.full, null, null),
RankViewEntry("Area", null, null, differentBG: true), RankViewEntry(t.stats.area.full, null, null, differentBG: true),
RankViewEntry(shortNames ? "eTR" : "Estimated TR", null, null), RankViewEntry(shortNames ? t.stats.etr.short : t.stats.etr.full, null, null),
RankViewEntry(shortNames ? "±eTR" : "Est. TR Accuracy", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.etracc.short : t.stats.etracc.full, null, null, differentBG: true),
RankViewEntry("Opener", null, null), RankViewEntry(shortNames ? t.stats.opener.short : t.stats.opener.full, null, null),
RankViewEntry("Plonk", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.plonk.short : t.stats.plonk.full, null, null, differentBG: true),
RankViewEntry("Stride", null, null), RankViewEntry(shortNames ? t.stats.stride.short : t.stats.stride.full, null, null),
RankViewEntry(shortNames ? "Inf DS" : "Infinite Downstack", null, null, differentBG: true), RankViewEntry(shortNames ? t.stats.infds.short : t.stats.infds.full, null, null, differentBG: true),
], ],
), ),
), ),
@ -167,9 +167,9 @@ class _RankState extends State<RankView> {
child: Card( child: Card(
child: Column( child: Column(
children: [ children: [
Text("Minimums", style: TextStyle(fontSize: 28)), Text(t.rankView.minimums, style: TextStyle(fontSize: 28)),
Divider(), Divider(),
RankViewEntry("${f4.format(snapshot.data![1]["lowestTR"])}${shortNames ? "" : " TR"}", snapshot.data![1]["lowestTRnick"], snapshot.data![1]["lowestTRid"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestTR"])}${shortNames ? "" : " ${t.stats.tr.short}"}", snapshot.data![1]["lowestTRnick"], snapshot.data![1]["lowestTRid"]),
RankViewEntry(f4.format(snapshot.data![1]["lowestGlicko"]), snapshot.data![1]["lowestGlickoNick"], snapshot.data![1]["lowestGlickoID"], differentBG: true), RankViewEntry(f4.format(snapshot.data![1]["lowestGlicko"]), snapshot.data![1]["lowestGlickoNick"], snapshot.data![1]["lowestGlickoID"], differentBG: true),
RankViewEntry(f4.format(snapshot.data![1]["lowestRD"]), snapshot.data![1]["lowestRdNick"], snapshot.data![1]["lowestRdID"]), RankViewEntry(f4.format(snapshot.data![1]["lowestRD"]), snapshot.data![1]["lowestRdNick"], snapshot.data![1]["lowestRdID"]),
RankViewEntry(f4.format(snapshot.data![1]["lowestGlixare"]), snapshot.data![1]["lowestGlixareNick"], snapshot.data![1]["lowestGlixareID"], differentBG: true), RankViewEntry(f4.format(snapshot.data![1]["lowestGlixare"]), snapshot.data![1]["lowestGlixareNick"], snapshot.data![1]["lowestGlixareID"], differentBG: true),
@ -177,20 +177,20 @@ class _RankState extends State<RankView> {
RankViewEntry(intf.format(snapshot.data![1]["lowestGamesPlayed"]), snapshot.data![1]["lowestGamesPlayedNick"], snapshot.data![1]["lowestGamesPlayedID"], differentBG: true), RankViewEntry(intf.format(snapshot.data![1]["lowestGamesPlayed"]), snapshot.data![1]["lowestGamesPlayedNick"], snapshot.data![1]["lowestGamesPlayedID"], differentBG: true),
RankViewEntry(intf.format(snapshot.data![1]["lowestGamesWon"]), snapshot.data![1]["lowestGamesWonNick"], snapshot.data![1]["lowestGamesWonID"]), RankViewEntry(intf.format(snapshot.data![1]["lowestGamesWon"]), snapshot.data![1]["lowestGamesWonNick"], snapshot.data![1]["lowestGamesWonID"]),
RankViewEntry(percentage.format(snapshot.data![1]["lowestWinrate"]), snapshot.data![1]["lowestWinrateNick"], snapshot.data![1]["lowestWinrateID"], differentBG: true), RankViewEntry(percentage.format(snapshot.data![1]["lowestWinrate"]), snapshot.data![1]["lowestWinrateNick"], snapshot.data![1]["lowestWinrateID"], differentBG: true),
RankViewEntry("${f2.format(snapshot.data![1]["lowestAPM"])}${shortNames ? "" : " APM"}", snapshot.data![1]["lowestAPMnick"], snapshot.data![1]["lowestAPMid"]), RankViewEntry("${f2.format(snapshot.data![1]["lowestAPM"])}${shortNames ? "" : " ${t.stats.apm.short}"}", snapshot.data![1]["lowestAPMnick"], snapshot.data![1]["lowestAPMid"]),
RankViewEntry("${f2.format(snapshot.data![1]["lowestPPS"])}${shortNames ? "" : " PPS"}", snapshot.data![1]["lowestPPSnick"], snapshot.data![1]["lowestPPSid"], differentBG: true), RankViewEntry("${f2.format(snapshot.data![1]["lowestPPS"])}${shortNames ? "" : " ${t.stats.pps.short}"}", snapshot.data![1]["lowestPPSnick"], snapshot.data![1]["lowestPPSid"], differentBG: true),
RankViewEntry("${f2.format(snapshot.data![1]["lowestVS"])}${shortNames ? "" : " VS"}", snapshot.data![1]["lowestVSnick"], snapshot.data![1]["lowestVSid"]), RankViewEntry("${f2.format(snapshot.data![1]["lowestVS"])}${shortNames ? "" : " ${t.stats.vs.short}"}", snapshot.data![1]["lowestVSnick"], snapshot.data![1]["lowestVSid"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestAPP"])}${shortNames ? "" : " APP"}", snapshot.data![1]["lowestAPPnick"], snapshot.data![1]["lowestAPPid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestAPP"])}${shortNames ? "" : " ${t.stats.app.short}"}", snapshot.data![1]["lowestAPPnick"], snapshot.data![1]["lowestAPPid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestVSAPM"])}${shortNames ? "" : " VS/APM"}", snapshot.data![1]["lowestVSAPMnick"], snapshot.data![1]["lowestVSAPMid"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestVSAPM"])}${shortNames ? "" : " ${t.stats.vsapm.short}"}", snapshot.data![1]["lowestVSAPMnick"], snapshot.data![1]["lowestVSAPMid"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestDSS"])}${shortNames ? "" : " DS/S"}", snapshot.data![1]["lowestDSSnick"], snapshot.data![1]["lowestDSSid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestDSS"])}${shortNames ? "" : " ${t.stats.dss.short}"}", snapshot.data![1]["lowestDSSnick"], snapshot.data![1]["lowestDSSid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestDSP"])}${shortNames ? "" : " DS/P"}", snapshot.data![1]["lowestDSPnick"], snapshot.data![1]["lowestDSPid"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestDSP"])}${shortNames ? "" : " ${t.stats.dsp.short}"}", snapshot.data![1]["lowestDSPnick"], snapshot.data![1]["lowestDSPid"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestAPPDSP"])}${shortNames ? "" : " APP+DS/P"}", snapshot.data![1]["lowestAPPDSPnick"], snapshot.data![1]["lowestAPPDSPid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestAPPDSP"])}${shortNames ? "" : " ${t.stats.appdsp.short}"}", snapshot.data![1]["lowestAPPDSPnick"], snapshot.data![1]["lowestAPPDSPid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestCheese"])}${shortNames ? "" : " Cheese"}", snapshot.data![1]["lowestCheeseNick"], snapshot.data![1]["lowestCheeseID"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestCheese"])}${shortNames ? "" : " ${t.stats.cheese.short}"}", snapshot.data![1]["lowestCheeseNick"], snapshot.data![1]["lowestCheeseID"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestGBE"])}${shortNames ? "" : " Gbe"}", snapshot.data![1]["lowestGBEnick"], snapshot.data![1]["lowestGBEid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestGBE"])}${shortNames ? "" : " ${t.stats.gbe.short}"}", snapshot.data![1]["lowestGBEnick"], snapshot.data![1]["lowestGBEid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestNyaAPP"])}${shortNames ? "" : " WAPP"}", snapshot.data![1]["lowestNyaAPPnick"], snapshot.data![1]["lowestNyaAPPid"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestNyaAPP"])}${shortNames ? "" : " ${t.stats.nyaapp.short}"}", snapshot.data![1]["lowestNyaAPPnick"], snapshot.data![1]["lowestNyaAPPid"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestArea"])}${shortNames ? "" : " Area"}", snapshot.data![1]["lowestAreaNick"], snapshot.data![1]["lowestAreaID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestArea"])}${shortNames ? "" : " ${t.stats.area.short}"}", snapshot.data![1]["lowestAreaNick"], snapshot.data![1]["lowestAreaID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestEstTR"])}${shortNames ? "" : " eTR"}", snapshot.data![1]["lowestEstTRnick"], snapshot.data![1]["lowestEstTRid"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestEstTR"])}${shortNames ? "" : " ${t.stats.etr.short}"}", snapshot.data![1]["lowestEstTRnick"], snapshot.data![1]["lowestEstTRid"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestEstAcc"])}${shortNames ? "" : " ±eTR"}", snapshot.data![1]["lowestEstAccNick"], snapshot.data![1]["lowestEstAccID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestEstAcc"])}${shortNames ? "" : " ${t.stats.etracc.short}"}", snapshot.data![1]["lowestEstAccNick"], snapshot.data![1]["lowestEstAccID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestOpener"])}", snapshot.data![1]["lowestOpenerNick"], snapshot.data![1]["lowestOpenerID"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestOpener"])}", snapshot.data![1]["lowestOpenerNick"], snapshot.data![1]["lowestOpenerID"]),
RankViewEntry("${f4.format(snapshot.data![1]["lowestPlonk"])}", snapshot.data![1]["lowestPlonkNick"], snapshot.data![1]["lowestPlonkID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["lowestPlonk"])}", snapshot.data![1]["lowestPlonkNick"], snapshot.data![1]["lowestPlonkID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["lowestStride"])}", snapshot.data![1]["lowestStrideNick"], snapshot.data![1]["lowestStrideID"]), RankViewEntry("${f4.format(snapshot.data![1]["lowestStride"])}", snapshot.data![1]["lowestStrideNick"], snapshot.data![1]["lowestStrideID"]),
@ -203,9 +203,9 @@ class _RankState extends State<RankView> {
child: Card( child: Card(
child: Column( child: Column(
children: [ children: [
Text("Maximums", style: TextStyle(fontSize: 28)), Text(t.rankView.maximums, style: TextStyle(fontSize: 28)),
Divider(), Divider(),
RankViewEntry("${f4.format(snapshot.data![1]["highestTR"])}${shortNames ? "" : " TR"}", snapshot.data![1]["highestTRnick"], snapshot.data![1]["highestTRid"]), RankViewEntry("${f4.format(snapshot.data![1]["highestTR"])}${shortNames ? "" : " ${t.stats.tr.short}"}", snapshot.data![1]["highestTRnick"], snapshot.data![1]["highestTRid"]),
RankViewEntry(f4.format(snapshot.data![1]["highestGlicko"]), snapshot.data![1]["highestGlickoNick"], snapshot.data![1]["highestGlickoID"], differentBG: true), RankViewEntry(f4.format(snapshot.data![1]["highestGlicko"]), snapshot.data![1]["highestGlickoNick"], snapshot.data![1]["highestGlickoID"], differentBG: true),
RankViewEntry(f4.format(snapshot.data![1]["highestRD"]), snapshot.data![1]["highestRdNick"], snapshot.data![1]["highestRdID"]), RankViewEntry(f4.format(snapshot.data![1]["highestRD"]), snapshot.data![1]["highestRdNick"], snapshot.data![1]["highestRdID"]),
RankViewEntry(f4.format(snapshot.data![1]["highestGlixare"]), snapshot.data![1]["highestGlixareNick"], snapshot.data![1]["highestGlixareID"], differentBG: true), RankViewEntry(f4.format(snapshot.data![1]["highestGlixare"]), snapshot.data![1]["highestGlixareNick"], snapshot.data![1]["highestGlixareID"], differentBG: true),
@ -213,20 +213,20 @@ class _RankState extends State<RankView> {
RankViewEntry(intf.format(snapshot.data![1]["highestGamesPlayed"]), snapshot.data![1]["highestGamesPlayedNick"], snapshot.data![1]["highestGamesPlayedID"], differentBG: true), RankViewEntry(intf.format(snapshot.data![1]["highestGamesPlayed"]), snapshot.data![1]["highestGamesPlayedNick"], snapshot.data![1]["highestGamesPlayedID"], differentBG: true),
RankViewEntry(intf.format(snapshot.data![1]["highestGamesWon"]), snapshot.data![1]["highestGamesWonNick"], snapshot.data![1]["highestGamesWonID"]), RankViewEntry(intf.format(snapshot.data![1]["highestGamesWon"]), snapshot.data![1]["highestGamesWonNick"], snapshot.data![1]["highestGamesWonID"]),
RankViewEntry(percentage.format(snapshot.data![1]["highestWinrate"]), snapshot.data![1]["highestWinrateNick"], snapshot.data![1]["highestWinrateID"], differentBG: true), RankViewEntry(percentage.format(snapshot.data![1]["highestWinrate"]), snapshot.data![1]["highestWinrateNick"], snapshot.data![1]["highestWinrateID"], differentBG: true),
RankViewEntry("${f2.format(snapshot.data![1]["highestAPM"])}${shortNames ? "" : " APM"}", snapshot.data![1]["highestAPMnick"], snapshot.data![1]["highestAPMid"]), RankViewEntry("${f2.format(snapshot.data![1]["highestAPM"])}${shortNames ? "" : " ${t.stats.apm.short}"}", snapshot.data![1]["highestAPMnick"], snapshot.data![1]["highestAPMid"]),
RankViewEntry("${f2.format(snapshot.data![1]["highestPPS"])}${shortNames ? "" : " PPS"}", snapshot.data![1]["highestPPSnick"], snapshot.data![1]["highestPPSid"], differentBG: true), RankViewEntry("${f2.format(snapshot.data![1]["highestPPS"])}${shortNames ? "" : " ${t.stats.pps.short}"}", snapshot.data![1]["highestPPSnick"], snapshot.data![1]["highestPPSid"], differentBG: true),
RankViewEntry("${f2.format(snapshot.data![1]["highestVS"])}${shortNames ? "" : " VS"}", snapshot.data![1]["highestVSnick"], snapshot.data![1]["highestVSid"]), RankViewEntry("${f2.format(snapshot.data![1]["highestVS"])}${shortNames ? "" : " ${t.stats.vs.short}"}", snapshot.data![1]["highestVSnick"], snapshot.data![1]["highestVSid"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestAPP"])}${shortNames ? "" : " APP"}", snapshot.data![1]["highestAPPnick"], snapshot.data![1]["highestAPPid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestAPP"])}${shortNames ? "" : " ${t.stats.app.short}"}", snapshot.data![1]["highestAPPnick"], snapshot.data![1]["highestAPPid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestVSAPM"])}${shortNames ? "" : " VS/APM"}", snapshot.data![1]["highestVSAPMnick"], snapshot.data![1]["highestVSAPMid"]), RankViewEntry("${f4.format(snapshot.data![1]["highestVSAPM"])}${shortNames ? "" : " ${t.stats.vsapm.short}"}", snapshot.data![1]["highestVSAPMnick"], snapshot.data![1]["highestVSAPMid"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestDSS"])}${shortNames ? "" : " DS/S"}", snapshot.data![1]["highestDSSnick"], snapshot.data![1]["highestDSSid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestDSS"])}${shortNames ? "" : " ${t.stats.dss.short}"}", snapshot.data![1]["highestDSSnick"], snapshot.data![1]["highestDSSid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestDSP"])}${shortNames ? "" : " DS/P"}", snapshot.data![1]["highestDSPnick"], snapshot.data![1]["highestDSPid"]), RankViewEntry("${f4.format(snapshot.data![1]["highestDSP"])}${shortNames ? "" : " ${t.stats.dsp.short}"}", snapshot.data![1]["highestDSPnick"], snapshot.data![1]["highestDSPid"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestAPPDSP"])}${shortNames ? "" : " APP+DS/P"}", snapshot.data![1]["highestAPPDSPnick"], snapshot.data![1]["highestAPPDSPid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestAPPDSP"])}${shortNames ? "" : " ${t.stats.appdsp.short}"}", snapshot.data![1]["highestAPPDSPnick"], snapshot.data![1]["highestAPPDSPid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestCheese"])}${shortNames ? "" : " Cheese"}", snapshot.data![1]["highestCheeseNick"], snapshot.data![1]["highestCheeseID"]), RankViewEntry("${f4.format(snapshot.data![1]["highestCheese"])}${shortNames ? "" : " ${t.stats.cheese.short}"}", snapshot.data![1]["highestCheeseNick"], snapshot.data![1]["highestCheeseID"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestGBE"])}${shortNames ? "" : " Gbe"}", snapshot.data![1]["highestGBEnick"], snapshot.data![1]["highestGBEid"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestGBE"])}${shortNames ? "" : " ${t.stats.gbe.short}"}", snapshot.data![1]["highestGBEnick"], snapshot.data![1]["highestGBEid"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestNyaAPP"])}${shortNames ? "" : " wAPP"}", snapshot.data![1]["highestNyaAPPnick"], snapshot.data![1]["highestNyaAPPid"]), RankViewEntry("${f4.format(snapshot.data![1]["highestNyaAPP"])}${shortNames ? "" : " ${t.stats.nyaapp.short}"}", snapshot.data![1]["highestNyaAPPnick"], snapshot.data![1]["highestNyaAPPid"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestArea"])}${shortNames ? "" : " Area"}", snapshot.data![1]["highestAreaNick"], snapshot.data![1]["highestAreaID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestArea"])}${shortNames ? "" : " ${t.stats.area.short}"}", snapshot.data![1]["highestAreaNick"], snapshot.data![1]["highestAreaID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestEstTR"])}${shortNames ? "" : " eTR"}", snapshot.data![1]["highestEstTRnick"], snapshot.data![1]["highestEstTRid"]), RankViewEntry("${f4.format(snapshot.data![1]["highestEstTR"])}${shortNames ? "" : " ${t.stats.etr.short}"}", snapshot.data![1]["highestEstTRnick"], snapshot.data![1]["highestEstTRid"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestEstAcc"])}${shortNames ? "" : " ±eTR"}", snapshot.data![1]["highestEstAccNick"], snapshot.data![1]["highestEstAccID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestEstAcc"])}${shortNames ? "" : " ${t.stats.etracc.short}"}", snapshot.data![1]["highestEstAccNick"], snapshot.data![1]["highestEstAccID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestOpener"])}", snapshot.data![1]["highestOpenerNick"], snapshot.data![1]["highestOpenerID"]), RankViewEntry("${f4.format(snapshot.data![1]["highestOpener"])}", snapshot.data![1]["highestOpenerNick"], snapshot.data![1]["highestOpenerID"]),
RankViewEntry("${f4.format(snapshot.data![1]["highestPlonk"])}", snapshot.data![1]["highestPlonkNick"], snapshot.data![1]["highestPlonkID"], differentBG: true), RankViewEntry("${f4.format(snapshot.data![1]["highestPlonk"])}", snapshot.data![1]["highestPlonkNick"], snapshot.data![1]["highestPlonkID"], differentBG: true),
RankViewEntry("${f4.format(snapshot.data![1]["highestStride"])}", snapshot.data![1]["highestStrideNick"], snapshot.data![1]["highestStrideID"]), RankViewEntry("${f4.format(snapshot.data![1]["highestStride"])}", snapshot.data![1]["highestStrideNick"], snapshot.data![1]["highestStrideID"]),
@ -272,7 +272,7 @@ class _RankState extends State<RankView> {
children: [ children: [
Card(child: Center(child: Padding( Card(child: Center(child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 8.0, 5.0, 10.0), padding: const EdgeInsets.fromLTRB(0.0, 8.0, 5.0, 10.0),
child: Text(widget.rank == "" ? "Everyone" : "${widget.rank.toUpperCase()} rank data", style: TextStyle(fontSize: 28)), child: Text(widget.rank == "" ? t.rankView.everyoneTitle : t.rankView.rankTitle(rank: widget.rank.toUpperCase()), style: TextStyle(fontSize: 28)),
))), ))),
Card( Card(
child: Center( child: Center(
@ -282,7 +282,7 @@ class _RankState extends State<RankView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Image.asset("res/tetrio_tl_alpha_ranks/${widget.rank == "" ? "z" : widget.rank}.png",fit: BoxFit.fitHeight,height: 128), Image.asset("res/tetrio_tl_alpha_ranks/${widget.rank == "" ? "z" : widget.rank}.png",fit: BoxFit.fitHeight,height: 128),
Text("${intf.format(widget.cutoffTetrio.count)} players", style: Theme.of(context).textTheme.titleSmall,), Text(t.stats.players(n: widget.cutoffTetrio.count), style: Theme.of(context).textTheme.titleSmall,),
], ],
), ),
), ),
@ -297,7 +297,7 @@ class _RankState extends State<RankView> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("TR range", style: Theme.of(context).textTheme.displayLarge), Text(t.rankView.trRange, style: Theme.of(context).textTheme.displayLarge),
Text("${f2.format(widget.cutoffTetrio.tr)}${f2.format(widget.nextRankTR)}", style: Theme.of(context).textTheme.displayLarge) Text("${f2.format(widget.cutoffTetrio.tr)}${f2.format(widget.nextRankTR)}", style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
@ -306,14 +306,14 @@ class _RankState extends State<RankView> {
child: Row( child: Row(
children: [ children: [
Spacer(), Spacer(),
Text("(${f2.format(widget.nextRankTR - widget.cutoffTetrio.tr)} TR gap)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) Text("(${t.rankView.trGap(value: f2.format(widget.nextRankTR - widget.cutoffTetrio.tr))})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
], ],
), ),
), ),
if (widget.rank != "") Row( if (widget.rank != "") Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Supposed to be", style: Theme.of(context).textTheme.displayLarge), Text(t.rankView.supposedToBe, style: Theme.of(context).textTheme.displayLarge),
Text("${intf.format(widget.cutoffTetrio.targetTr)}${intf.format(widget.nextRankTargetTR)}", style: Theme.of(context).textTheme.displayLarge) Text("${intf.format(widget.cutoffTetrio.targetTr)}${intf.format(widget.nextRankTargetTR)}", style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
@ -322,28 +322,28 @@ class _RankState extends State<RankView> {
child: Row( child: Row(
children: [ children: [
Spacer(), Spacer(),
Text("(${intf.format(widget.nextRankTargetTR - widget.cutoffTetrio.targetTr)} TR gap)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) Text("(${t.rankView.trGap(value: intf.format(widget.nextRankTargetTR - widget.cutoffTetrio.targetTr))})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
], ],
), ),
), ),
if (widget.nextRankTargetTR < widget.nextRankTR) Row( if (widget.nextRankTargetTR < widget.nextRankTR) Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Inflation gap", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.redAccent)), Text(t.rankView.inflationGap, style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.redAccent)),
Text("${f2.format(widget.nextRankTR - widget.nextRankTargetTR)} TR", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.redAccent)) Text("${f2.format(widget.nextRankTR - widget.nextRankTargetTR)} ${t.stats.tr.short}", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.redAccent))
], ],
), ),
if (widget.cutoffTetrio.tr < widget.cutoffTetrio.targetTr) Row( if (widget.cutoffTetrio.tr < widget.cutoffTetrio.targetTr) Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Deflation gap", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.greenAccent)), Text(t.rankView.deflationGap, style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.greenAccent)),
Text("${f2.format(widget.cutoffTetrio.targetTr - widget.cutoffTetrio.tr)} TR", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.greenAccent)) Text("${f2.format(widget.cutoffTetrio.targetTr - widget.cutoffTetrio.tr)} ${t.stats.tr.short}", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.greenAccent))
], ],
), ),
if (widget.rank != "") Row( if (widget.rank != "") Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("LB pos range", style: Theme.of(context).textTheme.displayLarge), Text(t.rankView.LBposRange, style: Theme.of(context).textTheme.displayLarge),
Text("${percentage.format(widget.cutoffTetrio.percentile)}${percentage.format(widget.nextRankPercentile)}", style: Theme.of(context).textTheme.displayLarge) Text("${percentage.format(widget.cutoffTetrio.percentile)}${percentage.format(widget.nextRankPercentile)}", style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
@ -352,15 +352,15 @@ class _RankState extends State<RankView> {
child: Row( child: Row(
children: [ children: [
Spacer(), Spacer(),
Text("(${percentage.format(percentileGap)} gap)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) Text("(${t.rankView.gap(value: percentage.format(percentileGap))})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
], ],
), ),
), ),
if (widget.rank != "") Row( if (widget.rank != "") Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("Supposed to be", style: Theme.of(context).textTheme.displayLarge), Text(t.rankView.supposedToBe, style: Theme.of(context).textTheme.displayLarge),
Text("${intf.format(supposedToBePlayers)} players", style: Theme.of(context).textTheme.displayLarge) Text(t.stats.players(n: supposedToBePlayers), style: Theme.of(context).textTheme.displayLarge)
], ],
), ),
if (widget.rank != "") Padding( if (widget.rank != "") Padding(
@ -368,9 +368,9 @@ class _RankState extends State<RankView> {
child: Row( child: Row(
children: [ children: [
Spacer(), Spacer(),
if (widget.cutoffTetrio.count > supposedToBePlayers) Text("(overpopulated by a ${intf.format(widget.cutoffTetrio.count - supposedToBePlayers)} players)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) if (widget.cutoffTetrio.count > supposedToBePlayers) Text("(${t.rankView.overpopulated(players: t.stats.players(n: widget.cutoffTetrio.count - supposedToBePlayers))})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
else if (widget.cutoffTetrio.count < supposedToBePlayers) Text("(underpopulated by a ${intf.format(supposedToBePlayers - widget.cutoffTetrio.count)} players)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) else if (widget.cutoffTetrio.count < supposedToBePlayers) Text("(${t.rankView.overpopulated(players: t.stats.players(n: supposedToBePlayers - widget.cutoffTetrio.count))})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
else Text("(cute)", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14)) else Text("(${t.rankView.PlayersEqualSupposedToBe})", style: Theme.of(context).textTheme.displayLarge!.copyWith(color: Colors.grey, fontSize: 14))
], ],
), ),
), ),

View File

@ -3,7 +3,6 @@ import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/views/destination_home.dart'; import 'package:tetra_stats/views/destination_home.dart';
import 'package:tetra_stats/widgets/singleplayer_record.dart'; import 'package:tetra_stats/widgets/singleplayer_record.dart';
import 'package:tetra_stats/widgets/text_timestamp.dart';
class SingleplayerRecordView extends StatelessWidget { class SingleplayerRecordView extends StatelessWidget {
final RecordSingle record; final RecordSingle record;
@ -33,8 +32,8 @@ class SingleplayerRecordView extends StatelessWidget {
maxWidth: 768 maxWidth: 768
), ),
child: switch (record.gamemode){ child: switch (record.gamemode){
"zenith" => ZenithCard(record, false), "zenith" => ZenithCard(record, false, width: MediaQuery.of(context).size.width),
"zenithex" => ZenithCard(record, false), "zenithex" => ZenithCard(record, false, width: MediaQuery.of(context).size.width),
_ => SingleplayerRecord(record: record, hideTitle: true) _ => SingleplayerRecord(record: record, hideTitle: true)
}, },
), ),

View File

@ -30,7 +30,7 @@ class StateState extends State<StateView> {
_scrollController = ScrollController(); _scrollController = ScrollController();
if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){ if (!kIsWeb && !Platform.isAndroid && !Platform.isIOS){
windowManager.getTitle().then((value) => oldWindowTitle = value); windowManager.getTitle().then((value) => oldWindowTitle = value);
windowManager.setTitle("State from ${timestamp(widget.state.timestamp)}"); windowManager.setTitle(t.stateView.title(date: timestamp(widget.state.timestamp)));
} }
super.initState(); super.initState();
} }
@ -47,7 +47,7 @@ class StateState extends State<StateView> {
//final t = Translations.of(context); //final t = Translations.of(context);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text("State from ${timestamp(widget.state.timestamp)}", style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28)), title: Text(t.stateView.title(date: timestamp(widget.state.timestamp)), style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 28)),
), ),
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: SafeArea( body: SafeArea(

View File

@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart';
import 'package:tetra_stats/views/destination_home.dart'; import 'package:tetra_stats/views/destination_home.dart';
import 'package:tetra_stats/views/main_view.dart'; import 'package:tetra_stats/views/main_view.dart';

View File

@ -7,7 +7,7 @@ import 'package:tetra_stats/widgets/text_timestamp.dart';
class BadgesThingy extends StatelessWidget{ class BadgesThingy extends StatelessWidget{
final List<Badge> badges; final List<Badge> badges;
// TODO: make it obvious, that it's scrollable
const BadgesThingy({super.key, required this.badges}); const BadgesThingy({super.key, required this.badges});
@override @override
@ -19,7 +19,7 @@ class BadgesThingy extends StatelessWidget{
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0), padding: const EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
child: Row( child: Row(
children: [ children: [
const Text("Badges", style: TextStyle(fontFamily: "Eurostile Round Extended")), Text(t.badges, style: TextStyle(fontFamily: "Eurostile Round Extended")),
const Spacer(), const Spacer(),
Text(intf.format(badges.length)) Text(intf.format(badges.length))
], ],

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/beta_record.dart'; import 'package:tetra_stats/data_objects/beta_record.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/views/tl_match_view.dart'; import 'package:tetra_stats/views/tl_match_view.dart';
import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart'; import 'package:tetra_stats/widgets/list_tile_trailing_stats.dart';
@ -8,37 +9,37 @@ import 'package:tetra_stats/widgets/text_timestamp.dart';
class BetaLeagueEntryThingy extends StatelessWidget{ class BetaLeagueEntryThingy extends StatelessWidget{
final BetaRecord record; final BetaRecord record;
final String userID; final String userID;
// TODO: Rating delta string is too long for small screens
const BetaLeagueEntryThingy(this.record, this.userID); const BetaLeagueEntryThingy(this.record, this.userID);
TextSpan matchResult(String result){ TextSpan matchResult(String result){
return switch(result){ return switch(result){
"victory" => TextSpan( "victory" => TextSpan(
text: "Victory", text: t.matchResult.victory,
style: TextStyle(color: Colors.greenAccent) style: TextStyle(color: Colors.greenAccent)
), ),
"defeat" => TextSpan( "defeat" => TextSpan(
text: "Defeat", text: t.matchResult.defeat,
style: TextStyle(color: Colors.redAccent) style: TextStyle(color: Colors.redAccent)
), ),
"tie" => TextSpan( "tie" => TextSpan(
text: "Tie", text: t.matchResult.tie,
style: TextStyle(color: Colors.white) style: TextStyle(color: Colors.white)
), ),
"dqvictory" => TextSpan( "dqvictory" => TextSpan(
text: "Opponent was DQ'ed", text: t.matchResult.dqvictory,
style: TextStyle(color: Colors.lightGreenAccent) style: TextStyle(color: Colors.lightGreenAccent)
), ),
"dqdefeat" => TextSpan( "dqdefeat" => TextSpan(
text: "Player was DQ'ed", text: t.matchResult.dqdefeat,
style: TextStyle(color: Colors.red) style: TextStyle(color: Colors.red)
), ),
"nocontest" => TextSpan( "nocontest" => TextSpan(
text: "No Contest", text: t.matchResult.nocontest,
style: TextStyle(color: Colors.blueAccent) style: TextStyle(color: Colors.blueAccent)
), ),
"nullified" => TextSpan( "nullified" => TextSpan(
text: "Nullified", text: t.matchResult.nullified,
style: TextStyle(color: Colors.purpleAccent) style: TextStyle(color: Colors.purpleAccent)
), ),
_ => TextSpan( _ => TextSpan(

View File

@ -11,9 +11,9 @@ class DistinguishmentThingy extends StatelessWidget{
List<InlineSpan> getDistinguishmentTitle(String? text) { List<InlineSpan> getDistinguishmentTitle(String? text) {
// TWC champions don't have header in their distinguishments // TWC champions don't have header in their distinguishments
if (distinguishment.type == "twc") return [const TextSpan(text: "TETR.IO World Champion", style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.yellowAccent))]; if (distinguishment.type == "twc") return [TextSpan(text: t.distinguishments.twc, style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.yellowAccent))];
// In case if it missing for some other reason, return this // In case if it missing for some other reason, return this
if (text == null) return [const TextSpan(text: "Header is missing", style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.redAccent))]; if (text == null) return [TextSpan(text: t.distinguishments.noHeader, style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.redAccent))];
// Handling placeholders for logos // Handling placeholders for logos
var exploded = text.split(" "); // wtf PHP reference? var exploded = text.split(" "); // wtf PHP reference?
@ -43,9 +43,9 @@ class DistinguishmentThingy extends StatelessWidget{
/// Receives [text], which is footer and returns sets of widgets for RichText widget /// Receives [text], which is footer and returns sets of widgets for RichText widget
String getDistinguishmentSubtitle(String? text){ String getDistinguishmentSubtitle(String? text){
// TWC champions don't have footer in their distinguishments // TWC champions don't have footer in their distinguishments
if (distinguishment.type == "twc") return "${distinguishment.detail} TETR.IO World Championship"; if (distinguishment.type == "twc") return "${t.distinguishments.twcYear(year: distinguishment.detail!)}";
// In case if it missing for some other reason, return this // In case if it missing for some other reason, return this
if (text == null) return "Footer is missing"; if (text == null) return t.distinguishments.noFooter;
// If everything ok, return as it is // If everything ok, return as it is
return text; return text;
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/main.dart'; import 'package:tetra_stats/main.dart';
class FakeDistinguishmentThingy extends StatelessWidget{ class FakeDistinguishmentThingy extends StatelessWidget{
@ -18,16 +19,16 @@ class FakeDistinguishmentThingy extends StatelessWidget{
InlineSpan getDistinguishmentTitle() { InlineSpan getDistinguishmentTitle() {
String text = ""; String text = "";
if (banned) text = "banned"; if (banned) text = t.banned;
if (badStanding) text = "bad standing"; if (badStanding) text = t.badStanding;
if (bot) text = "bot account"; if (bot) text = t.botAccount;
return TextSpan(text: text.toUpperCase(), style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.white)); return TextSpan(text: text.toUpperCase(), style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold, color: Colors.white));
} }
String getDistinguishmentSubtitle(){ String getDistinguishmentSubtitle(){
if (banned) return "Bans are placed when TETR.IO rules or terms of service are broken"; if (banned) return t.bannedSubtext;
if (badStanding) return "One or more recent bans on record"; if (badStanding) return t.badStandingSubtext;
if (bot) return "Operated by $botMaintainers"; if (bot) return t.botAccountSubtext(botMaintainers: botMaintainers!);
return ""; return "";
} }

View File

@ -2,6 +2,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/finesse.dart'; import 'package:tetra_stats/data_objects/finesse.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';
@ -28,7 +29,7 @@ class FinesseThingy extends StatelessWidget{
fontSize: 65, fontSize: 65,
height: 1.2, height: 1.2,
)), )),
const Positioned(left: 25, top: 20, child: Text("inesse", style: TextStyle(fontFamily: "Eurostile Round Extended"))), Positioned(left: 25, top: 20, child: Text(t.stats.finesse.widgetTitle, style: TextStyle(fontFamily: "Eurostile Round Extended"))),
Positioned( Positioned(
right: 0, top: 20, right: 0, top: 20,
child: Text("${finesse != null ? finesse!.faults : "---"}F", style: TextStyle( child: Text("${finesse != null ? finesse!.faults : "---"}F", style: TextStyle(

View File

@ -314,25 +314,25 @@ class Graphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: 'APM', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.apm.short, angle: angle, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: 'PPS', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.pps.short, angle: angle, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.vs.short, angle: angle, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.app.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 4: case 4:
return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.dss.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 5: case 5:
return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.dsp.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 6: case 6:
return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.appdsp.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 7: case 7:
return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.vsapm.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 8: case 8:
return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.cheese.short, angle: angle, positionPercentageOffset: 0.05);
case 9: case 9:
return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.gbe.short, angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }
@ -395,13 +395,13 @@ class Graphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: 'Opener\n${percentage.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.opener.short}\n${percentage.format(playstyle.opener)}', angle: 0, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: 'Stride\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.stride.short}\n${percentage.format(playstyle.stride)}', angle: 0, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'Inf DS\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.infds.short}\n${percentage.format(playstyle.infds)}', angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05); return RadarChartTitle(text: '${t.stats.plonk.short}\n${percentage.format(playstyle.plonk)}', angle: 0, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
class TrailingStats extends StatelessWidget{ class TrailingStats extends StatelessWidget{
@ -23,9 +24,9 @@ class TrailingStats extends StatelessWidget{
2: FixedColumnWidth(54), 2: FixedColumnWidth(54),
}, },
children: [ children: [
TableRow(children: [Text(f2.format(yourAPM), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourAPM), textAlign: TextAlign.right, style: style), const Text(" APM", textAlign: TextAlign.right, style: style)]), TableRow(children: [Text(f2.format(yourAPM), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourAPM), textAlign: TextAlign.right, style: style), Text(" ${t.stats.apm.short}", textAlign: TextAlign.right, style: style)]),
TableRow(children: [Text(f2.format(yourPPS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourPPS), textAlign: TextAlign.right, style: style), const Text(" PPS", textAlign: TextAlign.right, style: style)]), TableRow(children: [Text(f2.format(yourPPS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourPPS), textAlign: TextAlign.right, style: style), Text(" ${t.stats.pps.short}", textAlign: TextAlign.right, style: style)]),
TableRow(children: [Text(f2.format(yourVS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourVS), textAlign: TextAlign.right, style: style), const Text(" VS", textAlign: TextAlign.right, style: style)]), TableRow(children: [Text(f2.format(yourVS), textAlign: TextAlign.right, style: style), const Text(" :", style: style), Text(f2.format(notyourVS), textAlign: TextAlign.right, style: style), Text(" ${t.stats.vs.short}", textAlign: TextAlign.right, style: style)]),
], ],
); );
} }

View File

@ -60,7 +60,7 @@ class NerdStatsThingy extends StatelessWidget{
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: "Eurostile Round"), style: const TextStyle(fontFamily: "Eurostile Round"),
children: [ children: [
const TextSpan(text: "APP\n"), TextSpan(text: "${t.stats.app.short}\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))), 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 (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))) if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.app - oldNerdStats!.app)}", style: TextStyle(color: getDifferenceColor(nerdStats.app - oldNerdStats!.app)))
@ -101,7 +101,7 @@ class NerdStatsThingy extends StatelessWidget{
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: "Eurostile Round"), style: const TextStyle(fontFamily: "Eurostile Round"),
children: [ children: [
const TextSpan(text: "VS/APM\n"), TextSpan(text: "${t.stats.vsapm.short}\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))), 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 (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))), if (oldNerdStats != null) TextSpan(text: "\n${comparef.format(nerdStats.vsapm - oldNerdStats!.vsapm)}", style: TextStyle(color: getDifferenceColor(nerdStats.vsapm - oldNerdStats!.vsapm))),
@ -125,13 +125,13 @@ class NerdStatsThingy extends StatelessWidget{
runSpacing: 10.0, runSpacing: 10.0,
runAlignment: WrapAlignment.start, runAlignment: WrapAlignment.start,
children: [ 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.dss, oldValue: oldNerdStats?.dss, min: 0, max: 1.0, tickInterval: .2, label: t.stats.dss.short, 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.dsp, oldValue: oldNerdStats?.dsp, min: 0, max: 1.0, tickInterval: .2, label: t.stats.dsp.short, 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.appdsp, oldValue: oldNerdStats?.appdsp, min: 0, max: 1.2, tickInterval: .2, label: t.stats.appdsp.short, 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.cheese, oldValue: oldNerdStats?.cheese, min: -80, max: 80, tickInterval: 40, label: t.stats.cheese.short, 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.gbe, oldValue: oldNerdStats?.gbe, min: 0, max: 1.0, tickInterval: .2, label: t.stats.gbe.short, 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.nyaapp, oldValue: oldNerdStats?.nyaapp, min: 0, max: 1.2, tickInterval: .2, label: t.stats.nyaapp.short, 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), GaugetThingy(value: nerdStats.area, oldValue: oldNerdStats?.area, min: 0, max: 1000, tickInterval: 100, label: t.stats.area.short, sideSize: 128.0, fractionDigits: 1, moreIsBetter: true, avgValue: averages?.nerdStats?.area, lbPos: lbPos?.area),
], ],
); );
} }

View File

@ -1,89 +0,0 @@
import 'package:flutter/material.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/text_shadow.dart';
const int length = 25;
final TextEditingController controller = TextEditingController();
class SearchBox extends StatefulWidget {
final Function onSubmit;
final bool bigScreen;
const SearchBox({required this.onSubmit, required this.bigScreen, super.key});
@override
State<StatefulWidget> createState() => _SearchBoxState();
}
class _SearchBoxState extends State<SearchBox>{
late FocusNode textbotFocus;
@override
void initState() {
textbotFocus = FocusNode();
controller.addListener(() {
setState(() {});
});
super.initState();
}
@override
void dispose(){
controller.clear();
textbotFocus.dispose();
super.dispose();
}
Color getColorOfCounter(){
// if limit was hit
if ((length - controller.text.length) <= 0) return Colors.redAccent;
// if input more than 16 symbols (username length limit)
if ((length - controller.text.length) < 9) return Colors.yellowAccent;
// if we good (we not)
return Colors.grey;
}
double getFontSizeOfCounter(){
return (length - controller.text.length) <= 0 ? 24 : 16;
}
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
return Row(
mainAxisSize: MainAxisSize.min,
//alignment: Alignment.centerRight,
children: [
Expanded(
child: TextField(
controller: controller,
maxLength: length,
focusNode: textbotFocus,
autofocus: true,
autocorrect: false,
enableSuggestions: false,
decoration: InputDecoration(
counter: const Offstage(),
hintText: widget.bigScreen ? t.searchHint : null,
),
style: const TextStyle(shadows: textShadow, fontSize: 18),
onSubmitted: (String value) {
widget.onSubmit(value);
textbotFocus.unfocus();
},
),
),
AnimatedDefaultTextStyle(
style: TextStyle(
fontFamily: "Eurostile Round",
fontSize: getFontSizeOfCounter(),
color: getColorOfCounter(),
shadows: textShadow
),
duration: Durations.short4,
curve: Curves.easeOutCirc,
child: Text("${length - controller.text.length}")
)
]
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
@ -17,27 +18,27 @@ class SpTrailingStats extends StatelessWidget{
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text(switch(gamemode){ Text(switch(gamemode){
"40l" => "${record.stats.piecesPlaced} P, ${f2.format(record.stats.pps)} PPS", "40l" => "${record.stats.piecesPlaced} ${t.stats.pieces.short}, ${f2.format(record.stats.pps)} ${t.stats.pps.short}",
"blitz" => "${record.stats.piecesPlaced} P, ${f2.format(record.stats.pps)} PPS", "blitz" => "${record.stats.piecesPlaced} ${t.stats.pieces.short}, ${f2.format(record.stats.pps)} ${t.stats.pps.short}",
"5mblast" => "${record.stats.piecesPlaced} P, ${f2.format(record.stats.pps)} PPS", "5mblast" => "${record.stats.piecesPlaced} ${t.stats.pieces.short}, ${f2.format(record.stats.pps)} ${t.stats.pps.short}",
"zenith" => "${f2.format(record.aggregateStats.apm)} APM, ${f2.format(record.aggregateStats.pps)} PPS", "zenith" => "${f2.format(record.aggregateStats.apm)} ${t.stats.apm.short}, ${f2.format(record.aggregateStats.pps)} ${t.stats.pps.short}",
"zenithex" => "${f2.format(record.aggregateStats.apm)} APM, ${f2.format(record.aggregateStats.pps)} PPS", "zenithex" => "${f2.format(record.aggregateStats.apm)} ${t.stats.apm.short}, ${f2.format(record.aggregateStats.pps)} ${t.stats.pps.short}",
String() => "huh" String() => "huh"
}, style: style, textAlign: TextAlign.right), }, style: style, textAlign: TextAlign.right),
Text(switch(gamemode){ Text(switch(gamemode){
"40l" => "${intf.format(record.stats.finessePercentage*100)}% F, ${record.stats.finesse?.faults} FF", "40l" => "${intf.format(record.stats.finessePercentage*100)}% ${t.stats.finesse.short}, ${record.stats.finesse?.faults} ${t.stats.finesseFaults.short}",
"blitz" => "${intf.format(record.stats.finessePercentage*100)}% F, ${record.stats.finesse?.faults} FF", "blitz" => "${intf.format(record.stats.finessePercentage*100)}% ${t.stats.finesse.short}, ${record.stats.finesse?.faults} ${t.stats.finesseFaults.short}",
"5mblast" => "${intf.format(record.stats.finessePercentage*100)}% F, ${record.stats.finesse?.faults} FF", "5mblast" => "${intf.format(record.stats.finessePercentage*100)}% ${t.stats.finesse.short}, ${record.stats.finesse?.faults} ${t.stats.finesseFaults.short}",
"zenith" => "${f2.format(record.stats.cps)} CSP (${f2.format(record.stats.zenith!.peakrank)} peak)", "zenith" => "${f2.format(record.stats.cps)} ${t.stats.climbSpeed.short} (${f2.format(record.stats.zenith!.peakrank)} ${t.stats.peak})",
"zenithex" => "${f2.format(record.stats.cps)} CSP (${f2.format(record.stats.zenith!.peakrank)} peak)", "zenithex" => "${f2.format(record.stats.cps)} ${t.stats.climbSpeed.short} (${f2.format(record.stats.zenith!.peakrank)} ${t.stats.peak})",
String() => "huh" String() => "huh"
}, style: style, textAlign: TextAlign.right), }, style: style, textAlign: TextAlign.right),
Text(switch(gamemode){ Text(switch(gamemode){
"40l" => "${f2.format(record.stats.kps)} KPS, ${f2.format(record.stats.kpp)} KPP", "40l" => "${f2.format(record.stats.kps)} ${t.stats.kps.short}, ${f2.format(record.stats.kpp)} ${t.stats.kpp.short}",
"blitz" => "${intf.format(record.stats.spp)} SPP, lvl ${record.stats.level}", "blitz" => "${intf.format(record.stats.spp)} ${t.stats.spp.short}, ${t.stats.level.short} ${record.stats.level}",
"5mblast" => "${intf.format(record.stats.spp)} SPP, ${record.stats.lines} L", "5mblast" => "${intf.format(record.stats.spp)} ${t.stats.spp.short}, ${record.stats.lines} ${t.stats.linesShort}",
"zenith" => "${record.stats.kills} KO's, ${getMoreNormalTime(record.stats.finalTime)}", "zenith" => "${record.stats.kills} ${t.stats.kos.short}, ${getMoreNormalTime(record.stats.finalTime)}",
"zenithex" => "${record.stats.kills} KO's, ${getMoreNormalTime(record.stats.finalTime)}", "zenithex" => "${record.stats.kills} ${t.stats.kos.short}, ${getMoreNormalTime(record.stats.finalTime)}",
String() => "huh" String() => "huh"
}, style: style, textAlign: TextAlign.right) }, style: style, textAlign: TextAlign.right)
], ],

View File

@ -1,122 +0,0 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/leaderboard_position.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';
class StatCellNum extends StatelessWidget {
const StatCellNum(
{super.key,
required this.playerStat,
required this.playerStatLabel,
required this.isScreenBig,
this.smallDecimal = false,
this.alertWidgets,
this.fractionDigits,
this.oldPlayerStat,
required this.higherIsBetter,
this.okText, this.alertTitle, this.pos, this.averageStat});
final num playerStat;
final num? oldPlayerStat;
final bool higherIsBetter;
final String playerStatLabel;
final String? okText;
final bool isScreenBig;
final bool smallDecimal;
final String? alertTitle;
final List<Widget>? alertWidgets;
final int? fractionDigits;
final LeaderboardPosition? pos;
final num? averageStat;
Color getStatColor(){
if (averageStat == null) return Colors.white;
num percentile = (higherIsBetter ? playerStat / averageStat! : averageStat! / playerStat).abs();
if (percentile > 1.50) return Colors.purpleAccent;
if (percentile > 1.20) return Colors.blueAccent;
if (percentile > 0.90) return Colors.greenAccent;
if (percentile > 0.70) return Colors.yellowAccent;
return Colors.redAccent;
}
@override
Widget build(BuildContext context) {
NumberFormat f = NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: fractionDigits ?? 0);
NumberFormat comparef = NumberFormat("+#,###.###;-#,###.###")..maximumFractionDigits = fractionDigits ?? 0;
String formated = f.format(playerStat);
List<String> splited = formated.split(f.symbols.DECIMAL_SEP);
return Column(
children: [
RichText(
text: TextSpan(text: splited[0],
children: [
if ((fractionDigits??0) > 0 && splited.elementAtOrNull(1) != null) TextSpan(text: f.symbols.DECIMAL_SEP+splited[1], style: smallDecimal ? const TextStyle(fontFamily: "Eurostile Round", fontSize: 16) : null)
],
style: TextStyle(
fontFamily: "Eurostile Round Extended",
fontSize: isScreenBig ? 32 : 24,
color: getStatColor()
)
)
),
if (oldPlayerStat != null || pos != null) RichText(text: TextSpan(
text: "",
style: const TextStyle(fontFamily: "Eurostile Round", fontSize: 14, color: Colors.grey),
children: [
if (oldPlayerStat != null) TextSpan(text: comparef.format(playerStat - oldPlayerStat!), style: TextStyle(
color: higherIsBetter ?
oldPlayerStat! > playerStat ? Colors.redAccent : Colors.greenAccent :
oldPlayerStat! < playerStat ? Colors.redAccent : Colors.greenAccent
),),
if (oldPlayerStat != null && pos != null) const TextSpan(text: ""),
if (pos != null) TextSpan(text: pos!.position >= 1000 ? "${t.top} ${f2.format(pos!.percentage*100)}%" : "${pos!.position}", style: TextStyle(color: getColorOfRank(pos!.position)))
]
),
),
alertWidgets == null
? Text(
playerStatLabel,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: "Eurostile Round",
fontSize: 16,
height: 1.1
),
)
: TextButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) => AlertDialog(
title: Text(alertTitle??playerStatLabel.replaceAll(RegExp(r'\n'), " "),
style: const TextStyle(
fontFamily: "Eurostile Round Extended")),
content: SingleChildScrollView(
child: ListBody(children: alertWidgets!),
),
actions: <Widget>[
TextButton(
child: Text(okText??"OK"),
onPressed: () {Navigator.of(context).pop();}
)
],
)
);
},
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero)),
child: Text(
playerStatLabel,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: "Eurostile Round",
fontSize: 16,
height: 1.1
),
)),
],
);
}
}

View File

@ -45,7 +45,7 @@ class TLProgress extends StatelessWidget{
children: [ children: [
if (tlData.prevAt > 0) TextSpan(text: "${f0.format(tlData.prevAt)}"), if (tlData.prevAt > 0) TextSpan(text: "${f0.format(tlData.prevAt)}"),
if (tlData.prevAt > 0 && previousRankTRcutoff != null) const TextSpan(text: "\n"), if (tlData.prevAt > 0 && previousRankTRcutoff != null) const TextSpan(text: "\n"),
if (previousRankTRcutoff != null) TextSpan(text: "${f2.format(previousRankTRcutoff)} (${comparef2.format(previousRankTRcutoff!-tlData.tr)}) TR"), if (previousRankTRcutoff != null) TextSpan(text: "${f2.format(previousRankTRcutoff)} (${comparef2.format(previousRankTRcutoff!-tlData.tr)}) ${t.stats.tr.short}"),
if ((tlData.prevAt > 0 || previousRankTRcutoff != null) && previousGlickoCutoff != null) const TextSpan(text: "\n"), if ((tlData.prevAt > 0 || previousRankTRcutoff != null) && previousGlickoCutoff != null) const TextSpan(text: "\n"),
if (previousGlickoCutoff != null) TextSpan(text: (tlData.standing > tlData.prevAt || ((tlData.glicko!-previousGlickoCutoff!)/glickoForWin < 0.5 && tlData.percentileRank != "d")) ? t.demotionOnNextLoss : t.numOfdefeats(losses: f2.format((tlData.glicko!-previousGlickoCutoff!)/glickoForWin)), style: TextStyle(color: (tlData.standing > tlData.prevAt || ((tlData.glicko!-previousGlickoCutoff!)/glickoForWin < 0.5 && tlData.percentileRank != "d")) ? Colors.redAccent : null)) if (previousGlickoCutoff != null) TextSpan(text: (tlData.standing > tlData.prevAt || ((tlData.glicko!-previousGlickoCutoff!)/glickoForWin < 0.5 && tlData.percentileRank != "d")) ? t.demotionOnNextLoss : t.numOfdefeats(losses: f2.format((tlData.glicko!-previousGlickoCutoff!)/glickoForWin)), style: TextStyle(color: (tlData.standing > tlData.prevAt || ((tlData.glicko!-previousGlickoCutoff!)/glickoForWin < 0.5 && tlData.percentileRank != "d")) ? Colors.redAccent : null))
] ]
@ -59,7 +59,7 @@ class TLProgress extends StatelessWidget{
children: [ children: [
if (tlData.nextAt > 0) TextSpan(text: "${f0.format(tlData.nextAt)}"), if (tlData.nextAt > 0) TextSpan(text: "${f0.format(tlData.nextAt)}"),
if (tlData.nextAt > 0 && nextRankTRcutoff != null) const TextSpan(text: "\n"), if (tlData.nextAt > 0 && nextRankTRcutoff != null) const TextSpan(text: "\n"),
if (nextRankTRcutoff != null) TextSpan(text: "${f2.format(nextRankTRcutoff)} (${comparef2.format(nextRankTRcutoff!-tlData.tr)}) TR"), if (nextRankTRcutoff != null) TextSpan(text: "${f2.format(nextRankTRcutoff)} (${comparef2.format(nextRankTRcutoff!-tlData.tr)}) ${t.stats.tr.short}"),
if ((tlData.nextAt > 0 || nextRankTRcutoff != null) && nextRankGlickoCutoff != null) const TextSpan(text: "\n"), if ((tlData.nextAt > 0 || nextRankTRcutoff != null) && nextRankGlickoCutoff != null) const TextSpan(text: "\n"),
if (nextRankGlickoCutoff != null) TextSpan(text: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && ((tlData.rank != "x+" && tlData.rank != "z") || tlData.percentileRank != "x+"))) ? t.promotionOnNextWin : t.numOfVictories(wins: f2.format((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin)), style: TextStyle(color: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && tlData.percentileRank != "x+")) ? Colors.greenAccent : null)) if (nextRankGlickoCutoff != null) TextSpan(text: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && ((tlData.rank != "x+" && tlData.rank != "z") || tlData.percentileRank != "x+"))) ? t.promotionOnNextWin : t.numOfVictories(wins: f2.format((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin)), style: TextStyle(color: (tlData.standing < tlData.nextAt || ((nextRankGlickoCutoff!-tlData.glicko!)/glickoForWin < 0.5 && tlData.percentileRank != "x+")) ? Colors.greenAccent : null))
] ]

View File

@ -50,7 +50,7 @@ class TLRatingThingy extends StatelessWidget{
1 => [ 1 => [
TextSpan(text: formatedGlicko[0], style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), TextSpan(text: formatedGlicko[0], style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
if (formatedGlicko.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedGlicko[1]), if (formatedGlicko.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedGlicko[1]),
TextSpan(text: " Glicko", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)) TextSpan(text: " ${t.stats.glicko.short}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
], ],
2 => [ 2 => [
TextSpan(text: "${t.top} ${formatedPercentile[0]}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), TextSpan(text: "${t.top} ${formatedPercentile[0]}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
@ -60,7 +60,7 @@ class TLRatingThingy extends StatelessWidget{
_ => [ _ => [
TextSpan(text: formatedTR[0], style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)), TextSpan(text: formatedTR[0], style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)),
if (formatedTR.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedTR[1]), if (formatedTR.elementAtOrNull(1) != null) TextSpan(text: decimalSeparator + formatedTR[1]),
TextSpan(text: " TR", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28)) TextSpan(text: " ${t.stats.tr.short}", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28))
], ],
} : [TextSpan(text: "---\n", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28, color: Colors.grey)), TextSpan(text: t.gamesUntilRanked(left: 10-tlData.gamesPlayed), style: const TextStyle(color: Colors.grey, fontSize: 14)),] } : [TextSpan(text: "---\n", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: bigScreen ? 42 : 28, color: Colors.grey)), TextSpan(text: t.gamesUntilRanked(left: 10-tlData.gamesPlayed), style: const TextStyle(color: Colors.grey, fontSize: 14)),]
) )
@ -72,9 +72,9 @@ class TLRatingThingy extends StatelessWidget{
style: DefaultTextStyle.of(context).style, style: DefaultTextStyle.of(context).style,
children: [ children: [
TextSpan(text: switch(prefs.getInt("ratingMode")){ TextSpan(text: switch(prefs.getInt("ratingMode")){
1 => "${fDiff.format(tlData.glicko! - oldTl!.glicko!)} Glicko", 1 => "${fDiff.format(tlData.glicko! - oldTl!.glicko!)} ${t.stats.glicko.short}",
2 => "${fDiff.format(tlData.percentile * 100 - oldTl!.percentile * 100)} %", 2 => "${fDiff.format(tlData.percentile * 100 - oldTl!.percentile * 100)} %",
_ => "${fDiff.format(tlData.tr - oldTl!.tr)} TR" _ => "${fDiff.format(tlData.tr - oldTl!.tr)} ${t.stats.tr.short}"
}, },
style: TextStyle( style: TextStyle(
color: getDifferenceColor(switch(prefs.getInt("ratingMode")){ color: getDifferenceColor(switch(prefs.getInt("ratingMode")){
@ -86,8 +86,8 @@ class TLRatingThingy extends StatelessWidget{
), ),
const TextSpan(text: "", style: TextStyle(color: Colors.grey)), const TextSpan(text: "", style: TextStyle(color: Colors.grey)),
TextSpan(text: switch(prefs.getInt("ratingMode")){ TextSpan(text: switch(prefs.getInt("ratingMode")){
1 => "${fDiff.format(tlData.tr - oldTl!.tr)} TR", 1 => "${fDiff.format(tlData.tr - oldTl!.tr)} ${t.stats.tr.short}",
_ => "${fDiff.format(tlData.glicko! - oldTl!.glicko!)} Glicko" _ => "${fDiff.format(tlData.glicko! - oldTl!.glicko!)} ${t.stats.glicko.short}"
}, },
style: TextStyle( style: TextStyle(
color: getDifferenceColor(switch(prefs.getInt("ratingMode")){ color: getDifferenceColor(switch(prefs.getInt("ratingMode")){
@ -98,7 +98,7 @@ class TLRatingThingy extends StatelessWidget{
), ),
const TextSpan(text: "", style: TextStyle(color: Colors.grey)), const TextSpan(text: "", style: TextStyle(color: Colors.grey)),
TextSpan( TextSpan(
text: "${fDiff.format(tlData.rd! - oldTl!.rd!)} RD", text: "${fDiff.format(tlData.rd! - oldTl!.rd!)} ${t.stats.rd.short}",
style: TextStyle(color: getDifferenceColor(oldTl!.rd! - tlData.rd!)) style: TextStyle(color: getDifferenceColor(oldTl!.rd! - tlData.rd!))
) )
], ],
@ -133,7 +133,7 @@ class TLRatingThingy extends StatelessWidget{
children: [ children: [
if (tlData.standing != -1) TextSpan(text: "${intf.format(tlData.standing)}", style: TextStyle(color: getColorOfRank(tlData.standing))), if (tlData.standing != -1) TextSpan(text: "${intf.format(tlData.standing)}", style: TextStyle(color: getColorOfRank(tlData.standing))),
if (tlData.standing != -1 || tlData.standingLocal != -1) const TextSpan(text: ""), if (tlData.standing != -1 || tlData.standingLocal != -1) const TextSpan(text: ""),
if (tlData.standingLocal != -1) TextSpan(text: "${intf.format(tlData.standingLocal)} local", style: TextStyle(color: getColorOfRank(tlData.standingLocal))), if (tlData.standingLocal != -1) TextSpan(text: "${intf.format(tlData.standingLocal)} ${t.localStanding}", style: TextStyle(color: getColorOfRank(tlData.standingLocal))),
if (tlData.standing != -1 && tlData.standingLocal != -1) const TextSpan(text: ""), if (tlData.standing != -1 && tlData.standingLocal != -1) const TextSpan(text: ""),
TextSpan(text: timestamp(tlData.timestamp)), TextSpan(text: timestamp(tlData.timestamp)),
] ]

View File

@ -26,21 +26,21 @@ class TetraLeagueThingy extends StatelessWidget{
TableRow(children: [ TableRow(children: [
//Text("APM: ", style: TextStyle(fontSize: 21)), //Text("APM: ", style: TextStyle(fontSize: 21)),
Text(intf.format(league.gamesPlayed), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(intf.format(league.gamesPlayed), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Games", style: TextStyle(fontSize: 21)), Text(" ${t.stats.gp.short}", 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 (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)) 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: [ TableRow(children: [
//Text("PPS: ", style: TextStyle(fontSize: 21)), //Text("PPS: ", style: TextStyle(fontSize: 21)),
Text(intf.format(league.gamesWon), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(intf.format(league.gamesWon), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Won", style: TextStyle(fontSize: 21)), Text(" ${t.stats.gw.short}", 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 (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)) 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: [ TableRow(children: [
//Text("VS: ", style: TextStyle(fontSize: 21)), //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("${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"), Tooltip(child: Text(" ${t.stats.glixare.short}", 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 (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)) 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))
]), ]),
@ -75,25 +75,25 @@ class TetraLeagueThingy extends StatelessWidget{
children: [ children: [
TableRow(children: [ TableRow(children: [
Text(league.apm != null ? f2.format(league.apm) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)), Text(league.apm != null ? f2.format(league.apm) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)),
Text(" APM", style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)), Text(" ${t.stats.apm.short}", style: TextStyle(fontSize: 21, color: league.apm != null ? getStatColor(league.apm!, averages?.apm, true) : Colors.grey)),
if (toCompare != null) Text(" (${comparef2.format(league.apm!-toCompare!.apm!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.apm!-toCompare!.apm!))), if (toCompare != null) Text(" (${comparef2.format(league.apm!-toCompare!.apm!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.apm!-toCompare!.apm!))),
if (lbPos != null) Text(lbPos?.apm != null ? (lbPos!.apm!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.apm!.percentage*100)}%)" : " (№ ${lbPos!.apm!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.apm != null ? getColorOfRank(lbPos!.apm!.position) : null)) if (lbPos != null) Text(lbPos?.apm != null ? (lbPos!.apm!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.apm!.percentage*100)}%)" : " (№ ${lbPos!.apm!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.apm != null ? getColorOfRank(lbPos!.apm!.position) : null))
]), ]),
TableRow(children: [ TableRow(children: [
Text(league.pps != null ? f2.format(league.pps) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)), Text(league.pps != null ? f2.format(league.pps) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)),
Text(" PPS", style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)), Text(" ${t.stats.pps.short}", style: TextStyle(fontSize: 21, color: league.pps != null ? getStatColor(league.pps!, averages?.pps, true) : Colors.grey)),
if (toCompare != null) Text(" (${comparef2.format(league.pps!-toCompare!.pps!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.pps!-toCompare!.pps!))), if (toCompare != null) Text(" (${comparef2.format(league.pps!-toCompare!.pps!)})", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: getDifferenceColor(league.pps!-toCompare!.pps!))),
if (lbPos != null) Text(lbPos?.pps != null ? (lbPos!.pps!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.pps!.percentage*100)}%)" : " (№ ${lbPos!.pps!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.pps != null ? getColorOfRank(lbPos!.pps!.position) : null)) if (lbPos != null) Text(lbPos?.pps != null ? (lbPos!.pps!.position >= 1000 ? " (${t.top} ${f2.format(lbPos!.pps!.percentage*100)}%)" : " (№ ${lbPos!.pps!.position})") : "(№ ---)", style: TextStyle(color: lbPos?.pps != null ? getColorOfRank(lbPos!.pps!.position) : null))
]), ]),
TableRow(children: [ TableRow(children: [
Text(league.vs != null ? f2.format(league.vs) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)), Text(league.vs != null ? f2.format(league.vs) : "-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)),
Text(" VS", style: TextStyle(fontSize: 21, color: league.vs != null ? getStatColor(league.vs!, averages?.vs, true) : Colors.grey)), Text(" ${t.stats.vs.short}", 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 (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 (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: [ 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(!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)), Text(" ${t.stats.winrate.short}", 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 (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 (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))
]), ]),

View File

@ -129,7 +129,7 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
top: widget.player.bannerRevision != null ? 120.0 : 40.0, top: widget.player.bannerRevision != null ? 120.0 : 40.0,
left: 160.0, left: 160.0,
child: Tooltip( child: Tooltip(
message: "${widget.player.userId}\n(Click to copy user ID)", message: "${widget.player.userId}\n(${t.copyUserID})",
child: RichText(text: TextSpan(text: widget.player.username, style: TextStyle( child: RichText(text: TextSpan(text: widget.player.username, style: TextStyle(
fontFamily: fontStyle(widget.player.username.length), fontFamily: fontStyle(widget.player.username.length),
fontSize: 28, fontSize: 28,
@ -194,11 +194,11 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AlertDialog( builder: (BuildContext context) => AlertDialog(
title: Text("Level ${intf.format(widget.player.level.floor())}", textAlign: TextAlign.center), title: Text("${t.stats.level.full} ${intf.format(widget.player.level.floor())}", textAlign: TextAlign.center),
content: SingleChildScrollView( content: SingleChildScrollView(
child: ListBody(children: [ child: ListBody(children: [
Text( Text(
"${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2).format(widget.player.xp)} XP", "${NumberFormat.decimalPatternDigits(locale: LocaleSettings.currentLocale.languageCode, decimalDigits: 2).format(widget.player.xp)} ${t.stats.xp.short}",
style: const TextStyle(fontFamily: "Eurostile Round", fontWeight: FontWeight.bold) style: const TextStyle(fontFamily: "Eurostile Round", fontWeight: FontWeight.bold)
), ),
Padding( Padding(
@ -267,7 +267,7 @@ class _UserThingyState extends State<UserThingy> with SingleTickerProviderStateM
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: const Text("OK"), child: Text(t.actions.ok),
onPressed: () {Navigator.of(context).pop();} onPressed: () {Navigator.of(context).pop();}
) )
] ]

View File

@ -45,33 +45,25 @@ class VsGraphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle( return RadarChartTitle(text: t.stats.apm.short, angle: angle, positionPercentageOffset: 0.05);
text: 'APM',
angle: angle,
positionPercentageOffset: 0.05
);
case 1: case 1:
return RadarChartTitle( return RadarChartTitle(text: t.stats.pps.short, angle: angle, positionPercentageOffset: 0.05 );
text: 'PPS',
angle: angle,
positionPercentageOffset: 0.05
);
case 2: case 2:
return RadarChartTitle(text: 'VS', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.vs.short, angle: angle, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'APP', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.app.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 4: case 4:
return RadarChartTitle(text: 'DS/S', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.dss.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 5: case 5:
return RadarChartTitle(text: 'DS/P', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.dsp.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 6: case 6:
return RadarChartTitle(text: 'APP+DS/P', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.appdsp.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 7: case 7:
return RadarChartTitle(text: 'VS/APM', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.vsapm.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 8: case 8:
return RadarChartTitle(text: 'Cheese', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.cheese.short, angle: angle, positionPercentageOffset: 0.05);
case 9: case 9:
return RadarChartTitle(text: 'Gb Eff.', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.gbe.short, angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }
@ -150,13 +142,13 @@ class VsGraphs extends StatelessWidget{
getTitle: (index, angle) { getTitle: (index, angle) {
switch (index) { switch (index) {
case 0: case 0:
return RadarChartTitle(text: 'Opener',angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.opener.short,angle: angle, positionPercentageOffset: 0.05);
case 1: case 1:
return RadarChartTitle(text: 'Stride', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.stride.short, angle: angle, positionPercentageOffset: 0.05);
case 2: case 2:
return RadarChartTitle(text: 'Inf Ds', angle: angle + 180, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.infds.short, angle: angle + 180, positionPercentageOffset: 0.05);
case 3: case 3:
return RadarChartTitle(text: 'Plonk', angle: angle, positionPercentageOffset: 0.05); return RadarChartTitle(text: t.stats.plonk.short, angle: angle, positionPercentageOffset: 0.05);
default: default:
return const RadarChartTitle(text: ''); return const RadarChartTitle(text: '');
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/record_extras.dart'; import 'package:tetra_stats/data_objects/record_extras.dart';
import 'package:tetra_stats/data_objects/record_single.dart'; import 'package:tetra_stats/data_objects/record_single.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/colors_functions.dart'; import 'package:tetra_stats/utils/colors_functions.dart';
import 'package:tetra_stats/utils/numers_formats.dart'; import 'package:tetra_stats/utils/numers_formats.dart';
import 'package:tetra_stats/widgets/gauget_thingy.dart'; import 'package:tetra_stats/widgets/gauget_thingy.dart';
@ -17,40 +18,40 @@ class ZenithThingy extends StatelessWidget{
return [ return [
TableRow(children: [ TableRow(children: [
Text(intf.format(zenith!.stats.kills), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(intf.format(zenith!.stats.kills), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" KO's", style: TextStyle(fontSize: 21)) Text(" ${t.stats.kos.short}", style: TextStyle(fontSize: 21))
]), ]),
TableRow(children: [ TableRow(children: [
Text(zenith!.stats.topBtB.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(zenith!.stats.topBtB.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" B2B", style: TextStyle(fontSize: 21)) Text(" ${t.stats.b2b.short}", style: TextStyle(fontSize: 21))
]), ]),
TableRow(children: [ TableRow(children: [
Text(zenith!.stats.garbage.maxspike_nomult.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(zenith!.stats.garbage.maxspike_nomult.toString(), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Top spike", style: TextStyle(fontSize: 21)) Text(" ${t.stats.spike}", style: TextStyle(fontSize: 21))
]), ]),
if (width <= 600) TableRow(children: [ if (width <= 600) TableRow(children: [
Text(f2.format(zenith!.stats.zenith!.peakrank), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(zenith!.stats.zenith!.peakrank), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" Peak CSP", style: TextStyle(fontSize: 21)), Text(" ${t.stats.peakClimbSpeed.short}", style: TextStyle(fontSize: 21)),
]) ])
]; ];
} }
List<TableRow> noRecordSecondColumn(){ List<TableRow> noRecordSecondColumn(){
return [ return [
const TableRow(children: [ TableRow(children: [
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" KO's", style: TextStyle(fontSize: 21, color: Colors.grey)) Text(" ${t.stats.kos.short}", style: TextStyle(fontSize: 21, color: Colors.grey))
]), ]),
const TableRow(children: [ TableRow(children: [
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" B2B", style: TextStyle(fontSize: 21, color: Colors.grey)) Text(" ${t.stats.b2b.short}", style: TextStyle(fontSize: 21, color: Colors.grey))
]), ]),
const TableRow(children: [ TableRow(children: [
Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("---", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" Top spike", style: TextStyle(fontSize: 21, color: Colors.grey)) Text(" ${t.stats.spike}", style: TextStyle(fontSize: 21, color: Colors.grey))
]), ]),
if (width <= 600) TableRow(children: [ if (width <= 600) TableRow(children: [
Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)), Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)),
const Text(" Peak CSP", style: TextStyle(fontSize: 21, color: Colors.grey)), Text(" ${t.stats.peakClimbSpeed.short}", style: TextStyle(fontSize: 21, color: Colors.grey)),
]) ])
]; ];
} }
@ -102,26 +103,26 @@ class ZenithThingy extends StatelessWidget{
children: [ children: [
TableRow(children: [ TableRow(children: [
Text(f2.format(zenith!.aggregateStats.apm), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(zenith!.aggregateStats.apm), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" APM", style: TextStyle(fontSize: 21)), Text(" ${t.stats.apm.short}", style: TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(f2.format(zenith!.aggregateStats.pps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(zenith!.aggregateStats.pps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" PPS", style: TextStyle(fontSize: 21)), Text(" ${t.stats.pps.short}", style: TextStyle(fontSize: 21)),
]), ]),
TableRow(children: [ TableRow(children: [
Text(f2.format(zenith!.aggregateStats.vs), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(zenith!.aggregateStats.vs), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" VS", style: TextStyle(fontSize: 21)), Text(" ${t.stats.vs.short}", style: TextStyle(fontSize: 21)),
]), ]),
if (width <= 600) TableRow(children: [ if (width <= 600) TableRow(children: [
Text(f2.format(zenith!.stats.cps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)), Text(f2.format(zenith!.stats.cps), textAlign: TextAlign.right, style: const TextStyle(fontSize: 21)),
const Text(" CSP", style: TextStyle(fontSize: 21)), Text(" ${t.stats.climbSpeed.short}", style: TextStyle(fontSize: 21)),
]), ]),
if (width <= 400) ...secondColumn().reversed if (width <= 400) ...secondColumn().reversed
], ],
), ),
), ),
), ),
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 > 600) GaugetThingy(value: zenith!.stats.cps, min: 0, max: 12, tickInterval: 3, label: t.stats.climbSpeed.gaugetTitle, subString: "${t.stats.peak}: ${f2.format(zenith!.stats.zenith!.peakrank)}", sideSize: 128, fractionDigits: 2, moreIsBetter: true),
if (width > 400) Expanded( if (width > 400) Expanded(
child: Center( child: Center(
child: Table( child: Table(
@ -138,27 +139,27 @@ class ZenithThingy extends StatelessWidget{
child: Table( child: Table(
defaultColumnWidth: IntrinsicColumnWidth(), defaultColumnWidth: IntrinsicColumnWidth(),
children: [ children: [
const TableRow(children: [ TableRow(children: [
Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" APM", style: TextStyle(fontSize: 21, color: Colors.grey)), Text(" ${t.stats.apm.short}", style: TextStyle(fontSize: 21, color: Colors.grey)),
]), ]),
const TableRow(children: [ TableRow(children: [
Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" PPS", style: TextStyle(fontSize: 21, color: Colors.grey)), Text(" ${t.stats.pps.short}", style: TextStyle(fontSize: 21, color: Colors.grey)),
]), ]),
const TableRow(children: [ TableRow(children: [
Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)), Text("-.--", textAlign: TextAlign.right, style: TextStyle(fontSize: 21, color: Colors.grey)),
Text(" VS", style: TextStyle(fontSize: 21, color: Colors.grey)), Text(" ${t.stats.vs.short}", style: TextStyle(fontSize: 21, color: Colors.grey)),
]), ]),
if (width <= 600) TableRow(children: [ if (width <= 600) TableRow(children: [
Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)), Text("-.--", textAlign: TextAlign.right, style: const TextStyle(fontSize: 21, color: Colors.grey)),
const Text(" CSP", style: TextStyle(fontSize: 21, color: Colors.grey)), Text(" ${t.stats.climbSpeed.short}", style: TextStyle(fontSize: 21, color: Colors.grey)),
]) ])
], ],
), ),
), ),
), ),
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 > 600) GaugetThingy(value: null, min: 0, max: 12, tickInterval: 3, label: t.stats.climbSpeed.gaugetTitle, subString: "${t.stats.peak}: ---", sideSize: 128, fractionDigits: 0, moreIsBetter: true),
if (width > 400) Expanded( if (width > 400) Expanded(
child: Center( child: Center(
child: Table( child: Table(

View File

@ -67,12 +67,33 @@
"obtainDate": "Obtained ${date}", "obtainDate": "Obtained ${date}",
"assignedManualy": "That badge was assigned manualy by TETR.IO admins", "assignedManualy": "That badge was assigned manualy by TETR.IO admins",
"distinguishment": "Distinguishment", "distinguishment": "Distinguishment",
"bigRedBanned": "BANNED", "banned": "Banned",
"normalBanned": "Banned", "bannedSubtext": "Bans are placed when TETR.IO rules or terms of service are broken",
"bigRedBadStanding": "BAD STANDING", "badStanding": "Bad standing",
"badStandingSubtext": "One or more recent bans on record",
"botAccount": "Bot account",
"botAccountSubtext": "Operated by $botMaintainers",
"copiedToClipboard": "Copied to clipboard!", "copiedToClipboard": "Copied to clipboard!",
"bio": "Bio", "bio": "Bio",
"news": "News", "news": "News",
"matchResult": {
"victory": "Victory",
"defeat": "Defeat",
"tie": "Tie",
"dqvictory": "Opponent was DQ'ed",
"dqdefeat": "Disqualified",
"nocontest": "No Contest",
"nullified": "Nullified"
},
"distinguishments": {
"noHeader": "Header is missing",
"noFooter": "Footer is missing",
"twc": "TETR.IO World Champion",
"twcYear": "$year TETR.IO World Championship"
},
"newsEntrys":{
"leaderboard": "Got № $rank on $gametype"
},
"newsParts":{ "newsParts":{
"leaderboardStart": "Got ", "leaderboardStart": "Got ",
"leaderboardMiddle": "on ", "leaderboardMiddle": "on ",
@ -90,6 +111,9 @@
}, },
"copyUserID": "Click to copy user ID", "copyUserID": "Click to copy user ID",
"searchHint": "Username or ID", "searchHint": "Username or ID",
"navMenu": "Navigation menu",
"navMenuTooltip": "Open navigation menu",
"refresh": "Refresh data",
"searchButton": "Search", "searchButton": "Search",
"trackedPlayers": "Tracked Players", "trackedPlayers": "Tracked Players",
"standing": "Standing", "standing": "Standing",
@ -181,6 +205,7 @@
"trRange": "TR Range", "trRange": "TR Range",
"supposedToBe": "Supposed to be", "supposedToBe": "Supposed to be",
"gap": "$value gap", "gap": "$value gap",
"trGap": "$value TR gap",
"deflationGap": "Deflation gap", "deflationGap": "Deflation gap",
"inflationGap": "Inflation gap", "inflationGap": "Inflation gap",
"LBposRange": "LB pos range", "LBposRange": "LB pos range",
@ -192,6 +217,9 @@
"minimums": "Minimums", "minimums": "Minimums",
"maximums": "Maximums" "maximums": "Maximums"
}, },
"stateView": {
"title": "State from $date"
},
"tlMatchView": { "tlMatchView": {
"match": "Match", "match": "Match",
"vs": "vs", "vs": "vs",
@ -245,13 +273,57 @@
"ar": "Acievement Points", "ar": "Acievement Points",
"fullTLnote": "Heavy, but allows you to sort players by their stats and filter them by ranks" "fullTLnote": "Heavy, but allows you to sort players by their stats and filter them by ranks"
}, },
"savedDataDestination": {
"title": "Saved Data",
"tip": "Select nickname on the left to see data assosiated with it",
"seasonTLstates": "S$s TL States",
"TLrecords": "TL Records"
},
"settingsDestination": { "settingsDestination": {
"title": "Settings", "title": "Settings",
"timestamps": "Timestamps", "general": "General",
"timestampsDescription": "You can choose, in which way timestamps shows time", "customization": "Custonization",
"database": "Local database",
"checking": "Checking...",
"enterToSubmit": "Press Enter to submit",
"account": "Your account in TETR.IO",
"accountDescription": "Stats of that player will be loaded initially right after launching this app. By default it loads my (dan63) stats. To change that, enter your nickname here.",
"done": "Done!",
"noSuchAccount": "No such account",
"language": "Language",
"languageDescription": "Tetra Stats was translated on $languages. By default, app will pick your system one or English, if locale of your system isn't avaliable.",
"languages(plural)": {
"zero": "zero languages",
"one": "$n language",
"two": "$n languages",
"few": "$n languages",
"many": "$n languages",
"other": "$n languages"
},
"updateInTheBackground": "Update data in the background",
"updateInTheBackgroundDescription": "If on, Tetra Stats will attempt to retrieve new info once cache expires. Usually that happen every 5 minutes",
"compareStats": "Compare TL stats with rank averages",
"compareStatsDescription": "If on, Tetra Stats will provide additional metrics, which allow you to compare yourself with average player on your rank. The way you'll see it — stats will be highlited with corresponding color, hover over them with cursor for more info.",
"showPosition": "Show position on leaderboard by stats",
"showPositionDescription": "This can take some time (and traffic) to load, but will allow you to see your position on the leaderboard, sorted by a stat",
"accentColor": "Accent color",
"accentColorDescription": "That color is seen across this app and usually highlites interactive UI elements.",
"accentColorModale": "Pick an accent color",
"timestamps": "Timestamps format",
"timestampsDescriptionPart1": "You can choose, in which way timestamps shows time. By default, they show time in GMT timezone, formatted according to chosen locale, example: $d.",
"timestampsDescriptionPart2": "There is also:\n• Locale formatted in your timezone: $y\n• Relative timestamp: $r",
"timestampsAbsoluteGMT": "Absolute (GMT)", "timestampsAbsoluteGMT": "Absolute (GMT)",
"timestampsAbsoluteLocalTime": "Absolute (Your timezone)", "timestampsAbsoluteLocalTime": "Absolute (Your timezone)",
"timestampsRelative": "Relative", "timestampsRelative": "Relative",
"sheetbotLikeGraphs": "Sheetbot-like behavior for radar graphs",
"sheetbotLikeGraphsDescription": "Altough it was considered by me, that the way graphs work in SheetBot is not very correct, some people were confused to see, that -0.5 stride dosen't look the way it looks on SheetBot graph. Hence, he we are: if this toggle is on, points on the graphs can appear on the opposite half of the graph if value is negative.",
"oskKagariGimmick": "Osk-Kagari gimmick",
"oskKagariGimmickDescription": "If on, instead of osk's rank, :kagari: will be rendered.",
"bytesOfDataStored": "of data stored",
"TLrecordsSaved": "Tetra League records saved",
"TLplayerstatesSaved": "Tetra League playerstates saved",
"fixButton": "Fix",
"compressButton": "Compress",
"exportDB": "Export local database", "exportDB": "Export local database",
"desktopExportAlertTitle": "Desktop export", "desktopExportAlertTitle": "Desktop export",
"desktopExportText": "It seems like you using this app on desktop. Check your documents folder, you should find \"TetraStats.db\". Copy it somewhere", "desktopExportText": "It seems like you using this app on desktop. Check your documents folder, you should find \"TetraStats.db\". Copy it somewhere",
@ -280,6 +352,12 @@
"stats": "Stats Calculator", "stats": "Stats Calculator",
"damage": "Damage Calculator" "damage": "Damage Calculator"
}, },
"firstTimeView": {
"welcome": "Welcome to Tetra Stats",
"description": "Service, that allows you to keep track of various statistics for TETR.IO",
"nicknameQuestion": "What's your nickname?",
"inpuntHint": "Type it here... (3-16 symbols)"
},
"aboutView": { "aboutView": {
"title": "About Tetra Stats", "title": "About Tetra Stats",
"about": "Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with \"Track\" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity.", "about": "Tetra Stats is a service, that works with TETR.IO Tetra Channel API, providing data from it and calculating some addtitional metrics, based on this data. Service allows user to track their progress in Tetra League with \"Track\" function, which records every Tetra League change into local database (not automatically, you have to visit service from time to time), so these changes could be looked through graphs.\n\nBeanserver blaster is a part of a Tetra Stats, that decoupled into a serverside script. It provides full Tetra League leaderboard, allowing Tetra Stats to sort leaderboard by any metric and build scatter chart, that allows user to analyse Tetra League trends. It also provides history of Tetra League ranks cutoffs, which can be viewed by user via graph as well.\n\nThere is a plans to add replay analysis and tournaments history, so stay tuned!\n\nService is not associated with TETR.IO or osk in any capacity.",
@ -475,6 +553,7 @@
"piecesWithPerfectFinesse": "Placed with perfect finesse", "piecesWithPerfectFinesse": "Placed with perfect finesse",
"score": "Score", "score": "Score",
"lines": "Lines", "lines": "Lines",
"linesShort": "L",
"pcs": "Perfect Clears", "pcs": "Perfect Clears",
"holds": "Holds", "holds": "Holds",
"spike": "Top Spike", "spike": "Top Spike",
@ -486,6 +565,7 @@
"sent": "Sent", "sent": "Sent",
"received": "Received", "received": "Received",
"placement": "Placement", "placement": "Placement",
"peak": "peak",
"qpWithMods(plural)": { "qpWithMods(plural)": {
"one": "With 1 mod", "one": "With 1 mod",
"two": "With $n mods", "two": "With $n mods",