I wonder if it's actually gonna be good

This commit is contained in:
dan63047 2023-05-29 22:10:14 +03:00
parent ffad0ae6cb
commit a9964e7154
1 changed files with 283 additions and 128 deletions

View File

@ -1,15 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
import 'package:tetra_stats/data_objects/tetrio.dart'; import 'package:tetra_stats/data_objects/tetrio.dart';
import 'package:tetra_stats/services/tetrio_crud.dart'; import 'package:tetra_stats/services/tetrio_crud.dart';
import 'package:tetra_stats/services/sqlite_db_controller.dart'; import 'package:tetra_stats/services/sqlite_db_controller.dart';
String _searchFor = ""; String _searchFor = "";
late TetrioPlayer me; late Future<TetrioPlayer> me;
DB db = DB(); DB db = DB();
TetrioService teto = TetrioService(); TetrioService teto = TetrioService();
const allowedHeightForPlayerIdInPixels = 60.0; const allowedHeightForPlayerIdInPixels = 40.0;
const allowedHeightForPlayerBioInPixels = 30.0; const allowedHeightForPlayerBioInPixels = 30.0;
const givenTextHeightByScreenPercentage = 0.3; const givenTextHeightByScreenPercentage = 0.3;
@ -18,14 +19,14 @@ enum SampleItem { itemOne, itemTwo, itemThree }
class MainView extends StatefulWidget { class MainView extends StatefulWidget {
const MainView({Key? key}) : super(key: key); const MainView({Key? key}) : super(key: key);
String get title => "Tetra Stats: $_searchFor";
@override @override
State<MainView> createState() => _MainViewState(); State<MainView> createState() => _MainViewState();
} }
class _MainViewState extends State<MainView> { Future<TetrioPlayer> fetchTetrioPlayer(String user) async {
Future<TetrioPlayer> fetchTetrioPlayer(String user) async {
var url = Uri.https('ch.tetr.io', 'api/users/$user'); var url = Uri.https('ch.tetr.io', 'api/users/$user');
db.open();
final response = await http.get(url); final response = await http.get(url);
// final response = await http.get(Uri.parse('https://ch.tetr.io/')); // final response = await http.get(Uri.parse('https://ch.tetr.io/'));
@ -42,14 +43,42 @@ class _MainViewState extends State<MainView> {
// then throw an exception. // then throw an exception.
throw Exception('Failed to fetch player'); throw Exception('Failed to fetch player');
} }
} }
late Future<TetrioPlayer> me;
class _MainViewState extends State<MainView> {
bool _searchBoolean = false;
String _coverLink = "";
@override @override
void initState() { void initState() {
super.initState(); super.initState();
me = fetchTetrioPlayer("blaarg"); me = fetchTetrioPlayer("dan63047");
}
Widget _searchTextField() {
return TextField(
decoration: const InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white))),
style: const TextStyle(
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(0.0, 0.0),
blurRadius: 3.0,
color: Colors.black,
),
Shadow(
offset: Offset(0.0, 0.0),
blurRadius: 8.0,
color: Colors.black,
),
],
),
onSubmitted: (String value) => setState(() {
me = fetchTetrioPlayer(value);
_searchFor = value;
}),
);
} }
@override @override
@ -57,106 +86,96 @@ class _MainViewState extends State<MainView> {
return Scaffold( return Scaffold(
drawer: NavDrawer(), drawer: NavDrawer(),
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: CustomScrollView( appBar: AppBar(
slivers: [ title: !_searchBoolean
SliverAppBar( ? Text(
title: const Text("Tetra Stats"), widget.title,
floating: false, style: const TextStyle(
pinned: true, shadows: <Shadow>[
flexibleSpace: Row( Shadow(
mainAxisAlignment: MainAxisAlignment.center, offset: Offset(0.0, 0.0),
children: [ blurRadius: 3.0,
ClipRRect( color: Colors.black,
borderRadius: BorderRadius.circular(1000),
child: Image.network(
"https://tetr.io/user-content/avatars/6098518e3d5155e6ec429cdc.jpg?rv=1673453211638",
fit: BoxFit.fitHeight,
height: 256,
), ),
Shadow(
offset: Offset(0.0, 0.0),
blurRadius: 8.0,
color: Colors.black,
), ),
LayoutBuilder(builder: (context, constraints) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (constraints.maxHeight *
givenTextHeightByScreenPercentage >
allowedHeightForPlayerBioInPixels)
const Text("dan63047",
style: TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 42))
else
const Text("dan63047",
style: TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 36)),
if (constraints.maxHeight *
givenTextHeightByScreenPercentage >
allowedHeightForPlayerIdInPixels)
const Text(
"6098518e3d5155e6ec429cdc",
style: TextStyle(
fontFamily: "Eurostile Round Condensed",
color: Colors.white,
fontSize: 14),
),
if (constraints.maxHeight *
givenTextHeightByScreenPercentage >
allowedHeightForPlayerBioInPixels)
const Text(
"osk, please, if my supporter ends, let me use :petthekagari: in the chat",
style: TextStyle(
fontFamily: "Eurostile Round",
color: Colors.white,
fontSize: 16,
),
softWrap: true),
],
);
})
], ],
), ),
expandedHeight: 400, )
: _searchTextField(),
flexibleSpace: Image.network(
_coverLink,
fit: BoxFit.cover,
),
backgroundColor: Colors.black, backgroundColor: Colors.black,
actions: [ actions: [
IconButton( !_searchBoolean
onPressed: () {}, ? IconButton(
onPressed: () {
setState(() {
//add
_searchBoolean = true;
});
},
icon: const Icon(Icons.search), icon: const Icon(Icons.search),
tooltip: "Search player", tooltip: "Search player",
)
: IconButton(
onPressed: () {
setState(() {
//add
_searchBoolean = false;
});
},
icon: const Icon(Icons.clear),
tooltip: "Close search",
), ),
PopupMenuButton( PopupMenuButton(
itemBuilder: (BuildContext context) => itemBuilder: (BuildContext context) => <PopupMenuEntry<SampleItem>>[
<PopupMenuEntry<SampleItem>>[
const PopupMenuItem<SampleItem>( const PopupMenuItem<SampleItem>(
value: SampleItem.itemOne, value: SampleItem.itemOne,
child: Text('Item 1'), child: Text('Compare'),
), ),
const PopupMenuItem<SampleItem>( const PopupMenuItem<SampleItem>(
value: SampleItem.itemTwo, value: SampleItem.itemTwo,
child: Text('Item 2'), child: Text('States'),
), ),
const PopupMenuItem<SampleItem>( const PopupMenuItem<SampleItem>(
value: SampleItem.itemThree, value: SampleItem.itemThree,
child: Text('Item 3'), child: Text('Settings'),
), ),
], ],
), ),
], ],
), ),
SliverList( body: SafeArea(
delegate: SliverChildBuilderDelegate( child: FutureBuilder<TetrioPlayer>(
(context, index) => ListTile( future: me,
title: Text('Item #$index'), builder: (context, snapshot) {
tileColor: Colors.transparent, if (snapshot.hasData) {
textColor: Colors.white, _coverLink =
), "https://tetr.io/user-content/banners/${snapshot.data!.userId}.jpg?rv=${snapshot.data!.bannerRevision}";
childCount: 1000, return ListView(
), padding: const EdgeInsets.all(8),
), children: [
_UserThingy(player: snapshot.data!),
], ],
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}',
style: const TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 42));
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
), ),
); );
} }
@ -173,13 +192,7 @@ class NavDrawer extends StatelessWidget {
child: Text( child: Text(
'Side menu', 'Side menu',
style: TextStyle(color: Colors.white, fontSize: 25), style: TextStyle(color: Colors.white, fontSize: 25),
), )),
decoration: BoxDecoration(
color: Color.fromARGB(255, 40, 44, 41),
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage('assets/images/cover.jpg'))),
),
ListTile( ListTile(
leading: const Icon(Icons.input), leading: const Icon(Icons.input),
title: const Text('Welcome'), title: const Text('Welcome'),
@ -260,3 +273,145 @@ class NavDrawer extends StatelessWidget {
); );
} }
} }
class _UserThingy extends StatelessWidget {
final TetrioPlayer player;
const _UserThingy({Key? key, required this.player}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final settings = context
.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();
return Column(
children: [
Flex(
direction: Axis.vertical,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Image.network(
"https://tetr.io/user-content/avatars/${player.userId}.jpg?rv=${player.avatarRevision}",
fit: BoxFit.fitHeight,
height: 128,
),
),
Flexible(
child: Column(
children: [
Text(player.username,
style: const TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 42)),
Text(
player.userId,
style: const TextStyle(
fontFamily: "Eurostile Round Condensed",
color: Colors.white,
fontSize: 14),
),
],
),
),
],
),
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 25,
crossAxisAlignment: WrapCrossAlignment.start,
clipBehavior: Clip.hardEdge, // hard WHAT???
children: [
_StatCellNum(
playerStat: player.level,
playerStatLabel: "Level\n${player.xp.floor().toString()} XP"),
_StatCellDuration(
playerStat: player.gameTime, playerStatLabel: "Gametime"),
_StatCellNum(
playerStat: player.gamesPlayed,
playerStatLabel: "Games\nPlayed"),
_StatCellNum(
playerStat: player.gamesWon, playerStatLabel: "Games\nWon"),
],
)
],
);
});
}
}
class _StatCellNum extends StatelessWidget {
const _StatCellNum({
super.key,
required this.playerStat,
required this.playerStatLabel,
});
final num playerStat;
final String playerStatLabel;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
playerStat.toStringAsFixed(0),
style: const TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 32,
),
),
Text(
playerStatLabel,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: "Eurostile Round",
color: Colors.white,
fontSize: 16,
),
),
],
);
}
}
class _StatCellDuration extends StatelessWidget {
const _StatCellDuration({
super.key,
required this.playerStat,
required this.playerStatLabel,
});
final Duration playerStat;
final String playerStatLabel;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
playerStat.toString().toString().split('.').first.padLeft(8, "0"),
style: const TextStyle(
fontFamily: "Eurostile Round Extended",
color: Colors.white,
fontSize: 32,
),
),
Text(
playerStatLabel,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: "Eurostile Round",
color: Colors.white,
fontSize: 16,
),
),
],
);
}
}