Merge branch 'main' into last-updated-l2

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

@ -4010,9 +4010,9 @@
"wordsPerMinute": "Words per minute",
"autoIGCToolName": "Run Language Assistance Automatically",
"autoIGCToolDescription": "Automatically run language assistance after typing messages",
"runGrammarCorrection": "Run grammar correction",
"runGrammarCorrection": "Check message",
"grammarCorrectionFailed": "Issues to address",
"grammarCorrectionComplete": "Grammar correction complete",
"grammarCorrectionComplete": "Looks good!",
"leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.",
"archiveSpaceDescription": "All chats within this space will be moved to the archive for yourself and other non-admin users.",
"leaveSpaceDescription": "All chats within this space will be moved to the archive. Other users will be able to see that you have left the space.",

@ -4609,9 +4609,9 @@
"enterNumber": "Introduzca un valor numérico entero.",
"autoIGCToolName": "Ejecutar automáticamente la asistencia lingüística",
"autoIGCToolDescription": "Ejecutar automáticamente la asistencia lingüística después de escribir mensajes",
"runGrammarCorrection": "Corregir la gramática",
"runGrammarCorrection": "Comprobar mensaje",
"grammarCorrectionFailed": "Cuestiones a tratar",
"grammarCorrectionComplete": "Corrección gramatical completa",
"grammarCorrectionComplete": "¡Se ve bien!",
"leaveRoomDescription": "El chat se moverá al archivo. Los demás usuarios podrán ver que has abandonado el chat.",
"archiveSpaceDescription": "Todos los chats de este espacio se moverán al archivo para ti y otros usuarios que no sean administradores.",
"leaveSpaceDescription": "Todos los chats dentro de este espacio se moverán al archivo. Los demás usuarios podrán ver que has abandonado el espacio.",

