diff --git a/lib/data_objects/tetrio.dart b/lib/data_objects/tetrio.dart index ba3d586..74de230 100644 --- a/lib/data_objects/tetrio.dart +++ b/lib/data_objects/tetrio.dart @@ -344,7 +344,7 @@ class EndContextSingle { late int piecesPlaced; late int lines; late int score; - late int seed; + late double seed; late Duration finalTime; late int tSpins; late Clears clears; @@ -373,7 +373,7 @@ class EndContextSingle { required this.finesse}); EndContextSingle.fromJson(Map json) { - seed = json['seed']; + seed = json['seed'].toDouble(); lines = json['lines']; inputs = json['inputs']; holds = json['holds'] ?? 0; diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index 577bfbf..ace3d54 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -34,13 +34,14 @@ const String createTetrioUsersToTrack = ''' '''; const String createTetrioTLRecordsTable = ''' CREATE TABLE IF NOT EXISTS "tetrioAlphaLeagueMathces" ( - "id" TEXT, + "id" TEXT NOT NULL UNIQUE, "replayId" TEXT, "player1id" TEXT, "player2id" TEXT, "timestamp" TEXT, "endContext1" TEXT, - "endContext2" TEXT + "endContext2" TEXT, + PRIMARY KEY("id") ) '''; @@ -70,7 +71,6 @@ class TetrioService extends DB { final allPlayers = await getAllPlayers(); _players = allPlayers.toList().first; // ??? _tetrioStreamController.add(_players); - developer.log("_loadPlayers: $_players", name: "services/tetrio_crud"); } Future deletePlayer(String id) async { diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index ccaa900..d24c8b8 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'dart:math'; @@ -17,6 +19,9 @@ String _searchFor = "dan63047"; String _titleNickname = "dan63047"; final TetrioService teto = TetrioService(); late SharedPreferences prefs; +var chartsData = >>[]; +List chartsShortTitles = ["TR", "Glicko", "RD", "APM", "PPS", "VS", "APP", "DS/S", "DS/P", "APP + DS/P", "VS/APM", "Cheese", "GbE", "wAPP", "Area", "eTR", "±eTR"]; +int chartsIndex = 0; const allowedHeightForPlayerIdInPixels = 40.0; const allowedHeightForPlayerBioInPixels = 30.0; const givenTextHeightByScreenPercentage = 0.3; @@ -43,7 +48,7 @@ class _MainState extends State with SingleTickerProviderStateMixin { final List myTabs = [ const Tab(text: "Tetra League"), const Tab(text: "TL Records"), - const Tab(text: "TL History"), + const Tab(text: "History"), const Tab(text: "40 Lines"), const Tab(text: "Blitz"), const Tab(text: "Other"), @@ -110,33 +115,48 @@ class _MainState extends State with SingleTickerProviderStateMixin { Future fetch(String nickOrID) async { TetrioPlayer me = await teto.fetchPlayer(nickOrID); setState((){_titleNickname = me.username;}); + var tlStream = await teto.getTLStream(me.userId); + List tlMatches = []; bool isTracking = await teto.isPlayerTracking(me.userId); List states = []; if (isTracking){ teto.storeState(me); teto.saveTLMatchesFromStream(await teto.getTLStream(me.userId)); states.addAll(await teto.getPlayer(me.userId)); - } - Map records = await teto.fetchRecords(me.userId); - return [me, records, states, isTracking]; - } - - Future> getTLMatches(String userID) async { - var fetched = await teto.getTLStream(userID); - bool isTracked = await teto.isPlayerTracking(userID); - if (!isTracked) return fetched.records; - teto.saveTLMatchesFromStream(fetched); - var fromdb = await teto.getTLMatchesbyPlayerID(userID); - for (var match in fetched.records) { - if (!fromdb.contains(match)) fromdb.add(match); + chartsData = >>[ + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rating)], child: const Text("Tetra Rating")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.glicko!)], child: const Text("Glicko")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rd!)], child: const Text("Rating Deviation")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.apm != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.apm!)], child: const Text("Attack Per Minute")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.pps != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.pps!)], child: const Text("Pieces Per Second")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.vs != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.vs!)], child: const Text("Versus Score")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.app)], child: const Text("Attack Per Piece")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dss)], child: const Text("Downstack Per Second")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dsp)], child: const Text("Downstack Per Piece")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.appdsp)], child: const Text("APP + DS/P")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.vsapm)], child: const Text("VS/APM")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.cheese)], child: const Text("Cheese Index")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.gbe)], child: const Text("Garbage Efficiency")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.nyaapp)], child: const Text("Weighted APP")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.area)], child: const Text("Area")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.estTr != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.estTr!.esttr)], child: const Text("Est. of TR")), + DropdownMenuItem(value: [for (var state in states) if (state.tlSeason1.esttracc != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.esttracc!)], child: const Text("Accuracy of Est.")), + ]; + tlMatches.addAll(await teto.getTLMatchesbyPlayerID(me.userId)); + for (var match in tlStream.records) { + if (!tlMatches.contains(match)) tlMatches.add(match); } - fromdb.sort((a, b) { + tlMatches.sort((a, b) { if(a.timestamp.isBefore(b.timestamp)) return 1; if(a.timestamp.isAtSameMomentAs(b.timestamp)) return 0; if(a.timestamp.isAfter(b.timestamp)) return -1; return 0; }); - return fromdb; + } else{ + tlMatches = tlStream.records; + } + Map records = await teto.fetchRecords(me.userId); + return [me, records, states, tlMatches, isTracking]; } void _justUpdate() { @@ -234,44 +254,57 @@ class _MainState extends State with SingleTickerProviderStateMixin { case ConnectionState.done: //bool bigScreen = MediaQuery.of(context).size.width > 1024; if (snapshot.hasData) { - return NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (context, value) { - return [ - SliverToBoxAdapter( - child: UserThingy( - player: snapshot.data![0], - showStateTimestamp: false, - setState: _justUpdate, - )), - SliverToBoxAdapter( - child: TabBar( - controller: _tabController, - isScrollable: true, - tabs: myTabs, - ), - ), - ]; + return RefreshIndicator( + onRefresh: () { + return Future(() => changePlayer(snapshot.data![0].userId)); }, - body: TabBarView( - controller: _tabController, - children: [ - TLThingy( - tl: snapshot.data![0].tlSeason1, - userID: snapshot.data![0].userId), - _TLRecords(userID: snapshot.data![0].userId, get: getTLMatches,), - _TLHistory(states: snapshot.data![2]), - _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) - ], + notificationPredicate: (notification) { + // with NestedScrollView local(depth == 2) OverscrollNotification are not sent + if (notification is OverscrollNotification || Platform.isIOS) { + return notification.depth == 2; + } + return notification.depth == 0; + }, + child: NestedScrollView( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + headerSliverBuilder: (context, value) { + return [ + SliverToBoxAdapter( + child: UserThingy( + player: snapshot.data![0], + showStateTimestamp: false, + setState: _justUpdate, + )), + SliverToBoxAdapter( + child: TabBar( + controller: _tabController, + isScrollable: true, + tabs: myTabs, + ), + ), + ]; + }, + body: TabBarView( + controller: _tabController, + children: [ + TLThingy( + tl: snapshot.data![0].tlSeason1, + userID: snapshot.data![0].userId), + _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) + ], + ), ), ); } else if (snapshot.hasError) { @@ -401,99 +434,62 @@ class _NavDrawerState extends State { class _TLRecords extends StatelessWidget { final String userID; - final Future> Function(String user) get; + final List data; - const _TLRecords({required this.userID, required this.get}); + const _TLRecords({required this.userID, required this.data}); @override Widget build(BuildContext context) { - return FutureBuilder( - future: get(userID), - builder: (context, snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.none: - case ConnectionState.waiting: - case ConnectionState.active: - return const Center( - child: CircularProgressIndicator(color: Colors.white)); - case ConnectionState.done: - if (snapshot.hasError) { - return Text(snapshot.error.toString(), style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)); - } else { - return ListView( - physics: const ClampingScrollPhysics(), - children: (snapshot.data!.isNotEmpty) - ? [for (var value in snapshot.data!) ListTile( - leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}", - style: const TextStyle( - fontFamily: "Eurostile Round Extended", - fontSize: 28,)), - title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), - subtitle: Text(dateFormat.format(value.timestamp)), - trailing: Column(mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary)} APM", style: const TextStyle(height: 1.1)), - Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary)} PPS", style: const TextStyle(height: 1.1)), - Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra)} VS", style: const TextStyle(height: 1.1)), - ]), - onTap: (){Navigator.push( - context, - MaterialPageRoute( - builder: (context) => TlMatchResultView(record: value, initPlayerId: userID), - ), - );}, - )] - : [const Center(child: Text("No records", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))], - ); - } - } - }); + return ListView( // TODO: Redo using ListView.builder() + physics: const AlwaysScrollableScrollPhysics(), + children: (data.isNotEmpty) + ? [for (var value in data) ListTile( + leading: Text("${value.endContext.firstWhere((element) => element.userId == userID).points} : ${value.endContext.firstWhere((element) => element.userId != userID).points}", + style: const TextStyle( + fontFamily: "Eurostile Round Extended", + fontSize: 28,)), + title: Text("vs. ${value.endContext.firstWhere((element) => element.userId != userID).username}"), + subtitle: Text(dateFormat.format(value.timestamp)), + trailing: Column(mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).secondary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).secondary)} APM", style: const TextStyle(height: 1.1)), + Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).tertiary)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).tertiary)} PPS", style: const TextStyle(height: 1.1)), + Text("${f2.format(value.endContext.firstWhere((element) => element.userId == userID).extra)} : ${f2.format(value.endContext.firstWhere((element) => element.userId != userID).extra)} VS", style: const TextStyle(height: 1.1)), + ]), + onTap: (){Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TlMatchResultView(record: value, initPlayerId: userID), + ), + );}, + )] + : [const Center(child: Text("No records", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))], + ); } } -class _TLHistory extends StatelessWidget{ +class _History extends StatelessWidget{ final List states; - const _TLHistory({required this.states}); + final Function update; + const _History({required this.states, required this.update}); @override Widget build(BuildContext context) { bool bigScreen = MediaQuery.of(context).size.width > 768; - List trData = [for (var state in states) if (state.tlSeason1.gamesPlayed > 9) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.rating)]; - List apmData = [for (var state in states) if (state.tlSeason1.apm != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.apm!)]; - List ppsData = [for (var state in states) if (state.tlSeason1.pps != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.pps!)]; - List vsData = [for (var state in states) if (state.tlSeason1.vs != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.vs!)]; - List appData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.app)]; - List dssData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dss)]; - List dspData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.dsp)]; - List appdspData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.appdsp)]; - List vsapmData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.vsapm)]; - List cheeseData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.cheese)]; - List gbeData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.gbe)]; - List nyaappData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.nyaapp)]; - List areaData = [for (var state in states) if (state.tlSeason1.nerdStats != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.nerdStats!.area)]; - List estTrData = [for (var state in states) if (state.tlSeason1.estTr != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.estTr!.esttr)]; - List estaccData = [for (var state in states) if (state.tlSeason1.esttracc != null) FlSpot(state.state.millisecondsSinceEpoch.toDouble(), state.tlSeason1.esttracc!)]; return ListView(physics: const ClampingScrollPhysics(), children: states.isNotEmpty ? [ Column( children: [ - if(trData.length > 1) _HistoryChartThigy(data: trData, title: "Tetra Rating", yAxisTitle: "TR", bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),), - if(apmData.length > 1) _HistoryChartThigy(data: apmData, title: "Attack Per Minute", yAxisTitle: "APM", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),), - if(ppsData.length > 1) _HistoryChartThigy(data: ppsData, title: "Pieces Per Second", yAxisTitle: "PPS", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),), - if(vsData.length > 1) _HistoryChartThigy(data: vsData, title: "Versus Score", yAxisTitle: "VS", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),), - if(appData.length > 1) _HistoryChartThigy(data: appData, title: "Attack Per Piece", yAxisTitle: "APP", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(dssData.length > 1) _HistoryChartThigy(data: dssData, title: bigScreen ? "Downstack Per Second" : "Downstack\nPer Second", yAxisTitle: "DS/S", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(dspData.length > 1) _HistoryChartThigy(data: dspData, title: bigScreen ? "Downstack Per Piece" : "Downstack\nPer Piece", yAxisTitle: "DS/P", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(appdspData.length > 1) _HistoryChartThigy(data: appdspData, title: "APP + DS/P", yAxisTitle: "APP + DS/P", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(vsapmData.length > 1) _HistoryChartThigy(data: vsapmData, title: "VS/APM", yAxisTitle: "VS/APM", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(cheeseData.length > 1) _HistoryChartThigy(data: cheeseData, title: "Cheese Index", yAxisTitle: "Cheese", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),), - if(gbeData.length > 1) _HistoryChartThigy(data: gbeData, title: "Garbage Efficiency", yAxisTitle: "GbE", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(nyaappData.length > 1) _HistoryChartThigy(data: nyaappData, title: "Weighted APP", yAxisTitle: "wAPP", bigScreen: bigScreen, leftSpace: 48, yFormat: NumberFormat.compact(),), - if(areaData.length > 1) _HistoryChartThigy(data: areaData, title: "Area", yAxisTitle: "Area", bigScreen: bigScreen, leftSpace: 40, yFormat: NumberFormat.compact(),), - if(estTrData.length > 1) _HistoryChartThigy(data: estTrData, title: "Est. of TR", yAxisTitle: "eTR", bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),), - if(estaccData.length > 1) _HistoryChartThigy(data: estaccData, title: "Accuracy of Est.", yAxisTitle: "±eTR", bigScreen: bigScreen, leftSpace: 60, yFormat: NumberFormat.compact(explicitSign: true),), - if(trData.length <= 1 || apmData.length <= 1 || ppsData.length <= 1 || vsData.length <= 1 || appData.length <= 1 || dssData.length <= 1 || dspData.length <= 1 || appdspData.length <= 1 || vsapmData.length <= 1 || cheeseData.length <= 1 || gbeData.length <= 1 || nyaappData.length <= 1 || areaData.length <= 1 || estTrData.length <= 1 || estaccData.length <= 1) const Center(child: Text("Some charts aren't shown due to lack of data...", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))) - // Why it's look like a garbage solution??? + DropdownButton( + items: chartsData, + value: chartsData[chartsIndex].value, + onChanged: (value) { + chartsIndex = chartsData.indexWhere((element) => element.value == value); + update(); + } + ), + if(chartsData[chartsIndex].value!.length > 1) _HistoryChartThigy(data: chartsData[chartsIndex].value!, title: "ss", yAxisTitle: chartsShortTitles[chartsIndex], bigScreen: bigScreen, leftSpace: bigScreen? 80 : 45, yFormat: bigScreen? f2 : NumberFormat.compact(),) + else const Center(child: Text("Not enough data", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))) ], ), ] : [const Center(child: Text("No history saved", style: TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28)))]); @@ -512,12 +508,12 @@ class _HistoryChartThigy extends StatelessWidget{ @override Widget build(BuildContext context) { double xInterval = bigScreen ? max(1, (data.last.x - data.first.x) / 6) : max(1, (data.last.x - data.first.x) / 3); - return AspectRatio( - aspectRatio: bigScreen ? 1.9 : 1.1, + return SizedBox( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height - 100, child: Stack( children: [ - Row(mainAxisAlignment: MainAxisAlignment.center, children: [Text(title, style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 28))]), - Padding( padding: bigScreen ? const EdgeInsets.fromLTRB(40, 75, 40, 48) : const EdgeInsets.fromLTRB(0, 80, 0, 48) , + Padding( padding: bigScreen ? const EdgeInsets.fromLTRB(40, 40, 40, 48) : const EdgeInsets.fromLTRB(0, 40, 0, 48) , child: LineChart( LineChartData( lineBarsData: [LineChartBarData(spots: data)], @@ -558,7 +554,7 @@ class _RecordThingy extends StatelessWidget { return LayoutBuilder(builder: (context, constraints) { bool bigScreen = constraints.maxWidth > 768; return ListView.builder( - physics: const ClampingScrollPhysics(), + physics: const AlwaysScrollableScrollPhysics(), itemCount: 1, itemBuilder: (BuildContext context, int index) { return Column( @@ -881,7 +877,7 @@ class _OtherThingy extends StatelessWidget { return LayoutBuilder(builder: (context, constraints) { bool bigScreen = constraints.maxWidth > 768; return ListView.builder( - physics: const ClampingScrollPhysics(), + physics: const AlwaysScrollableScrollPhysics(), itemCount: 1, itemBuilder: (BuildContext context, int index) { return Column( diff --git a/pubspec.yaml b/pubspec.yaml index dd896dc..c9f1b7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -85,6 +85,8 @@ flutter: - res/tetrio_badges/early-supporter.png - res/tetrio_badges/founder.png - res/tetrio_badges/galactic2x2_1.png + - res/tetrio_badges/galactic2x2_2.png + - res/tetrio_badges/galactic2x2_3.png - res/tetrio_badges/ggc_1.png - res/tetrio_badges/ggc_2.png - res/tetrio_badges/ggc_3.png diff --git a/res/tetrio_badges/galactic2x2_2.png b/res/tetrio_badges/galactic2x2_2.png new file mode 100644 index 0000000..167cace Binary files /dev/null and b/res/tetrio_badges/galactic2x2_2.png differ diff --git a/res/tetrio_badges/galactic2x2_3.png b/res/tetrio_badges/galactic2x2_3.png new file mode 100644 index 0000000..77df947 Binary files /dev/null and b/res/tetrio_badges/galactic2x2_3.png differ