Peak TR + Markdown in bio + icons in news
Also small redesign, window title now changes, illegally downloaded badges and other small things
|
@ -639,7 +639,6 @@ class EstTr {
|
|||
final double _apm;
|
||||
final double _pps;
|
||||
final double _vs;
|
||||
final double _rd;
|
||||
final double _app;
|
||||
final double _dss;
|
||||
final double _dsp;
|
||||
|
@ -649,15 +648,11 @@ class EstTr {
|
|||
late double statrank;
|
||||
late double estglicko;
|
||||
|
||||
EstTr(this._apm, this._pps, this._vs, this._rd, this._app, this._dss, this._dsp, this._gbe) {
|
||||
EstTr(this._apm, this._pps, this._vs, this._app, this._dss, this._dsp, this._gbe) {
|
||||
srarea = (_apm * 0) + (_pps * 135) + (_vs * 0) + (_app * 290) + (_dss * 0) + (_dsp * 700) + (_gbe * 0);
|
||||
statrank = 11.2 * atan((srarea - 93) / 130) + 1;
|
||||
if (statrank <= 0) statrank = 0.001;
|
||||
estglicko = (4.0867 * srarea + 186.68);
|
||||
// double temp = (1500 - estglicko) * pi;
|
||||
// double temp2 = pow((15.9056943314 * (pow(_rd, 2)) + 3527584.25978), 0.5) as double;
|
||||
// double temp3 = 1 + pow(10, (temp / temp2)) as double;
|
||||
//esttr = 25000 / temp3;
|
||||
double ntemp = _pps*(150+(((_vs/_apm) - 1.66)*35))+_app*290+_dsp*700;
|
||||
esttr = 25000 /
|
||||
(
|
||||
|
@ -821,8 +816,8 @@ class EndContextMulti {
|
|||
extraTracking = json['points']['extraAvgTracking']['aggregatestats___vsscore'].map((e) => e.toDouble()).toList();
|
||||
nerdStats = NerdStats(secondary, tertiary, extra);
|
||||
nerdStatsTracking = [for (int i = 0; i < secondaryTracking.length; i++) NerdStats(secondaryTracking[i], tertiaryTracking[i], extraTracking[i])];
|
||||
estTr = EstTr(secondary, tertiary, extra, noTrRd, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||
estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], noTrRd, nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)];
|
||||
estTr = EstTr(secondary, tertiary, extra, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||
estTrTracking = [for (int i = 0; i < secondaryTracking.length; i++) EstTr(secondaryTracking[i], tertiaryTracking[i], extraTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].dss, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe)];
|
||||
playstyle = Playstyle(secondary, tertiary, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
||||
playstyleTracking = [for (int i = 0; i < secondaryTracking.length; i++) Playstyle(secondaryTracking[i], tertiaryTracking[i], nerdStatsTracking[i].app, nerdStatsTracking[i].vsapm, nerdStatsTracking[i].dsp, nerdStatsTracking[i].gbe, estTrTracking[i].srarea, estTrTracking[i].statrank)];
|
||||
}
|
||||
|
@ -890,7 +885,7 @@ class TetraLeagueAlpha {
|
|||
this.vs,
|
||||
this.records}){
|
||||
nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null;
|
||||
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, (rd != null) ? rd! : 69, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
|
||||
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
|
||||
playstyle =(nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null;
|
||||
}
|
||||
|
||||
|
@ -918,7 +913,7 @@ class TetraLeagueAlpha {
|
|||
nextAt = json['next_at'] ?? -1;
|
||||
percentileRank = json['percentile_rank'] ?? rank;
|
||||
nerdStats = (apm != null && pps != null && vs != null) ? NerdStats(apm!, pps!, vs!) : null;
|
||||
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, (rd != null) ? rd! : 69, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
|
||||
estTr = (nerdStats != null) ? EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe) : null;
|
||||
playstyle = (nerdStats != null) ? Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank) : null;
|
||||
}
|
||||
|
||||
|
@ -1769,7 +1764,7 @@ class TetrioPlayerFromLeaderboard {
|
|||
vs = json['league']['vs'].toDouble();
|
||||
decaying = json['league']['decaying'];
|
||||
nerdStats = NerdStats(apm, pps, vs);
|
||||
estTr = EstTr(apm, pps, vs, rd, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||
estTr = EstTr(apm, pps, vs, nerdStats.app, nerdStats.dss, nerdStats.dsp, nerdStats.gbe);
|
||||
playstyle = Playstyle(apm, pps, nerdStats.app, nerdStats.vsapm, nerdStats.dsp, nerdStats.gbe, estTr.srarea, estTr.statrank);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
|
||||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
|
@ -21,6 +22,10 @@ void main() async {
|
|||
databaseFactory = databaseFactoryFfi;
|
||||
}
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await WindowManager.instance.ensureInitialized();
|
||||
windowManager.waitUntilReadyToShow().then((_) async {
|
||||
await windowManager.setTitle('Tetra Stats');
|
||||
});
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
String? locale = prefs.getString("locale");
|
||||
if (locale == null){
|
||||
|
|
|
@ -54,6 +54,7 @@ class TetrioService extends DB {
|
|||
final Map<String, Map<String, dynamic>> _recordsCache = {};
|
||||
final Map<String, TetrioPlayersLeaderboard> _leaderboardsCache = {};
|
||||
final Map<String, List<News>> _newsCache = {};
|
||||
final Map<String, Map<String, double?>> _topTRcache = {};
|
||||
final Map<String, TetraLeagueAlphaStream> _tlStreamsCache = {}; // i'm trying to respect oskware api It should look something like {"cached_until": TetrioPlayer}
|
||||
final client = UserAgentClient("ebany u rot yatogo kazino blyat' (Tetra Stats v1.2.4 dev build)", http.Client());
|
||||
static final TetrioService _shared = TetrioService._sharedInstance();
|
||||
|
@ -105,6 +106,58 @@ class TetrioService extends DB {
|
|||
}
|
||||
}
|
||||
|
||||
Future<double?> fetchTopTR(String id) async {
|
||||
try{
|
||||
var cached = _topTRcache.entries.firstWhere((element) => element.value.keys.first == id);
|
||||
if (DateTime.fromMillisecondsSinceEpoch(int.parse(cached.key.toString()), isUtc: true).isAfter(DateTime.now())){
|
||||
developer.log("fetchTopTR: Top TR retrieved from cache, that expires ${DateTime.fromMillisecondsSinceEpoch(int.parse(cached.key.toString()), isUtc: true)}", name: "services/tetrio_crud");
|
||||
return cached.value.values.first;
|
||||
}else{
|
||||
_topTRcache.remove(cached.key);
|
||||
developer.log("fetchTopTR: Top TR expired (${DateTime.fromMillisecondsSinceEpoch(int.parse(cached.key.toString()), isUtc: true)})", name: "services/tetrio_crud");
|
||||
}
|
||||
}catch(e){
|
||||
developer.log("fetchTopTR: Trying to retrieve Top TR", name: "services/tetrio_crud");
|
||||
}
|
||||
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
url = Uri.https('ts.dan63.by', 'oskware_bridge.php', {"endpoint": "TLHistory", "user": id});
|
||||
} else {
|
||||
url = Uri.https('api.p1nkl0bst3r.xyz', 'toptr/$id');
|
||||
}
|
||||
try{
|
||||
final response = await client.get(url);
|
||||
|
||||
switch (response.statusCode) {
|
||||
case 200:
|
||||
_topTRcache[(DateTime.now().millisecondsSinceEpoch + 300000).toString()] = {id: double.tryParse(response.body)};
|
||||
return double.tryParse(response.body);
|
||||
case 404:
|
||||
developer.log("fetchTopTR: Probably, player doesn't have top TR", name: "services/tetrio_crud", error: response.statusCode);
|
||||
_topTRcache[(DateTime.now().millisecondsSinceEpoch + 300000).toString()] = {id: null};
|
||||
return null;
|
||||
case 403:
|
||||
throw P1nkl0bst3rForbidden();
|
||||
case 429:
|
||||
throw P1nkl0bst3rTooManyRequests();
|
||||
case 418:
|
||||
throw TetrioOskwareBridgeProblem();
|
||||
case 500:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
throw P1nkl0bst3rInternalProblem();
|
||||
default:
|
||||
developer.log("fetchTopTR: Failed to fetch top TR", name: "services/tetrio_crud", error: response.statusCode);
|
||||
throw ConnectionIssue(response.statusCode, response.reasonPhrase??"No reason");
|
||||
}
|
||||
} on http.ClientException catch (e, s) {
|
||||
developer.log("$e, $s");
|
||||
throw http.ClientException(e.message, e.uri);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<TetrioPlayer>> fetchAndsaveTLHistory(String id) async {
|
||||
Uri url;
|
||||
if (kIsWeb) {
|
||||
|
@ -238,7 +291,6 @@ class TetrioService extends DB {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Future<List<News>> getNews(String userID) async
|
||||
Future<List<News>> fetchNews(String userID) async{
|
||||
try{
|
||||
var cached = _newsCache.entries.firstWhere((element) => element.value[0].stream == "user_$userID");
|
||||
|
|
|
@ -42,7 +42,7 @@ class CalcState extends State<CalcView> {
|
|||
vs = double.tryParse(vsController.text);
|
||||
if (apm != null && pps != null && vs != null) {
|
||||
nerdStats = NerdStats(apm!, pps!, vs!);
|
||||
estTr = EstTr(apm!, pps!, vs!, 60.9, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe);
|
||||
estTr = EstTr(apm!, pps!, vs!, nerdStats!.app, nerdStats!.dss, nerdStats!.dsp, nerdStats!.gbe);
|
||||
playstyle = Playstyle(apm!, pps!, nerdStats!.app, nerdStats!.vsapm, nerdStats!.dsp, nerdStats!.gbe, estTr!.srarea, estTr!.statrank);
|
||||
setState(() {});
|
||||
} else {
|
||||
|
@ -124,7 +124,7 @@ class CalcState extends State<CalcView> {
|
|||
_ListEntry(value: estTr!.esttr, label: t.statCellNum.estOfTR, fractionDigits: 3),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
|
|
|
@ -642,7 +642,7 @@ class CompareState extends State<CompareView> {
|
|||
),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
|
|
|
@ -12,12 +12,14 @@ import 'package:tetra_stats/data_objects/tetrio.dart';
|
|||
import 'package:tetra_stats/gen/strings.g.dart';
|
||||
import 'package:tetra_stats/services/tetrio_crud.dart';
|
||||
import 'package:tetra_stats/services/crud_exceptions.dart';
|
||||
import 'package:tetra_stats/views/ranks_averages_view.dart';
|
||||
import 'package:tetra_stats/views/ranks_averages_view.dart' show RankAveragesView;
|
||||
import 'package:tetra_stats/views/tl_leaderboard_view.dart' show TLLeaderboardView;
|
||||
import 'package:tetra_stats/views/tl_match_view.dart' show TlMatchResultView;
|
||||
import 'package:tetra_stats/widgets/stat_sell_num.dart';
|
||||
import 'package:tetra_stats/widgets/tl_thingy.dart';
|
||||
import 'package:tetra_stats/widgets/user_thingy.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
|
||||
Future<List> me = Future.delayed(const Duration(seconds: 60), () => [null, null, null, null, null, null]);
|
||||
String _searchFor = "6098518e3d5155e6ec429cdc";
|
||||
|
@ -136,10 +138,25 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
|||
}
|
||||
_searchFor = me.userId;
|
||||
setState((){_titleNickname = me.username;});
|
||||
List<dynamic> requests = await Future.wait([teto.getTLStream(_searchFor), teto.fetchRecords(_searchFor), teto.fetchNews(_searchFor)]);
|
||||
TetraLeagueAlphaStream tlStream = requests[0] as TetraLeagueAlphaStream;
|
||||
Map<String, dynamic> records = requests[1] as Map<String, dynamic>;
|
||||
List<News> news = requests[2] as List<News>;
|
||||
await windowManager.setTitle('Tetra Stats: $_titleNickname'); //TODO: Change window title on every view
|
||||
late List<dynamic> requests;
|
||||
late TetraLeagueAlphaStream tlStream;
|
||||
late Map<String, dynamic> records;
|
||||
late List<News> news;
|
||||
late double? topTR;
|
||||
if (me.tlSeason1.gamesPlayed > 9) {
|
||||
requests = await Future.wait([teto.getTLStream(_searchFor), teto.fetchRecords(_searchFor), teto.fetchNews(_searchFor), teto.fetchTopTR(_searchFor)]);
|
||||
tlStream = requests[0] as TetraLeagueAlphaStream;
|
||||
records = requests[1] as Map<String, dynamic>;
|
||||
news = requests[2] as List<News>;
|
||||
topTR = requests[3] as double?;
|
||||
}else{
|
||||
requests = await Future.wait([teto.getTLStream(_searchFor), teto.fetchRecords(_searchFor), teto.fetchNews(_searchFor)]);
|
||||
tlStream = requests[0] as TetraLeagueAlphaStream;
|
||||
records = requests[1] as Map<String, dynamic>;
|
||||
news = requests[2] as List<News>;
|
||||
topTR = null;
|
||||
}
|
||||
List<TetraLeagueAlphaRecord> tlMatches = [];
|
||||
bool isTracking = await teto.isPlayerTracking(me.userId);
|
||||
List<TetrioPlayer> states = [];
|
||||
|
@ -191,7 +208,7 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
|||
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.estTr != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.estTr!.esttr)], child: Text(t.statCellNum.estOfTR.replaceAll(RegExp(r'\n'), " "))),
|
||||
DropdownMenuItem(value: [for (var tl in uniqueTL) if (tl.esttracc != null) FlSpot(tl.timestamp.millisecondsSinceEpoch.toDouble(), tl.esttracc!)], child: Text(t.statCellNum.accOfEst.replaceAll(RegExp(r'\n'), " "))),
|
||||
];
|
||||
return [me, records, states, tlMatches, compareWith, isTracking, news];
|
||||
return [me, records, states, tlMatches, compareWith, isTracking, news, topTR];
|
||||
}
|
||||
|
||||
void _justUpdate() {
|
||||
|
@ -330,24 +347,12 @@ class _MainState extends State<MainView> with SingleTickerProviderStateMixin {
|
|||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
TLThingy(
|
||||
tl: snapshot.data![0].tlSeason1,
|
||||
userID: snapshot.data![0].userId,
|
||||
oldTl: snapshot.data![4]),
|
||||
TLThingy(tl: snapshot.data![0].tlSeason1, userID: snapshot.data![0].userId, oldTl: snapshot.data![4], topTR: snapshot.data![7]),
|
||||
_TLRecords(userID: snapshot.data![0].userId, data: snapshot.data![3]),
|
||||
_History(states: snapshot.data![2], update: _justUpdate),
|
||||
_RecordThingy(
|
||||
record: (snapshot.data![1]['sprint'].isNotEmpty)
|
||||
? snapshot.data![1]['sprint'][0]
|
||||
: null),
|
||||
_RecordThingy(
|
||||
record: (snapshot.data![1]['blitz'].isNotEmpty)
|
||||
? snapshot.data![1]['blitz'][0]
|
||||
: null),
|
||||
_OtherThingy(
|
||||
zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio,
|
||||
distinguishment: snapshot.data![0].distinguishment,
|
||||
newsletter: snapshot.data![6],)
|
||||
_RecordThingy(record: (snapshot.data![1]['sprint'].isNotEmpty) ? snapshot.data![1]['sprint'][0] : null),
|
||||
_RecordThingy(record: (snapshot.data![1]['blitz'].isNotEmpty) ? snapshot.data![1]['blitz'][0] : null),
|
||||
_OtherThingy(zen: snapshot.data![1]['zen'], bio: snapshot.data![0].bio, distinguishment: snapshot.data![0].distinguishment, newsletter: snapshot.data![6],)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -466,7 +471,7 @@ class _NavDrawerState extends State<NavDrawer> {
|
|||
final allPlayers = (snapshot.data != null)
|
||||
? snapshot.data as Map<String, List<TetrioPlayer>>
|
||||
: <String, List<TetrioPlayer>>{};
|
||||
List<String> keys = allPlayers.keys.toList().reversed.toList(); // this is so dumb
|
||||
List<String> keys = allPlayers.keys.toList();
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (context, value) {
|
||||
return [
|
||||
|
@ -521,9 +526,9 @@ class _NavDrawerState extends State<NavDrawer> {
|
|||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
allPlayers[keys[index]]?.last.username as String),
|
||||
allPlayers[keys[allPlayers.length-1-index]]?.last.username as String),
|
||||
onTap: () {
|
||||
widget.changePlayer(keys[index]);
|
||||
widget.changePlayer(keys[allPlayers.length-1-index]);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
|
@ -966,6 +971,14 @@ class _OtherThingy extends StatelessWidget {
|
|||
)
|
||||
),
|
||||
subtitle: Text(dateFormat.format(news.timestamp)),
|
||||
leading: Image.asset(
|
||||
"res/icons/improvement-local.png",
|
||||
height: 48,
|
||||
width: 48,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Image.asset("res/icons/kagari.png", height: 64, width: 64);
|
||||
},
|
||||
),
|
||||
);
|
||||
case "badge":
|
||||
return ListTile(
|
||||
|
@ -980,6 +993,14 @@ class _OtherThingy extends StatelessWidget {
|
|||
)
|
||||
),
|
||||
subtitle: Text(dateFormat.format(news.timestamp)),
|
||||
leading: Image.asset(
|
||||
"res/tetrio_badges/${news.data["type"]}.png",
|
||||
height: 48,
|
||||
width: 48,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Image.asset("res/icons/kagari.png", height: 64, width: 64);
|
||||
},
|
||||
),
|
||||
);
|
||||
case "rankup":
|
||||
return ListTile(
|
||||
|
@ -994,32 +1015,56 @@ class _OtherThingy extends StatelessWidget {
|
|||
)
|
||||
),
|
||||
subtitle: Text(dateFormat.format(news.timestamp)),
|
||||
leading: Image.asset(
|
||||
"res/tetrio_tl_alpha_ranks/${news.data["rank"]}.png",
|
||||
height: 48,
|
||||
width: 48,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Image.asset("res/icons/kagari.png", height: 64, width: 64);
|
||||
},
|
||||
),
|
||||
);
|
||||
case "supporter":
|
||||
return ListTile(
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(fontFamily: 'Eurostile Round', fontSize: 16),
|
||||
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16),
|
||||
text: t.newsParts.supporterStart,
|
||||
children: [
|
||||
TextSpan(text: t.newsParts.tetoSupporter, style: TextStyle(fontWeight: FontWeight.bold))
|
||||
TextSpan(text: t.newsParts.tetoSupporter, style: const TextStyle(fontWeight: FontWeight.bold))
|
||||
]
|
||||
)
|
||||
),
|
||||
subtitle: Text(dateFormat.format(news.timestamp)),
|
||||
leading: Image.asset(
|
||||
"res/icons/supporter-tag.png",
|
||||
height: 48,
|
||||
width: 48,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Image.asset("res/icons/kagari.png", height: 64, width: 64);
|
||||
},
|
||||
),
|
||||
);
|
||||
case "supporter_gift":
|
||||
return ListTile(
|
||||
title: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(fontFamily: 'Eurostile Round', fontSize: 16),
|
||||
style: const TextStyle(fontFamily: 'Eurostile Round', fontSize: 16),
|
||||
text: t.newsParts.supporterGiftStart,
|
||||
children: [
|
||||
TextSpan(text: t.newsParts.tetoSupporter, style: TextStyle(fontWeight: FontWeight.bold))
|
||||
TextSpan(text: t.newsParts.tetoSupporter, style: const TextStyle(fontWeight: FontWeight.bold))
|
||||
]
|
||||
)
|
||||
),
|
||||
subtitle: Text(dateFormat.format(news.timestamp)),
|
||||
leading: Image.asset(
|
||||
"res/icons/supporter-tag.png",
|
||||
height: 48,
|
||||
width: 48,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Image.asset("res/icons/kagari.png", height: 64, width: 64);
|
||||
},
|
||||
),
|
||||
);
|
||||
default:
|
||||
return ListTile(
|
||||
|
@ -1057,11 +1102,11 @@ class _OtherThingy extends StatelessWidget {
|
|||
),
|
||||
if (bio != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 0, 0, 48),
|
||||
padding: const EdgeInsets.fromLTRB(8, 0, 8, 48),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(t.bio, style: TextStyle(fontFamily: "Eurostile Round Extended",fontSize: bigScreen ? 42 : 28)),
|
||||
Text(bio!, style: const TextStyle(fontSize: 18)),
|
||||
MarkdownBody(data: bio!, styleSheet: MarkdownStyleSheet(textScaleFactor: 1.5, textAlign: WrapAlignment.center)) // Text(bio!, style: const TextStyle(fontSize: 18)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -268,7 +268,7 @@ class TlMatchResultState extends State<TlMatchResultView> {
|
|||
),
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
|
|
|
@ -13,7 +13,8 @@ class TLThingy extends StatelessWidget {
|
|||
final String userID;
|
||||
final TetraLeagueAlpha? oldTl;
|
||||
final bool showTitle;
|
||||
const TLThingy({Key? key, required this.tl, required this.userID, this.oldTl, this.showTitle = true}) : super(key: key);
|
||||
final double? topTR;
|
||||
const TLThingy({Key? key, required this.tl, required this.userID, this.oldTl, this.showTitle = true, this.topTR}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -55,7 +56,7 @@ class TLThingy extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
Text(
|
||||
"${t.top} ${f2.format(tl.percentile * 100)}% (${tl.percentileRank.toUpperCase()})${tl.bestRank != "z" ? " • ${t.topRank}: ${tl.bestRank.toUpperCase()}" : ""} • Glicko: ${f2.format(tl.glicko!)}±${f2.format(tl.rd!)}${tl.decaying ? ' • ${t.decaying}' : ''}",
|
||||
"${t.top} ${f2.format(tl.percentile * 100)}% (${tl.percentileRank.toUpperCase()})${tl.bestRank != "z" ? " • ${t.topRank}: ${tl.bestRank.toUpperCase()}" : ""}${topTR != null ? " (${f2.format(topTR)} TR)" : ""} • Glicko: ${f2.format(tl.glicko!)}±${f2.format(tl.rd!)}${tl.decaying ? ' • ${t.decaying}' : ''}",
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
|
@ -346,7 +347,7 @@ class TLThingy extends StatelessWidget {
|
|||
if (tl.nerdStats != null)
|
||||
Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 25,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
|
|
|
@ -7,17 +7,25 @@
|
|||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
|
||||
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
||||
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) window_manager_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
|
||||
window_manager_plugin_register_with_registrar(window_manager_registrar);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
screen_retriever
|
||||
sqlite3_flutter_libs
|
||||
url_launcher_linux
|
||||
window_manager
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
|
@ -8,17 +8,21 @@ import Foundation
|
|||
import file_selector_macos
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import screen_retriever
|
||||
import shared_preferences_foundation
|
||||
import sqflite
|
||||
import sqlite3_flutter_libs
|
||||
import url_launcher_macos
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||
}
|
||||
|
|
32
pubspec.lock
|
@ -291,6 +291,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: "8afc9a6aa6d8e8063523192ba837149dbf3d377a37c0b0fc579149a1fbd4a619"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.18"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -421,6 +429,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: markdown
|
||||
sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.1.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -605,6 +621,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_retriever
|
||||
sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.9"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1018,6 +1042,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.8"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: window_manager
|
||||
sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.7"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
11
pubspec.yaml
|
@ -39,6 +39,8 @@ dependencies:
|
|||
csv: ^5.0.2
|
||||
url_launcher: ^6.1.12
|
||||
flutter_svg: any
|
||||
window_manager: ^0.3.7
|
||||
flutter_markdown: ^0.6.18
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -82,6 +84,8 @@ flutter:
|
|||
- res/icons/kagari.png
|
||||
- res/icons/osk.svg
|
||||
- res/icons/tetrio-logo.svg
|
||||
- res/icons/improvement-local.png
|
||||
- res/icons/supporter-tag.png
|
||||
- res/tetrio_tl_alpha_ranks/x.png
|
||||
- res/tetrio_tl_alpha_ranks/u.png
|
||||
- res/tetrio_tl_alpha_ranks/ss.png
|
||||
|
@ -127,6 +131,9 @@ flutter:
|
|||
- res/tetrio_badges/hnprism_1.png
|
||||
- res/tetrio_badges/hnprism_2.png
|
||||
- res/tetrio_badges/hnprism_3.png
|
||||
- res/tetrio_badges/hnstratosphere50_1.png
|
||||
- res/tetrio_badges/hnstratosphere50_2.png
|
||||
- res/tetrio_badges/hnstratosphere50_3.png
|
||||
- res/tetrio_badges/ift_1.png
|
||||
- res/tetrio_badges/ift_2.png
|
||||
- res/tetrio_badges/ift_3.png
|
||||
|
@ -140,6 +147,7 @@ flutter:
|
|||
- res/tetrio_badges/mmc_tabi_superlobby.png
|
||||
- res/tetrio_badges/mmc_tabi_superlobby2.png
|
||||
- res/tetrio_badges/mmc_tabi_superlobby3.png
|
||||
- res/tetrio_badges/mmc_tabi_superlobby4.png
|
||||
- res/tetrio_badges/redgevo_1.png
|
||||
- res/tetrio_badges/redgevo_2.png
|
||||
- res/tetrio_badges/redgevo_3.png
|
||||
|
@ -169,6 +177,9 @@ flutter:
|
|||
- res/tetrio_badges/thaitour_1.png
|
||||
- res/tetrio_badges/thaitour_2.png
|
||||
- res/tetrio_badges/thaitour_3.png
|
||||
- res/tetrio_badges/ttsdpf_1.png
|
||||
- res/tetrio_badges/ttsdpf_2.png
|
||||
- res/tetrio_badges/ttsdpf_3.png
|
||||
- res/tetrio_badges/ttsdtc_1.png
|
||||
- res/tetrio_badges/ttsdtc_2.png
|
||||
- res/tetrio_badges/ttsdtc_3.png
|
||||
|
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
|
@ -1,30 +0,0 @@
|
|||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:tetra_stats/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
// await tester.pumpWidget(const MyApp());
|
||||
//
|
||||
// // Verify that our counter starts at 0.
|
||||
// expect(find.text('0'), findsOneWidget);
|
||||
// expect(find.text('1'), findsNothing);
|
||||
//
|
||||
// // Tap the '+' icon and trigger a frame.
|
||||
// await tester.tap(find.byIcon(Icons.add));
|
||||
// await tester.pump();
|
||||
//
|
||||
// // Verify that our counter has incremented.
|
||||
// expect(find.text('0'), findsNothing);
|
||||
// expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -7,14 +7,20 @@
|
|||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
WindowManagerPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
screen_retriever
|
||||
sqlite3_flutter_libs
|
||||
url_launcher_windows
|
||||
window_manager
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|