@ -35,11 +35,26 @@ class ChatPermissionsSettingsView extends StatelessWidget {
final powerLevels = Map<String, dynamic>.from(powerLevelsContent)
// #Pangea
// ..removeWhere((k, v) => v is! int);
..removeWhere((k, v) => v is! int || k.equals("m.call.invite"));
..removeWhere(
(k, v) =>
v is! int ||
k.equals("m.call.invite") ||
k.equals("historical") ||
k.equals("state_default"),
);
// Pangea#
final eventsPowerLevels = Map<String, int?>.from(
powerLevelsContent.tryGetMap<String, int?>('events') ?? {},
)..removeWhere((k, v) => v is! int);
// #Pangea
)..removeWhere(
(k, v) =>
v is! int ||
k.equals("m.space.child") ||
k.equals("pangea.usranalytics") ||
k.equals(EventTypes.RoomPowerLevels),
);
// )..removeWhere((k, v) => v is! int);
// Pangea#
return Column(
children: [
Column(
@ -57,51 +72,59 @@ class ChatPermissionsSettingsView extends StatelessWidget {
),
canEdit: room.canChangePowerLevel,
),
Divider(color: Theme.of(context).dividerColor),
ListTile(
title: Text(
L10n.of(context)!.notifications,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
),
Builder(
builder: (context) {
const key = 'rooms';
final value = powerLevelsContent
.containsKey('notifications')
? powerLevelsContent
.tryGetMap<String, Object?>('notifications')
?.tryGet<int>('rooms') ??
0
: 0;
return PermissionsListTile(
permissionKey: key,
permission: value,
category: 'notifications',
canEdit: room.canChangePowerLevel,
onChanged: (level) => controller.editPowerLevel(
context,
key,
value,
newLevel: level,
category: 'notifications',
// #Pangea
// Why would teacher need to stop students from seeing notifications?
// Divider(color: Theme.of(context).dividerColor),
// ListTile(
// title: Text(
// L10n.of(context)!.notifications,
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// fontWeight: FontWeight.bold,
// ),
// ),
// ),
// Builder(
// builder: (context) {
// const key = 'rooms';
// final value = powerLevelsContent
// .containsKey('notifications')
// ? powerLevelsContent
// .tryGetMap<String, Object?>('notifications')
// ?.tryGet<int>('rooms') ??
// 0
// : 0;
// return PermissionsListTile(
// permissionKey: key,
// permission: value,
// category: 'notifications',
// canEdit: room.canChangePowerLevel,
// onChanged: (level) => controller.editPowerLevel(
// context,
// key,
// value,
// newLevel: level,
// category: 'notifications',
// ),
// );
// },
// ),
// Only show if there are actually items in this category
if (eventsPowerLevels.isNotEmpty)
// Pangea#
Divider(color: Theme.of(context).dividerColor),
// #Pangea
if (eventsPowerLevels.isNotEmpty)
// Pangea#
ListTile(
title: Text(
L10n.of(context)!.configureChat,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
);
},
),
Divider(color: Theme.of(context).dividerColor),
ListTile(
title: Text(
L10n.of(context)!.configureChat,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
),
for (final entry in eventsPowerLevels.entries)
PermissionsListTile(
permissionKey: entry.key,

@ -8,6 +8,7 @@ import 'package:fluffychat/pangea/choreographer/controllers/message_options.dart
import 'package:fluffychat/pangea/constants/language_keys.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/controllers/subscription_controller.dart';
import 'package:fluffychat/pangea/enum/assistance_state_enum.dart';
import 'package:fluffychat/pangea/enum/edit_type.dart';
import 'package:fluffychat/pangea/models/it_step.dart';
import 'package:fluffychat/pangea/models/language_detection_model.dart';
@ -570,13 +571,3 @@ class Choreographer {
return AssistanceState.complete;
}
}
// assistance state is, user has not typed a message, user has typed a message and IGC has not run,
// IGC is running, IGC has run and there are remaining steps (either IT or IGC), or all steps are done
enum AssistanceState {
noMessage,
notFetched,
fetching,
fetched,
complete,
}

@ -1,10 +1,9 @@
import 'dart:async';
import 'dart:math' as math;
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
import 'package:fluffychat/pangea/constants/colors.dart';
import 'package:fluffychat/pangea/controllers/subscription_controller.dart';
import 'package:fluffychat/pangea/enum/assistance_state_enum.dart';
import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -54,15 +53,15 @@ class StartIGCButtonState extends State<StartIGCButton>
setState(() => prevState = assistanceState);
}
bool get itEnabled => widget.controller.choreographer.itEnabled;
bool get igcEnabled => widget.controller.choreographer.igcEnabled;
CanSendStatus get canSendStatus =>
widget.controller.pangeaController.subscriptionController.canSendStatus;
bool get grammarCorrectionEnabled =>
(itEnabled || igcEnabled) && canSendStatus == CanSendStatus.subscribed;
@override
Widget build(BuildContext context) {
final bool itEnabled = widget.controller.choreographer.itEnabled;
final bool igcEnabled = widget.controller.choreographer.igcEnabled;
final CanSendStatus canSendStatus =
widget.controller.pangeaController.subscriptionController.canSendStatus;
final bool grammarCorrectionEnabled =
(itEnabled || igcEnabled) && canSendStatus == CanSendStatus.subscribed;
if (!grammarCorrectionEnabled ||
widget.controller.choreographer.isAutoIGCEnabled ||
widget.controller.choreographer.choreoMode == ChoreoMode.it) {
@ -89,7 +88,7 @@ class StartIGCButtonState extends State<StartIGCButton>
disabledElevation: 0,
shape: const CircleBorder(),
onPressed: () {
if (assistanceState != AssistanceState.complete) {
if (assistanceState != AssistanceState.fetching) {
widget.controller.choreographer
.getLanguageHelp(
false,
@ -142,32 +141,3 @@ class StartIGCButtonState extends State<StartIGCButton>
);
}
}
extension AssistanceStateExtension on AssistanceState {
Color stateColor(context) {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
case AssistanceState.fetching:
return Theme.of(context).colorScheme.primary;
case AssistanceState.fetched:
return PangeaColors.igcError;
case AssistanceState.complete:
return AppConfig.success;
}
}
String tooltip(L10n l10n) {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
return l10n.runGrammarCorrection;
case AssistanceState.fetching:
return "";
case AssistanceState.fetched:
return l10n.grammarCorrectionFailed;
case AssistanceState.complete:
return l10n.grammarCorrectionComplete;
}
}
}

@ -0,0 +1,43 @@
// assistance state is, user has not typed a message, user has typed a message and IGC has not run,
// IGC is running, IGC has run and there are remaining steps (either IT or IGC), or all steps are done
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/constants/colors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
enum AssistanceState {
noMessage,
notFetched,
fetching,
fetched,
complete,
}
extension AssistanceStateExtension on AssistanceState {
Color stateColor(context) {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
case AssistanceState.fetching:
return Theme.of(context).colorScheme.primary;
case AssistanceState.fetched:
return PangeaColors.igcError;
case AssistanceState.complete:
return AppConfig.success;
}
}
String tooltip(L10n l10n) {
switch (this) {
case AssistanceState.noMessage:
case AssistanceState.notFetched:
return l10n.runGrammarCorrection;
case AssistanceState.fetching:
return "";
case AssistanceState.fetched:
return l10n.grammarCorrectionFailed;
case AssistanceState.complete:
return l10n.grammarCorrectionComplete;
}
}
}

@ -4,14 +4,17 @@ import 'dart:developer';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/constants/class_default_values.dart';
import 'package:fluffychat/pangea/constants/language_keys.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/controllers/language_list_controller.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/models/analytics/analytics_event.dart';
import 'package:fluffychat/pangea/models/analytics/constructs_event.dart';
import 'package:fluffychat/pangea/models/analytics/summary_analytics_event.dart';
import 'package:fluffychat/pangea/models/analytics/summary_analytics_model.dart';
import 'package:fluffychat/pangea/models/bot_options_model.dart';
import 'package:fluffychat/pangea/models/language_model.dart';
import 'package:fluffychat/pangea/models/space_model.dart';
import 'package:fluffychat/pangea/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/utils/bot_name.dart';
@ -129,6 +132,9 @@ extension PangeaRoom on Room {
Event? get pangeaRoomRulesStateEvent => _pangeaRoomRulesStateEvent;
Future<List<LanguageModel>> targetLanguages() async =>
await _targetLanguages();
// events
Future<bool> leaveIfFull() async => await _leaveIfFull();

@ -92,6 +92,34 @@ extension SpaceRoomExtension on Room {
return null;
}
Future<List<LanguageModel>> _targetLanguages() async {
await requestParticipants();
final students = _students;
final Map<LanguageModel, int> langCounts = {};
final List<Room> allRooms = client.rooms;
for (final User student in students) {
for (final Room room in allRooms) {
if (!room.isAnalyticsRoomOfUser(student.id)) continue;
final String? langCode = room.madeForLang;
if (langCode == null ||
langCode.isEmpty ||
langCode == LanguageKeys.unknownLanguage) {
continue;
}
final LanguageModel lang = PangeaLanguage.byLangCode(langCode);
langCounts[lang] ??= 0;
langCounts[lang] = langCounts[lang]! + 1;
}
}
// get a list of language models, sorted
// by the number of students who are learning that language
return langCounts.entries.map((entry) => entry.key).toList()
..sort(
(a, b) => langCounts[b]!.compareTo(langCounts[a]!),
);
}
// DateTime? get _languageSettingsUpdatedAt {
// if (!isSpace) return null;
// return languageSettingsStateEvent?.originServerTs ?? creationTime;

@ -25,8 +25,9 @@ class BaseAnalyticsPage extends StatefulWidget {
final AnalyticsSelected defaultSelected;
final AnalyticsSelected? alwaysSelected;
final StudentAnalyticsController? myAnalyticsController;
final List<LanguageModel> targetLanguages;
const BaseAnalyticsPage({
BaseAnalyticsPage({
super.key,
required this.pageTitle,
required this.tabs,
@ -34,7 +35,10 @@ class BaseAnalyticsPage extends StatefulWidget {
required this.defaultSelected,
this.selectedView,
this.myAnalyticsController,
});
targetLanguages,
}) : targetLanguages = (targetLanguages?.isNotEmpty ?? false)
? targetLanguages
: MatrixState.pangeaController.pLanguageStore.targetOptions;
@override
State<BaseAnalyticsPage> createState() => BaseAnalyticsController();

@ -128,8 +128,7 @@ class BaseAnalyticsView extends StatelessWidget {
value: controller.pangeaController.analytics
.currentAnalyticsSpaceLang,
onChange: (lang) => controller.toggleSpaceLang(lang),
languages: controller
.pangeaController.pLanguageStore.targetOptions,
languages: controller.widget.targetLanguages,
),
],
),

@ -4,6 +4,7 @@ import 'dart:developer';
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/enum/bar_chart_view_enum.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/utils/error_handler.dart';
import 'package:fluffychat/pangea/widgets/common/list_placeholder.dart';
import 'package:fluffychat/pangea/widgets/common/p_circular_loader.dart';
@ -33,6 +34,18 @@ class SpaceAnalyticsV2Controller extends State<SpaceAnalyticsPage> {
List<User> students = [];
String? get spaceId => GoRouterState.of(context).pathParameters['spaceid'];
Room? _spaceRoom;
List<LanguageModel> targetLanguages = [];
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () async {
if (spaceRoom == null || (!(spaceRoom?.isSpace ?? false))) {
context.go('/rooms');
}
getChatAndStudents();
});
}
Room? get spaceRoom {
if (_spaceRoom == null || _spaceRoom!.id != spaceId) {
@ -44,23 +57,11 @@ class SpaceAnalyticsV2Controller extends State<SpaceAnalyticsPage> {
context.go('/rooms/analytics');
return null;
}
getChatAndStudents();
getChatAndStudents().then((_) => setTargetLanguages());
}
return _spaceRoom;
}
@override
void initState() {
super.initState();
debugPrint("init space analytics");
Future.delayed(Duration.zero, () async {
if (spaceRoom == null || (!(spaceRoom?.isSpace ?? false))) {
context.go('/rooms');
}
getChatAndStudents();
});
}
Future<void> getChatAndStudents() async {
try {
await spaceRoom?.postLoad();
@ -97,12 +98,12 @@ class SpaceAnalyticsV2Controller extends State<SpaceAnalyticsPage> {
}
}
// @override
// void dispose() {
// super.dispose();
// refreshTimer?.cancel();
// stateSub?.cancel();
// }
Future<void> setTargetLanguages() async {
// get a list of language models, sorted by the
// number of students who are learning that language
targetLanguages = await spaceRoom?.targetLanguages() ?? [];
setState(() {});
}
@override
Widget build(BuildContext context) {

@ -59,6 +59,7 @@ class SpaceAnalyticsView extends StatelessWidget {
AnalyticsEntryType.space,
controller.spaceRoom?.name ?? "",
),
targetLanguages: controller.targetLanguages,
)
: const SizedBox();
}

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:fluffychat/pangea/enum/time_span.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/pages/analytics/space_list/space_list_view.dart';
import 'package:flutter/material.dart';
@ -22,26 +23,47 @@ class AnalyticsSpaceList extends StatefulWidget {
class AnalyticsSpaceListController extends State<AnalyticsSpaceList> {
PangeaController pangeaController = MatrixState.pangeaController;
List<Room> spaces = [];
List<LanguageModel> targetLanguages = [];
@override
void initState() {
super.initState();
Matrix.of(context).client.spacesImTeaching.then((spaceList) {
spaceList = spaceList
.where(
(space) => !spaceList.any(
(parentSpace) => parentSpace.spaceChildren
.any((child) => child.roomId == space.id),
),
)
.toList();
spaces = spaceList;
setState(() {});
});
setSpaceList().then((_) => setTargetLanguages());
}
StreamController refreshStream = StreamController.broadcast();
Future<void> setSpaceList() async {
final spaceList = await Matrix.of(context).client.spacesImTeaching;
spaces = spaceList
.where(
(space) => !spaceList.any(
(parentSpace) => parentSpace.spaceChildren
.any((child) => child.roomId == space.id),
),
)
.toList();
setState(() {});
}
Future<void> setTargetLanguages() async {
if (spaces.isEmpty) return;
final Map<LanguageModel, int> langCounts = {};
for (final Room space in spaces) {
final List<LanguageModel> targetLangs = await space.targetLanguages();
for (final LanguageModel lang in targetLangs) {
langCounts[lang] ??= 0;
langCounts[lang] = langCounts[lang]! + 1;
}
}
targetLanguages = langCounts.entries.map((entry) => entry.key).toList()
..sort(
(a, b) => langCounts[b]!.compareTo(langCounts[a]!),
);
setState(() {});
}
void toggleTimeSpan(BuildContext context, TimeSpan timeSpan) {
pangeaController.analytics.setCurrentAnalyticsTimeSpan(timeSpan);
refreshStream.add(false);

@ -45,7 +45,9 @@ class AnalyticsSpaceListView extends StatelessWidget {
value:
controller.pangeaController.analytics.currentAnalyticsSpaceLang,
onChange: (lang) => controller.toggleSpaceLang(lang),
languages: controller.pangeaController.pLanguageStore.targetOptions,
languages: controller.targetLanguages.isEmpty
? controller.pangeaController.pLanguageStore.targetOptions
: controller.targetLanguages,
),
],
),

@ -109,7 +109,7 @@ class SubscriptionCard extends StatelessWidget {
title ?? subscription?.displayName(context) ?? '',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontSize: 20,
color:
enabled ? null : const Color.fromARGB(255, 174, 174, 174),
),

Loading…
Cancel
Save