diff --git a/assets/human-brain.png b/assets/human-brain.png deleted file mode 100644 index e96e296..0000000 Binary files a/assets/human-brain.png and /dev/null differ diff --git a/lib/main.dart b/lib/main.dart index c6861a8..fee997f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'package:rememberme/screens/Stats.dart'; import 'package:rememberme/screens/homescreen.dart'; import 'package:rememberme/screens/login-signup.dart'; -import 'package:rememberme/screens/profile.dart'; import 'package:rememberme/services/authservice.dart'; +import 'package:rememberme/services/userservice.dart'; import 'firebase_options.dart'; -import 'package:rememberme/screens/modifycard.dart'; -import 'Screens/MemorySelect.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -15,6 +12,8 @@ void main() async { options: DefaultFirebaseOptions.currentPlatform, ); + UserService.updateUserLoginDate(); + runApp(MyApp()); } @@ -53,4 +52,4 @@ class MyApp extends StatelessWidget { home: AuthService.isUserSignedIn() ? Homepage() : LoginOptions(), ); } -} \ No newline at end of file +} diff --git a/lib/screens/EndScreen.dart b/lib/screens/EndScreen.dart index 4ad6808..e78fd11 100644 --- a/lib/screens/EndScreen.dart +++ b/lib/screens/EndScreen.dart @@ -3,6 +3,7 @@ import 'package:rememberme/controllers/MemoryGameController.dart'; import 'package:rememberme/screens/Homescreen.dart'; import 'package:rememberme/screens/MemoryGame.dart'; import 'package:rememberme/controllers/MemoryGameController.dart'; +import 'package:rememberme/services/userservice.dart'; import '../widgets/memorygameselectdialog.dart'; class EndPage extends StatefulWidget { @@ -15,12 +16,21 @@ class EndPage extends StatefulWidget { } class _EndPageState extends State { + late int correct; + late int wrong; + late int accuracy; + @override - Widget build(BuildContext context) { - int correct = widget.m.correctGuesses; - int wrong = widget.m.wrongGuesses; - int accuracy = (((wrong - correct).abs() / correct) * 100).round(); + void initState() { + super.initState(); + correct = widget.m.correctGuesses; + wrong = widget.m.wrongGuesses; + accuracy = (correct / (correct + wrong) * 100).round(); + UserService.setMemoryGameHighScore(accuracy); + } + @override + Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.all(40), @@ -75,7 +85,7 @@ class _EndPageState extends State { Padding( padding: const EdgeInsets.fromLTRB(20, 30, 20, 10), child: Text( - 'Accuarcy: ${accuracy}%', + 'Accuracy: ${accuracy}%', style: TextStyle( color: Colors.black, fontSize: 25, diff --git a/lib/screens/Homescreen.dart b/lib/screens/Homescreen.dart index 1858f99..653cb0a 100644 --- a/lib/screens/Homescreen.dart +++ b/lib/screens/Homescreen.dart @@ -12,7 +12,6 @@ import 'package:rememberme/services/cardservice.dart'; import 'package:rememberme/services/deckservice.dart'; import 'package:rememberme/widgets/MemoryGameButton.dart'; import 'package:rememberme/widgets/deckcarousel.dart'; -import 'package:rememberme/widgets/memorygameselectdialog.dart'; import 'package:rememberme/widgets/roundedpage.dart'; import 'package:icon_decoration/icon_decoration.dart'; import 'package:rememberme/widgets/useravatar.dart'; @@ -26,15 +25,12 @@ class Homepage extends StatefulWidget { class _HomepageState extends State { List _masterCardList = []; + List _decks = []; @override void initState() { super.initState(); - DeckService.getMasterDeck().then((value) { - setState(() { - _masterCardList = value.cards; - }); - }); + _update(); } @override @@ -53,43 +49,63 @@ class _HomepageState extends State { labelStyle: TextStyle(fontSize: 22), child: const Icon(Icons.note_add, size: 30, color: Color.fromRGBO(239, 119, 55, 1.0)), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const ModifyCard()), - ), + onTap: () async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ModifyCard()), + ); + await _update(); + }, ), SpeedDialChild( label: 'New Deck', labelStyle: TextStyle(fontSize: 22), child: const Icon(Icons.collections_bookmark, size: 30, color: Color.fromRGBO(239, 119, 55, 1.0)), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const ModifyDeck()), - ), + onTap: () async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ModifyDeck()), + ); + await _update(); + }, ), SpeedDialChild( label: 'QR Code', labelStyle: TextStyle(fontSize: 22), child: const Icon(Icons.qr_code_outlined, size: 30, color: Color.fromRGBO(239, 119, 55, 1.0)), - onTap: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const QRScan()), - ), - onLongPress: () => Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const QRView()), - ), + onTap: () async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const QRScan()), + ); + await _update(); + }, + onLongPress: () async { + await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const QRView()), + ); + await _update(); + }, ), ], ), appBarActions: [ IconButton( - onPressed: () { + onPressed: () async { // method to show the search bar - showSearch( + var res = await showSearch( context: context, // delegate to customize the search bar delegate: _CustomSearchDelegate( cards: _masterCardList, )); + if (res != null && mounted) { + await Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ModifyCard( + existingCard: res, + ), + )); + } + await _update(); }, icon: const Icon(Icons.search), ) @@ -120,38 +136,36 @@ class _HomepageState extends State { MaterialPageRoute(builder: (context) => const Stats()), ); }, - icon: Stack( - alignment: AlignmentDirectional.center, - children: const [ - Icon( - Icons.circle, - size: 70, - color: Color.fromARGB(90, 60, 200, 10), - ), - DecoratedIcon( - icon: Icon(Icons.star, size: 30, color: Colors.yellow), - decoration: IconDecoration( - shadows: [ - Shadow( - blurRadius: 30, - offset: Offset(1, 0), - color: Colors.brown) + icon: Container( + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration( + color: Color.fromARGB(70, 60, 200, 10), + shape: BoxShape.circle, + ), + child: const DecoratedIcon( + icon: Icon(Icons.star, size: 35, color: Colors.yellow), + decoration: IconDecoration( + shadows: [ + Shadow( + blurRadius: 20, + offset: Offset(1, 0), + color: Colors.brown, + ) + ], + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xfffaf8f8), + Color(0xfffae16c), + Color.fromARGB(128, 250, 148, 75), ], - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xfffaf8f8), - Color(0xfffae16c), - Color.fromARGB(128, 250, 148, 75), - ], - ), ), ), - ], + ), ), label: Text( - '${_masterCardList.length} cards added! ', + ' ${_masterCardList.length} cards added! ', style: const TextStyle( fontSize: 24, color: Colors.black, @@ -176,7 +190,10 @@ class _HomepageState extends State { ), //THIS IS TO SET UP THE CAROUSEL - const DeckCarousel(), + DeckCarousel( + decks: _decks, + onChange: () => _update(), + ), Container( margin: const EdgeInsets.only(bottom: 60), @@ -187,9 +204,17 @@ class _HomepageState extends State { ), ); } + + _update() async { + var decks = await DeckService.getAllDecks(); + setState(() { + _decks = decks; + _masterCardList = decks.firstWhere((i) => i.isMaster).cards; + }); + } } -class _CustomSearchDelegate extends SearchDelegate { +class _CustomSearchDelegate extends SearchDelegate { final List cards; _CustomSearchDelegate({required this.cards}); @@ -246,11 +271,7 @@ class _CustomSearchDelegate extends SearchDelegate { var result = matchQuery[index]; return ListTile( title: Text(result.name), - onTap: () => Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => CardView(initialCard: result), - ), - ), + onTap: () => Navigator.of(context).pop(result), ); }, ); diff --git a/lib/screens/Stats.dart b/lib/screens/Stats.dart index c1e3397..c8e42c9 100644 --- a/lib/screens/Stats.dart +++ b/lib/screens/Stats.dart @@ -1,8 +1,7 @@ -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../services/userservice.dart'; -import '../widgets/CustomStatsWidget.dart'; +import 'package:rememberme/widgets/roundedpage.dart'; +import 'package:rememberme/services/userservice.dart'; +import 'package:rememberme/widgets/CustomStatsWidget.dart'; import 'package:rememberme/services/deckservice.dart'; class Stats extends StatefulWidget { @@ -16,73 +15,50 @@ class _Stats extends State { final Future deckFuture = DeckService.getMasterDeck(); final Future> allDeckFuture = DeckService.getAllDecks(); final Future date = UserService.getDaysLogged(); + final Future highScore = UserService.getMemoryGameHighScore(); @override Widget build(BuildContext context) { - return Scaffold( - appBar: PreferredSize( - //WITHIN THE APPBAR, FIRSTLY DEALING WITH CHANGED SIZE - preferredSize: Size.fromHeight(100.0), - child: AppBar( - //HERE WE ADD A BACK BUTTON (CONNECT SCREEN LATER) - automaticallyImplyLeading: false, - leadingWidth: 100, - leading: ElevatedButton.icon( - onPressed: () => Navigator.of(context).pop(), - icon: const Icon(Icons.arrow_left, size: 45), - label: const Text(''), - style: ElevatedButton.styleFrom( - elevation: 0, - backgroundColor: Colors.transparent)), - - //THIS ADDS THE TEXT IN THE APPBAR - title: Text('Statistics'), - centerTitle: true, - titleTextStyle: TextStyle( - fontSize: 27, - fontWeight: FontWeight.bold - ), - backgroundColor: Color.fromARGB(255, 253, 142, 84), - ) - ), - - - - - body: ListView( - children: [ - //For achievement heading on the Homepage------------------------- - - FutureBuilder(future: deckFuture, builder: (ctxt, snapshot) - { + return RoundedPage( + title: 'Statistics', + child: Column( + children: [ + FutureBuilder( + future: deckFuture, + builder: (ctxt, snapshot) { if (snapshot.hasData) { return CustomStats( titleText: "Cards Added", achievement: "${snapshot.data!.cards.length} cards added!", ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); } - else { - return CircularProgressIndicator(); - } - }), - - FutureBuilder(future: allDeckFuture, builder: (ctxt, snapshot) - { + }, + ), + FutureBuilder( + future: allDeckFuture, + builder: (ctxt, snapshot) { if (snapshot.hasData) { return CustomStats( titleText: "Number of Decks", achievement: "${snapshot.data!.length} deck(s)", ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); } - else { - return CircularProgressIndicator(); - } - }), - - FutureBuilder(future: allDeckFuture, builder: (ctxt, snapshot) - { + }, + ), + FutureBuilder( + future: allDeckFuture, + builder: (ctxt, snapshot) { if (snapshot.hasData) { - var master = snapshot.data!.firstWhere((element) => element.isMaster); + var master = + snapshot.data!.firstWhere((element) => element.isMaster); Map map = {}; for (var card in master.cards) { final split = card.name.split(' '); @@ -93,44 +69,50 @@ class _Stats extends State { map[firstname] = map[firstname]! + 1; } var sorted = map.entries.toList(); - sorted.sort((a,b)=>a.value.compareTo(b.value)); + sorted.sort((a, b) => a.value.compareTo(b.value)); var commonname = sorted.last; return CustomStats( titleText: "Most Common", achievement: "${commonname.value} ${commonname.key}(s)", ); - } - else { - return CircularProgressIndicator(); - } - }), - - FutureBuilder(future: date, builder: (ctxt, snapshot) - { - if (snapshot.hasData) { - - return CustomStats( - titleText: "Days in a Row", - achievement: "${snapshot.data!}", + } else { + return const Center( + child: CircularProgressIndicator(), ); } - else { - return CircularProgressIndicator(); - } - }), - - CustomStats( - titleText: "High Score Today", - achievement: "Memory Game: 90%" - ), - - ] + }, + ), + FutureBuilder( + future: date, + builder: (ctxt, snapshot) { + if (snapshot.hasData) { + return CustomStats( + titleText: "Days in a Row", + achievement: "${snapshot.data!}", + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }), + FutureBuilder( + future: highScore, + builder: (ctxt, snapshot) { + if (snapshot.hasData) { + return CustomStats( + titleText: "High Score", + achievement: "${snapshot.data}%", + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }), + ], ), ); } } - - - - diff --git a/lib/screens/qrview.dart b/lib/screens/qrview.dart index d296522..55a621c 100644 --- a/lib/screens/qrview.dart +++ b/lib/screens/qrview.dart @@ -1,3 +1,4 @@ +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:rememberme/screens/modifycard.dart'; @@ -34,12 +35,14 @@ class _QRViewState extends State { ), ), Flexible( - child: Text( + child: AutoSizeText( 'Nice to Meet You! I\'m ${AuthService.getUser()?.displayName}.', + maxLines: 3, + maxFontSize: 28, style: const TextStyle( - fontSize: 36, fontWeight: FontWeight.bold, color: Colors.white, + fontSize: 28, ), ), ), diff --git a/lib/services/userservice.dart b/lib/services/userservice.dart index bf82f10..9a950a9 100644 --- a/lib/services/userservice.dart +++ b/lib/services/userservice.dart @@ -47,7 +47,7 @@ class UserService { } await getUserDocRef() - .set({'lastlogin': currenttime, 'dayslogged': dayslogged}); + .update({'lastlogin': currenttime, 'dayslogged': dayslogged}); return dayslogged; } @@ -89,4 +89,19 @@ class UserService { return null; } } + + static Future setMemoryGameHighScore(int score) async { + var ref = await getUserDocRef(); + await ref.update({'memorygame_highscore': score}); + } + + static Future getMemoryGameHighScore() async { + var res = await getUserDocRef().get(); + var data = res.data(); + if (data == null || !data.containsKey('memorygame_highscore')) { + return 0; + } else { + return data['memorygame_highscore'] as int; + } + } } diff --git a/lib/widgets/CustomStatsWidget.dart b/lib/widgets/CustomStatsWidget.dart index 7f51e0a..a8f64d7 100644 --- a/lib/widgets/CustomStatsWidget.dart +++ b/lib/widgets/CustomStatsWidget.dart @@ -1,141 +1,64 @@ - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:icon_decoration/icon_decoration.dart'; - - class CustomStats extends StatelessWidget { final String titleText; final String achievement; - const CustomStats({required this.titleText, required this.achievement}); - - + const CustomStats({ + super.key, + required this.titleText, + required this.achievement, + }); @override Widget build(BuildContext context) { - return Row( - children: [ - //Space between left edge and star - Container( - margin: EdgeInsets.fromLTRB(50, 90, 0, 0) - ), - - Container( - margin: EdgeInsets.fromLTRB(0, 30, 0, 0), - child: Stack( - alignment: AlignmentDirectional.center, - children: [ - - - Icon( - Icons.circle, - size: 70, - color: Color.fromARGB(70,60,200,10), - ), - - DecoratedIcon( - icon: Icon( - Icons.star, - size: 30, - color: Colors.yellow - ), - decoration: IconDecoration( - shadows: [Shadow(blurRadius: 20, offset: Offset(1, 0), color: Colors.brown)], - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xfffaf8f8), - Color(0xfffae16c), - Color.fromARGB(128, 250, 148, 75), - ], - ) - ) - ), - - ], + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 16, + ), + child: ListTile( + title: Text( + titleText, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 23, + ), ), + subtitle: Text( + achievement, + style: const TextStyle(fontSize: 20), ), - //Space between star and text - Container( - margin: EdgeInsets.fromLTRB(50, 90, 0, 0) - ), - - //Space above text - Column( - children: [ - Column( - children: [ - Text( - ' ' - ), - ], - ), - //More space above text - Column( - children: [ - Text( - ' ' - ), - ], - ), - - //More space above text - Column( - children: [ - Text( - ' ' - ), - ], - ), - - //Bolded text - Column( - children: [ - SizedBox( - width: 225, - child: Text( - titleText, - style: TextStyle( - fontSize: 23, - fontWeight: FontWeight.bold - ) - ), - ), - ], - ), - - //Space between bolded and unbolded text - Column( - children: [ - Text( - ' ' - ), - ], - ), - -//Unbolded text - Column( - children: [ - SizedBox( - width: 225, - child: Text( - achievement, - style: TextStyle( - fontSize: 23 - ) - ), - ), + leading: Container( + padding: const EdgeInsets.all(16), + decoration: const BoxDecoration( + color: Color.fromARGB(70, 60, 200, 10), + shape: BoxShape.circle, + ), + child: const DecoratedIcon( + icon: Icon(Icons.star, size: 35, color: Colors.yellow), + decoration: IconDecoration( + shadows: [ + Shadow( + blurRadius: 20, + offset: Offset(1, 0), + color: Colors.brown, + ) + ], + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xfffaf8f8), + Color(0xfffae16c), + Color.fromARGB(128, 250, 148, 75), ], ), - ] + ), + ), ), - ], + ), ); } } - - - diff --git a/lib/widgets/MemoryGameTile.dart b/lib/widgets/MemoryGameTile.dart index 21a3799..5acf34b 100644 --- a/lib/widgets/MemoryGameTile.dart +++ b/lib/widgets/MemoryGameTile.dart @@ -149,12 +149,14 @@ class _MemoryGameTileState extends State child: Padding( padding: const EdgeInsets.all(16), child: GridTile( - header: Text( - widget.card.name, - textAlign: TextAlign.center, - ), + header: widget.isQuestion + ? Text( + widget.card.name, + textAlign: TextAlign.center, + ) + : null, child: Padding( - padding: const EdgeInsets.only(top: 16), + padding: EdgeInsets.only(top: (widget.isQuestion ? 16 : 0)), child: Center( child: AutoSizeText( widget.data, @@ -162,6 +164,7 @@ class _MemoryGameTileState extends State fontWeight: FontWeight.bold, fontSize: 30, ), + wrapWords: false, textAlign: TextAlign.center, ), ), @@ -176,6 +179,8 @@ class _MemoryGameTileState extends State @override void dispose() { _selectAnimationController.dispose(); + _colorAnimationController.dispose(); + _fadeAnimationController.dispose(); super.dispose(); } } diff --git a/lib/widgets/deckcarousel.dart b/lib/widgets/deckcarousel.dart index 39c7049..f210729 100644 --- a/lib/widgets/deckcarousel.dart +++ b/lib/widgets/deckcarousel.dart @@ -7,7 +7,10 @@ import 'package:rememberme/services/deckservice.dart'; import 'package:rememberme/widgets/cardavatar.dart'; class DeckCarousel extends StatefulWidget { - const DeckCarousel({super.key}); + const DeckCarousel({super.key, required this.decks, this.onChange}); + + final List decks; + final void Function()? onChange; @override State createState() => _DeckCarouselState(); @@ -17,12 +20,10 @@ class _DeckCarouselState extends State { double _scrollValue = -1; int _lastFullScroll = -1; int _currentPage = 0; - List _decks = []; @override void initState() { super.initState(); - _updateDecks(); } @override @@ -60,7 +61,7 @@ class _DeckCarouselState extends State { List _getCarouselItems() { double percent = sin(pi * (_scrollValue - _lastFullScroll)).abs(); - return _decks + return widget.decks .map( (deck) => _CarouselItem( percent: percent, @@ -71,20 +72,14 @@ class _DeckCarouselState extends State { builder: (context) => DeckView(initialDeck: deck), ), ); - _updateDecks(); + if (widget.onChange != null) { + widget.onChange!(); + } }, ), ) .toList(); } - - _updateDecks() { - DeckService.getAllDecks().then((value) { - setState(() { - _decks = value; - }); - }); - } } class _CarouselItem extends StatelessWidget { diff --git a/lib/widgets/memorygameselectdialog.dart b/lib/widgets/memorygameselectdialog.dart index 6d22d9c..f5d450a 100644 --- a/lib/widgets/memorygameselectdialog.dart +++ b/lib/widgets/memorygameselectdialog.dart @@ -48,13 +48,11 @@ class MemoryGameSelectDialog extends StatefulWidget { } class _MemoryGameSelectDialogState extends State { - late Deck _selectedDeck; List _sortedDecks = []; @override void initState() { super.initState(); - _selectedDeck = widget.decks.firstWhere((deck) => deck.isMaster); _sortedDecks = widget.decks.sublist(0); _sortedDecks.sort( (a, b) => _getQuestionCount(b).compareTo(_getQuestionCount(a)), @@ -93,7 +91,7 @@ class _MemoryGameSelectDialogState extends State { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (context) => MemoryGame( - deck: _selectedDeck, + deck: deck, ), ), ); diff --git a/pubspec.lock b/pubspec.lock index 3d2f567..839ec27 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,13 +15,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.2" - animations: - dependency: "direct main" - description: - name: animations - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.7" async: dependency: transitive description: @@ -603,7 +596,7 @@ packages: source: hosted version: "3.0.6" vector_math: - dependency: "direct main" + dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 10265ba..023f448 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,6 @@ dependencies: firebase_storage: ^10.3.11 image_picker: ^0.8.6 cached_network_image: ^3.2.2 - animations: ^2.0.7 page_transition: ^2.0.9 auto_size_text: ^3.0.0 flutter_staggered_grid_view: ^0.6.2 @@ -56,7 +55,6 @@ dependencies: crypto: ^3.0.2 file: ^6.1.4 animate_gradient: ^0.0.2 - vector_math: ^2.1.2 font_awesome_flutter: ^10.2.1 dev_dependencies: @@ -86,7 +84,6 @@ flutter: - assets/OrangeFlower.jpg - assets/avatar.webp - assets/logo.png - - assets/human-brain.png # An image asset can refer to one or more resolution-specific "variants", see