From 280915fc96d8a09db12b342e140641b6eabf2fdb Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 16 Jul 2024 13:43:11 -0400 Subject: [PATCH 1/4] removed excessive calls to setState in chat.dart and replaced them with smaller, stateful widgets --- lib/pages/chat/chat.dart | 97 ++---- lib/pages/chat/chat_event_list.dart | 2 - lib/pages/chat/chat_input_row.dart | 7 +- lib/pages/chat/chat_view.dart | 280 +++++++----------- lib/pages/chat/events/message.dart | 7 +- .../controllers/choreographer.dart | 3 - .../controllers/message_options.dart | 46 --- lib/pangea/choreographer/widgets/it_bar.dart | 232 ++++++++------- .../widgets/language_display_toggle.dart | 56 ---- .../choreographer/widgets/send_button.dart | 41 ++- .../pangea_message_event.dart | 3 +- .../pages/class_analytics/measure_able.dart | 57 ---- .../chat/chat_floating_action_button.dart | 94 ++++++ .../widgets/chat/input_bar_wrapper.dart | 82 +++++ lib/pangea/widgets/chat/message_actions.dart | 29 -- .../widgets/chat/text_to_speech_button.dart | 138 --------- 16 files changed, 471 insertions(+), 703 deletions(-) delete mode 100644 lib/pangea/choreographer/controllers/message_options.dart delete mode 100644 lib/pangea/choreographer/widgets/language_display_toggle.dart delete mode 100644 lib/pangea/pages/class_analytics/measure_able.dart create mode 100644 lib/pangea/widgets/chat/chat_floating_action_button.dart create mode 100644 lib/pangea/widgets/chat/input_bar_wrapper.dart delete mode 100644 lib/pangea/widgets/chat/message_actions.dart delete mode 100644 lib/pangea/widgets/chat/text_to_speech_button.dart diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index f998b62b3..8107993da 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -20,7 +20,6 @@ import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_e import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/choreo_record.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; -import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; @@ -294,10 +293,6 @@ class ChatController extends State } } - // #Pangea - bool showPermissionsError = false; - // #Pangea - @override void initState() { scrollController.addListener(_updateScrollController); @@ -327,31 +322,12 @@ class ChatController extends State context, () => Future.delayed( Duration.zero, - () => setState( - () {}, - ), + () => setState(() {}), ), ); } await Matrix.of(context).client.roomsLoading; - choreographer.setRoomId(roomId); - choreographer.messageOptions.resetSelectedDisplayLang(); - choreographer.stateListener.stream.listen((event) { - debugPrint("chat.dart choreo event $event"); - setState(() {}); - }); - showPermissionsError = !pangeaController.permissionsController - .isToolEnabled(ToolSetting.interactiveTranslator, room) || - !pangeaController.permissionsController - .isToolEnabled(ToolSetting.interactiveGrammar, room); }); - - Future.delayed( - const Duration(seconds: 5), - () { - if (mounted) setState(() => showPermissionsError = false); - }, - ); // Pangea# _tryLoadTimeline(); if (kIsWeb) { @@ -602,10 +578,9 @@ class ChatController extends State }); // #Pangea - final List edittingEvents = []; - void clearEdittingEvent(String eventId) { - edittingEvents.remove(eventId); - setState(() {}); + Event? pangeaEditingEvent; + void clearEditingEvent() { + pangeaEditingEvent = null; } // Future send() async { @@ -665,11 +640,9 @@ class ChatController extends State .then( (String? msgEventId) async { // #Pangea - setState(() { - if (previousEdit != null) { - edittingEvents.add(previousEdit.eventId); - } - }); + if (previousEdit != null) { + pangeaEditingEvent = previousEdit; + } GoogleAnalytics.sendMessage( room.id, @@ -1262,9 +1235,6 @@ class ChatController extends State void clearSelectedEvents() => setState(() { selectedEvents.clear(); showEmojiPicker = false; - //#Pangea - choreographer.messageOptions.resetSelectedDisplayLang(); - //Pangea# }); void clearSingleSelectedEvent() { @@ -1336,19 +1306,19 @@ class ChatController extends State // Pangea# if (!event.redacted) { // #Pangea - // If previous selectedEvent has same eventId, delete previous selectedEvent - final matches = - selectedEvents.where((e) => e.eventId == event.eventId).toList(); + // if (selectedEvents.contains(event)) { + // setState( + // () => selectedEvents.remove(event), + // ); + // } + + // If delete first selected event with the selected eventID + final matches = selectedEvents.where((e) => e.eventId == event.eventId); if (matches.isNotEmpty) { - // if (selectedEvents.contains(event)) { - // Pangea# - setState( - // #Pangea - () => selectedEvents.remove(matches.first), - // () => selectedEvents.remove(event), - // Pangea# - ); - } else { + setState(() => selectedEvents.remove(matches.first)); + } + // Pangea# + else { setState( () => selectedEvents.add(event), ); @@ -1557,35 +1527,6 @@ class ChatController extends State }); // #Pangea - double? availableSpace; - double? inputRowSize; - bool? lastState; - bool get isRowScrollable { - if (availableSpace == null || inputRowSize == null) { - if (lastState == null) { - lastState = false; - Future.delayed(Duration.zero, () { - setState(() {}); - }); - } - return false; - } - const double offSetValue = 10; - final bool currentState = inputRowSize! > (availableSpace! - offSetValue); - if (!lastState! && currentState) { - Future.delayed(Duration.zero, () { - setState(() {}); - }); - } - if (lastState! && !currentState) { - Future.delayed(Duration.zero, () { - setState(() {}); - }); - } - lastState = currentState; - return currentState; - } - final Map _pangeaMessageEvents = {}; final Map _toolbarDisplayControllers = {}; diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 24508bb62..9bca32169 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -170,8 +170,6 @@ class ChatEventList extends StatelessWidget { controller.scrollToEventId(eventId), longPressSelect: controller.selectedEvents.isNotEmpty, // #Pangea - selectedDisplayLang: - controller.choreographer.messageOptions.selectedDisplayLang, immersionMode: controller.choreographer.immersionMode, definitions: controller.choreographer.definitionsEnabled, controller: controller, diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 2ba6a0957..b1174fd2c 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -3,6 +3,7 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart'; import 'package:fluffychat/pangea/constants/language_constants.dart'; +import 'package:fluffychat/pangea/widgets/chat/input_bar_wrapper.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -12,7 +13,6 @@ import 'package:matrix/matrix.dart'; import '../../config/themes.dart'; import 'chat.dart'; -import 'input_bar.dart'; class ChatInputRow extends StatelessWidget { final ChatController controller; @@ -322,7 +322,10 @@ class ChatInputRow extends StatelessWidget { Expanded( child: Padding( padding: const EdgeInsets.symmetric(vertical: 0.0), - child: InputBar( + // #Pangea + // child: InputBar( + child: InputBarWrapper( + // Pangea# room: controller.room, minLines: 1, maxLines: 8, diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 3c819f412..36e6d69dc 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -7,11 +7,9 @@ import 'package:fluffychat/pages/chat/chat_event_list.dart'; import 'package:fluffychat/pages/chat/pinned_events.dart'; 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/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/pages/class_analytics/measure_able.dart'; +import 'package:fluffychat/pangea/widgets/chat/chat_floating_action_button.dart'; import 'package:fluffychat/utils/account_config.dart'; import 'package:fluffychat/widgets/chat_settings_popup_menu.dart'; import 'package:fluffychat/widgets/connection_status_header.dart'; @@ -266,32 +264,20 @@ class ChatView extends StatelessWidget { // #Pangea // floatingActionButton: controller.showScrollDownButton && // controller.selectedEvents.isEmpty - floatingActionButton: controller.selectedEvents.isEmpty - ? (controller.showScrollDownButton - // Pangea# - ? Padding( - padding: const EdgeInsets.only(bottom: 56.0), - child: FloatingActionButton( - onPressed: controller.scrollDown, - heroTag: null, - mini: true, - child: const Icon(Icons.arrow_downward_outlined), - ), - ) - // #Pangea - : controller.choreographer.errorService.error != null - ? ChoreographerHasErrorButton( - controller.pangeaController, - controller.choreographer.errorService.error!, - ) - : controller.showPermissionsError - ? LanguagePermissionsButtons( - choreographer: controller.choreographer, - roomID: controller.roomId, - ) - : null) - // #Pangea - : null, + // ? Padding( + // padding: const EdgeInsets.only(bottom: 56.0), + // child: FloatingActionButton( + // onPressed: controller.scrollDown, + // heroTag: null, + // mini: true, + // child: const Icon(Icons.arrow_downward_outlined), + // ), + // ) + // : null, + floatingActionButton: ChatFloatingActionButton( + controller: controller, + ), + // Pangea# body: // #Pangea // DropTarget( @@ -338,120 +324,100 @@ class ChatView extends StatelessWidget { ), if (controller.room.canSendDefaultMessages && controller.room.membership == Membership.join) - // #Pangea - // Container( - ConditionalFlexible( - isScroll: controller.isRowScrollable, - child: ConditionalScroll( - isScroll: controller.isRowScrollable, - child: MeasurableWidget( - onChange: (size, position) { - controller.inputRowSize = size!.height; - }, - child: Container( - // Pangea# - margin: EdgeInsets.only( - bottom: bottomSheetPadding, - left: bottomSheetPadding, - right: bottomSheetPadding, - ), - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 2.5, - ), - alignment: Alignment.center, - child: Material( - clipBehavior: Clip.hardEdge, - color: Theme.of(context) - .colorScheme - // ignore: deprecated_member_use - .surfaceVariant, - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), - child: controller.room.isAbandonedDMRoom == - true - ? Row( - 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( - 16, - ), - foregroundColor: - Theme.of(context) - .colorScheme - .error, - ), - icon: const Icon( - // #Pangea - // Icons.archive_outlined, - Icons.arrow_forward, - // Pangea# - ), - onPressed: controller.leaveChat, - label: Text( - L10n.of(context)!.leave, - ), - ), - TextButton.icon( - style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), - ), - icon: const Icon( - Icons.forum_outlined, - ), - onPressed: - controller.recreateChat, - label: Text( - L10n.of(context)!.reopenChat, - ), - ), - ], - ) - : Column( - mainAxisSize: MainAxisSize.min, - children: [ - const ConnectionStatusHeader(), - ITBar( - choreographer: - controller.choreographer, + Container( + margin: EdgeInsets.only( + bottom: bottomSheetPadding, + left: bottomSheetPadding, + right: bottomSheetPadding, + ), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth * 2.5, + ), + alignment: Alignment.center, + child: Material( + clipBehavior: Clip.hardEdge, + color: Theme.of(context) + .colorScheme + // ignore: deprecated_member_use + .surfaceVariant, + borderRadius: const BorderRadius.all( + Radius.circular(24), + ), + child: controller.room.isAbandonedDMRoom == true + ? Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + // #Pangea + if (controller.room.isRoomAdmin) + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.all( + 16, ), - ReactionsPicker(controller), - ReplyDisplay(controller), - ChatInputRow(controller), - ChatEmojiPicker(controller), - ], + 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( + 16, + ), + foregroundColor: Theme.of(context) + .colorScheme + .error, + ), + icon: const Icon( + // #Pangea + // Icons.archive_outlined, + Icons.arrow_forward, + // Pangea# + ), + onPressed: controller.leaveChat, + label: Text( + L10n.of(context)!.leave, + ), + ), + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.all( + 16, + ), + ), + icon: const Icon( + Icons.forum_outlined, + ), + onPressed: controller.recreateChat, + label: Text( + L10n.of(context)!.reopenChat, + ), + ), + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + const ConnectionStatusHeader(), + ITBar( + choreographer: + controller.choreographer, + ), + ReactionsPicker(controller), + ReplyDisplay(controller), + ChatInputRow(controller), + ChatEmojiPicker(controller), + ], + ), ), ), ], @@ -484,35 +450,3 @@ class ChatView extends StatelessWidget { ); } } - -// #Pangea -Widget ConditionalFlexible({required bool isScroll, required Widget child}) { - if (isScroll) { - return Flexible( - flex: 9999999, - child: child, - ); - } - return child; -} - -class ConditionalScroll extends StatelessWidget { - final bool isScroll; - final Widget child; - const ConditionalScroll({ - super.key, - required this.isScroll, - required this.child, - }); - - @override - Widget build(BuildContext context) { - if (isScroll) { - return SingleChildScrollView( - child: child, - ); - } - return child; - } -} -// Pangea# diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 3b2c1b2fb..b0fc6842f 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -2,7 +2,6 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pangea/enum/use_type.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; -import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/widgets/chat/message_buttons.dart'; import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; @@ -39,7 +38,6 @@ class Message extends StatelessWidget { final bool animateIn; final void Function()? resetAnimateIn; // #Pangea - final LanguageModel? selectedDisplayLang; final bool immersionMode; final bool definitions; final ChatController controller; @@ -64,7 +62,6 @@ class Message extends StatelessWidget { this.resetAnimateIn, this.avatarPresenceBackgroundColor, // #Pangea - required this.selectedDisplayLang, required this.immersionMode, required this.definitions, required this.controller, @@ -82,9 +79,9 @@ class Message extends StatelessWidget { // #Pangea debugPrint('Message.build()'); WidgetsBinding.instance.addPostFrameCallback((_) { - if (controller.edittingEvents.contains(event.eventId)) { + if (controller.pangeaEditingEvent?.eventId == event.eventId) { pangeaMessageEvent?.updateLatestEdit(); - controller.clearEdittingEvent(event.eventId); + controller.clearEditingEvent(); } }); // Pangea# diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index e5108ae4d..dd2078fa2 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -4,7 +4,6 @@ import 'dart:developer'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pangea/choreographer/controllers/alternative_translator.dart'; import 'package:fluffychat/pangea/choreographer/controllers/igc_controller.dart'; -import 'package:fluffychat/pangea/choreographer/controllers/message_options.dart'; import 'package:fluffychat/pangea/constants/language_constants.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/subscription_controller.dart'; @@ -38,7 +37,6 @@ class Choreographer { late PangeaTextController _textController; late ITController itController; late IgcController igc; - late MessageOptions messageOptions; late AlternativeTranslator altTranslator; late ErrorService errorService; @@ -59,7 +57,6 @@ class Choreographer { _textController = PangeaTextController(choreographer: this); itController = ITController(this); igc = IgcController(this); - messageOptions = MessageOptions(this); errorService = ErrorService(this); altTranslator = AlternativeTranslator(this); _textController.addListener(_onChangeListener); diff --git a/lib/pangea/choreographer/controllers/message_options.dart b/lib/pangea/choreographer/controllers/message_options.dart deleted file mode 100644 index 96df5d921..000000000 --- a/lib/pangea/choreographer/controllers/message_options.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/cupertino.dart'; - -import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; -import 'package:fluffychat/pangea/constants/language_constants.dart'; -import 'package:fluffychat/pangea/models/language_model.dart'; -import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; - -class MessageOptions { - Choreographer choreographer; - LanguageModel? _selectedDisplayLang; - - MessageOptions(this.choreographer); - - LanguageModel? get selectedDisplayLang { - if (_selectedDisplayLang != null && - _selectedDisplayLang!.langCode != LanguageKeys.unknownLanguage) { - return _selectedDisplayLang; - } - _selectedDisplayLang = choreographer.l2Lang; - return _selectedDisplayLang; - } - - bool get isTranslationOn => - _selectedDisplayLang?.langCode != choreographer.l2LangCode; - - // void setSelectedDisplayLang(LanguageModel? newLang) { - // _selectedDisplayLang = newLang; - // choreographer.setState(); - // } - - void toggleSelectedDisplayLang() { - if (_selectedDisplayLang?.langCode == choreographer.l2LangCode) { - _selectedDisplayLang = choreographer.l1Lang; - } else { - _selectedDisplayLang = choreographer.l2Lang; - } - debugPrint('toggleSelectedDisplayLang: ${_selectedDisplayLang?.langCode}'); - choreographer.setState(); - GoogleAnalytics.messageTranslate(); - } - - void resetSelectedDisplayLang() { - _selectedDisplayLang = choreographer.l2Lang; - choreographer.setState(); - } -} diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index 2ba630900..28b0f8bd8 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; @@ -7,7 +8,6 @@ import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart'; import 'package:fluffychat/pangea/choreographer/widgets/translation_finished_flow.dart'; import 'package:fluffychat/pangea/constants/choreo_constants.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -18,112 +18,140 @@ import '../../utils/overlay.dart'; import '../../widgets/igc/word_data_card.dart'; import 'choice_array.dart'; -class ITBar extends StatelessWidget { +class ITBar extends StatefulWidget { final Choreographer choreographer; const ITBar({super.key, required this.choreographer}); - ITController get itController => choreographer.itController; + @override + ITBarState createState() => ITBarState(); +} + +class ITBarState extends State { + ITController get itController => widget.choreographer.itController; + StreamSubscription? _choreoSub; @override - Widget build(BuildContext context) { + void initState() { + // Rebuild the widget each time there's an update from choreo. + _choreoSub = widget.choreographer.stateListener.stream.listen((_) { + setState(() {}); + }); + super.initState(); + } + @override + void dispose() { + _choreoSub?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { return AnimatedSize( duration: itController.willOpen - ? const Duration(milliseconds: 2000) - : const Duration(milliseconds: 500), + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), curve: Curves.fastOutSlowIn, clipBehavior: Clip.none, child: !itController.willOpen - ? const SizedBox() - : CompositedTransformTarget( - link: choreographer.itBarLinkAndKey.link, - child: AnimatedOpacity( - duration: itController.willOpen - ? const Duration(milliseconds: 2000) - : const Duration(milliseconds: 500), - opacity: itController.willOpen ? 1.0 : 0.0, - child: Container( - key: choreographer.itBarLinkAndKey.key, - decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.light - ? Colors.white - : Colors.black, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(AppConfig.borderRadius), - topRight: Radius.circular(AppConfig.borderRadius), - ), - ), - width: double.infinity, - padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), - child: Stack( - children: [ - SingleChildScrollView( - child: Column( - children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // // Row( - // // mainAxisAlignment: MainAxisAlignment.start, - // // crossAxisAlignment: CrossAxisAlignment.start, - // // children: [ - // // CounterDisplay( - // // correct: controller.correctChoices, - // // custom: controller.customChoices, - // // incorrect: controller.incorrectChoices, - // // yellow: controller.wildcardChoices, - // // ), - // // CompositedTransformTarget( - // // link: choreographer.itBotLayerLinkAndKey.link, - // // child: ITBotButton( - // // key: choreographer.itBotLayerLinkAndKey.key, - // // choreographer: choreographer, - // // ), - // // ), - // // ], - // // ), - // ITCloseButton(choreographer: choreographer), - // ], - // ), - // const SizedBox(height: 40.0), - OriginalText(controller: itController), - const SizedBox(height: 7.0), - IntrinsicHeight( - child: Container( - constraints: const BoxConstraints(minHeight: 80), - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: Center( - child: itController.choreographer.errorService.isError - ? ITError( - error: itController - .choreographer.errorService.error!, - controller: itController, - ) - : itController.showChoiceFeedback - ? ChoiceFeedbackText(controller: itController) - : itController.isTranslationDone - ? TranslationFeedback( - controller: itController, - ) - : ITChoices(controller: itController), - ), - ), - ), - ], + ? const SizedBox() + : CompositedTransformTarget( + link: widget.choreographer.itBarLinkAndKey.link, + child: AnimatedOpacity( + duration: itController.willOpen + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), + opacity: itController.willOpen ? 1.0 : 0.0, + child: Container( + key: widget.choreographer.itBarLinkAndKey.key, + decoration: BoxDecoration( + color: Theme.of(context).brightness == Brightness.light + ? Colors.white + : Colors.black, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(AppConfig.borderRadius), + topRight: Radius.circular(AppConfig.borderRadius), ), ), - Positioned( - top: 0.0, - right: 0.0, - child: ITCloseButton(choreographer: choreographer), + width: double.infinity, + padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), + child: Stack( + children: [ + SingleChildScrollView( + child: Column( + children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // // Row( + // // mainAxisAlignment: MainAxisAlignment.start, + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // CounterDisplay( + // // correct: controller.correctChoices, + // // custom: controller.customChoices, + // // incorrect: controller.incorrectChoices, + // // yellow: controller.wildcardChoices, + // // ), + // // CompositedTransformTarget( + // // link: choreographer.itBotLayerLinkAndKey.link, + // // child: ITBotButton( + // // key: choreographer.itBotLayerLinkAndKey.key, + // // choreographer: choreographer, + // // ), + // // ), + // // ], + // // ), + // ITCloseButton(choreographer: choreographer), + // ], + // ), + // const SizedBox(height: 40.0), + OriginalText(controller: itController), + const SizedBox(height: 7.0), + IntrinsicHeight( + child: Container( + constraints: + const BoxConstraints(minHeight: 80), + width: double.infinity, + padding: + const EdgeInsets.symmetric(horizontal: 4.0), + child: Center( + child: itController + .choreographer.errorService.isError + ? ITError( + error: itController.choreographer + .errorService.error!, + controller: itController, + ) + : itController.showChoiceFeedback + ? ChoiceFeedbackText( + controller: itController, + ) + : itController.isTranslationDone + ? TranslationFeedback( + controller: itController, + ) + : ITChoices( + controller: itController, + ), + ), + ), + ), + ], + ), + ), + Positioned( + top: 0.0, + right: 0.0, + child: + ITCloseButton(choreographer: widget.choreographer), + ), + ], ), - ], + ), ), ), - ), - ), ); } } @@ -199,20 +227,16 @@ class OriginalText extends StatelessWidget { ), ), ), - if ( - !controller.isEditingSourceText - && controller.sourceText != null - ) + if (!controller.isEditingSourceText && controller.sourceText != null) AnimatedOpacity( duration: const Duration(milliseconds: 500), - opacity: controller.nextITStep != null - ? 1.0 - : 0.0, + opacity: controller.nextITStep != null ? 1.0 : 0.0, child: IconButton( onPressed: () => { - if (controller.nextITStep != null) { - controller.setIsEditingSourceText(true), - }, + if (controller.nextITStep != null) + { + controller.setIsEditingSourceText(true), + }, }, icon: const Icon(Icons.edit_outlined), ), @@ -309,9 +333,9 @@ class ITChoices extends StatelessWidget { choices: controller.currentITStep!.continuances.map((e) { try { return Choice( - text: e.text.trim(), - color: e.color, - isGold: e.description == "best", + text: e.text.trim(), + color: e.color, + isGold: e.description == "best", ); } catch (e) { debugger(when: kDebugMode); diff --git a/lib/pangea/choreographer/widgets/language_display_toggle.dart b/lib/pangea/choreographer/widgets/language_display_toggle.dart deleted file mode 100644 index bc0efd492..000000000 --- a/lib/pangea/choreographer/widgets/language_display_toggle.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; - -import '../../../config/app_config.dart'; -import '../../../pages/chat/chat.dart'; - -class LanguageDisplayToggle extends StatelessWidget { - const LanguageDisplayToggle({ - super.key, - required this.controller, - }); - - final ChatController controller; - - get onPressed => - controller.choreographer.messageOptions.toggleSelectedDisplayLang; - - @override - Widget build(BuildContext context) { - // if (!controller.choreographer.translationEnabled) { - // return const SizedBox(); - // } - return Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: controller.choreographer.messageOptions.isTranslationOn - ? AppConfig.primaryColor - : null, - ), - child: IconButton( - tooltip: L10n.of(context)!.toggleLanguages, - onPressed: onPressed, - icon: const Icon(Icons.translate_outlined), - selectedIcon: const Icon(Icons.translate), - isSelected: controller.choreographer.messageOptions.isTranslationOn, - ), - ); - // return Tooltip( - // message: L10n.of(context)!.toggleLanguages, - // waitDuration: const Duration(milliseconds: 1000), - // child: FloatingActionButton( - // onPressed: onPressed, - // backgroundColor: Colors.white, - // mini: false, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(200), // <-- Radius - // ), - // child: LanguageFlag( - // flagUrl: controller - // .choreographer.messageOptions.displayLang?.languageFlag, - // size: 50, - // ), - // ), - // ); - } -} diff --git a/lib/pangea/choreographer/widgets/send_button.dart b/lib/pangea/choreographer/widgets/send_button.dart index 3f034b736..f5e358a31 100644 --- a/lib/pangea/choreographer/widgets/send_button.dart +++ b/lib/pangea/choreographer/widgets/send_button.dart @@ -1,22 +1,47 @@ +import 'dart:async'; + import 'package:fluffychat/pangea/enum/assistance_state_enum.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import '../../../pages/chat/chat.dart'; -class ChoreographerSendButton extends StatelessWidget { +class ChoreographerSendButton extends StatefulWidget { const ChoreographerSendButton({ super.key, required this.controller, }); - final ChatController controller; + @override + State createState() => + ChoreographerSendButtonState(); +} + +class ChoreographerSendButtonState extends State { + StreamSubscription? _choreoSub; + + @override + void initState() { + // Rebuild the widget each time there's an update from + // choreo. This keeps the spin up-to-date. + _choreoSub = + widget.controller.choreographer.stateListener.stream.listen((_) { + setState(() {}); + }); + super.initState(); + } + + @override + void dispose() { + _choreoSub?.cancel(); + super.dispose(); + } + @override Widget build(BuildContext context) { - // commit for cicd - return controller.choreographer.isFetching && - controller.choreographer.isAutoIGCEnabled + return widget.controller.choreographer.isFetching && + widget.controller.choreographer.isAutoIGCEnabled ? Container( height: 56, width: 56, @@ -28,10 +53,10 @@ class ChoreographerSendButton extends StatelessWidget { alignment: Alignment.center, child: IconButton( icon: const Icon(Icons.send_outlined), - color: - controller.choreographer.assistanceState.stateColor(context), + color: widget.controller.choreographer.assistanceState + .stateColor(context), onPressed: () { - controller.choreographer.send(context); + widget.controller.choreographer.send(context); }, tooltip: L10n.of(context)!.send, ), diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index 530a7a547..f1c9e5082 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -82,10 +82,9 @@ class PangeaMessageEvent { .firstOrNull ?? _event; - Event updateLatestEdit() { + void updateLatestEdit() { _latestEditCache = null; _representations = null; - return _latestEdit; } Future getMatrixAudioFile( diff --git a/lib/pangea/pages/class_analytics/measure_able.dart b/lib/pangea/pages/class_analytics/measure_able.dart deleted file mode 100644 index a569893fa..000000000 --- a/lib/pangea/pages/class_analytics/measure_able.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; - -class MeasurableWidget extends StatefulWidget { - final Widget child; - final Function(Size? size, Offset? position) onChange; - - const MeasurableWidget({ - super.key, - required this.onChange, - required this.child, - }); - - @override - _WidgetSizeState createState() => _WidgetSizeState(); -} - -class _WidgetSizeState extends State { - var widgetKey = GlobalKey(); - Offset? oldPosition; - @override - void initState() { - // TODO: implement initState - super.initState(); - } - - void postFrameCallback(_) { - final context = widgetKey.currentContext; - if (context == null) return; - - final RenderBox? box = - widgetKey.currentContext?.findRenderObject() as RenderBox?; - - if (box != null && box.hasSize) { - final Offset position = box.localToGlobal(Offset.zero); - - if (oldPosition != null) { - if (oldPosition!.dx == position.dx && oldPosition!.dy == position.dy) { - return; - } - } - oldPosition = position; - - final newSize = context.size; - widget.onChange(newSize, position); - } - } - - @override - Widget build(BuildContext context) { - SchedulerBinding.instance.addPostFrameCallback(postFrameCallback); - return Container( - key: widgetKey, - child: widget.child, - ); - } -} diff --git a/lib/pangea/widgets/chat/chat_floating_action_button.dart b/lib/pangea/widgets/chat/chat_floating_action_button.dart new file mode 100644 index 000000000..735b51b36 --- /dev/null +++ b/lib/pangea/widgets/chat/chat_floating_action_button.dart @@ -0,0 +1,94 @@ +import 'dart:async'; + +import 'package:fluffychat/pages/chat/chat.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/models/space_model.dart'; +import 'package:flutter/material.dart'; + +class ChatFloatingActionButton extends StatefulWidget { + final ChatController controller; + const ChatFloatingActionButton({ + super.key, + required this.controller, + }); + + @override + ChatFloatingActionButtonState createState() => + ChatFloatingActionButtonState(); +} + +class ChatFloatingActionButtonState extends State { + bool showPermissionsError = false; + StreamSubscription? _choreoSub; + + @override + void initState() { + final permissionsController = + widget.controller.pangeaController.permissionsController; + final itEnabled = permissionsController.isToolEnabled( + ToolSetting.interactiveTranslator, + widget.controller.room, + ); + final igcEnabled = permissionsController.isToolEnabled( + ToolSetting.interactiveGrammar, + widget.controller.room, + ); + showPermissionsError = !itEnabled || !igcEnabled; + debugPrint("showPermissionsError: $showPermissionsError"); + + if (showPermissionsError) { + Future.delayed( + const Duration(seconds: 5), + () { + if (mounted) setState(() => showPermissionsError = false); + }, + ); + } + + // Rebuild the widget each time there's an update from choreo (i.e., an error). + _choreoSub = + widget.controller.choreographer.stateListener.stream.listen((_) { + setState(() {}); + }); + + super.initState(); + } + + @override + void dispose() { + _choreoSub?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (widget.controller.selectedEvents.isNotEmpty) { + return const SizedBox.shrink(); + } + if (widget.controller.showScrollDownButton) { + return Padding( + padding: const EdgeInsets.only(bottom: 56.0), + child: FloatingActionButton( + onPressed: widget.controller.scrollDown, + heroTag: null, + mini: true, + child: const Icon(Icons.arrow_downward_outlined), + ), + ); + } + if (widget.controller.choreographer.errorService.error != null) { + return ChoreographerHasErrorButton( + widget.controller.pangeaController, + widget.controller.choreographer.errorService.error!, + ); + } + + return showPermissionsError + ? LanguagePermissionsButtons( + choreographer: widget.controller.choreographer, + roomID: widget.controller.roomId, + ) + : const SizedBox.shrink(); + } +} diff --git a/lib/pangea/widgets/chat/input_bar_wrapper.dart b/lib/pangea/widgets/chat/input_bar_wrapper.dart new file mode 100644 index 000000000..374f60a80 --- /dev/null +++ b/lib/pangea/widgets/chat/input_bar_wrapper.dart @@ -0,0 +1,82 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:fluffychat/pages/chat/input_bar.dart'; +import 'package:fluffychat/pangea/widgets/igc/pangea_text_controller.dart'; +import 'package:flutter/material.dart'; +import 'package:matrix/matrix.dart'; + +class InputBarWrapper extends StatefulWidget { + final Room room; + final int? minLines; + final int? maxLines; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final ValueChanged? onSubmitted; + final ValueChanged? onSubmitImage; + final FocusNode? focusNode; + final PangeaTextController? controller; + final InputDecoration? decoration; + final ValueChanged? onChanged; + final bool? autofocus; + final bool readOnly; + + const InputBarWrapper({ + required this.room, + this.minLines, + this.maxLines, + this.keyboardType, + this.onSubmitted, + this.onSubmitImage, + this.focusNode, + this.controller, + this.decoration, + this.onChanged, + this.autofocus, + this.textInputAction, + this.readOnly = false, + super.key, + }); + + @override + State createState() => InputBarWrapperState(); +} + +class InputBarWrapperState extends State { + StreamSubscription? _choreoSub; + + @override + void initState() { + // Rebuild the widget each time there's an update from choreo + _choreoSub = + widget.controller?.choreographer.stateListener.stream.listen((_) { + setState(() {}); + }); + super.initState(); + } + + @override + void dispose() { + _choreoSub?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return InputBar( + room: widget.room, + minLines: widget.minLines, + maxLines: widget.maxLines, + keyboardType: widget.keyboardType, + onSubmitted: widget.onSubmitted, + onSubmitImage: widget.onSubmitImage, + focusNode: widget.focusNode, + controller: widget.controller, + decoration: widget.decoration, + onChanged: widget.onChanged, + autofocus: widget.autofocus, + textInputAction: widget.textInputAction, + readOnly: widget.readOnly, + ); + } +} diff --git a/lib/pangea/widgets/chat/message_actions.dart b/lib/pangea/widgets/chat/message_actions.dart deleted file mode 100644 index 05731f234..000000000 --- a/lib/pangea/widgets/chat/message_actions.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:fluffychat/pages/chat/chat.dart'; -import 'package:fluffychat/pangea/widgets/chat/text_to_speech_button.dart'; -import 'package:flutter/material.dart'; - -class PangeaMessageActions extends StatelessWidget { - final ChatController chatController; - - const PangeaMessageActions({super.key, required this.chatController}); - - @override - Widget build(BuildContext context) { - return chatController.selectedEvents.length == 1 - ? Row( - children: [ - // LanguageToggleSwitch(controller: chatController), - TextToSpeechButton( - controller: chatController, - selectedEvent: chatController.selectedEvents.first, - ), - // IconButton( - // icon: Icon(Icons.mic), - // onPressed: chatController.onMicTap, - // ), - // Add more IconButton widgets here - ], - ) - : const SizedBox(); - } -} diff --git a/lib/pangea/widgets/chat/text_to_speech_button.dart b/lib/pangea/widgets/chat/text_to_speech_button.dart deleted file mode 100644 index 6e9e8e443..000000000 --- a/lib/pangea/widgets/chat/text_to_speech_button.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'dart:developer'; - -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/pages/chat/chat.dart'; -import 'package:fluffychat/pages/chat/events/audio_player.dart'; -import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.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'; -import 'package:just_audio/just_audio.dart'; -import 'package:matrix/matrix.dart'; - -class TextToSpeechButton extends StatefulWidget { - final ChatController controller; - final Event selectedEvent; - - const TextToSpeechButton({ - super.key, - required this.controller, - required this.selectedEvent, - }); - - @override - _TextToSpeechButtonState createState() => _TextToSpeechButtonState(); -} - -class _TextToSpeechButtonState extends State { - final AudioPlayer _audioPlayer = AudioPlayer(); - late PangeaMessageEvent _pangeaMessageEvent; - bool _isLoading = false; - - @override - void dispose() { - _audioPlayer.dispose(); - super.dispose(); - } - - @override - void initState() { - super.initState(); - _pangeaMessageEvent = PangeaMessageEvent( - event: widget.selectedEvent, - timeline: widget.controller.timeline!, - ownMessage: - widget.selectedEvent.senderId == Matrix.of(context).client.userID, - ); - } - - Event? get localAudioEvent => - langCode != null && text != null && text!.isNotEmpty - ? _pangeaMessageEvent.getTextToSpeechLocal(langCode!, text!) - : null; - - String? get langCode => - widget.controller.choreographer.messageOptions.selectedDisplayLang - ?.langCode ?? - widget.controller.choreographer.l2LangCode; - - String? get text => langCode != null - ? _pangeaMessageEvent.representationByLanguage(langCode!)?.text - : null; - - Future _getAudio() async { - try { - if (!mounted) return; - if (text == null || text!.isEmpty) return; - if (langCode == null || langCode!.isEmpty) return; - - setState(() => _isLoading = true); - await _pangeaMessageEvent.getTextToSpeechGlobal(langCode!); - setState(() => _isLoading = false); - } catch (e) { - setState(() => _isLoading = false); - debugger(when: kDebugMode); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context)!.errorGettingAudio), - ), - ); - ErrorHandler.logError( - e: Exception(), - s: StackTrace.current, - m: 'text is null or empty in text_to_speech_button.dart', - data: {'selectedEvent': widget.selectedEvent, 'langCode': langCode}, - ); - } - } - - @override - Widget build(BuildContext context) { - if (_isLoading) { - return const Center(child: CircularProgressIndicator()); - } - - final playButton = InkWell( - borderRadius: BorderRadius.circular(64), - onTap: text == null || text!.isEmpty ? null : _getAudio, - child: Material( - color: AppConfig.primaryColor.withAlpha(64), - borderRadius: BorderRadius.circular(64), - child: const Icon( - // Change the icon based on some condition. If you have an audio player state, use it here. - Icons.play_arrow_outlined, - color: AppConfig.primaryColor, - ), - ), - ); - - return localAudioEvent == null - ? Opacity( - opacity: text == null || text!.isEmpty ? 0.5 : 1, - child: SizedBox( - width: 44, // Match the size of the button in AudioPlayerState - height: 36, - child: Padding( - //only left side of the button is padded to match the padding of the AudioPlayerState - padding: const EdgeInsets.only(left: 8), - child: playButton, - ), - ), - ) - : Container( - constraints: const BoxConstraints( - maxWidth: 250, - ), - child: Column( - children: [ - AudioPlayerWidget( - localAudioEvent!, - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - ], - ), - ); - } -} From c9e023e684a628fc51418ffdc24971dc2f2d50be Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 16 Jul 2024 15:28:56 -0400 Subject: [PATCH 2/4] rate limited builds for unread room badge, don't call to load chat counts until it's needed for the UI --- lib/pages/chat_list/space_view.dart | 20 +++++++++++++++++--- lib/widgets/unread_rooms_badge.dart | 9 ++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index b57e4bdd6..954a19c14 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -451,9 +451,22 @@ class _SpaceViewState extends State { // #Pangea Future loadChatCounts() async { - for (final Room room in Matrix.of(context).client.rooms) { - if (room.isSpace && !chatCounts.containsKey(room.id)) { - await loadHierarchy(null, room.id); + // if not in the call spaces view, don't load chat count yet + if (widget.controller.activeSpaceId != null) return; + + final List allSpaces = + Matrix.of(context).client.rooms.where((room) => room.isSpace).toList(); + + for (final Room space in allSpaces) { + // check if the space is visible in the all spaces list + final bool isRootSpace = !allSpaces.any( + (parentSpace) => + parentSpace.spaceChildren.any((child) => child.roomId == space.id), + ); + + // if it's visible, and it hasn't been loaded yet, load chat count + if (isRootSpace && !chatCounts.containsKey(space.id)) { + await loadHierarchy(null, space.id); } } } @@ -479,6 +492,7 @@ class _SpaceViewState extends State { event.isSpaceChildUpdate( widget.controller.activeSpaceId!, )) { + debugPrint("refresh on update"); await loadHierarchy(); } setState(() => refreshing = false); diff --git a/lib/widgets/unread_rooms_badge.dart b/lib/widgets/unread_rooms_badge.dart index 332fa42a1..9104b0f07 100644 --- a/lib/widgets/unread_rooms_badge.dart +++ b/lib/widgets/unread_rooms_badge.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; - import 'package:badges/badges.dart' as b; +import 'package:fluffychat/utils/stream_extension.dart'; +import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; import 'matrix.dart'; @@ -24,7 +24,10 @@ class UnreadRoomsBadge extends StatelessWidget { .client .onSync .stream - .where((syncUpdate) => syncUpdate.hasRoomUpdate), + .where((syncUpdate) => syncUpdate.hasRoomUpdate) + // #Pangea + .rateLimit(const Duration(seconds: 1)), + // Pangea# builder: (context, _) { // #Pangea // final unreadCount = Matrix.of(context) From 4f1445d975fb4c0e116eee8f733dbe623e1cca8c Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 17 Jul 2024 09:21:55 -0400 Subject: [PATCH 3/4] fixes for null check / disposed widget errors --- lib/pages/chat/chat.dart | 2 +- lib/pages/chat_list/space_view.dart | 33 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 8107993da..4f25d8a70 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -416,7 +416,7 @@ class ChatController extends State onInsert: onInsert, ); // #Pangea - if (visibleEvents.length < 10) { + if (visibleEvents.length < 10 && timeline != null) { int prevNumEvents = timeline!.events.length; await requestHistory(); int numRequests = 0; diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 954a19c14..e625289c5 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -130,19 +130,27 @@ class _SpaceViewState extends State { if (prevBatch != null) { response.rooms.insertAll(0, _lastResponse[activeSpaceId]?.rooms ?? []); } - setState(() { - _lastResponse[activeSpaceId] = response; - }); + // #Pangea + if (mounted) { + // Pangea# + setState(() { + _lastResponse[activeSpaceId] = response; + }); + } return _lastResponse[activeSpaceId]!; } catch (e) { - setState(() { - error = e; - }); + // #Pangea + if (mounted) { + // Pangea# + setState(() { + error = e; + }); + } rethrow; } finally { // #Pangea if (activeSpace != null) { - await setChatCount( + setChatCount( activeSpace, _lastResponse[activeSpaceId] ?? GetSpaceHierarchyResponse( @@ -150,10 +158,12 @@ class _SpaceViewState extends State { ), ); } - // Pangea# - setState(() { - loading = false; - }); + if (mounted) { + // Pangea# + setState(() { + loading = false; + }); + } } } @@ -499,6 +509,7 @@ class _SpaceViewState extends State { } bool includeSpaceChild(sc, matchingSpaceChildren) { + if (!mounted) return false; final bool isAnalyticsRoom = sc.roomType == PangeaRoomTypes.analytics; final bool isMember = [Membership.join, Membership.invite] .contains(Matrix.of(context).client.getRoomById(sc.roomId)?.membership); From 4adbb1b3357088bb8306dd2cfa3aa7df5f1b3b15 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 17 Jul 2024 09:27:58 -0400 Subject: [PATCH 4/4] commented out pangea room rules editor in new space and chat details view --- lib/pages/chat_details/chat_details_view.dart | 14 ++-- lib/pages/new_space/new_space_view.dart | 66 +++++++++---------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index a51304b39..8b496afab 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_capacity_button.dart'; -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_rules_editor.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; @@ -269,11 +268,14 @@ class ChatDetailsView extends StatelessWidget { // roomId: controller.roomId, // startOpen: false, // ), - if (room.pangeaRoomRules != null) - RoomRulesEditor( - roomId: controller.roomId, - startOpen: false, - ), + + // Commenting out pangea room rules for now + // if (room.pangeaRoomRules != null) + // RoomRulesEditor( + // roomId: controller.roomId, + // startOpen: false, + // ), + // if (!room.canChangeStateEvent(EventTypes.RoomTopic)) // ListTile( // title: Text( diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index 22751a787..9ef9c9849 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -1,12 +1,8 @@ import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart'; -import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_rules_editor.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -133,35 +129,39 @@ class NewSpaceView extends StatelessWidget { startOpen: true, spaceMode: true, ), - if (controller.rulesEditorKey.currentState != null) - RoomRulesEditor( - key: controller.rulesEditorKey, - roomId: null, - startOpen: false, - initialRules: controller.rulesEditorKey.currentState!.rules, - ), - if (controller.rulesEditorKey.currentState == null) - FutureBuilder( - future: Matrix.of(context).client.lastUpdatedRoomRules, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - return RoomRulesEditor( - key: controller.rulesEditorKey, - roomId: null, - startOpen: false, - initialRules: snapshot.data, - ); - } else { - return const Padding( - padding: EdgeInsets.all(16.0), - child: Center( - child: - CircularProgressIndicator.adaptive(strokeWidth: 2), - ), - ); - } - }, - ), + // Commenting out pangea room rules for now + // if (controller.rulesEditorKey.currentState != null) + // RoomRulesEditor( + // key: controller.rulesEditorKey, + // roomId: null, + // startOpen: false, + // initialRules: controller.rulesEditorKey.currentState!.rules, + // ), + + // Commenting out pangea room rules for now + // if (controller.rulesEditorKey.currentState == null) + // FutureBuilder( + // future: Matrix.of(context).client.lastUpdatedRoomRules, + // builder: (context, snapshot) { + // if (snapshot.connectionState == ConnectionState.done) { + // return RoomRulesEditor( + // key: controller.rulesEditorKey, + // roomId: null, + // startOpen: false, + // initialRules: snapshot.data, + // ); + // } else { + // return const Padding( + // padding: EdgeInsets.all(16.0), + // child: Center( + // child: + // CircularProgressIndicator.adaptive(strokeWidth: 2), + // ), + // ); + // } + // }, + // ), + // SwitchListTile.adaptive( // title: Text(L10n.of(context)!.spaceIsPublic), // value: controller.publicGroup,