From ff04c27edb61163510c5ea491857534738a1a221 Mon Sep 17 00:00:00 2001 From: dan63047 Date: Thu, 8 Jun 2023 19:47:33 +0300 Subject: [PATCH] IT'S WORKING... Somehow --- lib/services/sqlite_db_controller.dart | 4 +- lib/services/tetrio_crud.dart | 78 +++++++++------- lib/views/main_view.dart | 124 +++++++++++++++---------- 3 files changed, 122 insertions(+), 84 deletions(-) diff --git a/lib/services/sqlite_db_controller.dart b/lib/services/sqlite_db_controller.dart index d59e7b7..700a48e 100644 --- a/lib/services/sqlite_db_controller.dart +++ b/lib/services/sqlite_db_controller.dart @@ -43,9 +43,9 @@ class DB { } } - Future _ensureDbIsOpen(DB udb) async { + Future ensureDbIsOpen() async { try { - await udb.open(); + await open(); } on DatabaseAlreadyOpen { // empty } diff --git a/lib/services/tetrio_crud.dart b/lib/services/tetrio_crud.dart index cf6939f..a398b94 100644 --- a/lib/services/tetrio_crud.dart +++ b/lib/services/tetrio_crud.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer' as developer; import 'package:http/http.dart' as http; +import 'dart:async'; +import 'package:sqflite/sqflite.dart'; // import 'package:sqflite/sqflite.dart'; // import 'package:path_provider/path_provider.dart' show MissingPlatformDirectoryException, getApplicationDocumentsDirectory; // import 'package:path/path.dart' show join; @@ -22,22 +24,34 @@ const String createTetrioUsersTable = ''' PRIMARY KEY("id") );'''; -class TetrioService { +class TetrioService extends DB { Map> _players = {}; - final _tetrioStreamController = StreamController>>.broadcast(); - - TetrioService(DB udb) { - _cachePlayers(udb); + static final TetrioService _shared = TetrioService._sharedInstance(); + factory TetrioService() => _shared; + late final StreamController>> _tetrioStreamController; + TetrioService._sharedInstance() { + _tetrioStreamController = StreamController>>.broadcast(onListen: () { + _tetrioStreamController.sink.add(_players); + }); } - Future _cachePlayers(DB udb) async { - final allPlayers = await getAllPlayers(udb: udb); + @override + Future open() async { + await super.open(); + await _cachePlayers(); + } + + Stream>> get allPlayers => _tetrioStreamController.stream; + + Future _cachePlayers() async { + final allPlayers = await getAllPlayers(); _players = allPlayers.toList().first; // ??? _tetrioStreamController.add(_players); developer.log("_cachePlayers: $_players", name: "services/tetrio_crud"); } Future deletePlayer({required String id, required DB udb}) async { + await ensureDbIsOpen(); final db = udb.getDatabaseOrThrow(); final deletedPlayer = await db.delete(tetrioUsersTable, where: '$idCol = ?', whereArgs: [id.toLowerCase()]); if (deletedPlayer != 1) { @@ -58,9 +72,9 @@ class TetrioService { // } // } - Future createPlayer({required TetrioPlayer tetrioPlayer, required DB udb}) async { - _ensureDbIsOpen(udb); - final db = udb.getDatabaseOrThrow(); + Future createPlayer(TetrioPlayer tetrioPlayer) async { + ensureDbIsOpen(); + final db = getDatabaseOrThrow(); final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [tetrioPlayer.userId.toLowerCase()]); if (results.isNotEmpty) { throw TetrioPlayerAlreadyExist(); @@ -73,15 +87,15 @@ class TetrioService { _tetrioStreamController.add(_players); } - Future storeState(TetrioPlayer tetrioPlayer, DB udb) async { - _ensureDbIsOpen(udb); - final db = udb.getDatabaseOrThrow(); + Future storeState(TetrioPlayer tetrioPlayer) async { + ensureDbIsOpen(); + final db = getDatabaseOrThrow(); late List states; try { - states = await getPlayer(id: tetrioPlayer.userId, udb: udb); + states = await getPlayer(tetrioPlayer.userId); } on TetrioPlayerNotExist { - await createPlayer(tetrioPlayer: tetrioPlayer, udb: udb); - states = await getPlayer(id: tetrioPlayer.userId, udb: udb); + await createPlayer(tetrioPlayer); + states = await getPlayer(tetrioPlayer.userId); } if (!_players[tetrioPlayer.userId]!.last.isSameState(tetrioPlayer)) states.add(tetrioPlayer); final Map statesJson = {}; @@ -94,9 +108,9 @@ class TetrioService { _tetrioStreamController.add(_players); } - Future> getPlayer({required String id, required DB udb}) async { - _ensureDbIsOpen(udb); - final db = udb.getDatabaseOrThrow(); + Future> getPlayer(String id) async { + ensureDbIsOpen(); + final db = getDatabaseOrThrow(); List states = []; final results = await db.query(tetrioUsersTable, limit: 1, where: '$idCol = ?', whereArgs: [id.toLowerCase()]); if (results.isEmpty) { @@ -112,7 +126,7 @@ class TetrioService { } } - Future fetchPlayer(String user, DB udb, bool addToDB) async { + Future fetchPlayer(String user, bool addToDB) async { var url = Uri.https('ch.tetr.io', 'api/users/${user.toLowerCase().trim()}'); final response = await http.get(url); @@ -121,8 +135,8 @@ class TetrioService { TetrioPlayer player = TetrioPlayer.fromJson( jsonDecode(response.body)['data']['user'], DateTime.fromMillisecondsSinceEpoch(jsonDecode(response.body)['cache']['cached_at'], isUtc: true), true); if (addToDB) { - _ensureDbIsOpen(udb); - storeState(player, udb); + await ensureDbIsOpen(); + storeState(player); } return player; } else { @@ -135,17 +149,17 @@ class TetrioService { } } - Future _ensureDbIsOpen(DB udb) async { - try { - await udb.open(); - } on DatabaseAlreadyOpen { - // empty - } - } + // Future _ensureDbIsOpen() async { + // try { + // await open(); + // } on DatabaseAlreadyOpen { + // // empty + // } + // } - Future>>> getAllPlayers({required DB udb}) async { - await _ensureDbIsOpen(udb); - final db = udb.getDatabaseOrThrow(); + Future>>> getAllPlayers() async { + await ensureDbIsOpen(); + final db = getDatabaseOrThrow(); final players = await db.query(tetrioUsersTable); Map> data = {}; //developer.log("getAllPlayers: $players", name: "services/tetrio_crud"); diff --git a/lib/views/main_view.dart b/lib/views/main_view.dart index 18f256f..35afdf7 100644 --- a/lib/views/main_view.dart +++ b/lib/views/main_view.dart @@ -17,8 +17,7 @@ extension StringExtension on String { String _searchFor = "dan63047"; Future? me; -DB db = DB(); -late final TetrioService teto; +final TetrioService teto = TetrioService(); late SharedPreferences prefs; const allowedHeightForPlayerIdInPixels = 40.0; const allowedHeightForPlayerBioInPixels = 30.0; @@ -76,8 +75,8 @@ class _MainState extends State with SingleTickerProviderStateMixin { @override void initState() { - db.open(); - teto = TetrioService(db); + //teto = TetrioService(); + teto.open(); _scrollController = ScrollController(); _tabController = TabController(length: 4, vsync: this); _getPreferences().then((value) => changePlayer(prefs.getString("player") ?? "dan63047")); @@ -89,7 +88,7 @@ class _MainState extends State with SingleTickerProviderStateMixin { void dispose() { _tabController.dispose(); _scrollController.dispose(); - db.close(); + //db.close(); super.dispose(); developer.log("Main view disposed", name: "main_view"); } @@ -102,7 +101,7 @@ class _MainState extends State with SingleTickerProviderStateMixin { setState(() { _tabController.animateTo(0, duration: const Duration(milliseconds: 300)); _searchFor = player; - me = teto.fetchPlayer(player, db, false); + me = teto.fetchPlayer(player, false); }); } @@ -195,51 +194,62 @@ class _MainState extends State with SingleTickerProviderStateMixin { future: me, builder: (context, snapshot) { developer.log("builder ($context): $snapshot", name: "main_view"); - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center( - child: CircularProgressIndicator( - color: Colors.white, - )); - } - if (snapshot.hasData) { - bool bigScreen = MediaQuery.of(context).size.width > 1024; - return NestedScrollView( - controller: _scrollController, - headerSliverBuilder: (context, value) { - return [ - SliverToBoxAdapter(child: _UserThingy(player: snapshot.data!)), - SliverToBoxAdapter( - child: TabBar( - controller: _tabController, - isScrollable: true, - tabs: myTabs, - onTap: (int tabId) { - setState(() { - developer.log("Tab changed to $tabId", name: "main_view"); - }); - }, - ), + switch (snapshot.connectionState) { + case ConnectionState.none: + return Center( + child: Text('none case of FutureBuilder', + style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + case ConnectionState.waiting: + return const Center(child: CircularProgressIndicator(color: Colors.white)); + case ConnectionState.active: + return Center( + child: Text('active case of FutureBuilder', + style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + 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!)), + SliverToBoxAdapter( + child: TabBar( + controller: _tabController, + isScrollable: true, + tabs: myTabs, + onTap: (int tabId) { + setState(() { + developer.log("Tab changed to $tabId", name: "main_view"); + }); + }, + ), + ), + ]; + }, + body: TabBarView( + controller: _tabController, + children: [ + _TLThingy(tl: snapshot.data!.tlSeason1, userID: snapshot.data!.userId), + _RecordThingy(record: (snapshot.data!.sprint.isNotEmpty) ? snapshot.data!.sprint[0] : null), + _RecordThingy(record: (snapshot.data!.blitz.isNotEmpty) ? snapshot.data!.blitz[0] : null), + _OtherThingy(zen: snapshot.data!.zen, bio: snapshot.data!.bio) + ], ), - ]; - }, - body: TabBarView( - controller: _tabController, - children: [ - _TLThingy(tl: snapshot.data!.tlSeason1, userID: snapshot.data!.userId), - _RecordThingy(record: (snapshot.data!.sprint.isNotEmpty) ? snapshot.data!.sprint[0] : null), - _RecordThingy(record: (snapshot.data!.blitz.isNotEmpty) ? snapshot.data!.blitz[0] : null), - _OtherThingy(zen: snapshot.data!.zen, bio: snapshot.data!.bio) - ], - ), - ); - } else if (snapshot.hasError) { - return Center( - child: Text('${snapshot.error}', style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + ); + } else if (snapshot.hasError) { + return Center( + child: + Text('${snapshot.error}', style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); + } + break; + default: + return Center( + child: Text('default case of FutureBuilder', + style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); } - return const Center( - child: CircularProgressIndicator( - color: Colors.white, - )); + return Center( + child: Text('end of FutureBuilder', style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42), textAlign: TextAlign.center)); }, ), ), @@ -271,6 +281,20 @@ class NavDrawer extends StatelessWidget { Navigator.of(context).pop(); }, ), + StreamBuilder( + stream: teto.allPlayers, + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + return Center(child: Text('none case of StreamBuilder')); + case ConnectionState.waiting: + case ConnectionState.active: + return Center(child: Text('${snapshot.data}')); + case ConnectionState.done: + return Center(child: Text('done case of StreamBuilder')); + } + }, + ) ], ), ); @@ -452,7 +476,7 @@ class _UserThingy extends StatelessWidget { children: [ Expanded( child: Text( - "${player.country != null ? "${player.country?.toUpperCase()} • " : ""}${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${player.registrationTime}'} • ${player.supporterTier == 0 ? "Not a supporter" : "Supporter tier ${player.supporterTier}"}", + "${player.country != null ? "${player.country?.toUpperCase()} • " : ""}${player.role.capitalize()} account ${player.registrationTime == null ? "that was from very beginning" : 'created ${player.registrationTime}'}${player.botmaster != null ? " by ${player.botmaster}" : ""} • ${player.supporterTier == 0 ? "Not a supporter" : "Supporter tier ${player.supporterTier}"}", textAlign: TextAlign.center, style: const TextStyle( fontFamily: "Eurostile Round",