add categories to analytics display

pull/1476/head
ggurdin 1 year ago
parent 6b643a841a
commit da6d64972b
No known key found for this signature in database
GPG Key ID: A01CB41737CBB478

@ -23,8 +23,8 @@ class ConstructListModel {
List<OneConstructUse> get uses =>
_uses.where((use) => use.constructType == type || type == null).toList();
/// All unique lemmas used in the construct events
List<String> get lemmas => constructList.map((e) => e.lemma).toSet().toList();
// /// All unique lemmas used in the construct events
// List<String> get lemmas => constructList.map((e) => e.lemma).toSet().toList();
/// All unique lemmas used in the construct events with non-zero points
List<String> get lemmasWithPoints =>
@ -36,8 +36,13 @@ class ConstructListModel {
final Map<String, List<OneConstructUse>> lemmaToUses = {};
for (final use in uses) {
if (use.lemma == null) continue;
lemmaToUses[use.lemma! + use.constructType.string] ??= [];
lemmaToUses[use.lemma! + use.constructType.string]!.add(use);
lemmaToUses[use.lemma! +
use.constructType.string +
(use.category ?? "Other")] ??= [];
lemmaToUses[use.lemma! +
use.constructType.string +
(use.category ?? "Other")]!
.add(use);
}
_constructMap = lemmaToUses.map(
@ -47,6 +52,7 @@ class ConstructListModel {
uses: value,
constructType: value.first.constructType,
lemma: value.first.lemma!,
category: value.first.category,
),
),
);
@ -68,7 +74,7 @@ class ConstructListModel {
_constructList = _constructMap!.values.toList();
_constructList!.sort((a, b) {
final comp = b.uses.length.compareTo(a.uses.length);
final comp = b.points.compareTo(a.points);
if (comp != 0) return comp;
return a.lemma.compareTo(b.lemma);
});
@ -79,6 +85,15 @@ class ConstructListModel {
List<ConstructUses> get constructListWithPoints =>
constructList.where((constructUse) => constructUse.points > 0).toList();
Map<String, List<ConstructUses>> get categoriesToUses {
final Map<String, List<ConstructUses>> categoriesMap = {};
for (final use in constructListWithPoints) {
categoriesMap[use.category] ??= [];
categoriesMap[use.category]!.add(use);
}
return categoriesMap;
}
get maxXPPerLemma {
return type != null
? type!.maxXPPerLemma
@ -141,12 +156,14 @@ class ConstructUses {
final List<OneConstructUse> uses;
final ConstructTypeEnum constructType;
final String lemma;
final String? _category;
ConstructUses({
required this.uses,
required this.constructType,
required this.lemma,
});
required category,
}) : _category = category;
// Total points for all uses of this lemma
int get points {
@ -165,6 +182,8 @@ class ConstructUses {
});
return _lastUsed = lastUse;
}
String get category => _category ?? "Other";
}
/// One lemma, a use type, and a list of uses

@ -74,7 +74,11 @@ class ConstructAnalyticsModel {
class OneConstructUse {
String? lemma;
String? form;
/// For vocab constructs, this is the POS. For morph
/// constructs, this is the morphological category.
String? category;
ConstructTypeEnum constructType;
ConstructUseTypeEnum useType;

@ -16,8 +16,76 @@ class AnalyticsPopup extends StatelessWidget {
super.key,
});
List<MapEntry<String, List<ConstructUses>>> get categoriesToUses {
final entries = constructsModel.categoriesToUses.entries.toList();
// Sort the list with custom logic
entries.sort((a, b) {
// Check if one of the keys is 'Other'
if (a.key == 'Other') return 1;
if (b.key == 'Other') return -1;
// Sort by the length of the list in descending order
final aTotalPoints = a.value.fold<int>(
0,
(previousValue, element) => previousValue + element.points,
);
final bTotalPoints = b.value.fold<int>(
0,
(previousValue, element) => previousValue + element.points,
);
return bTotalPoints.compareTo(aTotalPoints);
});
return entries;
}
@override
Widget build(BuildContext context) {
Widget? dialogContent;
final bool hasNoData = constructsModel.constructListWithPoints.isEmpty;
final bool hasNoCategories = constructsModel.categoriesToUses.length == 1 &&
constructsModel.categoriesToUses.keys.first == "Other";
if (hasNoData) {
dialogContent = Center(child: Text(L10n.of(context)!.noDataFound));
} else if (hasNoCategories) {
dialogContent = ListView.builder(
itemCount: constructsModel.constructListWithPoints.length,
itemBuilder: (context, index) {
return ConstructUsesXPTile(
indicator: indicator,
constructsModel: constructsModel,
constructUses: constructsModel.constructListWithPoints[index],
);
},
);
} else {
dialogContent = ListView.builder(
itemCount: categoriesToUses.length,
itemBuilder: (context, index) {
final category = categoriesToUses[index];
return Column(
children: [
ExpansionTile(
title: Text(
category.key != 'Other'
? getGrammarCopy(category.key, context)
: category.key,
),
children: category.value.map((constructUses) {
return ConstructUsesXPTile(
indicator: indicator,
constructsModel: constructsModel,
constructUses: constructUses,
);
}).toList(),
),
const Divider(height: 1),
],
);
},
);
}
return Dialog(
child: ConstrainedBox(
constraints: const BoxConstraints(
@ -36,46 +104,49 @@ class AnalyticsPopup extends StatelessWidget {
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: constructsModel.constructListWithPoints.isEmpty
? Center(
child: Text(L10n.of(context)!.noDataFound),
)
: ListView.builder(
itemCount: constructsModel.constructListWithPoints.length,
itemBuilder: (context, index) {
child: dialogContent,
),
),
),
),
);
}
}
class ConstructUsesXPTile extends StatelessWidget {
final ProgressIndicatorEnum indicator;
final ConstructListModel constructsModel;
final ConstructUses constructUses;
const ConstructUsesXPTile({
required this.indicator,
required this.constructsModel,
required this.constructUses,
super.key,
});
@override
Widget build(BuildContext context) {
final lemma = constructUses.lemma;
return Tooltip(
message:
"${constructsModel.constructListWithPoints[index].points} / ${constructsModel.maxXPPerLemma}",
message: "${constructUses.points} / ${constructsModel.maxXPPerLemma}",
child: ListTile(
onTap: () {},
title: Text(
constructsModel.type == ConstructTypeEnum.morph
? getGrammarCopy(
constructsModel
.constructListWithPoints[index].lemma,
context,
)
: constructsModel
.constructListWithPoints[index].lemma,
? getGrammarCopy(lemma, context)
: lemma,
),
subtitle: LinearProgressIndicator(
value: constructsModel
.constructListWithPoints[index].points /
constructsModel.maxXPPerLemma,
value: constructUses.points / constructsModel.maxXPPerLemma,
minHeight: 20,
borderRadius: const BorderRadius.all(
Radius.circular(AppConfig.borderRadius),
),
color: indicator.color(context),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 20),
),
);
},
),
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
),
),
);

Loading…
Cancel
Save