diff --git a/lib/main.dart b/lib/main.dart index 4a02ac5..7fe23d3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -27,7 +27,7 @@ import 'package:go_router/go_router.dart'; late final PackageInfo packageInfo; late SharedPreferences prefs; late TetrioService teto; -ColorScheme sheme = const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.white); +ThemeData theme = ThemeData(fontFamily: 'Eurostile Round', colorScheme: const ColorScheme.dark(primary: Colors.cyanAccent, secondary: Colors.white), scaffoldBackgroundColor: Colors.black); Future computeIsolate(Future Function() function) async { final receivePort = ReceivePort(); @@ -61,10 +61,6 @@ class _IsolateData { }); } -void setAccentColor(Color color){ // does this thing work??? yes??? no??? - sheme = ColorScheme.dark(primary: color, secondary: Colors.white); -} - final router = GoRouter( initialLocation: "/", routes: [ @@ -160,9 +156,21 @@ void main() async { )); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { const MyApp({super.key}); + @override + State createState() => MyAppState(); +} + +class MyAppState extends State { + + void setAccentColor(Color color){ // does this thing work??? yes??? no??? + setState(() { + theme = theme.copyWith(colorScheme: theme.colorScheme.copyWith(primary: color)); + }); + } + @override Widget build(BuildContext context) { return MaterialApp.router( @@ -174,11 +182,7 @@ class MyApp extends StatelessWidget { locale: TranslationProvider.of(context).flutterLocale, supportedLocales: AppLocaleUtils.supportedLocales, localizationsDelegates: GlobalMaterialLocalizations.delegates, - theme: ThemeData( - fontFamily: 'Eurostile Round', - colorScheme: sheme, - scaffoldBackgroundColor: Colors.black - ) + theme: theme ); } } diff --git a/lib/views/customization_view.dart b/lib/views/customization_view.dart index b6ff08c..7d2a0ac 100644 --- a/lib/views/customization_view.dart +++ b/lib/views/customization_view.dart @@ -1,8 +1,9 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; import 'package:tetra_stats/views/settings_view.dart' show subtitleStyle; -import 'package:tetra_stats/main.dart' show prefs; +import 'package:tetra_stats/main.dart' show MyApp, MyAppState, prefs, setAccentColor; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:window_manager/window_manager.dart'; @@ -87,36 +88,33 @@ class CustomizationState extends State { body: SafeArea( child: ListView( children: [ - // ListTile( - // title: const Text("Accent color"), - // trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary)), - // onTap: () { - // showDialog( - // context: context, - // builder: (BuildContext context) => AlertDialog( - // title: const Text('Pick an accent color'), - // content: SingleChildScrollView( - // child: ColorPicker( - // pickerColor: pickerColor, - // onColorChanged: changeColor, - // ), - // ), - // actions: [ - // ElevatedButton( - // child: const Text('Set'), - // onPressed: () { - // setState(() { - // setAccentColor(pickerColor); - // }); - // Navigator.of(context).pop(); - // }, - // ), - // ])); - // }), - // const ListTile( - // title: Text("Font"), - // subtitle: Text("Not implemented"), - // ), + ListTile( + title: const Text("Accent color"), + trailing: ColorIndicator(HSVColor.fromColor(Theme.of(context).colorScheme.primary), width: 25, height: 25), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: const Text('Pick an accent color'), + content: SingleChildScrollView( + child: ColorPicker( + pickerColor: pickerColor, + onColorChanged: changeColor, + ), + ), + actions: [ + ElevatedButton( + child: const Text('Set'), + onPressed: () { + setState(() { + context.findAncestorStateOfType()?.setAccentColor(pickerColor); + }); + Navigator.of(context).pop(); + }, + ), + ])); + } + ), // const ListTile( // title: Text("Stats Table in TL mathes list"), // subtitle: Text("Not implemented"), diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 6d3a71a..c9187c3 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -17,6 +17,7 @@ import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/main.dart' show prefs, teto; import 'package:tetra_stats/services/crud_exceptions.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; +import 'package:tetra_stats/utils/open_in_browser.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/views/singleplayer_record_view.dart'; @@ -948,6 +949,7 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { primaryYAxis: const NumericAxis( rangePadding: ChartRangePadding.additional, ), + margin: const EdgeInsets.all(0), series: [ if (_gamesPlayedInsteadOfDateAndTime) StepLineSeries<_HistoryChartSpot, int>( enableTooltip: true, @@ -958,12 +960,13 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { opacity: _smooth ? 0 : 1, xValueMapper: (_HistoryChartSpot data, _) => data.gamesPlayed, yValueMapper: (_HistoryChartSpot data, _) => data.stat, + color: Theme.of(context).colorScheme.primary, trendlines:[ Trendline( isVisible: _smooth, period: (widget.data.length/175).floor(), type: TrendlineType.movingAverage, - color: Colors.blue) + color: Theme.of(context).colorScheme.primary) ], ) else StepLineSeries<_HistoryChartSpot, DateTime>( @@ -975,12 +978,13 @@ class _HistoryChartThigyState extends State<_HistoryChartThigy> { opacity: _smooth ? 0 : 1, xValueMapper: (_HistoryChartSpot data, _) => data.timestamp, yValueMapper: (_HistoryChartSpot data, _) => data.stat, + color: Theme.of(context).colorScheme.primary, trendlines:[ Trendline( isVisible: _smooth, period: (widget.data.length/175).floor(), type: TrendlineType.movingAverage, - color: Colors.blue) + color: Theme.of(context).colorScheme.primary) ], ), ], @@ -1029,9 +1033,9 @@ class _TwoRecordsThingy extends StatelessWidget { } return SingleChildScrollView(child: Padding( padding: const EdgeInsets.only(top: 20.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + crossAxisAlignment: WrapCrossAlignment.start, children: [ Column( mainAxisAlignment: MainAxisAlignment.start, @@ -1084,6 +1088,15 @@ class _TwoRecordsThingy extends StatelessWidget { if (sprint != null) FinesseThingy(sprint?.endContext.finesse, sprint?.endContext.finessePercentage), if (sprint != null) LineclearsThingy(sprint!.endContext.clears, sprint!.endContext.lines, sprint!.endContext.holds, sprint!.endContext.tSpins), if (sprint != null) Text("${sprint!.endContext.inputs} KP • ${f2.format(sprint!.endContext.kps)} KPS"), + Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 20, + children: [ + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${sprint!.replayId}"));}, child: Text("Open replay in TETR.IO")), + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${sprint!.replayId}"));}, child: Text("Download replay")), + ], + ), if (sprintStream.records.length > 1) SizedBox( width: 400, child: Column( @@ -1161,6 +1174,15 @@ class _TwoRecordsThingy extends StatelessWidget { if (blitz != null) FinesseThingy(blitz?.endContext.finesse, blitz?.endContext.finessePercentage), if (blitz != null) LineclearsThingy(blitz!.endContext.clears, blitz!.endContext.lines, blitz!.endContext.holds, blitz!.endContext.tSpins), if (blitz != null) Text("${blitz!.endContext.piecesPlaced} P • ${blitz!.endContext.inputs} KP • ${f2.format(blitz!.endContext.kpp)} KPP • ${f2.format(blitz!.endContext.kps)} KPS"), + Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 20, + children: [ + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${blitz!.replayId}"));}, child: Text("Open replay in TETR.IO")), + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${blitz!.replayId}"));}, child: Text("Download replay")), + ], + ), if (blitzStream.records.length > 1) SizedBox( width: 400, child: Column( diff --git a/lib/views/singleplayer_record_view.dart b/lib/views/singleplayer_record_view.dart index eb23320..eb5b2fd 100644 --- a/lib/views/singleplayer_record_view.dart +++ b/lib/views/singleplayer_record_view.dart @@ -33,6 +33,7 @@ class SingleplayerRecordView extends StatelessWidget { Column( children: [ SingleplayerRecord(record: record, hideTitle: true), + // TODO: Insert replay link here ] ) ], diff --git a/lib/widgets/graphs.dart b/lib/widgets/graphs.dart index 366d0ba..e8f3ebd 100644 --- a/lib/widgets/graphs.dart +++ b/lib/widgets/graphs.dart @@ -332,6 +332,8 @@ class Graphs extends StatelessWidget{ }, dataSets: [ RadarDataSet( + fillColor: Theme.of(context).colorScheme.primary.withAlpha(100), + borderColor: Theme.of(context).colorScheme.primary, dataEntries: [ RadarEntry(value: apm * apmWeight), RadarEntry(value: pps * ppsWeight), @@ -399,6 +401,8 @@ class Graphs extends StatelessWidget{ }, dataSets: [ RadarDataSet( + fillColor: Theme.of(context).colorScheme.primary.withAlpha(100), + borderColor: Theme.of(context).colorScheme.primary, dataEntries: [ RadarEntry(value: playstyle.opener), RadarEntry(value: playstyle.stride), @@ -454,6 +458,8 @@ class Graphs extends StatelessWidget{ }, dataSets: [ RadarDataSet( + fillColor: Theme.of(context).colorScheme.primary.withAlpha(100), + borderColor: Theme.of(context).colorScheme.primary, dataEntries: [ RadarEntry(value: attack), RadarEntry(value: speed), diff --git a/lib/widgets/singleplayer_record.dart b/lib/widgets/singleplayer_record.dart index 594c539..9be5844 100644 --- a/lib/widgets/singleplayer_record.dart +++ b/lib/widgets/singleplayer_record.dart @@ -3,6 +3,7 @@ import 'package:intl/intl.dart'; import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/gen/strings.g.dart'; import 'package:tetra_stats/utils/numers_formats.dart'; +import 'package:tetra_stats/utils/open_in_browser.dart'; import 'package:tetra_stats/utils/relative_timestamps.dart'; import 'package:tetra_stats/utils/text_shadow.dart'; import 'package:tetra_stats/views/singleplayer_record_view.dart'; @@ -125,6 +126,15 @@ class SingleplayerRecord extends StatelessWidget { LineclearsThingy(record!.endContext.clears, record!.endContext.lines, record!.endContext.holds, record!.endContext.tSpins), if (record!.endContext.gameType == "40l") Text("${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kps)} KPS"), if (record!.endContext.gameType == "blitz") Text("${record!.endContext.piecesPlaced} P • ${record!.endContext.inputs} KP • ${f2.format(record!.endContext.kpp)} KPP • ${f2.format(record!.endContext.kps)} KPS"), + Wrap( + alignment: WrapAlignment.spaceBetween, + crossAxisAlignment: WrapCrossAlignment.start, + spacing: 20, + children: [ + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://tetr.io/#r:${record!.replayId}"));}, child: Text("Open replay in TETR.IO")), + TextButton(onPressed: (){launchInBrowser(Uri.parse("https://inoue.szy.lol/api/replay/${record!.replayId}"));}, child: Text("Download replay")), + ], + ), if (stream != null && stream!.records.length > 1) for(int i = 1; i < stream!.records.length; i++) ListTile( onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => SingleplayerRecordView(record: stream!.records[i]))), leading: Text("#${i+1}", diff --git a/lib/widgets/tl_progress_bar.dart b/lib/widgets/tl_progress_bar.dart index b13a7d4..e1afece 100644 --- a/lib/widgets/tl_progress_bar.dart +++ b/lib/widgets/tl_progress_bar.dart @@ -82,8 +82,8 @@ class TLProgress extends StatelessWidget{ maximum: 1, interval: 1, ranges: [ - if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tlData.rating)!, color: Colors.cyanAccent, position: LinearElementPosition.cross) - else if (tlData.standing != -1) LinearGaugeRange(endValue: getBarPosition(), color: Colors.cyanAccent, position: LinearElementPosition.cross), + if (previousRankTRcutoff != null && nextRankTRcutoff != null) LinearGaugeRange(endValue: getBarTR(tlData.rating)!, color: Theme.of(context).colorScheme.primary, position: LinearElementPosition.cross) + else if (tlData.standing != -1) LinearGaugeRange(endValue: getBarPosition(), color: Theme.of(context).colorScheme.primary, position: LinearElementPosition.cross), if (previousRankTRcutoff != null && previousRankTRcutoffTarget != null) LinearGaugeRange(endValue: getBarTR(previousRankTRcutoffTarget!)!, color: Colors.greenAccent, position: LinearElementPosition.inside), if (nextRankTRcutoff != null && nextRankTRcutoffTarget != null && previousRankTRcutoff != null) LinearGaugeRange(startValue: getBarTR(nextRankTRcutoffTarget!)!, endValue: 1, color: Colors.yellowAccent, position: LinearElementPosition.inside) ],