News widget was redone for the sake of i18n

This commit is contained in:
dan63047 2024-12-05 17:13:08 +03:00
parent 6761be0321
commit e46ad49e09
6 changed files with 110 additions and 88 deletions

View File

@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang` /// To regenerate, run: `dart run slang`
/// ///
/// Locales: 1 /// Locales: 1
/// Strings: 756 /// Strings: 750
/// ///
/// Built on 2024-12-02 at 19:52 UTC /// Built on 2024-12-04 at 18:43 UTC
// coverage:ignore-file // coverage:ignore-file
// ignore_for_file: type=lint // ignore_for_file: type=lint
@ -209,8 +209,8 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
String get news => 'News'; String get news => 'News';
late final _StringsMatchResultEn matchResult = _StringsMatchResultEn._(_root); late final _StringsMatchResultEn matchResult = _StringsMatchResultEn._(_root);
late final _StringsDistinguishmentsEn distinguishments = _StringsDistinguishmentsEn._(_root); late final _StringsDistinguishmentsEn distinguishments = _StringsDistinguishmentsEn._(_root);
late final _StringsNewsEntrysEn newsEntrys = _StringsNewsEntrysEn._(_root); late final _StringsNewsEntriesEn newsEntries = _StringsNewsEntriesEn._(_root);
late final _StringsNewsPartsEn newsParts = _StringsNewsPartsEn._(_root); String rankupMiddle({required Object r}) => '${r} rank';
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 navMenu => 'Navigation menu';
@ -577,36 +577,47 @@ class _StringsDistinguishmentsEn {
String twcYear({required Object year}) => '${year} TETR.IO World Championship'; String twcYear({required Object year}) => '${year} TETR.IO World Championship';
} }
// Path: newsEntrys // Path: newsEntries
class _StringsNewsEntrysEn { class _StringsNewsEntriesEn {
_StringsNewsEntrysEn._(this._root); _StringsNewsEntriesEn._(this._root);
final Translations _root; // ignore: unused_field final Translations _root; // ignore: unused_field
// Translations // Translations
String leaderboard({required Object rank, required Object gametype}) => 'Got № ${rank} on ${gametype}'; TextSpan leaderboard({required InlineSpan rank, required InlineSpan gametype}) => TextSpan(children: [
} const TextSpan(text: 'Got № '),
rank,
// Path: newsParts const TextSpan(text: ' in '),
class _StringsNewsPartsEn { gametype,
_StringsNewsPartsEn._(this._root); ]);
TextSpan personalbest({required InlineSpan gametype, required InlineSpan pb}) => TextSpan(children: [
final Translations _root; // ignore: unused_field const TextSpan(text: 'Got a new PB in '),
gametype,
// Translations const TextSpan(text: ' of '),
String get leaderboardStart => 'Got '; pb,
String get leaderboardMiddle => 'on '; ]);
String get personalbest => 'Got a new PB in '; TextSpan badge({required InlineSpan badge}) => TextSpan(children: [
String get personalbestMiddle => 'of '; const TextSpan(text: 'Obtained a '),
String get badgeStart => 'Obtained a '; badge,
String get badgeEnd => 'badge'; const TextSpan(text: ' badge'),
String get rankupStart => 'Obtained '; ]);
String rankupMiddle({required Object r}) => '${r} rank '; TextSpan rankup({required InlineSpan rank}) => TextSpan(children: [
String get rankupEnd => 'in Tetra League'; const TextSpan(text: 'Obtained '),
String get tetoSupporter => 'TETR.IO supporter'; rank,
String get supporterStart => 'Become a '; const TextSpan(text: ' in Tetra League'),
String get supporterGiftStart => 'Received the gift of '; ]);
String unknownNews({required Object type}) => 'Unknown news of type ${type}'; TextSpan supporter({required InlineSpanBuilder s}) => TextSpan(children: [
const TextSpan(text: 'Became a '),
s('TETR.IO supporter'),
]);
TextSpan supporter_gift({required InlineSpanBuilder s}) => TextSpan(children: [
const TextSpan(text: 'Received the gift of '),
s('TETR.IO supporter'),
]);
TextSpan unknown({required InlineSpan type}) => TextSpan(children: [
const TextSpan(text: 'Unknown news of type '),
type,
]);
} }
// Path: snackBarMessages // Path: snackBarMessages
@ -1064,7 +1075,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 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',
@ -1719,20 +1730,41 @@ extension on Translations {
case 'distinguishments.noFooter': return 'Footer is missing'; case 'distinguishments.noFooter': return 'Footer is missing';
case 'distinguishments.twc': return 'TETR.IO World Champion'; case 'distinguishments.twc': return 'TETR.IO World Champion';
case 'distinguishments.twcYear': return ({required Object year}) => '${year} TETR.IO World Championship'; 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 'newsEntries.leaderboard': return ({required InlineSpan rank, required InlineSpan gametype}) => TextSpan(children: [
case 'newsParts.leaderboardStart': return 'Got '; const TextSpan(text: 'Got № '),
case 'newsParts.leaderboardMiddle': return 'on '; rank,
case 'newsParts.personalbest': return 'Got a new PB in '; const TextSpan(text: ' in '),
case 'newsParts.personalbestMiddle': return 'of '; gametype,
case 'newsParts.badgeStart': return 'Obtained a '; ]);
case 'newsParts.badgeEnd': return 'badge'; case 'newsEntries.personalbest': return ({required InlineSpan gametype, required InlineSpan pb}) => TextSpan(children: [
case 'newsParts.rankupStart': return 'Obtained '; const TextSpan(text: 'Got a new PB in '),
case 'newsParts.rankupMiddle': return ({required Object r}) => '${r} rank '; gametype,
case 'newsParts.rankupEnd': return 'in Tetra League'; const TextSpan(text: ' of '),
case 'newsParts.tetoSupporter': return 'TETR.IO supporter'; pb,
case 'newsParts.supporterStart': return 'Become a '; ]);
case 'newsParts.supporterGiftStart': return 'Received the gift of '; case 'newsEntries.badge': return ({required InlineSpan badge}) => TextSpan(children: [
case 'newsParts.unknownNews': return ({required Object type}) => 'Unknown news of type ${type}'; const TextSpan(text: 'Obtained a '),
badge,
const TextSpan(text: ' badge'),
]);
case 'newsEntries.rankup': return ({required InlineSpan rank}) => TextSpan(children: [
const TextSpan(text: 'Obtained '),
rank,
const TextSpan(text: ' in Tetra League'),
]);
case 'newsEntries.supporter': return ({required InlineSpanBuilder s}) => TextSpan(children: [
const TextSpan(text: 'Became a '),
s('TETR.IO supporter'),
]);
case 'newsEntries.supporter_gift': return ({required InlineSpanBuilder s}) => TextSpan(children: [
const TextSpan(text: 'Received the gift of '),
s('TETR.IO supporter'),
]);
case 'newsEntries.unknown': return ({required InlineSpan type}) => TextSpan(children: [
const TextSpan(text: 'Unknown news of type '),
type,
]);
case 'rankupMiddle': return ({required Object r}) => '${r} rank';
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 'navMenu': return 'Navigation menu';
@ -2068,7 +2100,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.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

@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:ffi';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';

View File

@ -140,6 +140,7 @@ class _MainState extends State<MainView> with TickerProviderStateMixin {
void dispose() { void dispose() {
controller.dispose(); controller.dispose();
_searchController.dispose(); _searchController.dispose();
_backgroundUpdate.cancel();
super.dispose(); super.dispose();
} }

View File

@ -1,12 +1,9 @@
import 'dart:io';
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/data_objects/tetrio_constants.dart'; import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/utils/text_shadow.dart';
import 'package:window_manager/window_manager.dart';
late String oldWindowTitle; late String oldWindowTitle;
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode); final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode);

View File

@ -20,11 +20,11 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.leaderboardStart,
children: [ children: [
TextSpan(text: "${news.data["rank"]} ", style: const TextStyle(fontWeight: FontWeight.bold)), t.newsEntries.leaderboard(
TextSpan(text: t.newsParts.leaderboardMiddle), rank: TextSpan(text: news.data["rank"], style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: "${t.gamemodes[news.data["gametype"]]}", style: const TextStyle(fontWeight: FontWeight.bold)), gametype: TextSpan(text: t.gamemodes[news.data["gametype"]], style: const TextStyle(fontWeight: FontWeight.bold))
)
] ]
) )
), ),
@ -35,11 +35,10 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.personalbest,
children: [ children: [
TextSpan(text: "${t.gamemodes[news.data["gametype"]]} ", style: const TextStyle(fontWeight: FontWeight.bold)), t.newsEntries.personalbest(
TextSpan(text: t.newsParts.personalbestMiddle), gametype: TextSpan(text: t.gamemodes[news.data["gametype"]], style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: switch (news.data["gametype"]){ pb: TextSpan(text: switch (news.data["gametype"]){
"blitz" => NumberFormat.decimalPattern().format(news.data["result"]), "blitz" => NumberFormat.decimalPattern().format(news.data["result"]),
"40l" => get40lTime((news.data["result"]*1000).floor()), "40l" => get40lTime((news.data["result"]*1000).floor()),
"5mblast" => get40lTime((news.data["result"]*1000).floor()), "5mblast" => get40lTime((news.data["result"]*1000).floor()),
@ -48,7 +47,8 @@ class NewsThingy extends StatelessWidget{
_ => "unknown" _ => "unknown"
}, },
style: const TextStyle(fontWeight: FontWeight.bold) style: const TextStyle(fontWeight: FontWeight.bold)
), )
)
] ]
) )
), ),
@ -67,10 +67,8 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.badgeStart,
children: [ children: [
TextSpan(text: "${news.data["label"]} ", style: const TextStyle(fontWeight: FontWeight.bold)), t.newsEntries.badge(badge: TextSpan(text: news.data["label"], style: const TextStyle(fontWeight: FontWeight.bold)))
TextSpan(text: t.newsParts.badgeEnd)
] ]
) )
), ),
@ -89,10 +87,8 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.rankupStart,
children: [ children: [
TextSpan(text: t.newsParts.rankupMiddle(r: news.data["rank"].toString().toUpperCase()), style: const TextStyle(fontWeight: FontWeight.bold)), t.newsEntries.rankup(rank: TextSpan(text: t.rankupMiddle(r: news.data["rank"].toString().toUpperCase()), style: const TextStyle(fontWeight: FontWeight.bold)))
TextSpan(text: t.newsParts.rankupEnd)
] ]
) )
), ),
@ -111,9 +107,8 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.supporterStart,
children: [ children: [
TextSpan(text: t.newsParts.tetoSupporter, style: const TextStyle(fontWeight: FontWeight.bold)) t.newsEntries.supporter(s: (p0) => TextSpan(text: p0, style: const TextStyle(fontWeight: FontWeight.bold)))
] ]
) )
), ),
@ -132,9 +127,8 @@ class NewsThingy extends StatelessWidget{
title: RichText( title: RichText(
text: TextSpan( text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white), style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.supporterGiftStart,
children: [ children: [
TextSpan(text: t.newsParts.tetoSupporter, style: const TextStyle(fontWeight: FontWeight.bold)) t.newsEntries.supporter_gift(s: (p0) => TextSpan(text: p0, style: const TextStyle(fontWeight: FontWeight.bold)))
] ]
) )
), ),
@ -150,7 +144,14 @@ class NewsThingy extends StatelessWidget{
); );
default: // if type is unknown default: // if type is unknown
return ListTile( return ListTile(
title: Text(t.newsParts.unknownNews(type: news.type)), title: RichText(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
children: [
t.newsEntries.unknown(type: TextSpan(text: news.type, style: const TextStyle(fontWeight: FontWeight.bold)))
]
)
),
subtitle: Text(timestamp(news.timestamp)), subtitle: Text(timestamp(news.timestamp)),
); );
} }

View File

@ -91,24 +91,16 @@
"twc": "TETR.IO World Champion", "twc": "TETR.IO World Champion",
"twcYear": "$year TETR.IO World Championship" "twcYear": "$year TETR.IO World Championship"
}, },
"newsEntrys":{ "newsEntries":{
"leaderboard": "Got № $rank on $gametype" "leaderboard(rich)": "Got № $rank in $gametype",
}, "personalbest(rich)": "Got a new PB in $gametype of $pb",
"newsParts":{ "badge(rich)": "Obtained a $badge badge",
"leaderboardStart": "Got ", "rankup(rich)": "Obtained $rank in Tetra League",
"leaderboardMiddle": "on ", "supporter(rich)": "Became a ${s(TETR.IO supporter)}",
"personalbest": "Got a new PB in ", "supporter_gift(rich)": "Received the gift of ${s(TETR.IO supporter)}",
"personalbestMiddle": "of ", "unknown(rich)": "Unknown news of type $type"
"badgeStart": "Obtained a ",
"badgeEnd": "badge",
"rankupStart": "Obtained ",
"rankupMiddle": "${r} rank ",
"rankupEnd": "in Tetra League",
"tetoSupporter": "TETR.IO supporter",
"supporterStart": "Become a ",
"supporterGiftStart": "Received the gift of ",
"unknownNews": "Unknown news of type ${type}"
}, },
"rankupMiddle": "${r} rank",
"copyUserID": "Click to copy user ID", "copyUserID": "Click to copy user ID",
"searchHint": "Username or ID", "searchHint": "Username or ID",
"navMenu": "Navigation menu", "navMenu": "Navigation menu",
@ -565,7 +557,7 @@
"sent": "Sent", "sent": "Sent",
"received": "Received", "received": "Received",
"placement": "Placement", "placement": "Placement",
"peak": "peak", "peak": "Peak",
"qpWithMods(plural)": { "qpWithMods(plural)": {
"one": "With 1 mod", "one": "With 1 mod",
"two": "With $n mods", "two": "With $n mods",