From a077cc4f6a2fc48a7712ab6331e7d368afee7ebc Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 20 May 2024 10:09:47 -0400 Subject: [PATCH 01/26] button to run IGC manually --- assets/l10n/intl_en.arb | 7 +- lib/pages/chat/chat_view.dart | 10 +- .../controllers/choreographer.dart | 46 +++++- .../choreographer/widgets/send_button.dart | 9 +- .../widgets/start_igc_button.dart | 150 ++++++++++++++++++ lib/pangea/models/class_model.dart | 19 ++- lib/pangea/models/user_model.dart | 3 + 7 files changed, 231 insertions(+), 13 deletions(-) create mode 100644 lib/pangea/choreographer/widgets/start_igc_button.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 6677bc3d3..f84836933 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3948,5 +3948,10 @@ "studentAnalyticsNotAvailable": "Student data not currently available", "roomDataMissing": "Some data may be missing from rooms in which you are not a member.", "updatePhoneOS": "You may need to update your device's OS version.", - "wordsPerMinute": "Words per minute" + "wordsPerMinute": "Words per minute", + "autoIGCToolName": "Run Language Assistance Automatically", + "autoIGCToolDescription": "Automatically run language assistance after typing messages", + "runGrammarCorrection": "Run grammar correction", + "grammarCorrectionFailed": "Grammar correction failed", + "grammarCorrectionComplete": "Grammar correction complete" } \ No newline at end of file diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 57255ffc9..65aac4106 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat/reactions_picker.dart'; import 'package:fluffychat/pages/chat/reply_display.dart'; import 'package:fluffychat/pangea/choreographer/widgets/has_error_button.dart'; import 'package:fluffychat/pangea/choreographer/widgets/language_permissions_warning_buttons.dart'; +import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/pangea/pages/class_analytics/measure_able.dart'; import 'package:fluffychat/utils/account_config.dart'; @@ -416,8 +417,8 @@ class ChatView extends StatelessWidget { // #Pangea // if (controller.dragging) // Container( - // color: Theme.of(context) - // .scaffoldBackgroundColor + // color: Theme.of(context) + // .scaffoldBackgroundColor // .withOpacity(0.9), // alignment: Alignment.center, // child: const Icon( @@ -425,6 +426,11 @@ class ChatView extends StatelessWidget { // size: 100, // ), // ), + Positioned( + left: 20, + bottom: 75, + child: StartIGCButton(controller: controller), + ), // Pangea# ], ), diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 3a26676c6..7534529c6 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -51,7 +51,7 @@ class Choreographer { // last checked by IGC or translation String? _lastChecked; ChoreoMode choreoMode = ChoreoMode.igc; - final StreamController stateListener = StreamController(); + final StreamController stateListener = StreamController.broadcast(); StreamSubscription? trialStream; Choreographer(this.pangeaController, this.chatController) { @@ -205,14 +205,18 @@ class Choreographer { textController.editType = EditType.keyboard; } - Future getLanguageHelp([bool tokensOnly = false]) async { + Future getLanguageHelp([ + bool tokensOnly = false, + bool manual = false, + ]) async { try { if (errorService.isError) return; final CanSendStatus canSendStatus = pangeaController.subscriptionController.canSendStatus; if (canSendStatus != CanSendStatus.subscribed || - (!igcEnabled && !itEnabled)) { + (!igcEnabled && !itEnabled) || + (!isAutoIGCEnabled && !manual && choreoMode != ChoreoMode.it)) { return; } @@ -535,4 +539,40 @@ class Choreographer { pangeaController.permissionsController.isWritingAssistanceEnabled( chatController.room, ); + + bool get isAutoIGCEnabled => + pangeaController.permissionsController.isToolEnabled( + ToolSetting.autoIGC, + chatController.room, + ); + + AssistanceState get assistanceState { + if (currentText.isEmpty && itController.sourceText == null) { + return AssistanceState.noMessage; + } + + if (igc.igcTextData?.matches.isNotEmpty ?? false) { + return AssistanceState.fetched; + } + + if (isFetching) { + return AssistanceState.fetching; + } + + if (igc.igcTextData == null) { + return AssistanceState.notFetched; + } + + 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, } diff --git a/lib/pangea/choreographer/widgets/send_button.dart b/lib/pangea/choreographer/widgets/send_button.dart index 045f0c516..fa3189df5 100644 --- a/lib/pangea/choreographer/widgets/send_button.dart +++ b/lib/pangea/choreographer/widgets/send_button.dart @@ -1,8 +1,7 @@ +import 'package:fluffychat/pangea/constants/colors.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:fluffychat/pangea/constants/colors.dart'; import '../../../pages/chat/chat.dart'; class ChoreographerSendButton extends StatelessWidget { @@ -16,7 +15,8 @@ class ChoreographerSendButton extends StatelessWidget { @override Widget build(BuildContext context) { // commit for cicd - return controller.choreographer.isFetching + return controller.choreographer.isFetching && + controller.choreographer.isAutoIGCEnabled ? Container( height: 56, width: 56, @@ -28,7 +28,8 @@ class ChoreographerSendButton extends StatelessWidget { alignment: Alignment.center, child: IconButton( icon: const Icon(Icons.send_outlined), - color: controller.choreographer.igc.canSendMessage + color: controller.choreographer.igc.canSendMessage || + !controller.choreographer.isAutoIGCEnabled ? null : PangeaColors.igcError, onPressed: () { diff --git a/lib/pangea/choreographer/widgets/start_igc_button.dart b/lib/pangea/choreographer/widgets/start_igc_button.dart new file mode 100644 index 000000000..183ac690d --- /dev/null +++ b/lib/pangea/choreographer/widgets/start_igc_button.dart @@ -0,0 +1,150 @@ +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:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +import '../../../pages/chat/chat.dart'; + +class StartIGCButton extends StatefulWidget { + const StartIGCButton({ + super.key, + required this.controller, + }); + + final ChatController controller; + + @override + State createState() => StartIGCButtonState(); +} + +class StartIGCButtonState extends State + with SingleTickerProviderStateMixin { + AssistanceState get assistanceState => + widget.controller.choreographer.assistanceState; + AnimationController? _controller; + StreamSubscription? choreoListener; + AssistanceState? prevState; + + @override + void initState() { + _controller = AnimationController( + vsync: this, + duration: const Duration(seconds: 1), + ); + choreoListener = widget.controller.choreographer.stateListener.stream + .listen(updateSpinnerState); + super.initState(); + } + + void updateSpinnerState(_) { + if (prevState != AssistanceState.fetching && + assistanceState == AssistanceState.fetching) { + _controller?.repeat(); + } else if (prevState == AssistanceState.fetching && + assistanceState != AssistanceState.fetching) { + _controller?.stop(); + _controller?.reverse(); + } + setState(() => prevState = assistanceState); + } + + @override + Widget build(BuildContext context) { + if (widget.controller.choreographer.isAutoIGCEnabled) { + return const SizedBox.shrink(); + } + + final Widget icon = Icon( + Icons.autorenew_rounded, + size: 46, + color: assistanceState.stateColor, + ); + + return SizedBox( + height: 50, + width: 50, + child: FloatingActionButton( + tooltip: assistanceState.tooltip( + L10n.of(context)!, + ), + backgroundColor: Colors.white, + disabledElevation: 0, + shape: const CircleBorder(), + onPressed: () { + if (assistanceState != AssistanceState.complete) { + widget.controller.choreographer.getLanguageHelp( + false, + true, + ); + } + }, + child: Stack( + alignment: Alignment.center, + children: [ + _controller != null + ? RotationTransition( + turns: Tween(begin: 0.0, end: math.pi * 2) + .animate(_controller!), + child: icon, + ) + : icon, + Container( + width: 26, + height: 26, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + ), + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: assistanceState.stateColor, + ), + ), + const Icon( + size: 16, + Icons.check, + color: Colors.white, + ), + ], + ), + ), + ); + } +} + +extension AssistanceStateExtension on AssistanceState { + Color get stateColor { + switch (this) { + case AssistanceState.noMessage: + case AssistanceState.notFetched: + case AssistanceState.fetching: + return AppConfig.primaryColor; + 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; + } + } +} diff --git a/lib/pangea/models/class_model.dart b/lib/pangea/models/class_model.dart index 1f588980c..dc0822438 100644 --- a/lib/pangea/models/class_model.dart +++ b/lib/pangea/models/class_model.dart @@ -1,13 +1,12 @@ import 'dart:developer'; +import 'package:fluffychat/pangea/constants/model_keys.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/constants/model_keys.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; import '../constants/class_default_values.dart'; import '../constants/language_keys.dart'; import '../constants/pangea_event_types.dart'; @@ -124,6 +123,7 @@ class PangeaRoomRules { int immersionMode; int definitions; int translations; + int autoIGC; PangeaRoomRules({ this.isPublic = false, @@ -142,6 +142,7 @@ class PangeaRoomRules { this.immersionMode = ClassDefaultValues.languageToolPermissions, this.definitions = ClassDefaultValues.languageToolPermissions, this.translations = ClassDefaultValues.languageToolPermissions, + this.autoIGC = ClassDefaultValues.languageToolPermissions, }); updatePermission(String key, bool value) { @@ -201,6 +202,9 @@ class PangeaRoomRules { case ToolSetting.translations: translations = value; break; + case ToolSetting.autoIGC: + autoIGC = value; + break; default: throw Exception('Invalid key for setting permissions - $setting'); } @@ -235,6 +239,7 @@ class PangeaRoomRules { json['definitions'] ?? ClassDefaultValues.languageToolPermissions, translations: json['translations'] ?? ClassDefaultValues.languageToolPermissions, + autoIGC: json['auto_igc'] ?? ClassDefaultValues.languageToolPermissions, ); Map toJson() { @@ -256,6 +261,7 @@ class PangeaRoomRules { data['immersion_mode'] = immersionMode; data['definitions'] = definitions; data['translations'] = translations; + data['auto_igc'] = autoIGC; return data; } @@ -271,6 +277,8 @@ class PangeaRoomRules { return definitions; case ToolSetting.translations: return translations; + case ToolSetting.autoIGC: + return autoIGC; default: throw Exception('Invalid key for setting permissions - $setting'); } @@ -299,6 +307,7 @@ enum ToolSetting { immersionMode, definitions, translations, + autoIGC, } extension SettingCopy on ToolSetting { @@ -314,6 +323,8 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.definitionsToolName; case ToolSetting.translations: return L10n.of(context)!.messageTranslationsToolName; + case ToolSetting.autoIGC: + return L10n.of(context)!.autoIGCToolName; } } @@ -330,6 +341,8 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.definitionsToolDescription; case ToolSetting.translations: return L10n.of(context)!.translationsToolDescrption; + case ToolSetting.autoIGC: + return L10n.of(context)!.autoIGCToolDescription; } } } diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index 2169c6f70..10c382f9f 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -68,6 +68,7 @@ enum MatrixProfile { sourceLanguage, country, publicProfile, + autoIGC, } extension MatrixProfileExtension on MatrixProfile { @@ -89,6 +90,8 @@ extension MatrixProfileExtension on MatrixProfile { return ToolSetting.definitions.toString(); case MatrixProfile.translations: return ToolSetting.translations.toString(); + case MatrixProfile.autoIGC: + return ToolSetting.autoIGC.toString(); case MatrixProfile.showedItInstructions: return InstructionsEnum.itInstructions.toString(); case MatrixProfile.showedClickMessage: From e2878a1bca6baa10f787849f1ef12cee2c3924f4 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 23 May 2024 13:45:17 -0400 Subject: [PATCH 02/26] language detection updates --- lib/pangea/constants/model_keys.dart | 1 + .../language_detection_controller.dart | 34 +++++++++++++++++-- .../models/language_detection_model.dart | 12 ++++--- lib/pangea/repo/igc_repo.dart | 6 ++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart index ce427f3d3..ef84a7064 100644 --- a/lib/pangea/constants/model_keys.dart +++ b/lib/pangea/constants/model_keys.dart @@ -54,6 +54,7 @@ class ModelKey { static const String offset = "offset"; static const String length = "length"; static const String langCode = 'lang_code'; + static const String confidence = 'confidence'; // some old analytics rooms have langCode instead of lang_code in the room creation content static const String oldLangCode = 'langCode'; static const String wordLang = "word_lang"; diff --git a/lib/pangea/controllers/language_detection_controller.dart b/lib/pangea/controllers/language_detection_controller.dart index 0ff18b556..4d3326dde 100644 --- a/lib/pangea/controllers/language_detection_controller.dart +++ b/lib/pangea/controllers/language_detection_controller.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; +import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/network/urls.dart'; import 'package:http/http.dart' as http; @@ -48,7 +49,7 @@ class LanguageDetectionRequest { } class LanguageDetectionResponse { - List> detections; + List detections; String fullText; LanguageDetectionResponse({ @@ -58,7 +59,11 @@ class LanguageDetectionResponse { factory LanguageDetectionResponse.fromJson(Map json) { return LanguageDetectionResponse( - detections: List>.from(json['detections']), + detections: List.from( + json['detections'].map( + (e) => LanguageDetection.fromJson(e), + ), + ), fullText: json['full_text'], ); } @@ -69,6 +74,18 @@ class LanguageDetectionResponse { 'full_text': fullText, }; } + + LanguageDetection? get _bestDetection { + detections.sort((a, b) => b.confidence.compareTo(a.confidence)); + return detections.isNotEmpty ? detections.first : null; + } + + final double _confidenceThreshold = 0.95; + + LanguageDetection? get thresholdedDetection => + (_bestDetection?.confidence ?? 0) >= _confidenceThreshold + ? _bestDetection! + : null; } class _LanguageDetectionCacheItem { @@ -103,6 +120,19 @@ class LanguageDetectionController { _cacheClearTimer?.cancel(); } + Future detectLanguage( + String fullText, + String? userL2, + String? userL1, + ) async { + final LanguageDetectionRequest params = LanguageDetectionRequest( + fullText: fullText, + userL1: userL1, + userL2: userL2, + ); + return get(params); + } + Future get( LanguageDetectionRequest params, ) async { diff --git a/lib/pangea/models/language_detection_model.dart b/lib/pangea/models/language_detection_model.dart index 6fa3d7299..7ed44868c 100644 --- a/lib/pangea/models/language_detection_model.dart +++ b/lib/pangea/models/language_detection_model.dart @@ -1,19 +1,23 @@ +import 'package:fluffychat/pangea/constants/model_keys.dart'; + class LanguageDetection { String langCode; + double confidence; LanguageDetection({ required this.langCode, + required this.confidence, }); factory LanguageDetection.fromJson(Map json) { return LanguageDetection( - langCode: json[_langCodeKey], + langCode: json[ModelKey.langCode], + confidence: json[ModelKey.confidence], ); } - static const _langCodeKey = "lang_code"; - Map toJson() => { - _langCodeKey: langCode, + ModelKey.langCode: langCode, + ModelKey.confidence: confidence, }; } diff --git a/lib/pangea/repo/igc_repo.dart b/lib/pangea/repo/igc_repo.dart index 068a009e8..9517515d0 100644 --- a/lib/pangea/repo/igc_repo.dart +++ b/lib/pangea/repo/igc_repo.dart @@ -1,13 +1,13 @@ import 'dart:convert'; -import 'package:http/http.dart'; - import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/lemma.dart'; import 'package:fluffychat/pangea/models/pangea_match_model.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/repo/span_data_repo.dart'; +import 'package:http/http.dart'; + import '../constants/model_keys.dart'; import '../models/igc_text_data_model.dart'; import '../network/requests.dart'; @@ -39,7 +39,7 @@ class IgcRepo { await Future.delayed(const Duration(seconds: 2)); final IGCTextData igcTextData = IGCTextData( - detections: [LanguageDetection(langCode: "en")], + detections: [LanguageDetection(langCode: "en", confidence: 0.99)], tokens: [ PangeaToken( text: PangeaTokenText(content: "This", offset: 0, length: 4), From ec66e45b641ece878fd0bd53d211f1d976cccf3d Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 29 May 2024 13:54:17 -0400 Subject: [PATCH 03/26] toggle to set suggested status for all spaces --- assets/l10n/intl_en.arb | 20 +-- lib/pages/new_group/new_group.dart | 4 +- lib/pages/new_space/new_space.dart | 4 +- .../extensions/pangea_room_extension.dart | 35 +++- .../widgets/class/add_space_toggles.dart | 153 ++++++------------ 5 files changed, 84 insertions(+), 132 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index fe2a3da03..94abc00e1 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3681,24 +3681,8 @@ "lockSpace": "Lock Space", "lockChat": "Lock Chat", "archiveSpace": "Archive Space", - "suggestTo": "Suggest to {spaceName}", - "@suggestTo": { - "placeholders": { - "spaceName": {} - } - }, - "suggestChatDesc": "Suggested chats will appear in the chat list for {spaceName}", - "@suggestToDesc": { - "placeholders": { - "spaceName": {} - } - }, - "suggestExchangeDesc": "Suggested exchanges will appear in the chat list for {spaceName}", - "@suggestToExchangeDesc": { - "placeholders": { - "spaceName": {} - } - }, + "suggestToChat": "Suggest this chat", + "suggestToChatDesc": "Suggested chats will appear in chat lists", "acceptSelection": "Accept Correction", "acceptSelectionAnyway": "Use this anyway", "makingActivity": "Making activity", diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 2ada80dfa..2aec182fb 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -130,9 +130,7 @@ class NewGroupController extends State { powerLevelContentOverride: await ClassChatPowerLevels.powerLevelOverrideForClassChat( context, - addToSpaceKey.currentState!.parents - .map((suggestionStatus) => suggestionStatus.room) - .toList(), + addToSpaceKey.currentState!.parents, ), invite: [ if (addConversationBotKey.currentState?.addBot ?? false) diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index a310769cc..e11018f99 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -176,9 +176,7 @@ class NewSpaceController extends State { powerLevelContentOverride: addToSpaceKey.currentState != null ? await ClassChatPowerLevels.powerLevelOverrideForClassChat( context, - addToSpaceKey.currentState!.parents - .map((suggestionStatus) => suggestionStatus.room) - .toList(), + addToSpaceKey.currentState!.parents, ) : null, // initialState: [ diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 4d08f0b62..cfb19edab 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -977,7 +977,40 @@ extension PangeaRoom on Room { return joinedRooms > 0 ? true : false; } - Future suggestedInSpace(Room space) async { + Future isSuggested() async { + final List spaceParents = client.rooms + .where( + (room) => + room.isSpace && + room.spaceChildren.any( + (sc) => sc.roomId == id, + ), + ) + .toList(); + + for (final parent in spaceParents) { + final suggested = await isSuggestedInSpace(parent); + if (!suggested) return false; + } + return true; + } + + Future setSuggested(bool suggested) async { + final List spaceParents = client.rooms + .where( + (room) => + room.isSpace && + room.spaceChildren.any( + (sc) => sc.roomId == id, + ), + ) + .toList(); + for (final parent in spaceParents) { + await setSuggestedInSpace(suggested, parent); + } + } + + Future isSuggestedInSpace(Room space) async { try { final Map resp = await client.getRoomStateWithKey(space.id, EventTypes.spaceChild, id); diff --git a/lib/pangea/widgets/class/add_space_toggles.dart b/lib/pangea/widgets/class/add_space_toggles.dart index eb06cd26a..9e51b12d9 100644 --- a/lib/pangea/widgets/class/add_space_toggles.dart +++ b/lib/pangea/widgets/class/add_space_toggles.dart @@ -33,9 +33,10 @@ class AddToSpaceToggles extends StatefulWidget { class AddToSpaceState extends State { late Room? room; - late List parents; + late List parents; late List possibleParents; late bool isOpen; + late bool isSuggested; AddToSpaceState({Key? key}); @@ -46,6 +47,9 @@ class AddToSpaceState extends State { ? Matrix.of(context).client.getRoomById(widget.roomId!) : null; + isSuggested = true; + room?.isSuggested().then((value) => isSuggested = value); + possibleParents = Matrix.of(context) .client .rooms @@ -63,8 +67,6 @@ class AddToSpaceState extends State { (r) => r.spaceChildren.any((room) => room.roomId == widget.roomId), ) - .map((r) => SuggestionStatus(false, r)) - .cast() .toList() : []; @@ -72,7 +74,7 @@ class AddToSpaceState extends State { final activeSpace = Matrix.of(context).client.getRoomById(widget.activeSpaceId!); if (activeSpace != null && activeSpace.canIAddSpaceChild(null)) { - parents.add(SuggestionStatus(true, activeSpace)); + parents.add(activeSpace); } else { ErrorHandler.logError( e: Exception('activeSpaceId ${widget.activeSpaceId} not found'), @@ -84,10 +86,9 @@ class AddToSpaceState extends State { //if possibleParent in parents, put first //use sort but use any instead of contains because contains uses == and we want to compare by id possibleParents.sort((a, b) { - if (parents.any((suggestionStatus) => suggestionStatus.room.id == a.id)) { + if (parents.any((parent) => parent.id == a.id)) { return -1; - } else if (parents - .any((suggestionStatus) => suggestionStatus.room.id == b.id)) { + } else if (parents.any((parent) => parent.id == b.id)) { return 1; } else { return a.name.compareTo(b.name); @@ -95,35 +96,21 @@ class AddToSpaceState extends State { }); isOpen = widget.startOpen; - initSuggestedParents(); super.initState(); } - Future initSuggestedParents() async { - if (room != null) { - for (var i = 0; i < parents.length; i++) { - final parent = parents[i]; - final bool suggested = - await room?.suggestedInSpace(parent.room) ?? false; - parents[i].suggested = suggested; - } - setState(() {}); - } - } - Future _addSingleSpace(String roomToAddId, Room newParent) async { GoogleAnalytics.addParent(roomToAddId, newParent.classCode); await newParent.setSpaceChild( roomToAddId, - suggested: isSuggestedInSpace(newParent), + suggested: isSuggested, ); - await setSuggested(true, newParent); } Future addSpaces(String roomToAddId) async { final List> addFutures = []; - for (final SuggestionStatus newParent in parents) { - addFutures.add(_addSingleSpace(roomToAddId, newParent.room)); + for (final Room parent in parents) { + addFutures.add(_addSingleSpace(roomToAddId, parent)); } await addFutures.wait; } @@ -148,38 +135,15 @@ class AddToSpaceState extends State { setState( () => add - ? parents.add(SuggestionStatus(true, possibleParent)) + ? parents.add(possibleParent) : parents.removeWhere( - (suggestionStatus) => - suggestionStatus.room.id == possibleParent.id, + (parent) => parent.id == possibleParent.id, ), ); } - Future setSuggested(bool suggest, Room possibleParent) async { - if (room != null) { - await showFutureLoadingDialog( - context: context, - future: () => room!.setSuggestedInSpace(suggest, possibleParent), - ); - } - - for (final SuggestionStatus suggestionStatus in parents) { - if (suggestionStatus.room.id == possibleParent.id) { - suggestionStatus.suggested = suggest; - } - } - - setState(() {}); - } - - bool isSuggestedInSpace(Room parent) => - parents.firstWhereOrNull((r) => r.room.id == parent.id)?.suggested ?? - false; - Widget getAddToSpaceToggleItem(int index) { final Room possibleParent = possibleParents[index]; - final String possibleParentName = possibleParent.getLocalizedDisplayname(); final bool canAdd = possibleParent.canIAddSpaceChild(room); return Opacity( @@ -189,7 +153,7 @@ class AddToSpaceState extends State { SwitchListTile.adaptive( title: possibleParent.nameAndRoomTypeIcon(), activeColor: AppConfig.activeToggleColor, - value: parents.any((r) => r.room.id == possibleParent.id), + value: parents.any((r) => r.id == possibleParent.id), onChanged: (bool add) => canAdd ? handleAdd(add, possibleParent) : ScaffoldMessenger.of(context).showSnackBar( @@ -198,53 +162,6 @@ class AddToSpaceState extends State { ), ), ), - AnimatedSize( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - child: parents.any((r) => r.room.id == possibleParent.id) - ? SwitchListTile.adaptive( - title: Row( - children: [ - const SizedBox(width: 32), - Expanded( - child: Text( - L10n.of(context)!.suggestTo(possibleParentName), - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - subtitle: Row( - children: [ - const SizedBox(width: 32), - Expanded( - child: Text( - widget.mode == AddToClassMode.chat - ? L10n.of(context)! - .suggestChatDesc(possibleParentName) - : L10n.of(context)!.suggestExchangeDesc( - possibleParentName, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - activeColor: AppConfig.activeToggleColor, - value: isSuggestedInSpace(possibleParent), - onChanged: (bool suggest) => canAdd - ? setSuggested(suggest, possibleParent) - : ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context)!.noPermission), - ), - ), - ) - : Container(), - ), Divider( height: 0.5, color: Theme.of(context).colorScheme.secondary.withAlpha(25), @@ -254,6 +171,16 @@ class AddToSpaceState extends State { ); } + Future setSuggested(bool suggested) async { + setState(() => isSuggested = suggested); + if (room != null) { + await showFutureLoadingDialog( + context: context, + future: () async => await room?.setSuggested(suggested), + ); + } + } + @override Widget build(BuildContext context) { final String title = widget.mode == AddToClassMode.exchange @@ -292,9 +219,28 @@ class AddToSpaceState extends State { const Divider(height: 1), possibleParents.isNotEmpty ? Column( - children: possibleParents - .mapIndexed((index, _) => getAddToSpaceToggleItem(index)) - .toList(), + children: [ + SwitchListTile.adaptive( + title: Text(L10n.of(context)!.suggestToChat), + secondary: Icon( + isSuggested + ? Icons.visibility_outlined + : Icons.visibility_off_outlined, + ), + subtitle: Text(L10n.of(context)!.suggestToChatDesc), + activeColor: AppConfig.activeToggleColor, + value: isSuggested, + onChanged: (bool add) => setSuggested(add), + ), + Divider( + height: 0.5, + color: + Theme.of(context).colorScheme.secondary.withAlpha(25), + ), + ...possibleParents.mapIndexed( + (index, _) => getAddToSpaceToggleItem(index), + ), + ], ) : Center( child: Padding( @@ -312,10 +258,3 @@ class AddToSpaceState extends State { ); } } - -class SuggestionStatus { - bool suggested; - final Room room; - - SuggestionStatus(this.suggested, this.room); -} From 2fc8c30f25b510387068581e589873fdff37f317 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 29 May 2024 14:14:58 -0400 Subject: [PATCH 04/26] fix for inviting students to chats --- lib/pages/invitation_selection/invitation_selection.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart index 5f2bd5027..9a1e09553 100644 --- a/lib/pages/invitation_selection/invitation_selection.dart +++ b/lib/pages/invitation_selection/invitation_selection.dart @@ -159,6 +159,8 @@ class InvitationSelectionController extends State { future: () async { if (mode == InvitationSelectionMode.admin) { await inviteTeacherAction(room, id); + } else { + await room.invite(id); } }, // Pangea# From 1bce01614094107d84b4c6aeb4572b0ea7185d5f Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 29 May 2024 14:16:45 -0400 Subject: [PATCH 05/26] Separate archive and leave buttons --- assets/l10n/intl_en.arb | 5 +- lib/pages/chat/chat.dart | 12 ++ lib/pages/chat/chat_view.dart | 34 ++++- lib/pages/chat_details/chat_details_view.dart | 129 ++++++++++++------ lib/pages/chat_list/chat_list_header.dart | 30 +++- lib/pages/chat_list/space_view.dart | 5 +- lib/widgets/chat_settings_popup_menu.dart | 61 +++++++-- 7 files changed, 210 insertions(+), 66 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index fe2a3da03..dfab2d0fd 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3724,7 +3724,7 @@ }, "noTeachersFound": "No teachers found to report to", "pleaseEnterANumber": "Please enter a number greater than 0", - "archiveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.", + "archiveRoomDescription": "The chat will be moved to the archive for all participants.", "roomUpgradeDescription": "The chat will then be recreated with the new room version. All participants will be notified that they need to switch to the new chat. You can find out more about room versions at https://spec.matrix.org/latest/rooms/", "removeDevicesDescription": "You will be logged out of this device and will no longer be able to receive messages.", "banUserDescription": "The user will be banned from the chat and will not be able to enter the chat again until they are unbanned.", @@ -3963,5 +3963,6 @@ "studentAnalyticsNotAvailable": "Student data not currently available", "roomDataMissing": "Some data may be missing from rooms in which you are not a member.", "updatePhoneOS": "You may need to update your device's OS version.", - "wordsPerMinute": "Words per minute" + "wordsPerMinute": "Words per minute", + "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat." } \ No newline at end of file diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 460de198c..2bd931879 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -228,6 +228,18 @@ class ChatController extends State context.go('/rooms'); } + // #Pangea + void archiveChat() async { + final success = await showFutureLoadingDialog( + context: context, + future: room + .leave, // Edit - Add room.archive method in pangea_room_extension.dart + ); + if (success.error != null) return; + context.go('/rooms'); + } + // Pangea# + EmojiPickerType emojiPickerType = EmojiPickerType.keyboard; // #Pangea diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 21789f527..4cfc8b8ec 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -116,8 +116,10 @@ class ChatView extends StatelessWidget { // #Pangea } else { return [ - ChatSettingsPopupMenu(controller.room, - (!controller.room.isDirectChat && !controller.room.isArchived)), + ChatSettingsPopupMenu( + controller.room, + (!controller.room.isDirectChat && !controller.room.isArchived), + ), ]; } @@ -361,6 +363,29 @@ class ChatView extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + // #Pangea + if (controller.room.isRoomAdmin) + TextButton.icon( + style: TextButton.styleFrom( + padding: + const EdgeInsets.all( + 16, + ), + foregroundColor: + Theme.of(context) + .colorScheme + .error, + ), + icon: const Icon( + Icons.archive_outlined, + ), + onPressed: + controller.archiveChat, + label: Text( + L10n.of(context)!.archive, + ), + ), + // Pangea# TextButton.icon( style: TextButton.styleFrom( padding: const EdgeInsets.all( @@ -372,7 +397,10 @@ class ChatView extends StatelessWidget { .error, ), icon: const Icon( - Icons.archive_outlined, + // #Pangea + // Icons.archive_outlined, + Icons.arrow_forward, + // Pangea# ), onPressed: controller.leaveChat, label: Text( diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 2d46df11d..037626993 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -522,52 +522,101 @@ class ChatDetailsView extends StatelessWidget { ), const Divider(height: 1), if (!room.isDirectChat) - ListTile( - title: Text( - room.isSpace - ? L10n.of(context)!.archiveSpace - : L10n.of(context)!.archive, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, + if (room.isRoomAdmin) + ListTile( + title: Text( + room.isSpace + ? L10n.of(context)!.archiveSpace + : L10n.of(context)!.archive, + style: TextStyle( + color: + Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), ), - ), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, - child: const Icon( - Icons.archive_outlined, + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: const Icon( + Icons.archive_outlined, + ), ), - ), - onTap: () async { - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.ok, - cancelLabel: L10n.of(context)!.cancel, - message: - L10n.of(context)!.archiveRoomDescription, - ); - if (confirmed == OkCancelResult.ok) { - final success = await showFutureLoadingDialog( + onTap: () async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, context: context, - future: () async { - room.isSpace - ? await archiveSpace( - room, - Matrix.of(context).client, - ) - : await room.leave(); - }, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: + L10n.of(context)!.archiveRoomDescription, ); - if (success.error == null) { - context.go('/rooms'); + if (confirmed == OkCancelResult.ok) { + final success = await showFutureLoadingDialog( + context: context, + future: () async { + room.isSpace + ? await archiveSpace( + // Edit - contents + room, + Matrix.of(context).client, + ) + : await room + .leave(); // Edit - archive, not leave + }, + ); + if (success.error == null) { + context.go('/rooms'); + } } - } - }, + }, + ), + ListTile( + title: Text( + L10n.of(context)!.leave, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: const Icon( + Icons.arrow_forward, + ), ), + onTap: () async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)! + .archiveRoomDescription, // Edit + ); + if (confirmed == OkCancelResult.ok) { + final success = await showFutureLoadingDialog( + context: context, + future: () async { + room.isSpace + ? await archiveSpace( + // Edit = leaveSpace + room, + Matrix.of(context).client, + ) + : await room.leave(); + }, + ); + if (success.error == null) { + context.go('/rooms'); + } + } + }, + ), if (room.isRoomAdmin && !room.isDirectChat) SwitchListTile.adaptive( activeColor: AppConfig.activeToggleColor, diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index c5973d8bb..ac555cb45 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -1,6 +1,8 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat_list/chat_list.dart'; import 'package:fluffychat/pages/chat_list/client_chooser_button.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -168,14 +170,30 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget { tooltip: L10n.of(context)!.toggleMuted, onPressed: controller.toggleMuted, ), - IconButton( - // #Pangea - // icon: const Icon(Icons.delete_outlined), - icon: const Icon(Icons.archive_outlined), + // #Pangea + if (controller.selectedRoomIds.length == 1 && + (Matrix.of(context) + .client + .getRoomById(controller.selectedRoomIds.single) + ?.isRoomAdmin ?? + false)) // Pangea# - tooltip: L10n.of(context)!.archive, - onPressed: controller.archiveAction, + IconButton( + // #Pangea + // icon: const Icon(Icons.delete_outlined), + icon: const Icon(Icons.archive_outlined), + // Pangea# + tooltip: L10n.of(context)!.archive, + onPressed: controller.archiveAction, + ), + // #Pangea + IconButton( + icon: const Icon(Icons.arrow_forward), + tooltip: L10n.of(context)!.leave, + onPressed: + controller.archiveAction, // Edit - make leaveAction ), + // Pangea# ] : null, ); diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 48be9eb04..9b02845ef 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -291,7 +291,7 @@ class _SpaceViewState extends State { if (room!.isUnread) { await room.markUnread(false); } - await room.leave(); + await room.leave(); // Edit - use leaveAction? if (Matrix.of(context).activeRoomId == room.id) { context.go('/rooms'); } @@ -306,7 +306,8 @@ class _SpaceViewState extends State { ); break; // #Pangea - case SpaceChildContextAction.archive: + case SpaceChildContextAction + .archive: // Edit - change behavior to archive space for all users widget.controller.cancelAction(); // #Pangea if (room == null) return; diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index 781b8ab61..f93173e6d 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -85,20 +85,31 @@ class ChatSettingsPopupMenuState extends State { ), // #Pangea if (!widget.room.isArchived) - // Pangea# - PopupMenuItem( - value: 'leave', - child: Row( - children: [ - // #Pangea - // const Icon(Icons.delete_outlined), - const Icon(Icons.arrow_forward), - // Pangea# - const SizedBox(width: 12), - Text(L10n.of(context)!.leave), - ], + if (widget.room.isRoomAdmin) + PopupMenuItem( + value: 'archive', + child: Row( + children: [ + const Icon(Icons.archive_outlined), + const SizedBox(width: 12), + Text(L10n.of(context)!.archive), + ], + ), ), + // Pangea# + PopupMenuItem( + value: 'leave', + child: Row( + children: [ + // #Pangea + // const Icon(Icons.delete_outlined), + const Icon(Icons.arrow_forward), + // Pangea# + const SizedBox(width: 12), + Text(L10n.of(context)!.leave), + ], ), + ), // #Pangea if (classSettings != null) PopupMenuItem( @@ -167,6 +178,29 @@ class ChatSettingsPopupMenuState extends State { PopupMenuButton( onSelected: (String choice) async { switch (choice) { + // #Pangea + case 'archive': + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)! + .archiveRoomDescription, // Edit - contents + ); + if (confirmed == OkCancelResult.ok) { + final success = await showFutureLoadingDialog( + context: context, + future: () => + widget.room.leave(), // Edit - archive, not leave + ); + if (success.error == null) { + context.go('/rooms'); + } + } + break; + // Pangea# case 'leave': final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, @@ -174,7 +208,8 @@ class ChatSettingsPopupMenuState extends State { title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.archiveRoomDescription, + message: L10n.of(context)! + .archiveRoomDescription, // Edit - leave, not archive ); if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( From 270d3802ac1f1dfd0c6d97bc68329d7870137cce Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 29 May 2024 14:18:35 -0400 Subject: [PATCH 06/26] Update popup descriptions --- lib/pages/chat_details/chat_details_view.dart | 3 +-- lib/widgets/chat_settings_popup_menu.dart | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 037626993..36b136caa 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -595,8 +595,7 @@ class ChatDetailsView extends StatelessWidget { title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)! - .archiveRoomDescription, // Edit + message: L10n.of(context)!.leaveRoomDescription, ); if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index f93173e6d..970879918 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -186,8 +186,7 @@ class ChatSettingsPopupMenuState extends State { title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)! - .archiveRoomDescription, // Edit - contents + message: L10n.of(context)!.archiveRoomDescription, ); if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( @@ -208,8 +207,7 @@ class ChatSettingsPopupMenuState extends State { title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)! - .archiveRoomDescription, // Edit - leave, not archive + message: L10n.of(context)!.leaveRoomDescription, ); if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( From 71800b7a45de9d3ee3431f11eb0152b5a7876877 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 29 May 2024 15:01:16 -0400 Subject: [PATCH 07/26] Exchanges can only be added if user is admin --- lib/pangea/widgets/class/add_space_toggles.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pangea/widgets/class/add_space_toggles.dart b/lib/pangea/widgets/class/add_space_toggles.dart index 9e51b12d9..b4d1ebaea 100644 --- a/lib/pangea/widgets/class/add_space_toggles.dart +++ b/lib/pangea/widgets/class/add_space_toggles.dart @@ -144,7 +144,9 @@ class AddToSpaceState extends State { Widget getAddToSpaceToggleItem(int index) { final Room possibleParent = possibleParents[index]; - final bool canAdd = possibleParent.canIAddSpaceChild(room); + final bool canAdd = !(!possibleParent.isRoomAdmin && + widget.mode == AddToClassMode.exchange) && + possibleParent.canIAddSpaceChild(room); return Opacity( opacity: canAdd ? 1 : 0.5, From b5a35ad723d1736646c651cf6eddb0b2b0aea139 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 30 May 2024 09:43:07 -0400 Subject: [PATCH 08/26] Update archive implementation --- lib/pages/chat/chat.dart | 3 +- lib/pages/chat_details/chat_details_view.dart | 12 ++--- lib/pages/chat_list/chat_list.dart | 42 +++++++++++++++++- lib/pages/chat_list/chat_list_header.dart | 3 +- lib/pages/chat_list/chat_list_item.dart | 33 +++++++++++++- lib/pages/chat_list/space_view.dart | 44 ++++++++++--------- .../extensions/pangea_room_extension.dart | 37 ++++++++++++++++ lib/pangea/utils/archive_space.dart | 22 ---------- lib/widgets/chat_settings_popup_menu.dart | 3 +- 9 files changed, 139 insertions(+), 60 deletions(-) delete mode 100644 lib/pangea/utils/archive_space.dart diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 2bd931879..72e755afd 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -232,8 +232,7 @@ class ChatController extends State void archiveChat() async { final success = await showFutureLoadingDialog( context: context, - future: room - .leave, // Edit - Add room.archive method in pangea_room_extension.dart + future: room.archive, ); if (success.error != null) return; context.go('/rooms'); diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 36b136caa..e8a7e22c4 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -9,7 +9,6 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_det import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_name_button.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_rules_editor.dart'; -import 'package:fluffychat/pangea/utils/archive_space.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; import 'package:fluffychat/pangea/widgets/class/add_class_and_invite.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; @@ -557,13 +556,10 @@ class ChatDetailsView extends StatelessWidget { context: context, future: () async { room.isSpace - ? await archiveSpace( - // Edit - contents - room, + ? await room.archiveSpace( Matrix.of(context).client, ) - : await room - .leave(); // Edit - archive, not leave + : await room.archive(); }, ); if (success.error == null) { @@ -602,9 +598,7 @@ class ChatDetailsView extends StatelessWidget { context: context, future: () async { room.isSpace - ? await archiveSpace( - // Edit = leaveSpace - room, + ? await room.leaveSpace( Matrix.of(context).client, ) : await room.leave(); diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index c0791c936..ecb878083 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -679,6 +679,31 @@ class ChatListController extends State // Pangea# } + // #Pangea + Future leaveAction() async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)!.leaveRoomDescription, + ) == + OkCancelResult.ok; + if (!confirmed) return; + final bool leftActiveRoom = + selectedRoomIds.contains(Matrix.of(context).activeRoomId); + await showFutureLoadingDialog( + context: context, + future: () => _leaveSelectedRooms(), + ); + setState(() {}); + if (leftActiveRoom) { + context.go('/rooms'); + } + } + // Pangea# + void dismissStatusList() async { final result = await showOkCancelAlertDialog( title: L10n.of(context)!.hidePresences, @@ -729,16 +754,31 @@ class ChatListController extends State final roomId = selectedRoomIds.first; try { // #Pangea + // await client.getRoomById(roomId)!.leave(); + await client.getRoomById(roomId)!.archive(); + // Pangea# + } finally { + toggleSelection(roomId); + } + } + } + + // #Pangea + Future _leaveSelectedRooms() async { + final client = Matrix.of(context).client; + while (selectedRoomIds.isNotEmpty) { + final roomId = selectedRoomIds.first; + try { if (client.getRoomById(roomId)!.isUnread) { await client.getRoomById(roomId)!.markUnread(false); } - // Pangea# await client.getRoomById(roomId)!.leave(); } finally { toggleSelection(roomId); } } } + // Pangea# Future addToSpace() async { final selectedSpace = await showConfirmationDialog( diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index ac555cb45..e2e790bf1 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -190,8 +190,7 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget { IconButton( icon: const Icon(Icons.arrow_forward), tooltip: L10n.of(context)!.leave, - onPressed: - controller.archiveAction, // Edit - make leaveAction + onPressed: controller.leaveAction, ), // Pangea# ] diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index 9775ec624..df27aae21 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -53,11 +53,39 @@ class ChatListItem extends StatelessWidget { message: L10n.of(context)!.archiveRoomDescription, ); if (confirmed == OkCancelResult.cancel) return; - // #Pangea + await showFutureLoadingDialog( + context: context, + // #Pangea + // future: () => room.leave(), + future: () => room.archive(), + // Pangea# + ); + return; + } + } + + // #Pangea + Future leaveAction(BuildContext context) async { + { + if ([Membership.leave, Membership.ban].contains(room.membership)) { + await showFutureLoadingDialog( + context: context, + future: () => room.forget(), + ); + return; + } + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.no, + message: L10n.of(context)!.leaveRoomDescription, + ); + if (confirmed == OkCancelResult.cancel) return; if (room.isUnread) { await room.markUnread(false); } - // Pangea# await showFutureLoadingDialog( context: context, future: () => room.leave(), @@ -65,6 +93,7 @@ class ChatListItem extends StatelessWidget { return; } } + // Pangea# @override Widget build(BuildContext context) { diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 9b02845ef..63b1fd897 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -11,7 +11,6 @@ import 'package:fluffychat/pangea/constants/class_default_values.dart'; import 'package:fluffychat/pangea/constants/pangea_room_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/pangea/extensions/sync_update_extension.dart'; -import 'package:fluffychat/pangea/utils/archive_space.dart'; import 'package:fluffychat/pangea/utils/chat_list_handle_space_tap.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/widgets/avatar.dart'; @@ -283,22 +282,29 @@ class _SpaceViewState extends State { _onJoinSpaceChild(spaceChild!); break; case SpaceChildContextAction.leave: - await showFutureLoadingDialog( - context: context, - // #Pangea - // future: room!.leave, - future: () async { - if (room!.isUnread) { - await room.markUnread(false); - } - await room.leave(); // Edit - use leaveAction? - if (Matrix.of(context).activeRoomId == room.id) { - context.go('/rooms'); - } - }, - // Pangea# - ); + // #Pangea + widget.controller.cancelAction(); + if (room == null) return; + widget.controller.toggleSelection(room.id); + room.isSpace + ? await showFutureLoadingDialog( + context: context, + future: () async { + await room.leaveSpace( + Matrix.of(context).client, + ); + widget.controller.selectedRoomIds.clear(); + }, + ) + : await widget.controller.leaveAction(); + _refresh(); break; + // await showFutureLoadingDialog( + // context: context, + // future: room!.leave, + // ); + // break; + // Pangea# case SpaceChildContextAction.removeFromSpace: await showFutureLoadingDialog( context: context, @@ -306,8 +312,7 @@ class _SpaceViewState extends State { ); break; // #Pangea - case SpaceChildContextAction - .archive: // Edit - change behavior to archive space for all users + case SpaceChildContextAction.archive: widget.controller.cancelAction(); // #Pangea if (room == null) return; @@ -317,8 +322,7 @@ class _SpaceViewState extends State { ? await showFutureLoadingDialog( context: context, future: () async { - await archiveSpace( - room, + await room.archiveSpace( Matrix.of(context).client, ); widget.controller.selectedRoomIds.clear(); diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 4d08f0b62..626615cb4 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -808,6 +808,43 @@ extension PangeaRoom on Room { ); } + Future archive() async { + final participants = await requestParticipants(); + final students = participants + .where( + (e) => + e.powerLevel < ClassDefaultValues.powerLevelOfAdmin && + e.id != BotName.byEnvironment, + ) + .toList(); + for (final student in students) { + await kick(student.id); + } + if (isUnread) { + await markUnread(false); + } + await leave(); + } + + Future archiveSpace(Client client) async { + final List children = await getChildRooms(); + for (final Room child in children) { + await child.archive(); + } + await archive(); + } + + Future leaveSpace(Client client) async { + final List children = await getChildRooms(); + for (final Room child in children) { + if (child.isUnread) { + await child.markUnread(false); + } + await child.leave(); + } + await leave(); + } + bool canIAddSpaceChild(Room? room) { if (!isSpace) { ErrorHandler.logError( diff --git a/lib/pangea/utils/archive_space.dart b/lib/pangea/utils/archive_space.dart deleted file mode 100644 index ac83980fb..000000000 --- a/lib/pangea/utils/archive_space.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; -import 'package:matrix/matrix.dart'; - -Future archiveSpace(Room? space, Client client) async { - if (space == null) { - ErrorHandler.logError( - e: 'Tried to archive a space that is null. This should not happen.', - s: StackTrace.current, - ); - return; - } - - final List children = await space.getChildRooms(); - for (final Room child in children) { - if (child.isUnread) { - await child.markUnread(false); - } - await child.leave(); - } - await space.leave(); -} diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index 970879918..fe4a45c44 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -191,8 +191,7 @@ class ChatSettingsPopupMenuState extends State { if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( context: context, - future: () => - widget.room.leave(), // Edit - archive, not leave + future: () => widget.room.archive(), ); if (success.error == null) { context.go('/rooms'); From a2fde3d70c155655c96bc25911df613984a4b28e Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 30 May 2024 12:04:17 -0400 Subject: [PATCH 09/26] Consistently send double-check popup --- assets/l10n/intl_en.arb | 6 +- lib/pages/chat_details/chat_details_view.dart | 72 +++++++++++-------- lib/pages/chat_list/chat_list_header.dart | 7 -- lib/pages/chat_list/space_view.dart | 36 +++++----- .../extensions/pangea_room_extension.dart | 64 +++++++++++++---- 5 files changed, 117 insertions(+), 68 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index dfab2d0fd..3a25f152d 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3724,7 +3724,7 @@ }, "noTeachersFound": "No teachers found to report to", "pleaseEnterANumber": "Please enter a number greater than 0", - "archiveRoomDescription": "The chat will be moved to the archive for all participants.", + "archiveRoomDescription": "The chat will be moved to the archive for yourself and all students.", "roomUpgradeDescription": "The chat will then be recreated with the new room version. All participants will be notified that they need to switch to the new chat. You can find out more about room versions at https://spec.matrix.org/latest/rooms/", "removeDevicesDescription": "You will be logged out of this device and will no longer be able to receive messages.", "banUserDescription": "The user will be banned from the chat and will not be able to enter the chat again until they are unbanned.", @@ -3964,5 +3964,7 @@ "roomDataMissing": "Some data may be missing from rooms in which you are not a member.", "updatePhoneOS": "You may need to update your device's OS version.", "wordsPerMinute": "Words per minute", - "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat." + "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.", + "archiveSpaceDescription": "The space, and any chats within, will be moved to the archive for yourself and all students.", + "leaveSpaceDescription": "The space, and any chats within, will be moved to the archive. Other users will be able to see that you have left the space." } \ No newline at end of file diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index e8a7e22c4..c341ebba0 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -542,28 +542,39 @@ class ChatDetailsView extends StatelessWidget { ), ), onTap: () async { - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.ok, - cancelLabel: L10n.of(context)!.cancel, - message: - L10n.of(context)!.archiveRoomDescription, - ); - if (confirmed == OkCancelResult.ok) { - final success = await showFutureLoadingDialog( + OkCancelResult confirmed = OkCancelResult.ok; + // archiveSpace has its own popup; only show if not space + if (!room.isSpace) { + confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, context: context, - future: () async { - room.isSpace - ? await room.archiveSpace( - Matrix.of(context).client, - ) - : await room.archive(); - }, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)! + .archiveRoomDescription, ); - if (success.error == null) { - context.go('/rooms'); + } + if (confirmed == OkCancelResult.ok) { + if (room.isSpace) { + final archived = await room.archiveSpace( + context, + Matrix.of(context).client, + ); + if (archived) { + context.go('/rooms'); + } + } else { + final success = + await showFutureLoadingDialog( + context: context, + future: () async { + await room.archive(); + }, + ); + if (success.error == null) { + context.go('/rooms'); + } } } }, @@ -585,20 +596,25 @@ class ChatDetailsView extends StatelessWidget { ), ), onTap: () async { - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.ok, - cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.leaveRoomDescription, - ); + OkCancelResult confirmed = OkCancelResult.ok; + // leaveSpace has its own popup; only show if not space + if (!room.isSpace) { + confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)!.leaveRoomDescription, + ); + } if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( context: context, future: () async { room.isSpace ? await room.leaveSpace( + context, Matrix.of(context).client, ) : await room.leave(); diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index e2e790bf1..9a3aab506 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -186,13 +186,6 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget { tooltip: L10n.of(context)!.archive, onPressed: controller.archiveAction, ), - // #Pangea - IconButton( - icon: const Icon(Icons.arrow_forward), - tooltip: L10n.of(context)!.leave, - onPressed: controller.leaveAction, - ), - // Pangea# ] : null, ); diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 63b1fd897..bf2da572c 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -284,17 +284,13 @@ class _SpaceViewState extends State { case SpaceChildContextAction.leave: // #Pangea widget.controller.cancelAction(); + widget.controller.selectedRoomIds.clear(); if (room == null) return; widget.controller.toggleSelection(room.id); room.isSpace - ? await showFutureLoadingDialog( - context: context, - future: () async { - await room.leaveSpace( - Matrix.of(context).client, - ); - widget.controller.selectedRoomIds.clear(); - }, + ? await room.leaveSpace( + context, + Matrix.of(context).client, ) : await widget.controller.leaveAction(); _refresh(); @@ -315,20 +311,28 @@ class _SpaceViewState extends State { case SpaceChildContextAction.archive: widget.controller.cancelAction(); // #Pangea + widget.controller.selectedRoomIds.clear(); if (room == null) return; // Pangea# widget.controller.toggleSelection(room.id); room.isSpace - ? await showFutureLoadingDialog( - context: context, - future: () async { - await room.archiveSpace( - Matrix.of(context).client, - ); - widget.controller.selectedRoomIds.clear(); - }, + // #Pangea + // ? await showFutureLoadingDialog( + // context: context, + // future: () async { + // await room.archiveSpace( + // Matrix.of(context).client, + // ); + // widget.controller.selectedRoomIds.clear(); + // }, + // ) + // : await widget.controller.archiveAction(); + ? await room.archiveSpace( + context, + Matrix.of(context).client, ) : await widget.controller.archiveAction(); + // Pangea# _refresh(); break; case SpaceChildContextAction.addToSpace: diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 626615cb4..1a5e6381b 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -1,6 +1,7 @@ import 'dart:async'; 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/model_keys.dart'; @@ -13,6 +14,8 @@ import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:future_loading_dialog/future_loading_dialog.dart'; // import markdown.dart import 'package:html_unescape/html_unescape.dart'; import 'package:matrix/matrix.dart'; @@ -826,23 +829,54 @@ extension PangeaRoom on Room { await leave(); } - Future archiveSpace(Client client) async { - final List children = await getChildRooms(); - for (final Room child in children) { - await child.archive(); - } - await archive(); + Future archiveSpace(BuildContext context, Client client) async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)!.archiveSpaceDescription, + ) == + OkCancelResult.ok; + if (!confirmed) return false; + final success = await showFutureLoadingDialog( + context: context, + future: () async { + final List children = await getChildRooms(); + for (final Room child in children) { + await child.archive(); + } + await archive(); + }, + ); + return success.error == null; } - Future leaveSpace(Client client) async { - final List children = await getChildRooms(); - for (final Room child in children) { - if (child.isUnread) { - await child.markUnread(false); - } - await child.leave(); - } - await leave(); + Future leaveSpace(BuildContext context, Client client) async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)!.leaveSpaceDescription, + ) == + OkCancelResult.ok; + if (!confirmed) return; + await showFutureLoadingDialog( + context: context, + future: () async { + final List children = await getChildRooms(); + for (final Room child in children) { + if (child.isUnread) { + await child.markUnread(false); + } + await child.leave(); + } + await leave(); + }, + ); } bool canIAddSpaceChild(Room? room) { From 939a1e611158c3e9bfe7f5c4bd18811de17d9c15 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 30 May 2024 12:49:19 -0400 Subject: [PATCH 10/26] Updated l10n files --- assets/l10n/intl_en.arb | 4 ++-- assets/l10n/intl_es.arb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 3a25f152d..6954f1847 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3724,7 +3724,7 @@ }, "noTeachersFound": "No teachers found to report to", "pleaseEnterANumber": "Please enter a number greater than 0", - "archiveRoomDescription": "The chat will be moved to the archive for yourself and all students.", + "archiveRoomDescription": "The chat will be moved to the archive for yourself and other non-admin users.", "roomUpgradeDescription": "The chat will then be recreated with the new room version. All participants will be notified that they need to switch to the new chat. You can find out more about room versions at https://spec.matrix.org/latest/rooms/", "removeDevicesDescription": "You will be logged out of this device and will no longer be able to receive messages.", "banUserDescription": "The user will be banned from the chat and will not be able to enter the chat again until they are unbanned.", @@ -3965,6 +3965,6 @@ "updatePhoneOS": "You may need to update your device's OS version.", "wordsPerMinute": "Words per minute", "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.", - "archiveSpaceDescription": "The space, and any chats within, will be moved to the archive for yourself and all students.", + "archiveSpaceDescription": "The space, and any chats within, will be moved to the archive for yourself and other non-admin users.", "leaveSpaceDescription": "The space, and any chats within, will be moved to the archive. Other users will be able to see that you have left the space." } \ No newline at end of file diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index d463699be..bb04a51bf 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -3698,7 +3698,7 @@ "@optionalRedactReason": {}, "dehydrate": "Exportar sesión y borrar dispositivo", "@dehydrate": {}, - "archiveRoomDescription": "", + "archiveRoomDescription": "El chat se moverá al archivo para ti y para otros usuarios que no sean administradores", "@archiveRoomDescription": {}, "pleaseEnterRecoveryKeyDescription": "Para desbloquear sus mensajes antiguos, ingrese su clave de recuperación que se generó en una sesión anterior. Su clave de recuperación NO es su contraseña.", "@pleaseEnterRecoveryKeyDescription": {}, From e4af2f764ef4f82e89af2408cdaa01ff120f6d72 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 30 May 2024 13:53:18 -0400 Subject: [PATCH 11/26] Minor error/structure corrections --- assets/l10n/intl_en.arb | 4 +- lib/pages/chat_details/chat_details_view.dart | 43 ++++++++++--------- lib/pages/chat_list/chat_list_item.dart | 31 ------------- lib/pages/chat_list/space_view.dart | 2 +- .../extensions/pangea_room_extension.dart | 7 +-- 5 files changed, 30 insertions(+), 57 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 6954f1847..6b009f949 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3965,6 +3965,6 @@ "updatePhoneOS": "You may need to update your device's OS version.", "wordsPerMinute": "Words per minute", "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.", - "archiveSpaceDescription": "The space, and any chats within, will be moved to the archive for yourself and other non-admin users.", - "leaveSpaceDescription": "The space, and any chats within, will be moved to the archive. Other users will be able to see that you have left the space." + "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." } \ No newline at end of file diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index c341ebba0..c976e5bcb 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -543,6 +543,7 @@ class ChatDetailsView extends StatelessWidget { ), onTap: () async { OkCancelResult confirmed = OkCancelResult.ok; + bool shouldGo = false; // archiveSpace has its own popup; only show if not space if (!room.isSpace) { confirmed = await showOkCancelAlertDialog( @@ -557,13 +558,10 @@ class ChatDetailsView extends StatelessWidget { } if (confirmed == OkCancelResult.ok) { if (room.isSpace) { - final archived = await room.archiveSpace( + shouldGo = await room.archiveSpace( context, Matrix.of(context).client, ); - if (archived) { - context.go('/rooms'); - } } else { final success = await showFutureLoadingDialog( @@ -572,9 +570,10 @@ class ChatDetailsView extends StatelessWidget { await room.archive(); }, ); - if (success.error == null) { - context.go('/rooms'); - } + shouldGo = (success.error == null); + } + if (shouldGo) { + context.go('/rooms'); } } }, @@ -597,7 +596,8 @@ class ChatDetailsView extends StatelessWidget { ), onTap: () async { OkCancelResult confirmed = OkCancelResult.ok; - // leaveSpace has its own popup; only show if not space + bool shouldGo = false; + // archiveSpace has its own popup; only show if not space if (!room.isSpace) { confirmed = await showOkCancelAlertDialog( useRootNavigator: false, @@ -609,18 +609,21 @@ class ChatDetailsView extends StatelessWidget { ); } if (confirmed == OkCancelResult.ok) { - final success = await showFutureLoadingDialog( - context: context, - future: () async { - room.isSpace - ? await room.leaveSpace( - context, - Matrix.of(context).client, - ) - : await room.leave(); - }, - ); - if (success.error == null) { + if (room.isSpace) { + shouldGo = await room.leaveSpace( + context, + Matrix.of(context).client, + ); + } else { + final success = await showFutureLoadingDialog( + context: context, + future: () async { + await room.leave(); + }, + ); + shouldGo = (success.error == null); + } + if (shouldGo) { context.go('/rooms'); } } diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index df27aae21..1f7a5dcad 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -64,37 +64,6 @@ class ChatListItem extends StatelessWidget { } } - // #Pangea - Future leaveAction(BuildContext context) async { - { - if ([Membership.leave, Membership.ban].contains(room.membership)) { - await showFutureLoadingDialog( - context: context, - future: () => room.forget(), - ); - return; - } - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.yes, - cancelLabel: L10n.of(context)!.no, - message: L10n.of(context)!.leaveRoomDescription, - ); - if (confirmed == OkCancelResult.cancel) return; - if (room.isUnread) { - await room.markUnread(false); - } - await showFutureLoadingDialog( - context: context, - future: () => room.leave(), - ); - return; - } - } - // Pangea# - @override Widget build(BuildContext context) { final isMuted = room.pushRuleState != PushRuleState.notify; diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index bf2da572c..0fb584be5 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -284,7 +284,6 @@ class _SpaceViewState extends State { case SpaceChildContextAction.leave: // #Pangea widget.controller.cancelAction(); - widget.controller.selectedRoomIds.clear(); if (room == null) return; widget.controller.toggleSelection(room.id); room.isSpace @@ -293,6 +292,7 @@ class _SpaceViewState extends State { Matrix.of(context).client, ) : await widget.controller.leaveAction(); + widget.controller.selectedRoomIds.clear(); _refresh(); break; // await showFutureLoadingDialog( diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 1a5e6381b..4ad4baca1 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -853,7 +853,7 @@ extension PangeaRoom on Room { return success.error == null; } - Future leaveSpace(BuildContext context, Client client) async { + Future leaveSpace(BuildContext context, Client client) async { final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, @@ -863,8 +863,8 @@ extension PangeaRoom on Room { message: L10n.of(context)!.leaveSpaceDescription, ) == OkCancelResult.ok; - if (!confirmed) return; - await showFutureLoadingDialog( + if (!confirmed) return false; + final success = await showFutureLoadingDialog( context: context, future: () async { final List children = await getChildRooms(); @@ -877,6 +877,7 @@ extension PangeaRoom on Room { await leave(); }, ); + return success.error == null; } bool canIAddSpaceChild(Room? room) { From 5feaed1d42ddacaf22b4c42b814020319bb21713 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 31 May 2024 14:17:45 -0400 Subject: [PATCH 12/26] Close chat selection menu asap --- lib/pages/chat_list/space_view.dart | 63 ++++++++++++++++------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 0fb584be5..c95ba9007 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -285,14 +285,16 @@ class _SpaceViewState extends State { // #Pangea widget.controller.cancelAction(); if (room == null) return; - widget.controller.toggleSelection(room.id); - room.isSpace - ? await room.leaveSpace( - context, - Matrix.of(context).client, - ) - : await widget.controller.leaveAction(); - widget.controller.selectedRoomIds.clear(); + if (room.isSpace) { + await room.leaveSpace( + context, + Matrix.of(context).client, + ); + } else { + widget.controller.toggleSelection(room.id); + await widget.controller.leaveAction(); + widget.controller.toggleSelection(room.id); + } _refresh(); break; // await showFutureLoadingDialog( @@ -311,27 +313,28 @@ class _SpaceViewState extends State { case SpaceChildContextAction.archive: widget.controller.cancelAction(); // #Pangea - widget.controller.selectedRoomIds.clear(); if (room == null) return; - // Pangea# - widget.controller.toggleSelection(room.id); - room.isSpace - // #Pangea - // ? await showFutureLoadingDialog( - // context: context, - // future: () async { - // await room.archiveSpace( - // Matrix.of(context).client, - // ); - // widget.controller.selectedRoomIds.clear(); - // }, - // ) - // : await widget.controller.archiveAction(); - ? await room.archiveSpace( - context, - Matrix.of(context).client, - ) - : await widget.controller.archiveAction(); + // room.isSpace + // ? await showFutureLoadingDialog( + // context: context, + // future: () async { + // await room.archiveSpace( + // Matrix.of(context).client, + // ); + // widget.controller.selectedRoomIds.clear(); + // }, + // ) + // : await widget.controller.archiveAction(); + if (room.isSpace) { + await room.archiveSpace( + context, + Matrix.of(context).client, + ); + } else { + widget.controller.toggleSelection(room.id); + await widget.controller.archiveAction(); + widget.controller.toggleSelection(room.id); + } // Pangea# _refresh(); break; @@ -342,8 +345,10 @@ class _SpaceViewState extends State { // Pangea# widget.controller.toggleSelection(room.id); await widget.controller.addToSpace(); + // #Pangea + setState(() => widget.controller.selectedRoomIds.clear()); + // Pangea# break; - // Pangea# } } From 2127277d817c5eb28f553aa9bbd214096801bc89 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 3 Jun 2024 11:28:12 -0400 Subject: [PATCH 13/26] Don't return to archived space view --- lib/pages/chat/chat.dart | 6 +++++- lib/pages/chat_list/chat_list.dart | 12 ++++++++---- lib/pages/chat_list/space_view.dart | 1 + lib/pages/chat_list/utils/on_chat_tap.dart | 4 +++- lib/pangea/controllers/class_controller.dart | 2 +- lib/pangea/extensions/pangea_room_extension.dart | 15 +++++++++++++-- 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 72e755afd..4ac0a981f 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -454,7 +454,11 @@ class ChatController extends State } } timeline!.requestKeys(onlineKeyBackupOnly: false); - if (room.markedUnread) room.markUnread(false); + if (!room.isSpace && + room.membership == Membership.join && + room.markedUnread) { + room.markUnread(false); + } // when the scroll controller is attached we want to scroll to an event id, if specified // and update the scroll controller...which will trigger a request history, if the diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index ecb878083..9f2ca0b48 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -515,7 +515,8 @@ class ChatListController extends State //#Pangea classStream = pangeaController.classController.stateStream.listen((event) { - if (event["activeSpaceId"] != null && mounted) { + // if (event["activeSpaceId"] != null && mounted) { + if (mounted) { setActiveSpace(event["activeSpaceId"]); } }); @@ -769,10 +770,13 @@ class ChatListController extends State while (selectedRoomIds.isNotEmpty) { final roomId = selectedRoomIds.first; try { - if (client.getRoomById(roomId)!.isUnread) { - await client.getRoomById(roomId)!.markUnread(false); + final room = client.getRoomById(roomId); + if (!room!.isSpace && + room.membership == Membership.join && + room.isUnread) { + await room.markUnread(false); } - await client.getRoomById(roomId)!.leave(); + await room.leave(); } finally { toggleSelection(roomId); } diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index c95ba9007..351af511d 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -261,6 +261,7 @@ class _SpaceViewState extends State { ? L10n.of(context)!.archiveSpace : L10n.of(context)!.archive, icon: Icons.architecture_outlined, + isDestructiveAction: true, ), // Pangea# if (room != null) diff --git a/lib/pages/chat_list/utils/on_chat_tap.dart b/lib/pages/chat_list/utils/on_chat_tap.dart index d9f1c8191..b272d424e 100644 --- a/lib/pages/chat_list/utils/on_chat_tap.dart +++ b/lib/pages/chat_list/utils/on_chat_tap.dart @@ -46,7 +46,9 @@ void onChatTap(Room room, BuildContext context) async { } if (inviteAction == InviteActions.decline) { // #Pangea - if (room.isUnread) { + if (!room.isSpace && + room.membership == Membership.join && + room.isUnread) { await room.markUnread(false); } // Pangea# diff --git a/lib/pangea/controllers/class_controller.dart b/lib/pangea/controllers/class_controller.dart index c0a8e6093..51a368be6 100644 --- a/lib/pangea/controllers/class_controller.dart +++ b/lib/pangea/controllers/class_controller.dart @@ -27,7 +27,7 @@ class ClassController extends BaseController { _pangeaController = pangeaController; } - setActiveSpaceIdInChatListController(String classId) { + setActiveSpaceIdInChatListController(String? classId) { setState(data: {"activeSpaceId": classId}); } diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 4ad4baca1..dd5635fbe 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/models/class_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -823,7 +824,7 @@ extension PangeaRoom on Room { for (final student in students) { await kick(student.id); } - if (isUnread) { + if (!isSpace && membership == Membership.join && isUnread) { await markUnread(false); } await leave(); @@ -850,6 +851,10 @@ extension PangeaRoom on Room { await archive(); }, ); + MatrixState.pangeaController.classController + .setActiveSpaceIdInChatListController( + null, + ); return success.error == null; } @@ -869,7 +874,9 @@ extension PangeaRoom on Room { future: () async { final List children = await getChildRooms(); for (final Room child in children) { - if (child.isUnread) { + if (!child.isSpace && + child.membership == Membership.join && + child.isUnread) { await child.markUnread(false); } await child.leave(); @@ -877,6 +884,10 @@ extension PangeaRoom on Room { await leave(); }, ); + MatrixState.pangeaController.classController + .setActiveSpaceIdInChatListController( + null, + ); return success.error == null; } From 42406dd36007012f7d5a7aa3e8fd84a650132466 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 3 Jun 2024 14:21:18 -0400 Subject: [PATCH 14/26] Minor fixes --- .../extensions/pangea_room_extension.dart | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index dd5635fbe..bd996bc5e 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -813,21 +813,26 @@ extension PangeaRoom on Room { } Future archive() async { - final participants = await requestParticipants(); - final students = participants + final students = (await requestParticipants()) .where( (e) => + e.id != client.userID && e.powerLevel < ClassDefaultValues.powerLevelOfAdmin && e.id != BotName.byEnvironment, ) .toList(); - for (final student in students) { - await kick(student.id); - } - if (!isSpace && membership == Membership.join && isUnread) { - await markUnread(false); + try { + for (final student in students) { + await kick(student.id); + } + if (!isSpace && membership == Membership.join && isUnread) { + await markUnread(false); + } + await leave(); + } catch (err, s) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: s, data: toJson()); } - await leave(); } Future archiveSpace(BuildContext context, Client client) async { @@ -872,16 +877,22 @@ extension PangeaRoom on Room { final success = await showFutureLoadingDialog( context: context, future: () async { - final List children = await getChildRooms(); - for (final Room child in children) { - if (!child.isSpace && - child.membership == Membership.join && - child.isUnread) { - await child.markUnread(false); + try { + final List children = await getChildRooms(); + for (final Room child in children) { + if (!child.isSpace && + child.membership == Membership.join && + child.isUnread) { + await child.markUnread(false); + } + await child.leave(); } - await child.leave(); + await leave(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack, data: powerLevels); + rethrow; } - await leave(); }, ); MatrixState.pangeaController.classController @@ -1091,7 +1102,7 @@ extension PangeaRoom on Room { for (final child in spaceChildren) { if (child.roomId == null) continue; final Room? room = client.getRoomById(child.roomId!); - if (room != null) { + if (room != null && !room.isAnalyticsRoom) { children.add(room); } } From d0f36842cc2631f9ac985f3674e9de237aaa202d Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 3 Jun 2024 16:58:39 -0400 Subject: [PATCH 15/26] Shorten name of DM analytics category --- assets/l10n/intl_en.arb | 2 +- assets/l10n/intl_es.arb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index bb9d15f0c..1d5ff4218 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3609,7 +3609,7 @@ "zmCountryDisplayName": "Zambia", "zwCountryDisplayName": "Zimbabwe", "pay": "Pay", - "allPrivateChats": "All private chats in space (including with Pangea Bot)", + "allPrivateChats": "Direct chats", "unknownPrivateChat": "Unknown private chat", "copyClassCodeDesc": "Students who are already in the app can 'Join class or exchange' via the main menu.", "addToClass": "Add exchange to class", diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index d8f54304a..f71abe93d 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -4274,7 +4274,7 @@ "zwCountryDisplayName": "Zimbabue", "downloadXLSXFile": "Descargar archivo Excel", "unknownPrivateChat": "Chat Privado Desconocido", - "allPrivateChats": "Todos los chats privados (incluso con bots) en clase", + "allPrivateChats": "Chats privado", "chatHasBeenAddedToThisSpace": "Se ha añadido el chat a este espacio", "classes": "Clases", "spaceIsPublic": "El espacio es público", From bb5c3004f95028e3f193399ca8f730d4404fbac1 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 4 Jun 2024 13:17:18 -0400 Subject: [PATCH 16/26] invitation fix for students --- lib/pages/invitation_selection/invitation_selection.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart index 368bf0584..5b69e7049 100644 --- a/lib/pages/invitation_selection/invitation_selection.dart +++ b/lib/pages/invitation_selection/invitation_selection.dart @@ -159,6 +159,8 @@ class InvitationSelectionController extends State { future: () async { if (mode == InvitationSelectionMode.admin) { await inviteTeacherAction(room, id); + } else { + await room.invite(id); } }, // Pangea# From 83b30dc084c7493bc801ef65ead69e777eda244d Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 5 Jun 2024 10:51:26 -0400 Subject: [PATCH 17/26] add call to language detection after send without IGC --- assets/l10n/intl_en.arb | 2 +- assets/l10n/intl_es.arb | 2 +- lib/pages/chat/events/message_content.dart | 21 +++-------------- .../controllers/choreographer.dart | 20 ++++++++++++++-- .../language_detection_controller.dart | 10 ++++---- lib/pangea/controllers/local_settings.dart | 10 ++++++-- .../pangea_message_event.dart | 23 ------------------- 7 files changed, 37 insertions(+), 51 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e4cd0e530..e4e96800c 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3128,7 +3128,7 @@ "maybeLater": "Maybe Later", "mainMenu": "Main Menu", "toggleImmersionMode": "Immersion Mode", - "toggleImmersionModeDesc": "When enabled, all messages are displayed in your target language and you can click the message to access definitions and translations.", + "toggleImmersionModeDesc": "When enabled, all messages are displayed in your target language. This setting is most useful in language exchanges.", "itToggleDescription": "This language learning tool will identify words in your base language and help you translate them to your target language. Though rare, the AI can make translation errors.", "igcToggleDescription": "This language learning tool will identify common spelling, grammar and punctuation errors in your message and suggest corrections. Though rare, the AI can make correction errors.", "sendOnEnterDescription": "Turn this off to be able to add line spaces in messages. When the toggle is off on the browser app, you can press Shift + Enter to start a new line. When the toggle is off on mobile apps, just Enter will start a new line.", diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index f71abe93d..679710dcb 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -3281,7 +3281,7 @@ "generateVocabulary": "Generar vocabulario basado en el título y la descripción", "generatePrompts": "Generar preguntas basado en el título y la descripción", "toggleImmersionMode": "Modo de inmersión", - "toggleImmersionModeDesc": "Cuando está habilitado, todos los mensajes se muestran en su idioma de destino y puede hacer clic en el mensaje para acceder a definiciones y traducciones.", + "toggleImmersionModeDesc": "Cuando está habilitado, todos los mensajes se muestran en su idioma de destino. Esta configuración es más útil en intercambios de idiomas.", "subscribe": "Subscríbase", "getAccess": "Activar herramientas", "subscriptionDesc": "¡Enviar y recibir mensajes es gratis! Suscríbase para aceder a la traducción interactiva, la revisión gramatical y el análisis de aprendizaje.", diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 41997afea..776a3039e 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -199,18 +199,8 @@ class MessageContent extends StatelessWidget { case MessageTypes.Notice: case MessageTypes.Emote: if (AppConfig.renderHtml && - !event.redacted && - event.isRichMessage - // #Pangea - && - !(pangeaMessageEvent?.showRichText( - selected, - isOverlay: isOverlay, - highlighted: toolbarController?.highlighted ?? false, - ) ?? - false) - // Pangea# - ) { + !event.redacted && + event.isRichMessage) { var html = event.formattedText; if (event.messageType == MessageTypes.Emote) { html = '* $html'; @@ -306,12 +296,7 @@ class MessageContent extends StatelessWidget { decoration: event.redacted ? TextDecoration.lineThrough : null, height: 1.3, ); - if (pangeaMessageEvent?.showRichText( - selected, - isOverlay: isOverlay, - highlighted: toolbarController?.highlighted ?? false, - ) ?? - false) { + if (immersionMode && pangeaMessageEvent != null) { return PangeaRichText( style: messageTextStyle, pangeaMessageEvent: pangeaMessageEvent!, diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 5f6da2b7e..340aa591b 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -13,6 +13,7 @@ import 'package:fluffychat/pangea/enum/edit_type.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/class_model.dart'; import 'package:fluffychat/pangea/models/it_step.dart'; +import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart'; @@ -93,7 +94,7 @@ class Choreographer { } } - void _sendWithIGC(BuildContext context) { + Future _sendWithIGC(BuildContext context) async { if (igc.canSendMessage) { final PangeaRepresentation? originalWritten = choreoRecord.includedIT && itController.sourceText != null @@ -105,7 +106,6 @@ class Choreographer { ) : null; - // PTODO - just put this in original message event final PangeaRepresentation originalSent = PangeaRepresentation( langCode: langCodeOfCurrentText ?? LanguageKeys.unknownLanguage, text: currentText, @@ -115,6 +115,22 @@ class Choreographer { final ChoreoRecord? applicableChoreo = isITandIGCEnabled && igc.igcTextData != null ? choreoRecord : null; + // if the message has not been processed to determine its language + // then run it through the language detection endpoint. If the detection + // confidence is high enough, use that language code as the message's language + // to save that pangea representation + if (applicableChoreo == null) { + final resp = await pangeaController.languageDetection.detectLanguage( + currentText, + pangeaController.languageController.userL2?.langCode, + pangeaController.languageController.userL1?.langCode, + ); + final LanguageDetection? bestDetection = resp.bestDetection(); + if (bestDetection != null) { + originalSent.langCode = bestDetection.langCode; + } + } + final UseType useType = useTypeCalculator(applicableChoreo); debugPrint("use type in choreographer $useType"); diff --git a/lib/pangea/controllers/language_detection_controller.dart b/lib/pangea/controllers/language_detection_controller.dart index 4d3326dde..4ddfabc88 100644 --- a/lib/pangea/controllers/language_detection_controller.dart +++ b/lib/pangea/controllers/language_detection_controller.dart @@ -82,10 +82,12 @@ class LanguageDetectionResponse { final double _confidenceThreshold = 0.95; - LanguageDetection? get thresholdedDetection => - (_bestDetection?.confidence ?? 0) >= _confidenceThreshold - ? _bestDetection! - : null; + LanguageDetection? bestDetection({double? threshold}) { + threshold ??= _confidenceThreshold; + return (_bestDetection?.confidence ?? 0) >= _confidenceThreshold + ? _bestDetection! + : null; + } } class _LanguageDetectionCacheItem { diff --git a/lib/pangea/controllers/local_settings.dart b/lib/pangea/controllers/local_settings.dart index 5984a7bf5..2dc30cfe7 100644 --- a/lib/pangea/controllers/local_settings.dart +++ b/lib/pangea/controllers/local_settings.dart @@ -8,8 +8,14 @@ class LocalSettings { _pangeaController = pangeaController; } - bool userLanguageToolSetting(ToolSetting setting) => - _pangeaController.pStoreService.read(setting.toString()) ?? true; + bool userLanguageToolSetting(ToolSetting setting) { + final profileSetting = + _pangeaController.pStoreService.read(setting.toString()); + if (profileSetting != null) { + return profileSetting; + } + return setting == ToolSetting.immersionMode ? false : true; + } // bool get userEnableIT => // _pangeaController.pStoreService.read(ToolSetting.interactiveTranslator.toString()) ?? true; diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index 5fa2e2659..ff8696989 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -80,29 +80,6 @@ class PangeaMessageEvent { return _latestEdit; } - bool showRichText( - bool selected, { - bool highlighted = false, - bool isOverlay = false, - }) { - if (!_isValidPangeaMessageEvent) { - return false; - } - - if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { - return false; - } - - if (isOverlay) return true; - - // if ownMessage, don't show rich text if not selected or highlighted - // and don't show is the message is not an overlay - if (ownMessage && ((!selected && !highlighted) || !isOverlay)) { - return false; - } - return true; - } - Future getMatrixAudioFile( String langCode, BuildContext context, From 6b606ef2c7296a5de0b39663a484623b270eef5d Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 6 Jun 2024 15:28:22 -0400 Subject: [PATCH 18/26] Non=admins kicked when only admin leaves --- assets/l10n/intl_en.arb | 3 +- lib/pages/chat_details/chat_details_view.dart | 24 ++++++++++---- lib/pages/chat_list/chat_list.dart | 15 ++++++--- lib/pages/chat_list/chat_list_header.dart | 11 +++++++ lib/pages/chat_list/space_view.dart | 26 ++++++++++----- .../extensions/pangea_room_extension.dart | 33 +++++++++++++++++-- lib/widgets/chat_settings_popup_menu.dart | 8 +++-- 7 files changed, 97 insertions(+), 23 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 6b009f949..28a550f97 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3966,5 +3966,6 @@ "wordsPerMinute": "Words per minute", "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." + "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.", + "onlyAdminDescription": "Since there are no other admins, all other participants will also be removed." } \ No newline at end of file diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index c976e5bcb..d45f50f15 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -597,6 +597,8 @@ class ChatDetailsView extends StatelessWidget { onTap: () async { OkCancelResult confirmed = OkCancelResult.ok; bool shouldGo = false; + // If user is only admin, room will be archived + final bool onlyAdmin = await room.isOnlyAdmin(); // archiveSpace has its own popup; only show if not space if (!room.isSpace) { confirmed = await showOkCancelAlertDialog( @@ -605,20 +607,30 @@ class ChatDetailsView extends StatelessWidget { title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.leaveRoomDescription, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.leaveRoomDescription, ); } if (confirmed == OkCancelResult.ok) { if (room.isSpace) { - shouldGo = await room.leaveSpace( - context, - Matrix.of(context).client, - ); + shouldGo = onlyAdmin + ? await room.archiveSpace( + context, + Matrix.of(context).client, + onlyAdmin: true, + ) + : await room.leaveSpace( + context, + Matrix.of(context).client, + ); } else { final success = await showFutureLoadingDialog( context: context, future: () async { - await room.leave(); + onlyAdmin + ? await room.archive() + : await room.leave(); }, ); shouldGo = (success.error == null); diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 9f2ca0b48..6facc381d 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -682,13 +682,20 @@ class ChatListController extends State // #Pangea Future leaveAction() async { + final bool onlyAdmin = await Matrix.of(context) + .client + .getRoomById(selectedRoomIds.first) + ?.isOnlyAdmin() ?? + false; final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.yes, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.leaveRoomDescription, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.leaveRoomDescription, ) == OkCancelResult.ok; if (!confirmed) return; @@ -696,7 +703,7 @@ class ChatListController extends State selectedRoomIds.contains(Matrix.of(context).activeRoomId); await showFutureLoadingDialog( context: context, - future: () => _leaveSelectedRooms(), + future: () => _leaveSelectedRooms(onlyAdmin), ); setState(() {}); if (leftActiveRoom) { @@ -765,7 +772,7 @@ class ChatListController extends State } // #Pangea - Future _leaveSelectedRooms() async { + Future _leaveSelectedRooms(bool onlyAdmin) async { final client = Matrix.of(context).client; while (selectedRoomIds.isNotEmpty) { final roomId = selectedRoomIds.first; @@ -776,7 +783,7 @@ class ChatListController extends State room.isUnread) { await room.markUnread(false); } - await room.leave(); + onlyAdmin ? await room.archive() : await room.leave(); } finally { toggleSelection(roomId); } diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index 9a3aab506..41b9a6bf1 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -171,6 +171,17 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget { onPressed: controller.toggleMuted, ), // #Pangea + if (controller.selectedRoomIds.length == 1 && + !(Matrix.of(context) + .client + .getRoomById(controller.selectedRoomIds.single) + ?.isRoomAdmin ?? + false)) + IconButton( + icon: const Icon(Icons.arrow_forward), + tooltip: L10n.of(context)!.leave, + onPressed: controller.leaveAction, + ), if (controller.selectedRoomIds.length == 1 && (Matrix.of(context) .client diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 351af511d..c8d9b5ef7 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -229,7 +229,7 @@ class _SpaceViewState extends State { ), message: spaceChild?.topic ?? room?.topic, actions: [ - if (room == null) + if (room == null || room.membership == Membership.leave) SheetAction( key: SpaceChildContextAction.join, label: L10n.of(context)!.joinRoom, @@ -254,7 +254,9 @@ class _SpaceViewState extends State { label: L10n.of(context)!.addToSpace, icon: Icons.workspaces_outlined, ), - if (room != null && room.isRoomAdmin) + if (room != null && + room.isRoomAdmin && + room.membership != Membership.leave) SheetAction( key: SpaceChildContextAction.archive, label: room.isSpace @@ -263,8 +265,10 @@ class _SpaceViewState extends State { icon: Icons.architecture_outlined, isDestructiveAction: true, ), - // Pangea# - if (room != null) + + if (room != null && room.membership != Membership.leave) + // if (room != null) + // Pangea# SheetAction( key: SpaceChildContextAction.leave, label: L10n.of(context)!.leave, @@ -287,10 +291,16 @@ class _SpaceViewState extends State { widget.controller.cancelAction(); if (room == null) return; if (room.isSpace) { - await room.leaveSpace( - context, - Matrix.of(context).client, - ); + await room.isOnlyAdmin() + ? await room.archiveSpace( + context, + Matrix.of(context).client, + onlyAdmin: true, + ) + : await room.leaveSpace( + context, + Matrix.of(context).client, + ); } else { widget.controller.toggleSelection(room.id); await widget.controller.leaveAction(); diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index bd996bc5e..62ba97c86 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -835,14 +835,43 @@ extension PangeaRoom on Room { } } - Future archiveSpace(BuildContext context, Client client) async { + // If there are no other admins, and at least one non-admin, return true + Future isOnlyAdmin() async { + if (!isRoomAdmin) { + return false; + } + final List participants = await requestParticipants(); + + return ((participants + .where( + (e) => + e.powerLevel == ClassDefaultValues.powerLevelOfAdmin && + e.id != BotName.byEnvironment, + ) + .toList() + .length) == + 1) && + (participants + .where( + (e) => + e.powerLevel < ClassDefaultValues.powerLevelOfAdmin && + e.id != BotName.byEnvironment, + ) + .toList()) + .isNotEmpty; + } + + Future archiveSpace(BuildContext context, Client client, + {bool onlyAdmin = false}) async { final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.yes, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.archiveSpaceDescription, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.archiveSpaceDescription, ) == OkCancelResult.ok; if (!confirmed) return false; diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index fe4a45c44..55672911e 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -200,18 +200,22 @@ class ChatSettingsPopupMenuState extends State { break; // Pangea# case 'leave': + final bool onlyAdmin = await widget.room.isOnlyAdmin(); final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.ok, cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.leaveRoomDescription, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.leaveRoomDescription, ); if (confirmed == OkCancelResult.ok) { final success = await showFutureLoadingDialog( context: context, - future: () => widget.room.leave(), + future: () => + onlyAdmin ? widget.room.archive() : widget.room.leave(), ); if (success.error == null) { context.go('/rooms'); From 33de062a6e362c34d18d0e8a35b0a0ed7dc361c7 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 6 Jun 2024 16:02:10 -0400 Subject: [PATCH 19/26] Organized room extension methods --- .../events_extension.dart | 96 ++++++++++++++++ .../pangea_room_extension.dart | 108 ++---------------- 2 files changed, 108 insertions(+), 96 deletions(-) diff --git a/lib/pangea/extensions/pangea_room_extension/events_extension.dart b/lib/pangea/extensions/pangea_room_extension/events_extension.dart index ecf9ac941..9b5922041 100644 --- a/lib/pangea/extensions/pangea_room_extension/events_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/events_extension.dart @@ -1,6 +1,102 @@ part of "pangea_room_extension.dart"; extension EventsRoomExtension on Room { + Future _archive() async { + final students = (await requestParticipants()) + .where( + (e) => + e.id != client.userID && + e.powerLevel < ClassDefaultValues.powerLevelOfAdmin && + e.id != BotName.byEnvironment, + ) + .toList(); + try { + for (final student in students) { + await kick(student.id); + } + if (!isSpace && membership == Membership.join && isUnread) { + await markUnread(false); + } + await leave(); + } catch (err, s) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: s, data: toJson()); + } + } + + Future _archiveSpace( + BuildContext context, + Client client, { + bool onlyAdmin = false, + }) async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.archiveSpaceDescription, + ) == + OkCancelResult.ok; + if (!confirmed) return false; + final success = await showFutureLoadingDialog( + context: context, + future: () async { + final List children = await getChildRooms(); + for (final Room child in children) { + await child.archive(); + } + await archive(); + }, + ); + MatrixState.pangeaController.classController + .setActiveSpaceIdInChatListController( + null, + ); + return success.error == null; + } + + Future _leaveSpace(BuildContext context, Client client) async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)!.leaveSpaceDescription, + ) == + OkCancelResult.ok; + if (!confirmed) return false; + final success = await showFutureLoadingDialog( + context: context, + future: () async { + try { + final List children = await getChildRooms(); + for (final Room child in children) { + if (!child.isSpace && + child.membership == Membership.join && + child.isUnread) { + await child.markUnread(false); + } + await child.leave(); + } + await leave(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack, data: powerLevels); + rethrow; + } + }, + ); + MatrixState.pangeaController.classController + .setActiveSpaceIdInChatListController( + null, + ); + return success.error == null; + } + Future _sendPangeaEvent({ required Map content, required String parentEventId, diff --git a/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart index 2f1346446..25790f476 100644 --- a/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart @@ -142,6 +142,18 @@ extension PangeaRoom on Room { // events + Future archive() async => await _archive(); + + Future archiveSpace( + BuildContext context, + Client client, { + bool onlyAdmin = false, + }) async => + await _archiveSpace(context, client, onlyAdmin: onlyAdmin); + + Future leaveSpace(BuildContext context, Client client) async => + await _leaveSpace(context, client); + Future sendPangeaEvent({ required Map content, required String parentEventId, @@ -289,100 +301,4 @@ extension PangeaRoom on Room { bool pangeaCanSendEvent(String eventType) => _pangeaCanSendEvent(eventType); int? get eventsDefaultPowerLevel => _eventsDefaultPowerLevel; - - Future archive() async { - final students = (await requestParticipants()) - .where( - (e) => - e.id != client.userID && - e.powerLevel < ClassDefaultValues.powerLevelOfAdmin && - e.id != BotName.byEnvironment, - ) - .toList(); - try { - for (final student in students) { - await kick(student.id); - } - if (!isSpace && membership == Membership.join && isUnread) { - await markUnread(false); - } - await leave(); - } catch (err, s) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: s, data: toJson()); - } - } - - Future archiveSpace( - BuildContext context, - Client client, { - bool onlyAdmin = false, - }) async { - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.yes, - cancelLabel: L10n.of(context)!.cancel, - message: onlyAdmin - ? L10n.of(context)!.onlyAdminDescription - : L10n.of(context)!.archiveSpaceDescription, - ) == - OkCancelResult.ok; - if (!confirmed) return false; - final success = await showFutureLoadingDialog( - context: context, - future: () async { - final List children = await getChildRooms(); - for (final Room child in children) { - await child.archive(); - } - await archive(); - }, - ); - MatrixState.pangeaController.classController - .setActiveSpaceIdInChatListController( - null, - ); - return success.error == null; - } - - Future leaveSpace(BuildContext context, Client client) async { - final confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.yes, - cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)!.leaveSpaceDescription, - ) == - OkCancelResult.ok; - if (!confirmed) return false; - final success = await showFutureLoadingDialog( - context: context, - future: () async { - try { - final List children = await getChildRooms(); - for (final Room child in children) { - if (!child.isSpace && - child.membership == Membership.join && - child.isUnread) { - await child.markUnread(false); - } - await child.leave(); - } - await leave(); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack, data: powerLevels); - rethrow; - } - }, - ); - MatrixState.pangeaController.classController - .setActiveSpaceIdInChatListController( - null, - ); - return success.error == null; - } } From 199e71159d1eca83a94bbbd7e44967159a783be8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 6 Jun 2024 16:37:14 -0400 Subject: [PATCH 20/26] some small fix for archive/leave button PR --- lib/pages/chat/chat.dart | 6 +----- lib/pages/chat_list/space_view.dart | 5 +++-- .../class_and_exchange_settings_extension.dart | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 62603e86a..4a204c404 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -454,11 +454,7 @@ class ChatController extends State } } timeline!.requestKeys(onlineKeyBackupOnly: false); - if (!room.isSpace && - room.membership == Membership.join && - room.markedUnread) { - room.markUnread(false); - } + if (room.markedUnread) room.markUnread(false); // when the scroll controller is attached we want to scroll to an event id, if specified // and update the scroll controller...which will trigger a request history, if the diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 2639be184..1fde5f0f8 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -229,7 +229,10 @@ class _SpaceViewState extends State { ), message: spaceChild?.topic ?? room?.topic, actions: [ + // #Pangea + // if (room == null) if (room == null || room.membership == Membership.leave) + // Pangea# SheetAction( key: SpaceChildContextAction.join, label: L10n.of(context)!.joinRoom, @@ -304,7 +307,6 @@ class _SpaceViewState extends State { } else { widget.controller.toggleSelection(room.id); await widget.controller.leaveAction(); - widget.controller.toggleSelection(room.id); } _refresh(); break; @@ -344,7 +346,6 @@ class _SpaceViewState extends State { } else { widget.controller.toggleSelection(room.id); await widget.controller.archiveAction(); - widget.controller.toggleSelection(room.id); } // Pangea# _refresh(); diff --git a/lib/pangea/extensions/pangea_room_extension/class_and_exchange_settings_extension.dart b/lib/pangea/extensions/pangea_room_extension/class_and_exchange_settings_extension.dart index 14ee5f4ce..e71ed8f4f 100644 --- a/lib/pangea/extensions/pangea_room_extension/class_and_exchange_settings_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/class_and_exchange_settings_extension.dart @@ -71,8 +71,8 @@ extension ClassAndExchangeSettingsRoomExtension on Room { } final spaceChildPower = currentPowerContent["events"][EventTypes.spaceChild]; - final studentAnalyticsPower = - currentPowerContent[PangeaEventTypes.studentAnalyticsSummary]; + final studentAnalyticsPower = currentPowerContent["events"] + [PangeaEventTypes.studentAnalyticsSummary]; if ((spaceChildPower == null || studentAnalyticsPower == null)) { currentPowerContent["events"][EventTypes.spaceChild] = 0; From bb01635c9f7ba27bd25ec316a8a4c2955bf46ad2 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 7 Jun 2024 10:35:02 -0400 Subject: [PATCH 21/26] Fixed text selection, removed translationEnabled --- lib/pages/chat/events/message_content.dart | 4 ++++ .../controllers/choreographer.dart | 10 +++++----- .../widgets/language_display_toggle.dart | 6 +++--- lib/pangea/controllers/user_controller.dart | 18 ++++++++--------- lib/pangea/models/class_model.dart | 20 +++++++++---------- lib/pangea/models/user_model.dart | 6 +++--- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 776a3039e..2d27807b8 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -303,6 +303,10 @@ class MessageContent extends StatelessWidget { immersionMode: immersionMode, toolbarController: toolbarController, ); + } else if (pangeaMessageEvent != null) { + toolbarController?.toolbar?.textSelection.setMessageText( + pangeaMessageEvent!.body, + ); } // Pangea# return FutureBuilder( diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 340aa591b..3d84b0e1d 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -545,11 +545,11 @@ class Choreographer { chatController.room, ); - bool get translationEnabled => - pangeaController.permissionsController.isToolEnabled( - ToolSetting.translations, - chatController.room, - ); + // bool get translationEnabled => + // pangeaController.permissionsController.isToolEnabled( + // ToolSetting.translations, + // chatController.room, + // ); bool get isITandIGCEnabled => pangeaController.permissionsController.isWritingAssistanceEnabled( diff --git a/lib/pangea/choreographer/widgets/language_display_toggle.dart b/lib/pangea/choreographer/widgets/language_display_toggle.dart index 9478b4220..bc0efd492 100644 --- a/lib/pangea/choreographer/widgets/language_display_toggle.dart +++ b/lib/pangea/choreographer/widgets/language_display_toggle.dart @@ -17,9 +17,9 @@ class LanguageDisplayToggle extends StatelessWidget { @override Widget build(BuildContext context) { - if (!controller.choreographer.translationEnabled) { - return const SizedBox(); - } + // if (!controller.choreographer.translationEnabled) { + // return const SizedBox(); + // } return Container( decoration: BoxDecoration( shape: BoxShape.circle, diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index d3a17d365..69b50bf69 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -131,7 +131,7 @@ class UserController extends BaseController { final bool? immersionMode = migratedProfileInfo(MatrixProfile.immersionMode); final bool? definitions = migratedProfileInfo(MatrixProfile.definitions); - final bool? translations = migratedProfileInfo(MatrixProfile.translations); + // final bool? translations = migratedProfileInfo(MatrixProfile.translations); final bool? showItInstructions = migratedProfileInfo(MatrixProfile.showedItInstructions); final bool? showClickMessage = @@ -147,7 +147,7 @@ class UserController extends BaseController { interactiveGrammar: interactiveGrammar, immersionMode: immersionMode, definitions: definitions, - translations: translations, + // translations: translations, showedItInstructions: showItInstructions, showedClickMessage: showClickMessage, showedBlurMeansTranslate: showBlurMeansTranslate, @@ -228,7 +228,7 @@ class UserController extends BaseController { bool? interactiveGrammar, bool? immersionMode, bool? definitions, - bool? translations, + // bool? translations, bool? showedItInstructions, bool? showedClickMessage, bool? showedBlurMeansTranslate, @@ -280,12 +280,12 @@ class UserController extends BaseController { definitions, ); } - if (translations != null) { - await _pangeaController.pStoreService.save( - MatrixProfile.translations.title, - translations, - ); - } + // if (translations != null) { + // await _pangeaController.pStoreService.save( + // MatrixProfile.translations.title, + // translations, + // ); + // } if (showedItInstructions != null) { await _pangeaController.pStoreService.save( MatrixProfile.showedItInstructions.title, diff --git a/lib/pangea/models/class_model.dart b/lib/pangea/models/class_model.dart index dc0822438..7e95c9d26 100644 --- a/lib/pangea/models/class_model.dart +++ b/lib/pangea/models/class_model.dart @@ -199,9 +199,9 @@ class PangeaRoomRules { case ToolSetting.definitions: definitions = value; break; - case ToolSetting.translations: - translations = value; - break; + // case ToolSetting.translations: + // translations = value; + // break; case ToolSetting.autoIGC: autoIGC = value; break; @@ -275,8 +275,8 @@ class PangeaRoomRules { return immersionMode; case ToolSetting.definitions: return definitions; - case ToolSetting.translations: - return translations; + // case ToolSetting.translations: + // return translations; case ToolSetting.autoIGC: return autoIGC; default: @@ -306,7 +306,7 @@ enum ToolSetting { interactiveGrammar, immersionMode, definitions, - translations, + // translations, autoIGC, } @@ -321,8 +321,8 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.toggleImmersionMode; case ToolSetting.definitions: return L10n.of(context)!.definitionsToolName; - case ToolSetting.translations: - return L10n.of(context)!.messageTranslationsToolName; + // case ToolSetting.translations: + // return L10n.of(context)!.messageTranslationsToolName; case ToolSetting.autoIGC: return L10n.of(context)!.autoIGCToolName; } @@ -339,8 +339,8 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.toggleImmersionModeDesc; case ToolSetting.definitions: return L10n.of(context)!.definitionsToolDescription; - case ToolSetting.translations: - return L10n.of(context)!.translationsToolDescrption; + // case ToolSetting.translations: + // return L10n.of(context)!.translationsToolDescrption; case ToolSetting.autoIGC: return L10n.of(context)!.autoIGCToolDescription; } diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index 10c382f9f..7be3848e2 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -59,7 +59,7 @@ enum MatrixProfile { interactiveGrammar, immersionMode, definitions, - translations, + // translations, showedItInstructions, showedClickMessage, showedBlurMeansTranslate, @@ -88,8 +88,8 @@ extension MatrixProfileExtension on MatrixProfile { return ToolSetting.immersionMode.toString(); case MatrixProfile.definitions: return ToolSetting.definitions.toString(); - case MatrixProfile.translations: - return ToolSetting.translations.toString(); + // case MatrixProfile.translations: + // return ToolSetting.translations.toString(); case MatrixProfile.autoIGC: return ToolSetting.autoIGC.toString(); case MatrixProfile.showedItInstructions: From 4f692a03b8f735701fc3875426db5ab55d057be2 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 7 Jun 2024 13:29:51 -0400 Subject: [PATCH 22/26] Added instructions for tooltips --- assets/l10n/intl_en.arb | 5 ++++- lib/pangea/controllers/user_controller.dart | 10 ++++++++++ lib/pangea/models/user_model.dart | 3 +++ lib/pangea/utils/instructions.dart | 8 ++++++++ .../widgets/chat/message_speech_to_text_card.dart | 13 +++++++++++++ lib/pangea/widgets/common/icon_number_widget.dart | 13 +++++++++---- 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 3451205da..68ce39bfd 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3951,5 +3951,8 @@ "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.", - "onlyAdminDescription": "Since there are no other admins, all other participants will also be removed." + "onlyAdminDescription": "Since there are no other admins, all other participants will also be removed.", + "tooltipInstructionsTitle": "Not sure what that does?", + "tooltipInstructionsMobileBody": "Press and hold items to view tooltips.", + "tooltipInstructionsBrowserBody": "Hover over items to view tooltips." } \ No newline at end of file diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index d3a17d365..e06ca82e5 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -138,6 +138,8 @@ class UserController extends BaseController { migratedProfileInfo(MatrixProfile.showedClickMessage); final bool? showBlurMeansTranslate = migratedProfileInfo(MatrixProfile.showedBlurMeansTranslate); + final bool? showTooltipInstructions = + migratedProfileInfo(MatrixProfile.showedTooltipInstructions); await updateMatrixProfile( dateOfBirth: dob, @@ -151,6 +153,7 @@ class UserController extends BaseController { showedItInstructions: showItInstructions, showedClickMessage: showClickMessage, showedBlurMeansTranslate: showBlurMeansTranslate, + showedTooltipInstructions: showTooltipInstructions, createdAt: createdAt, targetLanguage: targetLanguage, sourceLanguage: sourceLanguage, @@ -232,6 +235,7 @@ class UserController extends BaseController { bool? showedItInstructions, bool? showedClickMessage, bool? showedBlurMeansTranslate, + bool? showedTooltipInstructions, String? createdAt, String? targetLanguage, String? sourceLanguage, @@ -304,6 +308,12 @@ class UserController extends BaseController { showedBlurMeansTranslate, ); } + if (showedTooltipInstructions != null) { + await _pangeaController.pStoreService.save( + MatrixProfile.showedTooltipInstructions.title, + showedTooltipInstructions, + ); + } if (createdAt != null) { await _pangeaController.pStoreService.save( MatrixProfile.createdAt.title, diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index 2169c6f70..c5d597f57 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -63,6 +63,7 @@ enum MatrixProfile { showedItInstructions, showedClickMessage, showedBlurMeansTranslate, + showedTooltipInstructions, createdAt, targetLanguage, sourceLanguage, @@ -95,6 +96,8 @@ extension MatrixProfileExtension on MatrixProfile { return InstructionsEnum.clickMessage.toString(); case MatrixProfile.showedBlurMeansTranslate: return InstructionsEnum.blurMeansTranslate.toString(); + case MatrixProfile.showedTooltipInstructions: + return InstructionsEnum.tooltipInstructions.toString(); case MatrixProfile.createdAt: return ModelKey.userCreatedAt; case MatrixProfile.targetLanguage: diff --git a/lib/pangea/utils/instructions.dart b/lib/pangea/utils/instructions.dart index f1fa8b59f..43350f518 100644 --- a/lib/pangea/utils/instructions.dart +++ b/lib/pangea/utils/instructions.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -102,6 +103,7 @@ enum InstructionsEnum { itInstructions, clickMessage, blurMeansTranslate, + tooltipInstructions, } extension Copy on InstructionsEnum { @@ -113,6 +115,8 @@ extension Copy on InstructionsEnum { return L10n.of(context)!.clickMessageTitle; case InstructionsEnum.blurMeansTranslate: return L10n.of(context)!.blurMeansTranslateTitle; + case InstructionsEnum.tooltipInstructions: + return L10n.of(context)!.tooltipInstructionsTitle; } } @@ -124,6 +128,10 @@ extension Copy on InstructionsEnum { return L10n.of(context)!.clickMessageBody; case InstructionsEnum.blurMeansTranslate: return L10n.of(context)!.blurMeansTranslateBody; + case InstructionsEnum.tooltipInstructions: + return PlatformInfos.isMobile + ? L10n.of(context)!.tooltipInstructionsMobileBody + : L10n.of(context)!.tooltipInstructionsBrowserBody; } } } diff --git a/lib/pangea/widgets/chat/message_speech_to_text_card.dart b/lib/pangea/widgets/chat/message_speech_to_text_card.dart index 37b013b53..663e39ffe 100644 --- a/lib/pangea/widgets/chat/message_speech_to_text_card.dart +++ b/lib/pangea/widgets/chat/message_speech_to_text_card.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/speech_to_text_models.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/pangea/utils/instructions.dart'; import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/common/icon_number_widget.dart'; import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart'; @@ -175,12 +176,24 @@ class MessageSpeechToTextCardState extends State { number: "${selectedToken?.confidence ?? speechToTextResponse!.transcript.confidence}%", toolTip: L10n.of(context)!.accuracy, + onPressed: () => MatrixState.pangeaController.instructions.show( + context, + InstructionsEnum.tooltipInstructions, + widget.messageEvent.eventId, + true, + ), ), IconNumberWidget( icon: Icons.speed, number: wordsPerMinuteString != null ? "$wordsPerMinuteString" : "??", toolTip: L10n.of(context)!.wordsPerMinute, + onPressed: () => MatrixState.pangeaController.instructions.show( + context, + InstructionsEnum.tooltipInstructions, + widget.messageEvent.eventId, + true, + ), ), ], ), diff --git a/lib/pangea/widgets/common/icon_number_widget.dart b/lib/pangea/widgets/common/icon_number_widget.dart index b42777f91..f677ea579 100644 --- a/lib/pangea/widgets/common/icon_number_widget.dart +++ b/lib/pangea/widgets/common/icon_number_widget.dart @@ -6,6 +6,7 @@ class IconNumberWidget extends StatelessWidget { final Color? iconColor; final double? iconSize; final String? toolTip; + final VoidCallback onPressed; const IconNumberWidget({ super.key, @@ -14,16 +15,20 @@ class IconNumberWidget extends StatelessWidget { this.toolTip, this.iconColor, this.iconSize, + required this.onPressed, }); Widget _content(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - color: iconColor ?? Theme.of(context).iconTheme.color, - size: iconSize ?? Theme.of(context).iconTheme.size, + IconButton( + icon: Icon( + icon, + color: iconColor ?? Theme.of(context).iconTheme.color, + size: iconSize ?? Theme.of(context).iconTheme.size, + ), + onPressed: onPressed, ), const SizedBox(width: 8), Text( From abc70ceef1f1225138edbd1f64a414e89d8f3bd6 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 7 Jun 2024 14:32:08 -0400 Subject: [PATCH 23/26] removed new instuction enum entry from matrix profile migration function --- lib/pangea/controllers/user_controller.dart | 3 - needed-translations.txt | 288 ++++++++++++++++---- 2 files changed, 240 insertions(+), 51 deletions(-) diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index e06ca82e5..f5ecc879d 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -138,8 +138,6 @@ class UserController extends BaseController { migratedProfileInfo(MatrixProfile.showedClickMessage); final bool? showBlurMeansTranslate = migratedProfileInfo(MatrixProfile.showedBlurMeansTranslate); - final bool? showTooltipInstructions = - migratedProfileInfo(MatrixProfile.showedTooltipInstructions); await updateMatrixProfile( dateOfBirth: dob, @@ -153,7 +151,6 @@ class UserController extends BaseController { showedItInstructions: showItInstructions, showedClickMessage: showClickMessage, showedBlurMeansTranslate: showBlurMeansTranslate, - showedTooltipInstructions: showTooltipInstructions, createdAt: createdAt, targetLanguage: targetLanguage, sourceLanguage: sourceLanguage, diff --git a/needed-translations.txt b/needed-translations.txt index 70b061369..4b09cb2ee 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -841,7 +841,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "be": [ @@ -2281,7 +2285,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "bn": [ @@ -3183,7 +3191,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "bo": [ @@ -4085,7 +4097,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ca": [ @@ -4987,7 +5003,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "cs": [ @@ -5889,7 +5909,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "de": [ @@ -6738,7 +6762,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "el": [ @@ -7640,7 +7668,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "eo": [ @@ -8542,7 +8574,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "es": [ @@ -8550,7 +8586,11 @@ "suggestToChatDesc", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "et": [ @@ -9395,7 +9435,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "eu": [ @@ -10240,7 +10284,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fa": [ @@ -11142,7 +11190,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fi": [ @@ -12044,7 +12096,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fr": [ @@ -12946,7 +13002,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ga": [ @@ -13848,7 +13908,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "gl": [ @@ -14693,7 +14757,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "he": [ @@ -15595,7 +15663,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hi": [ @@ -16497,7 +16569,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hr": [ @@ -17386,7 +17462,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hu": [ @@ -18288,7 +18368,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ia": [ @@ -19714,7 +19798,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "id": [ @@ -20616,7 +20704,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ie": [ @@ -21518,7 +21610,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "it": [ @@ -22405,7 +22501,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ja": [ @@ -23307,7 +23407,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ko": [ @@ -24209,7 +24313,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "lt": [ @@ -25111,7 +25219,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "lv": [ @@ -26013,7 +26125,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "nb": [ @@ -26915,7 +27031,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "nl": [ @@ -27817,7 +27937,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pl": [ @@ -28719,7 +28843,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt": [ @@ -29621,7 +29749,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt_BR": [ @@ -30492,7 +30624,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt_PT": [ @@ -31394,7 +31530,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ro": [ @@ -32296,7 +32436,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ru": [ @@ -33141,7 +33285,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sk": [ @@ -34043,7 +34191,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sl": [ @@ -34945,7 +35097,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sr": [ @@ -35847,7 +36003,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sv": [ @@ -36714,7 +36874,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ta": [ @@ -37616,7 +37780,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "th": [ @@ -38518,7 +38686,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "tr": [ @@ -39405,7 +39577,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "uk": [ @@ -40250,7 +40426,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "vi": [ @@ -41152,7 +41332,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "zh": [ @@ -41997,7 +42181,11 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "zh_Hant": [ @@ -42899,6 +43087,10 @@ "wordsPerMinute", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ] } From 3f803a5cc300287390a0defd1f9d265ac2872d60 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 7 Jun 2024 15:12:17 -0400 Subject: [PATCH 24/26] hotfix for span card bug --- lib/pangea/widgets/igc/span_card.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pangea/widgets/igc/span_card.dart b/lib/pangea/widgets/igc/span_card.dart index fd44383a0..4f0b22dfe 100644 --- a/lib/pangea/widgets/igc/span_card.dart +++ b/lib/pangea/widgets/igc/span_card.dart @@ -61,7 +61,7 @@ class SpanCardState extends State { SpanChoice? get selectedChoice { if (selectedChoiceIndex == null || widget.scm.pangeaMatch?.match.choices == null || - widget.scm.pangeaMatch!.match.choices!.length >= selectedChoiceIndex!) { + widget.scm.pangeaMatch!.match.choices!.length <= selectedChoiceIndex!) { return null; } return widget.scm.pangeaMatch?.match.choices?[selectedChoiceIndex!]; From b65e7138808f0b537d39b6ee4bc1d71fdff6093c Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 7 Jun 2024 15:34:56 -0400 Subject: [PATCH 25/26] filter pangea event types from chat list subtitles --- .../utils/get_chat_list_item_subtitle.dart | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/pangea/utils/get_chat_list_item_subtitle.dart b/lib/pangea/utils/get_chat_list_item_subtitle.dart index 2fee578bf..5ccb623d7 100644 --- a/lib/pangea/utils/get_chat_list_item_subtitle.dart +++ b/lib/pangea/utils/get_chat_list_item_subtitle.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/constants/language_keys.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; @@ -10,6 +11,17 @@ import 'package:matrix/matrix.dart'; import '../../utils/matrix_sdk_extensions/matrix_locals.dart'; class GetChatListItemSubtitle { + final List hideContentKeys = [ + ModelKey.transcription, + ]; + + bool moveBackInTimeline(Event event) => + hideContentKeys.any( + (key) => event.content.tryGet(key) != null, + ) || + event.type.startsWith("p.") || + event.type.startsWith("pangea."); + Future getSubtitle( L10n l10n, Event? event, @@ -22,23 +34,14 @@ class GetChatListItemSubtitle { eventContextId = null; } - final Timeline timeline = - await event.room.getTimeline(eventContextId: eventContextId); - - if (event.content.tryGet(ModelKey.transcription) != null) { - int index = timeline.events.indexWhere( - (e) => e.eventId == event!.eventId, - ); - - while (index < timeline.events.length && - (timeline.events[index].content.tryGet(ModelKey.transcription) != - null || - timeline.events[index].type != EventTypes.Message)) { - index++; - } + final Timeline timeline = await event.room.getTimeline( + eventContextId: eventContextId, + ); - if (timeline.events.length > index + 1) { - event = timeline.events[index]; + if (moveBackInTimeline(event)) { + event = timeline.events.firstWhereOrNull((e) => !moveBackInTimeline(e)); + if (event == null) { + return l10n.emptyChat; } } From 7deb23515d93c2656b9919734ee0a5932d2d3c8f Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Fri, 7 Jun 2024 15:38:48 -0400 Subject: [PATCH 26/26] fix it feedback request --- lib/pangea/choreographer/controllers/it_controller.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 6d5f8e347..61c8c2312 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -183,7 +183,7 @@ class ITController { } } - FuturegetNextTranslationData() async { + Future getNextTranslationData() async { try { if (completedITSteps.length < goldRouteTracker.continuances.length) { final String currentText = choreographer.currentText; @@ -478,5 +478,5 @@ class CurrentITStep { // get continuance with highest level Continuance get best => - continuances.reduce((a, b) => a.level > b.level ? a : b); + continuances.reduce((a, b) => a.level < b.level ? a : b); }