From f96cdf067ed0bf231f4f1eb43b2ba41cf5f2f389 Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:05:52 -0400 Subject: [PATCH] Load level stats (#3515) * Make LearningProgressBar load when analytics are initializing * Hide level dialog while analytics loads * chore: some simplifications --------- Co-authored-by: ggurdin --- .../learning_progress_bar.dart | 12 + .../learning_progress_indicators.dart | 22 +- .../level_dialog_content.dart | 210 ++++++++++-------- 3 files changed, 136 insertions(+), 108 deletions(-) diff --git a/lib/pangea/analytics_summary/learning_progress_bar.dart b/lib/pangea/analytics_summary/learning_progress_bar.dart index 40d2387f1..b9f413520 100644 --- a/lib/pangea/analytics_summary/learning_progress_bar.dart +++ b/lib/pangea/analytics_summary/learning_progress_bar.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar.dart'; import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -8,16 +9,27 @@ class LearningProgressBar extends StatelessWidget { final int level; final int totalXP; final double? height; + final bool loading; const LearningProgressBar({ required this.level, required this.totalXP, + required this.loading, this.height, super.key, }); @override Widget build(BuildContext context) { + if (loading) { + return Container( + alignment: Alignment.center, + height: height, + child: const LinearProgressIndicator( + color: AppConfig.goldLight, + ), + ); + } return ProgressBar( height: height, levelBars: [ diff --git a/lib/pangea/analytics_summary/learning_progress_indicators.dart b/lib/pangea/analytics_summary/learning_progress_indicators.dart index aa8bde499..77bdc366d 100644 --- a/lib/pangea/analytics_summary/learning_progress_indicators.dart +++ b/lib/pangea/analytics_summary/learning_progress_indicators.dart @@ -180,18 +180,20 @@ class LearningProgressIndicatorsState level: _constructsModel.level, totalXP: _constructsModel.totalXP, height: 24.0, + loading: _loading, ), ), - Text( - "⭐ ${_constructsModel.level}", - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith( - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary, - ), - ), + if (!_loading) + Text( + "⭐ ${_constructsModel.level}", + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + ), ], ), ), diff --git a/lib/pangea/analytics_summary/level_dialog_content.dart b/lib/pangea/analytics_summary/level_dialog_content.dart index 7f1afba70..49864d9b5 100644 --- a/lib/pangea/analytics_summary/level_dialog_content.dart +++ b/lib/pangea/analytics_summary/level_dialog_content.dart @@ -14,113 +14,127 @@ class LevelDialogContent extends StatelessWidget { super.key, }); - GetAnalyticsController get getAnalyticsController => + GetAnalyticsController get analytics => MatrixState.pangeaController.getAnalytics; - int get level => getAnalyticsController.constructListModel.level; - int get totalXP => getAnalyticsController.constructListModel.totalXP; - int get maxLevelXP => getAnalyticsController.minXPForNextLevel; - List get uses => - getAnalyticsController.constructListModel.truncatedUses; + + int get level => analytics.constructListModel.level; + int get totalXP => analytics.constructListModel.totalXP; + int get maxLevelXP => analytics.minXPForNextLevel; + List get uses => analytics.constructListModel.truncatedUses; + + bool get _loading => + !MatrixState.pangeaController.getAnalytics.initCompleter.isCompleted; @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - titleSpacing: 0, - automaticallyImplyLeading: false, - title: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "⭐ ${L10n.of(context).levelShort(level)}", - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.w900, - color: AppConfig.gold, - ), - ), - Text( - L10n.of(context).xpIntoLevel(totalXP, maxLevelXP), - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.w900, - color: AppConfig.gold, - ), - ), - ], - ), - ), - ), - body: Column( - children: [ - Expanded( - child: ListView.builder( - itemCount: uses.length, - itemBuilder: (context, index) { - final use = uses[index]; - String lemmaCopy = use.lemma; - if (use.constructType == ConstructTypeEnum.morph) { - lemmaCopy = getGrammarCopy( - category: use.category, - lemma: use.lemma, - context: context, - ) ?? - use.lemma; - } - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 16, + return StreamBuilder( + stream: analytics.analyticsStream.stream, + builder: (context, _) { + if (_loading) { + return const Center( + child: CircularProgressIndicator.adaptive(), + ); + } + + return Scaffold( + appBar: AppBar( + titleSpacing: 0, + automaticallyImplyLeading: false, + title: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "⭐ ${L10n.of(context).levelShort(level)}", + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.w900, + color: AppConfig.gold, + ), ), - child: IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Align( - alignment: Alignment.centerLeft, - child: Container( - width: 40, - alignment: Alignment.centerLeft, - child: Icon(use.useType.icon), - ), - ), - const SizedBox(width: 10), - Expanded( - child: Text( - "\"$lemmaCopy\" - ${use.useType.description(context)}", - style: const TextStyle(fontSize: 14), - ), - ), - Container( - alignment: Alignment.topRight, - width: 60, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "${use.xp > 0 ? '+' : ''}${use.xp}", - style: TextStyle( - fontWeight: FontWeight.w900, - fontSize: 14, - height: 1, - color: use.pointValueColor(context), - ), - ), - ], - ), - ), - ], + Text( + L10n.of(context).xpIntoLevel(totalXP, maxLevelXP), + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.w900, + color: AppConfig.gold, ), ), - ); - }, + ], + ), ), ), - ], - ), + body: Column( + children: [ + Expanded( + child: ListView.builder( + itemCount: uses.length, + itemBuilder: (context, index) { + final use = uses[index]; + String lemmaCopy = use.lemma; + if (use.constructType == ConstructTypeEnum.morph) { + lemmaCopy = getGrammarCopy( + category: use.category, + lemma: use.lemma, + context: context, + ) ?? + use.lemma; + } + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Container( + width: 40, + alignment: Alignment.centerLeft, + child: Icon(use.useType.icon), + ), + ), + const SizedBox(width: 10), + Expanded( + child: Text( + "\"$lemmaCopy\" - ${use.useType.description(context)}", + style: const TextStyle(fontSize: 14), + ), + ), + Container( + alignment: Alignment.topRight, + width: 60, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "${use.xp > 0 ? '+' : ''}${use.xp}", + style: TextStyle( + fontWeight: FontWeight.w900, + fontSize: 14, + height: 1, + color: use.pointValueColor(context), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ), + ], + ), + ); + }, ); } }