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`
///
/// 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
// ignore_for_file: type=lint
@ -209,8 +209,8 @@ class Translations implements BaseTranslations<AppLocale, Translations> {
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 _StringsNewsEntriesEn newsEntries = _StringsNewsEntriesEn._(_root);
String rankupMiddle({required Object r}) => '${r} rank';
String get copyUserID => 'Click to copy user ID';
String get searchHint => 'Username or ID';
String get navMenu => 'Navigation menu';
@ -577,36 +577,47 @@ class _StringsDistinguishmentsEn {
String twcYear({required Object year}) => '${year} TETR.IO World Championship';
}
// Path: newsEntrys
class _StringsNewsEntrysEn {
_StringsNewsEntrysEn._(this._root);
// Path: newsEntries
class _StringsNewsEntriesEn {
_StringsNewsEntriesEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String leaderboard({required Object rank, required Object gametype}) => 'Got № ${rank} on ${gametype}';
}
// Path: newsParts
class _StringsNewsPartsEn {
_StringsNewsPartsEn._(this._root);
final Translations _root; // ignore: unused_field
// Translations
String get leaderboardStart => 'Got ';
String get leaderboardMiddle => 'on ';
String get personalbest => 'Got a new PB in ';
String get personalbestMiddle => 'of ';
String get badgeStart => 'Obtained a ';
String get badgeEnd => 'badge';
String get rankupStart => 'Obtained ';
String rankupMiddle({required Object r}) => '${r} rank ';
String get rankupEnd => 'in Tetra League';
String get tetoSupporter => 'TETR.IO supporter';
String get supporterStart => 'Become a ';
String get supporterGiftStart => 'Received the gift of ';
String unknownNews({required Object type}) => 'Unknown news of type ${type}';
TextSpan leaderboard({required InlineSpan rank, required InlineSpan gametype}) => TextSpan(children: [
const TextSpan(text: 'Got № '),
rank,
const TextSpan(text: ' in '),
gametype,
]);
TextSpan personalbest({required InlineSpan gametype, required InlineSpan pb}) => TextSpan(children: [
const TextSpan(text: 'Got a new PB in '),
gametype,
const TextSpan(text: ' of '),
pb,
]);
TextSpan badge({required InlineSpan badge}) => TextSpan(children: [
const TextSpan(text: 'Obtained a '),
badge,
const TextSpan(text: ' badge'),
]);
TextSpan rankup({required InlineSpan rank}) => TextSpan(children: [
const TextSpan(text: 'Obtained '),
rank,
const TextSpan(text: ' in Tetra League'),
]);
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
@ -1064,7 +1075,7 @@ class _StringsStatsEn {
String get sent => 'Sent';
String get received => 'Received';
String get placement => 'Placement';
String get peak => 'peak';
String get peak => 'Peak';
String qpWithMods({required num n}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(n,
one: 'With 1 mod',
two: 'With ${n} mods',
@ -1719,20 +1730,41 @@ extension on Translations {
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.leaderboardMiddle': return 'on ';
case 'newsParts.personalbest': return 'Got a new PB in ';
case 'newsParts.personalbestMiddle': return 'of ';
case 'newsParts.badgeStart': return 'Obtained a ';
case 'newsParts.badgeEnd': return 'badge';
case 'newsParts.rankupStart': return 'Obtained ';
case 'newsParts.rankupMiddle': return ({required Object r}) => '${r} rank ';
case 'newsParts.rankupEnd': return 'in Tetra League';
case 'newsParts.tetoSupporter': return 'TETR.IO supporter';
case 'newsParts.supporterStart': return 'Become a ';
case 'newsParts.supporterGiftStart': return 'Received the gift of ';
case 'newsParts.unknownNews': return ({required Object type}) => 'Unknown news of type ${type}';
case 'newsEntries.leaderboard': return ({required InlineSpan rank, required InlineSpan gametype}) => TextSpan(children: [
const TextSpan(text: 'Got № '),
rank,
const TextSpan(text: ' in '),
gametype,
]);
case 'newsEntries.personalbest': return ({required InlineSpan gametype, required InlineSpan pb}) => TextSpan(children: [
const TextSpan(text: 'Got a new PB in '),
gametype,
const TextSpan(text: ' of '),
pb,
]);
case 'newsEntries.badge': return ({required InlineSpan badge}) => TextSpan(children: [
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 'searchHint': return 'Username or ID';
case 'navMenu': return 'Navigation menu';
@ -2068,7 +2100,7 @@ extension on Translations {
case 'stats.sent': return 'Sent';
case 'stats.received': return 'Received';
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,
one: 'With 1 mod',
two: 'With ${n} mods',

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:math';
import 'package:flutter/material.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() {
controller.dispose();
_searchController.dispose();
_backgroundUpdate.cancel();
super.dispose();
}

View File

@ -1,12 +1,9 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:tetra_stats/data_objects/tetrio_constants.dart';
import 'package:tetra_stats/gen/strings.g.dart';
import 'package:tetra_stats/utils/relative_timestamps.dart';
import 'package:tetra_stats/utils/text_shadow.dart';
import 'package:window_manager/window_manager.dart';
late String oldWindowTitle;
final DateFormat dateFormat = DateFormat.yMMMd(LocaleSettings.currentLocale.languageCode);

View File

@ -20,11 +20,11 @@ class NewsThingy extends StatelessWidget{
title: RichText(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.leaderboardStart,
children: [
TextSpan(text: "${news.data["rank"]} ", style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.leaderboardMiddle),
TextSpan(text: "${t.gamemodes[news.data["gametype"]]}", style: const TextStyle(fontWeight: FontWeight.bold)),
t.newsEntries.leaderboard(
rank: TextSpan(text: news.data["rank"], 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(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.personalbest,
children: [
TextSpan(text: "${t.gamemodes[news.data["gametype"]]} ", style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.personalbestMiddle),
TextSpan(text: switch (news.data["gametype"]){
t.newsEntries.personalbest(
gametype: TextSpan(text: t.gamemodes[news.data["gametype"]], style: const TextStyle(fontWeight: FontWeight.bold)),
pb: TextSpan(text: switch (news.data["gametype"]){
"blitz" => NumberFormat.decimalPattern().format(news.data["result"]),
"40l" => get40lTime((news.data["result"]*1000).floor()),
"5mblast" => get40lTime((news.data["result"]*1000).floor()),
@ -48,7 +47,8 @@ class NewsThingy extends StatelessWidget{
_ => "unknown"
},
style: const TextStyle(fontWeight: FontWeight.bold)
),
)
)
]
)
),
@ -67,10 +67,8 @@ class NewsThingy extends StatelessWidget{
title: RichText(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.badgeStart,
children: [
TextSpan(text: "${news.data["label"]} ", style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.badgeEnd)
t.newsEntries.badge(badge: TextSpan(text: news.data["label"], style: const TextStyle(fontWeight: FontWeight.bold)))
]
)
),
@ -89,10 +87,8 @@ class NewsThingy extends StatelessWidget{
title: RichText(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.rankupStart,
children: [
TextSpan(text: t.newsParts.rankupMiddle(r: news.data["rank"].toString().toUpperCase()), style: const TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: t.newsParts.rankupEnd)
t.newsEntries.rankup(rank: TextSpan(text: t.rankupMiddle(r: news.data["rank"].toString().toUpperCase()), style: const TextStyle(fontWeight: FontWeight.bold)))
]
)
),
@ -111,9 +107,8 @@ class NewsThingy extends StatelessWidget{
title: RichText(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.supporterStart,
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(
text: TextSpan(
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16, color: Colors.white),
text: t.newsParts.supporterGiftStart,
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
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)),
);
}

View File

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