Merge pull request #404 from pangeachat/edit-analytics-layout

Edit analytics layout
pull/1384/head
ggurdin 1 year ago committed by GitHub
commit 933ec9b2ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4058,5 +4058,12 @@
"suggestToSpaceDesc": "Suggested spaces will appear in the chat lists for their parent spaces", "suggestToSpaceDesc": "Suggested spaces will appear in the chat lists for their parent spaces",
"practice": "Practice", "practice": "Practice",
"noLanguagesSet": "No languages set", "noLanguagesSet": "No languages set",
"noActivitiesFound": "No practice activities found for this message" "noActivitiesFound": "No practice activities found for this message",
"languageButtonLabel": "Language: {currentLanguage}",
"@languageButtonLabel": {
"type": "text",
"placeholders": {
"currentLanguage": {}
}
}
} }

@ -62,12 +62,13 @@ class AnalyticsController extends BaseController {
timeSpan.toString(), timeSpan.toString(),
local: true, local: true,
); );
setState();
} }
///////// SPACE ANALYTICS LANGUAGES ////////// ///////// SPACE ANALYTICS LANGUAGES //////////
String get _analyticsSpaceLangKey => "ANALYTICS_SPACE_LANG_KEY"; String get _analyticsSpaceLangKey => "ANALYTICS_SPACE_LANG_KEY";
LanguageModel get currentAnalyticsSpaceLang { LanguageModel get currentAnalyticsLang {
try { try {
final String? str = _pangeaController.pStoreService.read( final String? str = _pangeaController.pStoreService.read(
_analyticsSpaceLangKey, _analyticsSpaceLangKey,
@ -83,41 +84,43 @@ class AnalyticsController extends BaseController {
} }
} }
Future<void> setCurrentAnalyticsSpaceLang(LanguageModel lang) async { Future<void> setCurrentAnalyticsLang(LanguageModel lang) async {
await _pangeaController.pStoreService.save( await _pangeaController.pStoreService.save(
_analyticsSpaceLangKey, _analyticsSpaceLangKey,
lang.langCode, lang.langCode,
local: true, local: true,
); );
setState();
} }
/// given an analytics event type and the current analytics language,
/// get the last time the user updated their analytics
Future<DateTime?> myAnalyticsLastUpdated(String type) async { Future<DateTime?> myAnalyticsLastUpdated(String type) async {
// given an analytics event type, get the last updated times
// for each of the user's analytics rooms and return the most recent
// Most Recent instead of the oldest because, for instance:
// My last Spanish event was sent 3 days ago.
// My last English event was sent 1 day ago.
// When I go to check if the cached data is out of date, the cached item was set 2 days ago.
// I know theres new data available because the English update data (the most recent) is after the caches creation time.
// So, I should update the cache.
final List<Room> analyticsRooms = _pangeaController final List<Room> analyticsRooms = _pangeaController
.matrixState.client.allMyAnalyticsRooms .matrixState.client.allMyAnalyticsRooms
.where((room) => room.isAnalyticsRoom) .where((room) => room.isAnalyticsRoom)
.toList(); .toList();
final List<DateTime> lastUpdates = []; final Map<String, DateTime> langCodeLastUpdates = {};
for (final Room analyticsRoom in analyticsRooms) { for (final Room analyticsRoom in analyticsRooms) {
final String? roomLang = analyticsRoom.madeForLang;
if (roomLang == null) continue;
final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated( final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated(
type, type,
_pangeaController.matrixState.client.userID!, _pangeaController.matrixState.client.userID!,
); );
if (lastUpdated != null) { if (lastUpdated != null) {
lastUpdates.add(lastUpdated); langCodeLastUpdates[roomLang] = lastUpdated;
} }
} }
if (lastUpdates.isEmpty) return null; if (langCodeLastUpdates.isEmpty) return null;
return lastUpdates.reduce( final String? l2Code =
_pangeaController.languageController.userL2?.langCode;
if (l2Code != null && langCodeLastUpdates.containsKey(l2Code)) {
return langCodeLastUpdates[l2Code];
}
return langCodeLastUpdates.values.reduce(
(check, mostRecent) => check.isAfter(mostRecent) ? check : mostRecent, (check, mostRecent) => check.isAfter(mostRecent) ? check : mostRecent,
); );
} }
@ -134,7 +137,7 @@ class AnalyticsController extends BaseController {
final List<Future<DateTime?>> lastUpdatedFutures = []; final List<Future<DateTime?>> lastUpdatedFutures = [];
for (final student in space.students) { for (final student in space.students) {
final Room? analyticsRoom = _pangeaController.matrixState.client final Room? analyticsRoom = _pangeaController.matrixState.client
.analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id);
if (analyticsRoom == null) continue; if (analyticsRoom == null) continue;
lastUpdatedFutures.add( lastUpdatedFutures.add(
analyticsRoom.analyticsLastUpdated( analyticsRoom.analyticsLastUpdated(
@ -177,28 +180,20 @@ class AnalyticsController extends BaseController {
//////////////////////////// MESSAGE SUMMARY ANALYTICS //////////////////////////// //////////////////////////// MESSAGE SUMMARY ANALYTICS ////////////////////////////
/// get all the summary analytics events for the current user
/// in the current language's analytics room
Future<List<SummaryAnalyticsEvent>> mySummaryAnalytics() async { Future<List<SummaryAnalyticsEvent>> mySummaryAnalytics() async {
// gets all the summary analytics events for the user final Room? analyticsRoom = _pangeaController.matrixState.client
// since the current timespace's cut off date .analyticsRoomLocal(currentAnalyticsLang.langCode);
final analyticsRooms = if (analyticsRoom == null) return [];
_pangeaController.matrixState.client.allMyAnalyticsRooms;
final List<SummaryAnalyticsEvent> allEvents = [];
// TODO switch to using list of futures
for (final Room analyticsRoom in analyticsRooms) {
final List<AnalyticsEvent>? roomEvents = final List<AnalyticsEvent>? roomEvents =
await analyticsRoom.getAnalyticsEvents( await analyticsRoom.getAnalyticsEvents(
type: PangeaEventTypes.summaryAnalytics, type: PangeaEventTypes.summaryAnalytics,
since: currentAnalyticsTimeSpan.cutOffDate, since: currentAnalyticsTimeSpan.cutOffDate,
userId: _pangeaController.matrixState.client.userID!, userId: _pangeaController.matrixState.client.userID!,
); );
return roomEvents?.cast<SummaryAnalyticsEvent>() ?? [];
allEvents.addAll(
roomEvents?.cast<SummaryAnalyticsEvent>() ?? [],
);
}
return allEvents;
} }
Future<List<SummaryAnalyticsEvent>> spaceMemberAnalytics( Future<List<SummaryAnalyticsEvent>> spaceMemberAnalytics(
@ -216,7 +211,7 @@ class AnalyticsController extends BaseController {
final List<SummaryAnalyticsEvent> analyticsEvents = []; final List<SummaryAnalyticsEvent> analyticsEvents = [];
for (final student in space.students) { for (final student in space.students) {
final Room? analyticsRoom = _pangeaController.matrixState.client final Room? analyticsRoom = _pangeaController.matrixState.client
.analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id);
if (analyticsRoom != null) { if (analyticsRoom != null) {
final List<AnalyticsEvent>? roomEvents = final List<AnalyticsEvent>? roomEvents =
@ -261,7 +256,7 @@ class AnalyticsController extends BaseController {
(e.defaultSelected.type == defaultSelected.type) && (e.defaultSelected.type == defaultSelected.type) &&
(e.selected?.id == selected?.id) && (e.selected?.id == selected?.id) &&
(e.selected?.type == selected?.type) && (e.selected?.type == selected?.type) &&
(e.langCode == currentAnalyticsSpaceLang.langCode), (e.langCode == currentAnalyticsLang.langCode),
); );
if (index != -1) { if (index != -1) {
@ -289,7 +284,7 @@ class AnalyticsController extends BaseController {
chartAnalyticsModel: chartAnalyticsModel, chartAnalyticsModel: chartAnalyticsModel,
defaultSelected: defaultSelected, defaultSelected: defaultSelected,
selected: selected, selected: selected,
langCode: currentAnalyticsSpaceLang.langCode, langCode: currentAnalyticsLang.langCode,
), ),
); );
} }
@ -525,11 +520,10 @@ class AnalyticsController extends BaseController {
//////////////////////////// CONSTRUCTS //////////////////////////// //////////////////////////// CONSTRUCTS ////////////////////////////
Future<List<ConstructAnalyticsEvent>> allMyConstructs() async { Future<List<ConstructAnalyticsEvent>> allMyConstructs() async {
final List<Room> analyticsRooms = final Room? analyticsRoom = _pangeaController.matrixState.client
_pangeaController.matrixState.client.allMyAnalyticsRooms; .analyticsRoomLocal(currentAnalyticsLang.langCode);
if (analyticsRoom == null) return [];
final List<ConstructAnalyticsEvent> allConstructs = [];
for (final Room analyticsRoom in analyticsRooms) {
final List<ConstructAnalyticsEvent>? roomEvents = final List<ConstructAnalyticsEvent>? roomEvents =
(await analyticsRoom.getAnalyticsEvents( (await analyticsRoom.getAnalyticsEvents(
type: PangeaEventTypes.construct, type: PangeaEventTypes.construct,
@ -537,8 +531,7 @@ class AnalyticsController extends BaseController {
userId: _pangeaController.matrixState.client.userID!, userId: _pangeaController.matrixState.client.userID!,
)) ))
?.cast<ConstructAnalyticsEvent>(); ?.cast<ConstructAnalyticsEvent>();
allConstructs.addAll(roomEvents ?? []); final List<ConstructAnalyticsEvent> allConstructs = roomEvents ?? [];
}
final List<String> adminSpaceRooms = final List<String> adminSpaceRooms =
await _pangeaController.matrixState.client.teacherRoomIds; await _pangeaController.matrixState.client.teacherRoomIds;
@ -561,7 +554,7 @@ class AnalyticsController extends BaseController {
final List<ConstructAnalyticsEvent> constructEvents = []; final List<ConstructAnalyticsEvent> constructEvents = [];
for (final student in space.students) { for (final student in space.students) {
final Room? analyticsRoom = _pangeaController.matrixState.client final Room? analyticsRoom = _pangeaController.matrixState.client
.analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id);
if (analyticsRoom != null) { if (analyticsRoom != null) {
final List<ConstructAnalyticsEvent>? roomEvents = final List<ConstructAnalyticsEvent>? roomEvents =
(await analyticsRoom.getAnalyticsEvents( (await analyticsRoom.getAnalyticsEvents(
@ -661,7 +654,7 @@ class AnalyticsController extends BaseController {
e.defaultSelected.type == defaultSelected.type && e.defaultSelected.type == defaultSelected.type &&
e.selected?.id == selected?.id && e.selected?.id == selected?.id &&
e.selected?.type == selected?.type && e.selected?.type == selected?.type &&
e.langCode == currentAnalyticsSpaceLang.langCode, e.langCode == currentAnalyticsLang.langCode,
); );
if (index > -1) { if (index > -1) {
@ -687,7 +680,7 @@ class AnalyticsController extends BaseController {
events: List.from(events), events: List.from(events),
defaultSelected: defaultSelected, defaultSelected: defaultSelected,
selected: selected, selected: selected,
langCode: currentAnalyticsSpaceLang.langCode, langCode: currentAnalyticsLang.langCode,
); );
_cachedConstructs.add(entry); _cachedConstructs.add(entry);
} }

@ -16,7 +16,6 @@ class AnalyticsLanguageButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenuButton<LanguageModel>( return PopupMenuButton<LanguageModel>(
icon: const Icon(Icons.language_outlined),
tooltip: L10n.of(context)!.changeAnalyticsLanguage, tooltip: L10n.of(context)!.changeAnalyticsLanguage,
initialValue: value, initialValue: value,
onSelected: (LanguageModel? lang) { onSelected: (LanguageModel? lang) {
@ -33,6 +32,21 @@ class AnalyticsLanguageButton extends StatelessWidget {
child: Text(lang.getDisplayName(context) ?? lang.langCode), child: Text(lang.getDisplayName(context) ?? lang.langCode),
); );
}).toList(), }).toList(),
child: TextButton.icon(
label: Text(
L10n.of(context)!.languageButtonLabel(
value.getDisplayName(context) ?? value.langCode,
),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
icon: Icon(
Icons.language_outlined,
color: Theme.of(context).colorScheme.onSurface,
),
onPressed: null,
),
); );
} }
} }

@ -163,7 +163,7 @@ class BaseAnalyticsController extends State<BaseAnalyticsPage> {
} }
Future<void> toggleSpaceLang(LanguageModel lang) async { Future<void> toggleSpaceLang(LanguageModel lang) async {
await pangeaController.analytics.setCurrentAnalyticsSpaceLang(lang); await pangeaController.analytics.setCurrentAnalyticsLang(lang);
await setChartData(); await setChartData();
refreshStream.add(false); refreshStream.add(false);
} }

@ -108,25 +108,23 @@ class BaseAnalyticsView extends StatelessWidget {
? Column( ? Column(
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
if (controller.widget.defaultSelected.type == // if (controller.widget.defaultSelected.type ==
AnalyticsEntryType.student) // AnalyticsEntryType.student)
IconButton( // IconButton(
icon: const Icon(Icons.refresh), // icon: const Icon(Icons.refresh),
onPressed: controller.onRefresh, // onPressed: controller.onRefresh,
tooltip: L10n.of(context)!.refresh, // tooltip: L10n.of(context)!.refresh,
), // ),
TimeSpanMenuButton( TimeSpanMenuButton(
value: controller.currentTimeSpan, value: controller.currentTimeSpan,
onChange: (TimeSpan value) => onChange: (TimeSpan value) =>
controller.toggleTimeSpan(context, value), controller.toggleTimeSpan(context, value),
), ),
if (controller.widget.defaultSelected.type ==
AnalyticsEntryType.space)
AnalyticsLanguageButton( AnalyticsLanguageButton(
value: controller.pangeaController.analytics value: controller
.currentAnalyticsSpaceLang, .pangeaController.analytics.currentAnalyticsLang,
onChange: (lang) => controller.toggleSpaceLang(lang), onChange: (lang) => controller.toggleSpaceLang(lang),
languages: controller.widget.targetLanguages, languages: controller.widget.targetLanguages,
), ),

@ -355,15 +355,17 @@ class ConstructMessagesDialog extends StatelessWidget {
final msgEventMatches = controller.getMessageEventMatches(); final msgEventMatches = controller.getMessageEventMatches();
final noData = controller.constructs![controller.lemmaIndex].uses.length >
controller._msgEvents.length;
return AlertDialog( return AlertDialog(
title: Center(child: Text(controller.widget.controller.currentLemma!)), title: Center(child: Text(controller.widget.controller.currentLemma!)),
content: SizedBox( content: SizedBox(
height: 350, height: noData ? 90 : 250,
width: 500, width: noData ? 200 : 400,
child: Column( child: Column(
children: [ children: [
if (controller.constructs![controller.lemmaIndex].uses.length > if (noData)
controller._msgEvents.length)
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -398,8 +400,8 @@ class ConstructMessagesDialog extends StatelessWidget {
child: Text( child: Text(
L10n.of(context)!.close.toUpperCase(), L10n.of(context)!.close.toUpperCase(),
style: TextStyle( style: TextStyle(
color: color: Theme.of(context).colorScheme.primary,
Theme.of(context).textTheme.bodyMedium?.color?.withAlpha(150), fontWeight: FontWeight.bold,
), ),
), ),
), ),

@ -23,13 +23,24 @@ class AnalyticsSpaceList extends StatefulWidget {
class AnalyticsSpaceListController extends State<AnalyticsSpaceList> { class AnalyticsSpaceListController extends State<AnalyticsSpaceList> {
PangeaController pangeaController = MatrixState.pangeaController; PangeaController pangeaController = MatrixState.pangeaController;
List<Room> spaces = []; List<Room> spaces = [];
StreamSubscription? stateSub;
List<LanguageModel> targetLanguages = []; List<LanguageModel> targetLanguages = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
setSpaceList().then((_) => setTargetLanguages()); setSpaceList().then((_) => setTargetLanguages());
// reload dropdowns when their values change in analytics page
stateSub = pangeaController.analytics.stateStream.listen(
(_) => setState(() {}),
);
}
@override
void dispose() {
stateSub?.cancel();
super.dispose();
} }
StreamController refreshStream = StreamController.broadcast(); StreamController refreshStream = StreamController.broadcast();
@ -71,7 +82,7 @@ class AnalyticsSpaceListController extends State<AnalyticsSpaceList> {
} }
Future<void> toggleSpaceLang(LanguageModel lang) async { Future<void> toggleSpaceLang(LanguageModel lang) async {
await pangeaController.analytics.setCurrentAnalyticsSpaceLang(lang); await pangeaController.analytics.setCurrentAnalyticsLang(lang);
refreshStream.add(false); refreshStream.add(false);
setState(() {}); setState(() {});
} }

@ -1,3 +1,4 @@
import 'package:fluffychat/pangea/enum/time_span.dart';
import 'package:fluffychat/pangea/pages/analytics/analytics_language_button.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_language_button.dart';
import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.dart';
import 'package:fluffychat/pangea/pages/analytics/time_span_menu_button.dart'; import 'package:fluffychat/pangea/pages/analytics/time_span_menu_button.dart';
@ -5,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../../enum/time_span.dart';
import '../base_analytics.dart'; import '../base_analytics.dart';
import 'space_list.dart'; import 'space_list.dart';
@ -32,10 +32,15 @@ class AnalyticsSpaceListView extends StatelessWidget {
icon: const Icon(Icons.close_outlined), icon: const Icon(Icons.close_outlined),
onPressed: () => context.pop(), onPressed: () => context.pop(),
), ),
actions: [ ),
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TimeSpanMenuButton( TimeSpanMenuButton(
value: value: controller
controller.pangeaController.analytics.currentAnalyticsTimeSpan, .pangeaController.analytics.currentAnalyticsTimeSpan,
onChange: (TimeSpan value) => controller.toggleTimeSpan( onChange: (TimeSpan value) => controller.toggleTimeSpan(
context, context,
value, value,
@ -43,16 +48,13 @@ class AnalyticsSpaceListView extends StatelessWidget {
), ),
AnalyticsLanguageButton( AnalyticsLanguageButton(
value: value:
controller.pangeaController.analytics.currentAnalyticsSpaceLang, controller.pangeaController.analytics.currentAnalyticsLang,
onChange: (lang) => controller.toggleSpaceLang(lang), onChange: (lang) => controller.toggleSpaceLang(lang),
languages: controller.targetLanguages.isEmpty languages:
? controller.pangeaController.pLanguageStore.targetOptions controller.pangeaController.pLanguageStore.targetOptions,
: controller.targetLanguages,
), ),
], ],
), ),
body: Column(
children: [
Flexible( Flexible(
child: ListView.builder( child: ListView.builder(
itemCount: controller.spaces.length, itemCount: controller.spaces.length,

@ -1,7 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:fluffychat/pangea/constants/language_keys.dart';
import 'package:fluffychat/pangea/controllers/language_list_controller.dart';
import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart';
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/models/language_model.dart';
import 'package:fluffychat/pangea/widgets/common/list_placeholder.dart'; import 'package:fluffychat/pangea/widgets/common/list_placeholder.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -75,6 +80,24 @@ class StudentAnalyticsController extends State<StudentAnalyticsPage> {
return id; return id;
} }
List<LanguageModel> get targetLanguages {
final LanguageModel? l2 =
_pangeaController.languageController.activeL2Model();
final List<LanguageModel> analyticsRoomLangs =
_pangeaController.matrixState.client.allMyAnalyticsRooms
.map((analyticsRoom) => analyticsRoom.madeForLang)
.where((langCode) => langCode != null)
.map((langCode) => PangeaLanguage.byLangCode(langCode!))
.where(
(langModel) => langModel.langCode != LanguageKeys.unknownLanguage,
)
.toList();
if (l2 != null) {
analyticsRoomLangs.add(l2);
}
return analyticsRoomLangs.toSet().toList();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PLoadingStatusV2( return PLoadingStatusV2(

@ -59,6 +59,7 @@ class StudentAnalyticsView extends StatelessWidget {
AnalyticsEntryType.student, AnalyticsEntryType.student,
L10n.of(context)!.allChatsAndClasses, L10n.of(context)!.allChatsAndClasses,
), ),
targetLanguages: controller.targetLanguages,
) )
: const SizedBox(); : const SizedBox();
} }

@ -15,7 +15,6 @@ class TimeSpanMenuButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopupMenuButton<TimeSpan>( return PopupMenuButton<TimeSpan>(
icon: const Icon(Icons.calendar_month_outlined),
tooltip: L10n.of(context)!.changeDateRange, tooltip: L10n.of(context)!.changeDateRange,
initialValue: value, initialValue: value,
onSelected: (TimeSpan? timeSpan) { onSelected: (TimeSpan? timeSpan) {
@ -32,6 +31,19 @@ class TimeSpanMenuButton extends StatelessWidget {
child: Text(timeSpan.string(context)), child: Text(timeSpan.string(context)),
); );
}).toList(), }).toList(),
child: TextButton.icon(
label: Text(
value.string(context),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
),
),
icon: Icon(
Icons.calendar_month_outlined,
color: Theme.of(context).colorScheme.onSurface,
),
onPressed: null,
),
); );
} }
} }

@ -863,7 +863,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"be": [ "be": [
@ -2363,7 +2364,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"bn": [ "bn": [
@ -3859,7 +3861,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"bo": [ "bo": [
@ -5359,7 +5362,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ca": [ "ca": [
@ -6261,7 +6265,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"cs": [ "cs": [
@ -7245,7 +7250,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"de": [ "de": [
@ -8112,7 +8118,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"el": [ "el": [
@ -9563,7 +9570,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"eo": [ "eo": [
@ -10712,7 +10720,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"es": [ "es": [
@ -10727,7 +10736,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"et": [ "et": [
@ -11594,7 +11604,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"eu": [ "eu": [
@ -12463,7 +12474,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"fa": [ "fa": [
@ -13469,7 +13481,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"fi": [ "fi": [
@ -14439,7 +14452,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"fil": [ "fil": [
@ -15765,7 +15779,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"fr": [ "fr": [
@ -16770,7 +16785,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ga": [ "ga": [
@ -17904,7 +17920,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"gl": [ "gl": [
@ -18771,7 +18788,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"he": [ "he": [
@ -20024,7 +20042,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"hi": [ "hi": [
@ -21517,7 +21536,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"hr": [ "hr": [
@ -22463,7 +22483,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"hu": [ "hu": [
@ -23346,7 +23367,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ia": [ "ia": [
@ -24832,7 +24854,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"id": [ "id": [
@ -25705,7 +25728,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ie": [ "ie": [
@ -26962,7 +26986,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"it": [ "it": [
@ -27886,7 +27911,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ja": [ "ja": [
@ -28921,7 +28947,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ka": [ "ka": [
@ -30275,7 +30302,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ko": [ "ko": [
@ -31144,7 +31172,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"lt": [ "lt": [
@ -32179,7 +32208,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"lv": [ "lv": [
@ -33054,7 +33084,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"nb": [ "nb": [
@ -34253,7 +34284,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"nl": [ "nl": [
@ -35216,7 +35248,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"pl": [ "pl": [
@ -36188,7 +36221,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"pt": [ "pt": [
@ -37666,7 +37700,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"pt_BR": [ "pt_BR": [
@ -38539,7 +38574,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"pt_PT": [ "pt_PT": [
@ -39739,7 +39775,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ro": [ "ro": [
@ -40746,7 +40783,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ru": [ "ru": [
@ -41619,7 +41657,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"sk": [ "sk": [
@ -42885,7 +42924,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"sl": [ "sl": [
@ -44281,7 +44321,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"sr": [ "sr": [
@ -45451,7 +45492,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"sv": [ "sv": [
@ -46355,7 +46397,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"ta": [ "ta": [
@ -47852,7 +47895,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"th": [ "th": [
@ -49303,7 +49347,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"tr": [ "tr": [
@ -50170,7 +50215,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"uk": [ "uk": [
@ -51074,7 +51120,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"vi": [ "vi": [
@ -52426,7 +52473,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"zh": [ "zh": [
@ -53293,7 +53341,8 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
], ],
"zh_Hant": [ "zh_Hant": [
@ -54441,6 +54490,7 @@
"suggestToSpaceDesc", "suggestToSpaceDesc",
"practice", "practice",
"noLanguagesSet", "noLanguagesSet",
"noActivitiesFound" "noActivitiesFound",
"languageButtonLabel"
] ]
} }

Loading…
Cancel
Save