3873 add superlatives for most vocab grammar and xp (#3977)
* add grammar and vocab superlatives - adds superlatives to the summary cards for each user - WIP, doesn't include XP superlative yet and it continuously reinitializes state which reloads the superlatives * get analytic superlatives from saved state event Revert activity user summaries widget to stateless, get info from saved state event instead of awaiting it, and fix some spacing issues. * add xp superlative - simplify 3 loop logic into one - change from constant updates to only generate superlatives on analytics save * sort imports * put analytics loading inside buttonControlledCarouselView * delete commented out code * return superlative map instead of setting value
This commit is contained in:
parent
6c05ffaf2a
commit
617030cd78
3 changed files with 127 additions and 28 deletions
|
|
@ -127,7 +127,6 @@ extension ActivityRoomExtension on Room {
|
|||
if (activitySummary?.summary != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await setActivitySummary(
|
||||
ActivitySummaryModel(
|
||||
requestedAt: DateTime.now(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
|
|
@ -87,10 +88,10 @@ class ButtonControlledCarouselView extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final room = controller.room;
|
||||
|
||||
final superlatives =
|
||||
room.activitySummary?.analytics?.generateSuperlatives();
|
||||
final availableRoles = room.activityPlan!.roles;
|
||||
final assignedRoles = room.assignedRoles ?? {};
|
||||
|
||||
final userSummaries = summary.participants
|
||||
.where(
|
||||
(p) => assignedRoles.values.any(
|
||||
|
|
@ -160,21 +161,17 @@ class ButtonControlledCarouselView extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
spacing: 14.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12,
|
||||
runSpacing: 8,
|
||||
//crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.school,
|
||||
size: 12.0,
|
||||
color: AppConfig.yellowDark,
|
||||
),
|
||||
Text(
|
||||
p.cefrLevel,
|
||||
style: const TextStyle(
|
||||
|
|
@ -182,18 +179,42 @@ class ButtonControlledCarouselView extends StatelessWidget {
|
|||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
//const SizedBox(width: 8),
|
||||
if (superlatives != null &&
|
||||
(superlatives['vocab']!.contains(
|
||||
p.participantId,
|
||||
))) ...[
|
||||
const SuperlativeTile(
|
||||
icon: Symbols.dictionary,
|
||||
),
|
||||
],
|
||||
if (superlatives != null &&
|
||||
(superlatives['grammar']!.contains(
|
||||
p.participantId,
|
||||
))) ...[
|
||||
const SuperlativeTile(
|
||||
icon: Symbols.toys_and_games,
|
||||
),
|
||||
],
|
||||
if (superlatives != null &&
|
||||
(superlatives['xp']!.contains(
|
||||
p.participantId,
|
||||
))) ...[
|
||||
const SuperlativeTile(
|
||||
icon: Icons.star,
|
||||
),
|
||||
],
|
||||
if (p.superlatives.isNotEmpty) ...[
|
||||
//const SizedBox(width: 8),
|
||||
Text(
|
||||
p.superlatives.first,
|
||||
style: const TextStyle(fontSize: 12.0),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (p.superlatives.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Text(
|
||||
p.superlatives.first,
|
||||
style: const TextStyle(fontSize: 12.0),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -229,3 +250,30 @@ class ButtonControlledCarouselView extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SuperlativeTile extends StatelessWidget {
|
||||
final IconData icon;
|
||||
|
||||
const SuperlativeTile({
|
||||
super.key,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, size: 14, color: AppConfig.gold),
|
||||
const SizedBox(width: 2),
|
||||
const Text(
|
||||
"1st",
|
||||
style: TextStyle(
|
||||
color: AppConfig.gold,
|
||||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,9 +55,61 @@ class ActivitySummaryAnalyticsModel {
|
|||
}
|
||||
}
|
||||
|
||||
Map<String, List> generateSuperlatives() {
|
||||
final Map<String, List<String>> superlatives = {
|
||||
'vocab': [],
|
||||
'grammar': [],
|
||||
'xp': [],
|
||||
};
|
||||
// Find all user IDs
|
||||
final userIds = constructs.keys.toList();
|
||||
if (userIds.isEmpty) {
|
||||
return superlatives;
|
||||
}
|
||||
int maxVocab = 0;
|
||||
int maxGrammar = 0;
|
||||
int maxXp = 0;
|
||||
final Map<String, int> allVocabs = {};
|
||||
final Map<String, int> allGrammars = {};
|
||||
final Map<String, int> allXPs = {};
|
||||
|
||||
for (final userId in userIds) {
|
||||
//vocab
|
||||
final vocabCount =
|
||||
uniqueConstructCountForUser(userId, ConstructTypeEnum.vocab);
|
||||
allVocabs[userId] = vocabCount;
|
||||
if (vocabCount > maxVocab) maxVocab = vocabCount;
|
||||
|
||||
//grammar
|
||||
final grammarCount =
|
||||
uniqueConstructCountForUser(userId, ConstructTypeEnum.morph);
|
||||
allGrammars[userId] = grammarCount;
|
||||
if (grammarCount > maxGrammar) maxGrammar = grammarCount;
|
||||
|
||||
//XP
|
||||
final xpCount = totalXPForUser(userId);
|
||||
allXPs[userId] = xpCount;
|
||||
if (xpCount > maxXp) maxXp = xpCount;
|
||||
}
|
||||
superlatives['vocab'] = allVocabs.entries
|
||||
.where((e) => e.value == maxVocab && maxVocab > 0)
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
|
||||
superlatives['grammar'] = allGrammars.entries
|
||||
.where((e) => e.value == maxGrammar && maxGrammar > 0)
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
|
||||
superlatives['xp'] = allXPs.entries
|
||||
.where((e) => e.value == maxXp && maxXp > 0)
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
return superlatives;
|
||||
}
|
||||
|
||||
factory ActivitySummaryAnalyticsModel.fromJson(Map<String, dynamic> json) {
|
||||
final model = ActivitySummaryAnalyticsModel();
|
||||
|
||||
for (final userEntry in json.entries) {
|
||||
final userId = userEntry.key;
|
||||
final constructList = userEntry.value as List<dynamic>;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue