fix: add new analytics update type for initial data (from local and s… (#4484)
* fix: add new analytics update type for initial data (from local and server), listen for init updates in analytics page to rebuild on language change * fix: URL encode construct IDs during construct analytics navigation * chore: add tooltip to level analytics page, update divider in construct analytics details page
This commit is contained in:
parent
29c2602adc
commit
f53b010105
11 changed files with 88 additions and 93 deletions
|
|
@ -5310,5 +5310,6 @@
|
|||
"activityAnalyticsTooltipBody": "These are your saved activities for review and practice.",
|
||||
"numSavedActivities": "Number of saved activities",
|
||||
"saveActivityTitle": "Save activity",
|
||||
"saveActivityDesc": "Good job! Save this activity for later review and practice"
|
||||
"saveActivityDesc": "Good job! Save this activity for later review and practice",
|
||||
"levelInfoTooltip": "Here you can see all the points you’ve earned and how!"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/lemma_usage_dots.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/lemma_use_example_messages.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
|
|
@ -43,14 +39,9 @@ class AnalyticsDetailsViewContent extends StatelessWidget {
|
|||
subtitle,
|
||||
const SizedBox(height: 16.0),
|
||||
headerContent,
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${AnalyticsConstants.popupDividerFileName}",
|
||||
placeholder: (context, url) => const CircularProgressIndicator(),
|
||||
errorWidget: (context, url, error) => const Icon(Icons.error),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class MorphFeatureBox extends StatelessWidget {
|
|||
morphTag: morphTag,
|
||||
constructAnalytics: analytics,
|
||||
onTap: () => context.go(
|
||||
"/rooms/analytics/${id.type.string}/${id.string}",
|
||||
"/rooms/analytics/${id.type.string}/${Uri.encodeComponent(id.string)}",
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ class VocabAnalyticsListView extends StatelessWidget {
|
|||
final vocabItem = _filteredVocab[index];
|
||||
return VocabAnalyticsListTile(
|
||||
onTap: () => context.go(
|
||||
"/rooms/analytics/${vocabItem.id.type.string}/${vocabItem.id.string}",
|
||||
"/rooms/analytics/${vocabItem.id.type.string}/${Uri.encodeComponent(vocabItem.id.string)}",
|
||||
),
|
||||
constructUse: vocabItem,
|
||||
emoji: vocabItem.id.userSetEmoji.firstOrNull,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class AnalyticsConstants {
|
|||
static const String emojiForFlower = "🌸";
|
||||
static const levelUpAudioFileName = "LevelUp_chime.mp3";
|
||||
static const levelUpImageFileName = "LvL_Up_Full_Banner.png";
|
||||
static const popupDividerFileName = "divider.png";
|
||||
static const vocabIconFileName = "Vocabulary_icon.png";
|
||||
static const morphIconFileName = "grammar_icon.png";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class GetAnalyticsController extends BaseController {
|
|||
);
|
||||
} finally {
|
||||
_updateAnalyticsStream(
|
||||
type: AnalyticsUpdateType.local,
|
||||
type: AnalyticsUpdateType.init,
|
||||
points: 0,
|
||||
newConstructs: [],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
|||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
enum AnalyticsUpdateType { server, local, activities }
|
||||
enum AnalyticsUpdateType { server, local, activities, init }
|
||||
|
||||
/// handles the processing of analytics for
|
||||
/// 1) messages sent by the user and
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:fluffychat/config/app_config.dart';
|
|||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_page/activity_archive.dart';
|
||||
import 'package:fluffychat/pangea/analytics_page/analytics_page_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
||||
|
|
@ -15,7 +16,7 @@ import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dar
|
|||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class AnalyticsPage extends StatefulWidget {
|
||||
class AnalyticsPage extends StatelessWidget {
|
||||
final ProgressIndicatorEnum? indicator;
|
||||
final ConstructIdentifier? construct;
|
||||
final bool isSidebar;
|
||||
|
|
@ -27,84 +28,73 @@ class AnalyticsPage extends StatefulWidget {
|
|||
this.isSidebar = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AnalyticsPage> createState() => _AnalyticsPageState();
|
||||
}
|
||||
|
||||
class _AnalyticsPageState extends State<AnalyticsPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final analytics = MatrixState.pangeaController.getAnalytics;
|
||||
|
||||
// Check if getAnalytics is initialized, if not wait for the first stream entry
|
||||
if (!analytics.initCompleter.isCompleted) {
|
||||
analytics.analyticsStream.stream.first.then((_) {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final analyticsRoomId = GoRouterState.of(context).pathParameters['roomid'];
|
||||
return Scaffold(
|
||||
appBar: widget.construct != null ? AppBar() : null,
|
||||
appBar: construct != null ? AppBar() : null,
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsGeometry.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.isSidebar ||
|
||||
(!FluffyThemes.isColumnMode(context) &&
|
||||
widget.construct == null))
|
||||
LearningProgressIndicators(
|
||||
selected: widget.indicator,
|
||||
canSelect: widget.indicator != ProgressIndicatorEnum.level,
|
||||
),
|
||||
Expanded(
|
||||
child: () {
|
||||
if (widget.indicator == ProgressIndicatorEnum.level) {
|
||||
return const LevelDialogContent();
|
||||
} else if (widget.indicator ==
|
||||
ProgressIndicatorEnum.morphsUsed) {
|
||||
return ConstructAnalyticsView(
|
||||
construct: widget.construct,
|
||||
view: ConstructTypeEnum.morph,
|
||||
);
|
||||
} else if (widget.indicator ==
|
||||
ProgressIndicatorEnum.wordsUsed) {
|
||||
return ConstructAnalyticsView(
|
||||
construct: widget.construct,
|
||||
view: ConstructTypeEnum.vocab,
|
||||
);
|
||||
} else if (widget.indicator ==
|
||||
ProgressIndicatorEnum.activities) {
|
||||
return ActivityArchive(
|
||||
selectedRoomId: analyticsRoomId,
|
||||
);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 250.0,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}",
|
||||
errorWidget: (context, url, error) => const SizedBox(),
|
||||
placeholder: (context, url) => const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}(),
|
||||
),
|
||||
],
|
||||
child: StreamBuilder(
|
||||
stream: MatrixState
|
||||
.pangeaController.getAnalytics.analyticsStream.stream
|
||||
.where(
|
||||
(u) => u.type == AnalyticsUpdateType.init,
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
return Padding(
|
||||
padding: const EdgeInsetsGeometry.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (isSidebar ||
|
||||
(!FluffyThemes.isColumnMode(context) &&
|
||||
construct == null))
|
||||
LearningProgressIndicators(
|
||||
selected: indicator,
|
||||
canSelect: indicator != ProgressIndicatorEnum.level,
|
||||
),
|
||||
Expanded(
|
||||
child: () {
|
||||
if (indicator == ProgressIndicatorEnum.level) {
|
||||
return const LevelDialogContent();
|
||||
} else if (indicator ==
|
||||
ProgressIndicatorEnum.morphsUsed) {
|
||||
return ConstructAnalyticsView(
|
||||
construct: construct,
|
||||
view: ConstructTypeEnum.morph,
|
||||
);
|
||||
} else if (indicator == ProgressIndicatorEnum.wordsUsed) {
|
||||
return ConstructAnalyticsView(
|
||||
construct: construct,
|
||||
view: ConstructTypeEnum.vocab,
|
||||
);
|
||||
} else if (indicator ==
|
||||
ProgressIndicatorEnum.activities) {
|
||||
return ActivityArchive(
|
||||
selectedRoomId: analyticsRoomId,
|
||||
);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 250.0,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}",
|
||||
errorWidget: (context, url, error) =>
|
||||
const SizedBox(),
|
||||
placeholder: (context, url) => const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
|
|
@ -72,8 +74,16 @@ class LevelDialogContent extends StatelessWidget {
|
|||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: uses.length,
|
||||
itemCount: uses.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == 0) {
|
||||
return const InstructionsInlineTooltip(
|
||||
instructionsEnum: InstructionsEnum.levelAnalytics,
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
);
|
||||
}
|
||||
index--;
|
||||
|
||||
final use = uses[index];
|
||||
String lemmaCopy = use.lemma;
|
||||
if (use.constructType == ConstructTypeEnum.morph) {
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ class ConstructNotificationOverlayState
|
|||
|
||||
void _showDetails() {
|
||||
context.go(
|
||||
"/rooms/analytics/${ConstructTypeEnum.morph.string}/${widget.construct.string}",
|
||||
"/rooms/analytics/${ConstructTypeEnum.morph.string}/${Uri.encodeComponent(widget.construct.string)}",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ enum InstructionsEnum {
|
|||
analyticsVocabList,
|
||||
morphAnalyticsList,
|
||||
activityAnalyticsList,
|
||||
levelAnalytics,
|
||||
readingAssistanceOverview,
|
||||
emptyChatWarning,
|
||||
activityStatsMenu,
|
||||
|
|
@ -51,6 +52,7 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
case InstructionsEnum.activityStatsMenu:
|
||||
case InstructionsEnum.chatListTooltip:
|
||||
case InstructionsEnum.activityAnalyticsList:
|
||||
case InstructionsEnum.levelAnalytics:
|
||||
ErrorHandler.logError(
|
||||
e: Exception("No title for this instruction"),
|
||||
m: 'InstructionsEnumExtension.title',
|
||||
|
|
@ -105,6 +107,8 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
return l10n.activityStatsButtonInstruction;
|
||||
case InstructionsEnum.chatListTooltip:
|
||||
return l10n.chatListTooltip;
|
||||
case InstructionsEnum.levelAnalytics:
|
||||
return l10n.levelInfoTooltip;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue