From 0c7042b51cee9c9c1d46ef9e92a3463685396acf Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 23 Oct 2024 16:36:40 -0400 Subject: [PATCH 01/21] store num completed activities in memory instead of local cache --- .../practice_activity_record_controller.dart | 101 ++++++++---------- .../pangea_message_event.dart | 3 +- pubspec.yaml | 2 +- 3 files changed, 49 insertions(+), 57 deletions(-) diff --git a/lib/pangea/controllers/practice_activity_record_controller.dart b/lib/pangea/controllers/practice_activity_record_controller.dart index 45b036611..8ee52e696 100644 --- a/lib/pangea/controllers/practice_activity_record_controller.dart +++ b/lib/pangea/controllers/practice_activity_record_controller.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:collection'; import 'dart:developer'; -import 'package:fluffychat/pangea/constants/local.key.dart'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; @@ -26,66 +25,60 @@ class PracticeActivityRecordController { static const int maxStoredEvents = 100; static final Map _cache = {}; late final PangeaController _pangeaController; - Timer? _cacheClearTimer; - PracticeActivityRecordController(this._pangeaController) { - _initializeCacheClearing(); + PracticeActivityRecordController(this._pangeaController); + + int getCompletedActivityCount(String messageID) { + return _completedActivities[messageID] ?? 0; } - LinkedHashMap get completedActivities { - try { - final dynamic locallySaved = _pangeaController.pStoreService.read( - PLocalKey.completedActivities, - ); - if (locallySaved == null) return LinkedHashMap(); - try { - final LinkedHashMap cache = - LinkedHashMap.from(locallySaved); - return cache; - } catch (err) { - _pangeaController.pStoreService.delete( - PLocalKey.completedActivities, - ); - return LinkedHashMap(); - } - } catch (exception, stackTrace) { - ErrorHandler.logError( - e: PangeaWarningError( - "Failed to get completed activities from cache: $exception", - ), - s: stackTrace, - m: 'Failed to get completed activities from cache', - ); - return LinkedHashMap(); - } - } + final LinkedHashMap _completedActivities = + LinkedHashMap(); + + // LinkedHashMap get _completedActivities { + // try { + // final dynamic locallySaved = _pangeaController.pStoreService.read( + // PLocalKey.completedActivities, + // ); + // if (locallySaved == null) return LinkedHashMap(); + // try { + // final LinkedHashMap cache = + // LinkedHashMap.from(locallySaved); + // return cache; + // } catch (err) { + // _pangeaController.pStoreService.delete( + // PLocalKey.completedActivities, + // ); + // return LinkedHashMap(); + // } + // } catch (exception, stackTrace) { + // ErrorHandler.logError( + // e: PangeaWarningError( + // "Failed to get completed activities from cache: $exception", + // ), + // s: stackTrace, + // m: 'Failed to get completed activities from cache', + // ); + // return LinkedHashMap(); + // } + // } Future completeActivity(String messageID) async { - final LinkedHashMap currentCache = completedActivities; - final numCompleted = currentCache[messageID] ?? 0; - currentCache[messageID] = numCompleted + 1; + final numCompleted = _completedActivities[messageID] ?? 0; + _completedActivities[messageID] = numCompleted + 1; + // final LinkedHashMap currentCache = _completedActivities; + // final numCompleted = currentCache[messageID] ?? 0; + // currentCache[messageID] = numCompleted + 1; - if (currentCache.length > maxStoredEvents) { - currentCache.remove(currentCache.keys.first); - } + // if (currentCache.length > maxStoredEvents) { + // currentCache.remove(currentCache.keys.first); + // } - await _pangeaController.pStoreService.save( - PLocalKey.completedActivities, - currentCache, - ); - } - - void _initializeCacheClearing() { - const duration = Duration(minutes: 2); - _cacheClearTimer = Timer.periodic(duration, (Timer t) => _clearCache()); - } - - void _clearCache() { - _cache.clear(); - } - - void dispose() { - _cacheClearTimer?.cancel(); + // await _pangeaController.pStoreService.save( + // PLocalKey.completedActivities, + // currentCache, + // ); + debugPrint("completed activities is now: $_completedActivities"); } /// Sends a practice activity record to the server and returns the corresponding event. diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index 85dfb8760..39d1bd314 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -540,8 +540,7 @@ class PangeaMessageEvent { int get numberOfActivitiesCompleted { return MatrixState.pangeaController.activityRecordController - .completedActivities[eventId] ?? - 0; + .getCompletedActivityCount(eventId); } String? get l2Code => diff --git a/pubspec.yaml b/pubspec.yaml index 43430c50c..cdb13d908 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.5+3545 +version: 1.21.6+3546 environment: sdk: ">=3.0.0 <4.0.0" From 9b97895a9d02e8b8471a70e893191e722aa56d0e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 08:50:41 -0400 Subject: [PATCH 02/21] merge main into toolbar-min-dimensions --- lib/config/app_config.dart | 2 ++ .../widgets/chat/message_audio_card.dart | 2 -- .../chat/message_selection_overlay.dart | 4 +-- lib/pangea/widgets/chat/message_toolbar.dart | 3 ++ .../chat/message_translation_card.dart | 7 +++- .../chat/message_unsubscribed_card.dart | 4 +-- .../toolbar_content_loading_indicator.dart | 32 +++++++++++-------- .../practice_activity_card.dart | 18 +++++------ 8 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 5a0706fe8..b044da3ee 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -23,6 +23,8 @@ abstract class AppConfig { static const bool allowOtherHomeservers = true; static const bool enableRegistration = true; static const double toolbarMaxHeight = 300.0; + static const double toolbarMinHeight = 70.0; + static const double toolbarMinWidth = 350.0; // #Pangea // static const Color primaryColor = Color(0xFF5625BA); // static const Color primaryColorLight = Color(0xFFCCBDEA); diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index 7a003a01c..133e16b1e 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -8,7 +8,6 @@ import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dar import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart'; @@ -190,7 +189,6 @@ class MessageAudioCardState extends State { children: [ Container( padding: const EdgeInsets.all(8), - constraints: const BoxConstraints(minHeight: minCardHeight), alignment: Alignment.center, child: _isLoading ? const ToolbarContentLoadingIndicator() diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index 48cdfbd47..5cf9e70b5 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -443,9 +443,7 @@ class MessageOverlayController extends State } final overlayMessage = Container( - constraints: BoxConstraints( - maxWidth: maxWidth, - ), + constraints: BoxConstraints(maxWidth: maxWidth), child: Material( type: MaterialType.transparency, child: Column( diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index bcffbdf2a..cf4192691 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -114,6 +114,9 @@ class MessageToolbar extends StatelessWidget { ), constraints: const BoxConstraints( maxHeight: AppConfig.toolbarMaxHeight, + minWidth: AppConfig.toolbarMinWidth, + minHeight: AppConfig.toolbarMinHeight, + // maxWidth is set by MessageSelectionOverlay ), child: SingleChildScrollView( child: AnimatedSize( diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 4d8bad28d..f37238a6b 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -134,26 +134,31 @@ class MessageTranslationCardState extends State { } return Padding( - padding: const EdgeInsets.all(8), + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), child: Row( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ _fetchingTranslation ? const ToolbarContentLoadingIndicator() : Flexible( child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, children: [ widget.selection != null ? selectionTranslation != null ? Text( selectionTranslation!, style: BotStyle.text(context), + textAlign: TextAlign.center, ) : const ToolbarContentLoadingIndicator() : repEvent != null ? Text( repEvent!.text, style: BotStyle.text(context), + textAlign: TextAlign.center, ) : const ToolbarContentLoadingIndicator(), if (notGoingToTranslate && widget.selection == null) diff --git a/lib/pangea/widgets/chat/message_unsubscribed_card.dart b/lib/pangea/widgets/chat/message_unsubscribed_card.dart index 5d91099b1..99a08456e 100644 --- a/lib/pangea/widgets/chat/message_unsubscribed_card.dart +++ b/lib/pangea/widgets/chat/message_unsubscribed_card.dart @@ -18,8 +18,8 @@ class MessageUnsubscribedCard extends StatelessWidget { final bool inTrialWindow = MatrixState.pangeaController.userController.inTrialWindow; - return Container( - padding: const EdgeInsets.all(8), + return Padding( + padding: const EdgeInsets.all(16), child: Column( children: [ Text( diff --git a/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart b/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart index f61496013..28f15c1a9 100644 --- a/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart +++ b/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart @@ -1,4 +1,3 @@ -import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:flutter/material.dart'; class ToolbarContentLoadingIndicator extends StatelessWidget { @@ -8,20 +7,25 @@ class ToolbarContentLoadingIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8), - constraints: const BoxConstraints(minHeight: minCardHeight), - alignment: Alignment.center, - child: Center( - child: SizedBox( - height: 14, - width: 14, - child: CircularProgressIndicator( - strokeWidth: 2.0, - color: Theme.of(context).colorScheme.primary, - ), + return Column( + // mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 14, + width: 14, + child: CircularProgressIndicator( + strokeWidth: 2.0, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], ), - ), + ], ); } } diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index 7a2af7fc9..13d22890f 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -13,9 +13,9 @@ import 'package:fluffychat/pangea/utils/bot_style.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/animations/gain_points.dart'; import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; +import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/content_issue_button.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/multiple_choice_activity.dart'; -import 'package:fluffychat/pangea/widgets/practice_activity/no_more_practice_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/target_tokens_controller.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; @@ -321,11 +321,13 @@ class PracticeActivityCardState extends State { @override Widget build(BuildContext context) { - if (!fetchingActivity && currentActivity == null) { - return GamifiedTextWidget( - userMessage: L10n.of(context)!.noActivitiesFound, - ); - } + // if (!fetchingActivity && currentActivity == null) { + // return GamifiedTextWidget( + // userMessage: L10n.of(context)!.noActivitiesFound, + // ); + // } + + return const ToolbarContentLoadingIndicator(); return Stack( alignment: Alignment.center, @@ -340,10 +342,6 @@ class PracticeActivityCardState extends State { ), // Conditionally show the darkening and progress indicator based on the loading state if (!savoringTheJoy && fetchingActivity) ...[ - // Semi-transparent overlay - Container( - color: Colors.black.withOpacity(0.5), // Darkening effect - ), // Circular progress indicator in the center const Center( child: CircularProgressIndicator(), From 59682599a5a6a3b5d3109cd44d1c10a512cae369 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 10:47:02 -0400 Subject: [PATCH 03/21] turn off choice array animation --- .../choreographer/widgets/choice_array.dart | 150 +++++++++--------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index 32395099e..549665064 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -1,5 +1,4 @@ import 'dart:developer'; -import 'dart:math'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; @@ -213,98 +212,99 @@ class ChoiceAnimationWidgetState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _animation; - AnimationState animationState = AnimationState.ready; + // AnimationState animationState = AnimationState.ready; @override void initState() { super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 300), - vsync: this, - ); + // _controller = AnimationController( + // duration: const Duration(milliseconds: 300), + // vsync: this, + // ); - _animation = widget.isGold - ? Tween(begin: 1.0, end: 1.2).animate(_controller) - : TweenSequence([ - TweenSequenceItem( - tween: Tween(begin: 0, end: -8 * pi / 180), - weight: 1.0, - ), - TweenSequenceItem( - tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), - weight: 2.0, - ), - TweenSequenceItem( - tween: Tween(begin: 16 * pi / 180, end: 0), - weight: 1.0, - ), - ]).animate(_controller); + // _animation = widget.isGold + // ? Tween(begin: 1.0, end: 1.2).animate(_controller) + // : TweenSequence([ + // TweenSequenceItem( + // tween: Tween(begin: 0, end: -8 * pi / 180), + // weight: 1.0, + // ), + // TweenSequenceItem( + // tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), + // weight: 2.0, + // ), + // TweenSequenceItem( + // tween: Tween(begin: 16 * pi / 180, end: 0), + // weight: 1.0, + // ), + // ]).animate(_controller); widget.enableInteraction(); - if (widget.selected && animationState == AnimationState.ready) { - widget.disableInteraction(); - _controller.forward(); - setState(() { - animationState = AnimationState.forward; - }); - } - _controller.addStatusListener((status) { - if (status == AnimationStatus.completed && - animationState == AnimationState.forward) { - _controller.reverse(); - setState(() { - animationState = AnimationState.reverse; - }); - } - if (status == AnimationStatus.dismissed && - animationState == AnimationState.reverse) { - widget.enableInteraction(); - setState(() { - animationState = AnimationState.finished; - }); - } - }); + // if (widget.selected && animationState == AnimationState.ready) { + // widget.disableInteraction(); + // _controller.forward(); + // setState(() { + // animationState = AnimationState.forward; + // }); + // } + // _controller.addStatusListener((status) { + // if (status == AnimationStatus.completed && + // animationState == AnimationState.forward) { + // _controller.reverse(); + // setState(() { + // animationState = AnimationState.reverse; + // }); + // } + // if (status == AnimationStatus.dismissed && + // animationState == AnimationState.reverse) { + // widget.enableInteraction(); + // setState(() { + // animationState = AnimationState.finished; + // }); + // } + // }); } @override void didUpdateWidget(ChoiceAnimationWidget oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.selected && animationState == AnimationState.ready) { - widget.disableInteraction(); - _controller.forward(); - setState(() { - animationState = AnimationState.forward; - }); - } + // if (widget.selected && animationState == AnimationState.ready) { + // widget.disableInteraction(); + // _controller.forward(); + // setState(() { + // animationState = AnimationState.forward; + // }); + // } } @override Widget build(BuildContext context) { - return widget.isGold - ? AnimatedBuilder( - key: UniqueKey(), - animation: _animation, - builder: (context, child) { - return Transform.scale( - scale: _animation.value, - child: child, - ); - }, - child: widget.child, - ) - : AnimatedBuilder( - key: UniqueKey(), - animation: _animation, - builder: (context, child) { - return Transform.rotate( - angle: _animation.value, - child: child, - ); - }, - child: widget.child, - ); + return widget.child; + // widget.isGold + // ? AnimatedBuilder( + // key: UniqueKey(), + // animation: _animation, + // builder: (context, child) { + // return Transform.scale( + // scale: _animation.value, + // child: child, + // ); + // }, + // child: widget.child, + // ) + // : AnimatedBuilder( + // key: UniqueKey(), + // animation: _animation, + // builder: (context, child) { + // return Transform.rotate( + // angle: _animation.value, + // child: child, + // ); + // }, + // child: widget.child, + // ); } @override From 612296d341ef01c7bcd2e0e2e091a4aaa9a3570a Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 10:47:31 -0400 Subject: [PATCH 04/21] bump version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index cdb13d908..98b846ae7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.6+3546 +version: 1.21.7+3547 environment: sdk: ">=3.0.0 <4.0.0" From f141680cc73ca672a08c94fb6bc29242a81db93b Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:07:05 -0400 Subject: [PATCH 05/21] comment out some references to myAnalytics stream --- lib/pangea/utils/logout.dart | 4 +-- .../multiple_choice_activity.dart | 26 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/pangea/utils/logout.dart b/lib/pangea/utils/logout.dart index e2bdce074..c94cb8909 100644 --- a/lib/pangea/utils/logout.dart +++ b/lib/pangea/utils/logout.dart @@ -20,8 +20,8 @@ void pLogoutAction(BuildContext context, {bool? isDestructiveAction}) async { final matrix = Matrix.of(context); // before wiping out locally cached construct data, save it to the server - await MatrixState.pangeaController.myAnalytics - .sendLocalAnalyticsToAnalyticsRoom(); + // await MatrixState.pangeaController.myAnalytics + // .sendLocalAnalyticsToAnalyticsRoom(); await showFutureLoadingDialog( context: context, diff --git a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart index ee892837b..3e8a9f126 100644 --- a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart +++ b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart @@ -2,13 +2,11 @@ import 'dart:developer'; import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/choreographer/widgets/choice_array.dart'; -import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart'; import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_record_model.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/practice_activity_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/word_audio_button.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -68,18 +66,18 @@ class MultipleChoiceActivityState extends State { } // #freeze-activity - MatrixState.pangeaController.myAnalytics.setState( - AnalyticsStream( - // note - this maybe should be the activity event id - eventId: - widget.practiceCardController.widget.pangeaMessageEvent.eventId, - roomId: widget.practiceCardController.widget.pangeaMessageEvent.room.id, - constructs: currentRecordModel!.latestResponse!.toUses( - widget.practiceCardController.currentActivity!, - widget.practiceCardController.metadata, - ), - ), - ); + // MatrixState.pangeaController.myAnalytics.setState( + // AnalyticsStream( + // // note - this maybe should be the activity event id + // eventId: + // widget.practiceCardController.widget.pangeaMessageEvent.eventId, + // roomId: widget.practiceCardController.widget.pangeaMessageEvent.room.id, + // constructs: currentRecordModel!.latestResponse!.toUses( + // widget.practiceCardController.currentActivity!, + // widget.practiceCardController.metadata, + // ), + // ), + // ); // If the selected choice is correct, send the record and get the next activity if (widget.currentActivity.content.isCorrect(value, index)) { From 70d598c7b2cadfbab1f334b6c388c37f3182cf4f Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:07:25 -0400 Subject: [PATCH 06/21] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 98b846ae7..444472501 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.7+3547 +version: 1.21.8+3548 environment: sdk: ">=3.0.0 <4.0.0" From 4c51bb15f63313f424bf9e9366535b6d540a144e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:22:04 -0400 Subject: [PATCH 07/21] turn back on analytics stream call in logout --- lib/pangea/utils/logout.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pangea/utils/logout.dart b/lib/pangea/utils/logout.dart index c94cb8909..e2bdce074 100644 --- a/lib/pangea/utils/logout.dart +++ b/lib/pangea/utils/logout.dart @@ -20,8 +20,8 @@ void pLogoutAction(BuildContext context, {bool? isDestructiveAction}) async { final matrix = Matrix.of(context); // before wiping out locally cached construct data, save it to the server - // await MatrixState.pangeaController.myAnalytics - // .sendLocalAnalyticsToAnalyticsRoom(); + await MatrixState.pangeaController.myAnalytics + .sendLocalAnalyticsToAnalyticsRoom(); await showFutureLoadingDialog( context: context, From 636fb150e8bac8e7b9f19b553a9432808a600fec Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:22:21 -0400 Subject: [PATCH 08/21] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 444472501..0a45647dc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.8+3548 +version: 1.21.9+3549 environment: sdk: ">=3.0.0 <4.0.0" From 1944c19c50f1f6356a0f71db48f81051e98eaca6 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:28:20 -0400 Subject: [PATCH 09/21] Revert "when inviting tachers to analytics room, request all particpants to ensure teacher isn't already a member" This reverts commit bc1dfc1e0e8f017c9c4032afcd4b18112042d35b. --- .../pangea_room_extension/room_analytics_extension.dart | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/pangea/extensions/pangea_room_extension/room_analytics_extension.dart b/lib/pangea/extensions/pangea_room_extension/room_analytics_extension.dart index b44c40ece..73371b080 100644 --- a/lib/pangea/extensions/pangea_room_extension/room_analytics_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/room_analytics_extension.dart @@ -99,7 +99,7 @@ extension AnalyticsRoomExtension on Room { await analyticsRoom.requestParticipants(); } - final List participants = await analyticsRoom.requestParticipants(); + final List participants = analyticsRoom.getParticipants(); final List uninvitedTeachers = teachersLocal .where((teacher) => !participants.contains(teacher)) .toList(); @@ -110,12 +110,8 @@ extension AnalyticsRoomExtension on Room { (teacher) => analyticsRoom.invite(teacher.id).catchError((err, s) { ErrorHandler.logError( e: err, - m: "Failed to invite teacher to analytics room", + m: "Failed to invite teacher ${teacher.id} to analytics room ${analyticsRoom.id}", s: s, - data: { - "teacherId": teacher.id, - "analyticsRoomId": analyticsRoom.id, - }, ); }), ), From f6bd07400098c4a0fd9205d6ae41926af9c0ccb2 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:29:02 -0400 Subject: [PATCH 10/21] revert change to getting room participants --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 0a45647dc..dba848cf1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.9+3549 +version: 1.22.0+3550 environment: sdk: ">=3.0.0 <4.0.0" From 5b232cea69df588ca3dbec732aad4378bb8d7bc4 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:37:24 -0400 Subject: [PATCH 11/21] turn back on setState on analytics data --- .../multiple_choice_activity.dart | 26 ++++++++++--------- pubspec.yaml | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart index 3e8a9f126..ee892837b 100644 --- a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart +++ b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart @@ -2,11 +2,13 @@ import 'dart:developer'; import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/choreographer/widgets/choice_array.dart'; +import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart'; import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_record_model.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/practice_activity_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/word_audio_button.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -66,18 +68,18 @@ class MultipleChoiceActivityState extends State { } // #freeze-activity - // MatrixState.pangeaController.myAnalytics.setState( - // AnalyticsStream( - // // note - this maybe should be the activity event id - // eventId: - // widget.practiceCardController.widget.pangeaMessageEvent.eventId, - // roomId: widget.practiceCardController.widget.pangeaMessageEvent.room.id, - // constructs: currentRecordModel!.latestResponse!.toUses( - // widget.practiceCardController.currentActivity!, - // widget.practiceCardController.metadata, - // ), - // ), - // ); + MatrixState.pangeaController.myAnalytics.setState( + AnalyticsStream( + // note - this maybe should be the activity event id + eventId: + widget.practiceCardController.widget.pangeaMessageEvent.eventId, + roomId: widget.practiceCardController.widget.pangeaMessageEvent.room.id, + constructs: currentRecordModel!.latestResponse!.toUses( + widget.practiceCardController.currentActivity!, + widget.practiceCardController.metadata, + ), + ), + ); // If the selected choice is correct, send the record and get the next activity if (widget.currentActivity.content.isCorrect(value, index)) { diff --git a/pubspec.yaml b/pubspec.yaml index dba848cf1..f1b17f029 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.22.0+3550 +version: 1.22.1+3551 environment: sdk: ">=3.0.0 <4.0.0" From 63cd77baf49819322ade33aa646bfd9665a192bd Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 11:58:11 -0400 Subject: [PATCH 12/21] Revert "turn off choice array animation" This reverts commit 59682599a5a6a3b5d3109cd44d1c10a512cae369. --- .../choreographer/widgets/choice_array.dart | 150 +++++++++--------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index 549665064..32395099e 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -1,4 +1,5 @@ import 'dart:developer'; +import 'dart:math'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; @@ -212,99 +213,98 @@ class ChoiceAnimationWidgetState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _animation; - // AnimationState animationState = AnimationState.ready; + AnimationState animationState = AnimationState.ready; @override void initState() { super.initState(); - // _controller = AnimationController( - // duration: const Duration(milliseconds: 300), - // vsync: this, - // ); + _controller = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); - // _animation = widget.isGold - // ? Tween(begin: 1.0, end: 1.2).animate(_controller) - // : TweenSequence([ - // TweenSequenceItem( - // tween: Tween(begin: 0, end: -8 * pi / 180), - // weight: 1.0, - // ), - // TweenSequenceItem( - // tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), - // weight: 2.0, - // ), - // TweenSequenceItem( - // tween: Tween(begin: 16 * pi / 180, end: 0), - // weight: 1.0, - // ), - // ]).animate(_controller); + _animation = widget.isGold + ? Tween(begin: 1.0, end: 1.2).animate(_controller) + : TweenSequence([ + TweenSequenceItem( + tween: Tween(begin: 0, end: -8 * pi / 180), + weight: 1.0, + ), + TweenSequenceItem( + tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), + weight: 2.0, + ), + TweenSequenceItem( + tween: Tween(begin: 16 * pi / 180, end: 0), + weight: 1.0, + ), + ]).animate(_controller); widget.enableInteraction(); - // if (widget.selected && animationState == AnimationState.ready) { - // widget.disableInteraction(); - // _controller.forward(); - // setState(() { - // animationState = AnimationState.forward; - // }); - // } - // _controller.addStatusListener((status) { - // if (status == AnimationStatus.completed && - // animationState == AnimationState.forward) { - // _controller.reverse(); - // setState(() { - // animationState = AnimationState.reverse; - // }); - // } - // if (status == AnimationStatus.dismissed && - // animationState == AnimationState.reverse) { - // widget.enableInteraction(); - // setState(() { - // animationState = AnimationState.finished; - // }); - // } - // }); + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); + _controller.forward(); + setState(() { + animationState = AnimationState.forward; + }); + } + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed && + animationState == AnimationState.forward) { + _controller.reverse(); + setState(() { + animationState = AnimationState.reverse; + }); + } + if (status == AnimationStatus.dismissed && + animationState == AnimationState.reverse) { + widget.enableInteraction(); + setState(() { + animationState = AnimationState.finished; + }); + } + }); } @override void didUpdateWidget(ChoiceAnimationWidget oldWidget) { super.didUpdateWidget(oldWidget); - // if (widget.selected && animationState == AnimationState.ready) { - // widget.disableInteraction(); - // _controller.forward(); - // setState(() { - // animationState = AnimationState.forward; - // }); - // } + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); + _controller.forward(); + setState(() { + animationState = AnimationState.forward; + }); + } } @override Widget build(BuildContext context) { - return widget.child; - // widget.isGold - // ? AnimatedBuilder( - // key: UniqueKey(), - // animation: _animation, - // builder: (context, child) { - // return Transform.scale( - // scale: _animation.value, - // child: child, - // ); - // }, - // child: widget.child, - // ) - // : AnimatedBuilder( - // key: UniqueKey(), - // animation: _animation, - // builder: (context, child) { - // return Transform.rotate( - // angle: _animation.value, - // child: child, - // ); - // }, - // child: widget.child, - // ); + return widget.isGold + ? AnimatedBuilder( + key: UniqueKey(), + animation: _animation, + builder: (context, child) { + return Transform.scale( + scale: _animation.value, + child: child, + ); + }, + child: widget.child, + ) + : AnimatedBuilder( + key: UniqueKey(), + animation: _animation, + builder: (context, child) { + return Transform.rotate( + angle: _animation.value, + child: child, + ); + }, + child: widget.child, + ); } @override From 6052e1618981b7fcc0f87f2412331df36fcbe75c Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 12:01:05 -0400 Subject: [PATCH 13/21] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f1b17f029..10b124acf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.22.1+3551 +version: 1.22.2+3552 environment: sdk: ">=3.0.0 <4.0.0" From 23b6dd08b55f3409b94066b250c0195f620d39ce Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 12:19:00 -0400 Subject: [PATCH 14/21] when sending analytics to the server at logout, don't update the getAnalytics stream afterwards --- .../controllers/get_analytics_controller.dart | 7 ++--- .../controllers/my_analytics_controller.dart | 26 +++++++++++++++---- lib/pangea/utils/logout.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/pangea/controllers/get_analytics_controller.dart b/lib/pangea/controllers/get_analytics_controller.dart index 03cb2d60b..66cf39501 100644 --- a/lib/pangea/controllers/get_analytics_controller.dart +++ b/lib/pangea/controllers/get_analytics_controller.dart @@ -22,7 +22,7 @@ import 'package:sentry_flutter/sentry_flutter.dart'; class GetAnalyticsController { late PangeaController _pangeaController; final List _cache = []; - StreamSubscription? _analyticsUpdateSubscription; + StreamSubscription? _analyticsUpdateSubscription; CachedStreamController> analyticsStream = CachedStreamController>(); @@ -87,8 +87,9 @@ class GetAnalyticsController { prevXP = null; } - Future onAnalyticsUpdate(AnalyticsUpdateType type) async { - if (type == AnalyticsUpdateType.server) { + Future onAnalyticsUpdate(AnalyticsUpdate analyticsUpdate) async { + if (analyticsUpdate.isLogout) return; + if (analyticsUpdate.type == AnalyticsUpdateType.server) { await getConstructs(forceUpdate: true); } updateAnalyticsStream(); diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index 77e6caf27..6ffa1ef31 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -21,8 +21,8 @@ enum AnalyticsUpdateType { server, local } /// 2) constructs used by the user, both in sending messages and doing practice activities class MyAnalyticsController extends BaseController { late PangeaController _pangeaController; - CachedStreamController analyticsUpdateStream = - CachedStreamController(); + CachedStreamController analyticsUpdateStream = + CachedStreamController(); StreamSubscription? _analyticsStream; Timer? _updateTimer; @@ -237,7 +237,9 @@ class MyAnalyticsController extends BaseController { final int newLevel = _pangeaController.analytics.level; newLevel > prevLevel ? sendLocalAnalyticsToAnalyticsRoom() - : analyticsUpdateStream.add(AnalyticsUpdateType.local); + : analyticsUpdateStream.add( + AnalyticsUpdate(AnalyticsUpdateType.local), + ); } /// Clears the local cache of recently sent constructs. Called before updating analytics @@ -281,7 +283,9 @@ class MyAnalyticsController extends BaseController { /// for the completion of the previous update and returns. Otherwise, it creates a new [_updateCompleter] and /// proceeds with the update process. If the update is successful, it clears any messages that were received /// since the last update and notifies the [analyticsUpdateStream]. - Future sendLocalAnalyticsToAnalyticsRoom() async { + Future sendLocalAnalyticsToAnalyticsRoom({ + onLogout = false, + }) async { if (_pangeaController.matrixState.client.userID == null) return; if (!(_updateCompleter?.isCompleted ?? true)) { await _updateCompleter!.future; @@ -293,7 +297,12 @@ class MyAnalyticsController extends BaseController { clearMessagesSinceUpdate(); lastUpdated = DateTime.now(); - analyticsUpdateStream.add(AnalyticsUpdateType.server); + analyticsUpdateStream.add( + AnalyticsUpdate( + AnalyticsUpdateType.server, + isLogout: onLogout, + ), + ); } catch (err, s) { ErrorHandler.logError( e: err, @@ -340,3 +349,10 @@ class AnalyticsStream { required this.constructs, }); } + +class AnalyticsUpdate { + final AnalyticsUpdateType type; + final bool isLogout; + + AnalyticsUpdate(this.type, {this.isLogout = false}); +} diff --git a/lib/pangea/utils/logout.dart b/lib/pangea/utils/logout.dart index e2bdce074..def632828 100644 --- a/lib/pangea/utils/logout.dart +++ b/lib/pangea/utils/logout.dart @@ -21,7 +21,7 @@ void pLogoutAction(BuildContext context, {bool? isDestructiveAction}) async { // before wiping out locally cached construct data, save it to the server await MatrixState.pangeaController.myAnalytics - .sendLocalAnalyticsToAnalyticsRoom(); + .sendLocalAnalyticsToAnalyticsRoom(onLogout: true); await showFutureLoadingDialog( context: context, diff --git a/pubspec.yaml b/pubspec.yaml index 98b846ae7..076a0ed49 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.7+3547 +version: 1.22.3+3553 environment: sdk: ">=3.0.0 <4.0.0" From 00d6277bc6cc1cbf4eb7d357f53d5a6ecdf3f3e1 Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Thu, 24 Oct 2024 12:48:51 -0400 Subject: [PATCH 15/21] some code cleanup and comments --- lib/pangea/controllers/base_controller.dart | 8 ++++---- lib/pangea/controllers/user_controller.dart | 7 +++++++ lib/pangea/enum/construct_use_type_enum.dart | 9 +++++++++ lib/pangea/models/analytics/constructs_model.dart | 5 +---- .../message_activity_request.dart | 7 +------ 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/pangea/controllers/base_controller.dart b/lib/pangea/controllers/base_controller.dart index 69939e50a..51a66dd00 100644 --- a/lib/pangea/controllers/base_controller.dart +++ b/lib/pangea/controllers/base_controller.dart @@ -1,18 +1,18 @@ import 'dart:async'; class BaseController { - final StreamController stateListener = StreamController(); + final StreamController _stateListener = StreamController(); late Stream stateStream; BaseController() { - stateStream = stateListener.stream.asBroadcastStream(); + stateStream = _stateListener.stream.asBroadcastStream(); } dispose() { - stateListener.close(); + _stateListener.close(); } setState(T data) { - stateListener.add(data); + _stateListener.add(data); } } diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index 5ee8672ff..ca7e2869a 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -121,19 +121,26 @@ class UserController extends BaseController { /// Initializes the user's profile by waiting for account data to load, reading in account /// data to profile, and migrating from the pangea profile if the account data is not present. Future _initialize() async { + // wait for account data to load + // as long as it's not null, then this we've already migrated the profile await _pangeaController.matrixState.client.waitForAccountData(); if (profile.userSettings.dateOfBirth != null) { return; } + // we used to store the user's profile in the pangea server + // we now store it in the matrix account data final PangeaProfileResponse? resp = await PUserRepo.fetchPangeaUserInfo( userID: userId!, matrixAccessToken: _matrixAccessToken!, ); + + // if it's null, we don't have a profile in the pangea server if (resp?.profile == null) { return; } + // if we have a profile in the pangea server, we need to migrate it to the matrix account data final userSetting = UserSettings.fromJson(resp!.profile.toJson()); final newProfile = Profile(userSettings: userSetting); await newProfile.saveProfileData(waitForDataInSync: true); diff --git a/lib/pangea/enum/construct_use_type_enum.dart b/lib/pangea/enum/construct_use_type_enum.dart index 1f1d37dfe..6ced270b7 100644 --- a/lib/pangea/enum/construct_use_type_enum.dart +++ b/lib/pangea/enum/construct_use_type_enum.dart @@ -125,3 +125,12 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum { } } } + +class ConstructUseTypeUtil { + static ConstructUseTypeEnum fromString(String value) { + return ConstructUseTypeEnum.values.firstWhere( + (e) => e.string == value, + orElse: () => ConstructUseTypeEnum.nan, + ); + } +} diff --git a/lib/pangea/models/analytics/constructs_model.dart b/lib/pangea/models/analytics/constructs_model.dart index 10a47516a..a9781f9ae 100644 --- a/lib/pangea/models/analytics/constructs_model.dart +++ b/lib/pangea/models/analytics/constructs_model.dart @@ -1,6 +1,5 @@ import 'dart:developer'; -import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/enum/construct_use_type_enum.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; @@ -106,9 +105,7 @@ class OneConstructUse { debugger(when: kDebugMode && constructType == null); return OneConstructUse( - useType: ConstructUseTypeEnum.values - .firstWhereOrNull((e) => e.string == json['useType']) ?? - ConstructUseTypeEnum.unk, + useType: ConstructUseTypeUtil.fromString(json['useType']), lemma: json['lemma'], form: json['form'], categories: json['categories'] != null diff --git a/lib/pangea/models/practice_activities.dart/message_activity_request.dart b/lib/pangea/models/practice_activities.dart/message_activity_request.dart index 0740fb8c3..9101a78ce 100644 --- a/lib/pangea/models/practice_activities.dart/message_activity_request.dart +++ b/lib/pangea/models/practice_activities.dart/message_activity_request.dart @@ -27,12 +27,7 @@ class ConstructWithXP { ? DateTime.parse(json['last_used'] as String) : null, condensedConstructUses: (json['uses'] as List).map((e) { - return ConstructUseTypeEnum.values.firstWhereOrNull( - (element) => - element.string == e || - element.toString().split('.').last == e, - ) ?? - ConstructUseTypeEnum.nan; + return ConstructUseTypeUtil.fromString(e); }).toList(), ); } From cb566d06bced6a26dd3f57d653a995378b1b71e9 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 13:24:41 -0400 Subject: [PATCH 16/21] add minimum dimensions to toolbar contents --- lib/config/app_config.dart | 2 +- lib/pages/chat/events/audio_player.dart | 2 +- lib/pangea/utils/inline_tooltip.dart | 17 +- .../widgets/chat/message_audio_card.dart | 2 + .../chat/message_speech_to_text_card.dart | 8 +- .../chat/message_translation_card.dart | 73 ++--- .../toolbar_content_loading_indicator.dart | 31 +- .../common_widgets/overlay_container.dart | 2 + lib/pangea/widgets/igc/card_error_widget.dart | 39 ++- lib/pangea/widgets/igc/card_header.dart | 37 +-- lib/pangea/widgets/igc/word_data_card.dart | 295 ++++++++---------- .../no_more_practice_card.dart | 28 +- .../practice_activity_card.dart | 61 ++-- lib/pangea/widgets/select_to_define.dart | 17 +- pubspec.yaml | 2 +- 15 files changed, 287 insertions(+), 329 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index b044da3ee..418244fb9 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -24,7 +24,7 @@ abstract class AppConfig { static const bool enableRegistration = true; static const double toolbarMaxHeight = 300.0; static const double toolbarMinHeight = 70.0; - static const double toolbarMinWidth = 350.0; + static const double toolbarMinWidth = 250.0; // #Pangea // static const Color primaryColor = Color(0xFF5625BA); // static const Color primaryColorLight = Color(0xFFCCBDEA); diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 41e0dc388..4a4f6fac9 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -467,7 +467,7 @@ class AudioPlayerState extends State { borderRadius: BorderRadius.circular(2), ), height: 32 * (waveform[i] / 1024), - width: 1.5, + width: 3, ), ], ), diff --git a/lib/pangea/utils/inline_tooltip.dart b/lib/pangea/utils/inline_tooltip.dart index bef617b98..26ec05426 100644 --- a/lib/pangea/utils/inline_tooltip.dart +++ b/lib/pangea/utils/inline_tooltip.dart @@ -30,6 +30,7 @@ class InlineTooltip extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, children: [ // Lightbulb icon on the left Icon( @@ -39,16 +40,14 @@ class InlineTooltip extends StatelessWidget { ), const SizedBox(width: 8), // Text in the middle - Expanded( - child: Center( - child: Text( - instructionsEnum.body(context), - style: TextStyle( - color: Theme.of(context).colorScheme.onSurface, - height: 1.5, - ), - textAlign: TextAlign.left, + Center( + child: Text( + instructionsEnum.body(context), + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + height: 1.5, ), + textAlign: TextAlign.left, ), ), // Close button on the right diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index 133e16b1e..97ffe36d5 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'dart:math'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/events/audio_player.dart'; import 'package:fluffychat/pangea/controllers/text_to_speech_controller.dart'; import 'package:fluffychat/pangea/extensions/pangea_event_extension.dart'; @@ -208,6 +209,7 @@ class MessageAudioCardState extends State { ) : const CardErrorWidget( error: "Null audio file in message_audio_card", + maxWidth: AppConfig.toolbarMinWidth, ), ), ], 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 92489ce29..aae3b3eeb 100644 --- a/lib/pangea/widgets/chat/message_speech_to_text_card.dart +++ b/lib/pangea/widgets/chat/message_speech_to_text_card.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/enum/instructions_enum.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/speech_to_text_models.dart'; @@ -148,9 +149,12 @@ class MessageSpeechToTextCardState extends State { return const ToolbarContentLoadingIndicator(); } - //done fetchig but not results means some kind of error + // done fetchig but not results means some kind of error if (speechToTextResponse == null) { - return CardErrorWidget(error: error); + return CardErrorWidget( + error: error, + maxWidth: AppConfig.toolbarMinWidth, + ); } //TODO: find better icons diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index f37238a6b..3c0d750a3 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/enum/instructions_enum.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; @@ -130,7 +131,18 @@ class MessageTranslationCardState extends State { if (!_fetchingTranslation && repEvent == null && selectionTranslation == null) { - return const CardErrorWidget(error: "No translation found"); + return const CardErrorWidget( + error: "No translation found", + maxWidth: AppConfig.toolbarMinWidth, + ); + } + + final loadingTranslation = + (widget.selection != null && selectionTranslation == null) || + (widget.selection == null && repEvent == null); + + if (_fetchingTranslation || loadingTranslation) { + return const ToolbarContentLoadingIndicator(); } return Padding( @@ -139,42 +151,31 @@ class MessageTranslationCardState extends State { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - _fetchingTranslation - ? const ToolbarContentLoadingIndicator() - : Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - widget.selection != null - ? selectionTranslation != null - ? Text( - selectionTranslation!, - style: BotStyle.text(context), - textAlign: TextAlign.center, - ) - : const ToolbarContentLoadingIndicator() - : repEvent != null - ? Text( - repEvent!.text, - style: BotStyle.text(context), - textAlign: TextAlign.center, - ) - : const ToolbarContentLoadingIndicator(), - if (notGoingToTranslate && widget.selection == null) - InlineTooltip( - instructionsEnum: InstructionsEnum.l1Translation, - onClose: () => setState(() {}), - ), - if (widget.selection != null) - InlineTooltip( - instructionsEnum: - InstructionsEnum.clickAgainToDeselect, - onClose: () => setState(() {}), - ), - ], - ), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + widget.selection != null + ? selectionTranslation! + : repEvent!.text, + style: BotStyle.text(context), + textAlign: TextAlign.center, ), + if (notGoingToTranslate && widget.selection == null) + InlineTooltip( + instructionsEnum: InstructionsEnum.l1Translation, + onClose: () => setState(() {}), + ), + if (widget.selection != null) + InlineTooltip( + instructionsEnum: InstructionsEnum.clickAgainToDeselect, + onClose: () => setState(() {}), + ), + ], + ), + ), ], ), ); diff --git a/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart b/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart index 28f15c1a9..a497e121d 100644 --- a/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart +++ b/lib/pangea/widgets/chat/toolbar_content_loading_indicator.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:flutter/material.dart'; class ToolbarContentLoadingIndicator extends StatelessWidget { @@ -7,25 +8,19 @@ class ToolbarContentLoadingIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - // mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 14, - width: 14, - child: CircularProgressIndicator( - strokeWidth: 2.0, - color: Theme.of(context).colorScheme.primary, - ), - ), - ], + return SizedBox( + width: AppConfig.toolbarMinWidth, + height: AppConfig.toolbarMinHeight, + child: Center( + child: SizedBox( + height: 14, + width: 14, + child: CircularProgressIndicator( + strokeWidth: 2.0, + color: Theme.of(context).colorScheme.primary, + ), ), - ], + ), ); } } diff --git a/lib/pangea/widgets/common_widgets/overlay_container.dart b/lib/pangea/widgets/common_widgets/overlay_container.dart index 5e2991be7..eae6c935f 100644 --- a/lib/pangea/widgets/common_widgets/overlay_container.dart +++ b/lib/pangea/widgets/common_widgets/overlay_container.dart @@ -32,6 +32,8 @@ class OverlayContainer extends StatelessWidget { constraints: BoxConstraints( maxWidth: maxWidth, maxHeight: maxHeight, + minHeight: 100, + minWidth: 100, ), //PTODO - position card above input/message // margin: const EdgeInsets.all(10), diff --git a/lib/pangea/widgets/igc/card_error_widget.dart b/lib/pangea/widgets/igc/card_error_widget.dart index 708fdd88f..52f66f5a0 100644 --- a/lib/pangea/widgets/igc/card_error_widget.dart +++ b/lib/pangea/widgets/igc/card_error_widget.dart @@ -9,37 +9,44 @@ class CardErrorWidget extends StatelessWidget { final Object? error; final Choreographer? choreographer; final int? offset; + final double? maxWidth; + const CardErrorWidget({ super.key, this.error, this.choreographer, this.offset, + this.maxWidth, }); @override Widget build(BuildContext context) { final ErrorCopy errorCopy = ErrorCopy(context, error); - return Padding( - padding: const EdgeInsets.all(8), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CardHeader( - text: errorCopy.title, - botExpression: BotExpression.addled, - onClose: () => choreographer?.onMatchError( - cursorOffset: offset, + return ConstrainedBox( + constraints: maxWidth != null + ? BoxConstraints(maxWidth: maxWidth!) + : const BoxConstraints(), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CardHeader( + text: errorCopy.title, + botExpression: BotExpression.addled, + onClose: () => choreographer?.onMatchError( + cursorOffset: offset, + ), ), - ), - const SizedBox(height: 10.0), - Center( - child: Text( + const SizedBox(height: 12.0), + Text( errorCopy.body, style: BotStyle.text(context), + textAlign: TextAlign.center, ), - ), - ], + ], + ), ), ); } diff --git a/lib/pangea/widgets/igc/card_header.dart b/lib/pangea/widgets/igc/card_header.dart index 671e58492..270314f72 100644 --- a/lib/pangea/widgets/igc/card_header.dart +++ b/lib/pangea/widgets/igc/card_header.dart @@ -1,8 +1,6 @@ -import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; import 'package:flutter/material.dart'; -import '../../../widgets/matrix.dart'; import '../common/bot_face_svg.dart'; class CardHeader extends StatelessWidget { @@ -30,26 +28,25 @@ class CardHeader extends StatelessWidget { expression: botExpression, ), ), - const SizedBox(width: 5.0), - Text( - text, - style: BotStyle.text(context), - textAlign: TextAlign.left, - ), - const SizedBox(width: 5.0), - CircleAvatar( - backgroundColor: AppConfig.primaryColor.withOpacity(0.1), - child: IconButton( - icon: const Icon(Icons.close_outlined), - onPressed: () { - if (onClose != null) onClose!(); - MatrixState.pAnyState.closeOverlay(); - }, - color: Theme.of(context).brightness == Brightness.dark - ? AppConfig.primaryColorLight - : AppConfig.primaryColor, + const SizedBox(width: 12.0), + Flexible( + child: Text( + text, + style: BotStyle.text(context), + softWrap: true, ), ), + // const SizedBox(width: 5.0), + // IconButton( + // icon: const Icon(Icons.close_outlined), + // onPressed: () { + // if (onClose != null) onClose!(); + // MatrixState.pAnyState.closeOverlay(); + // }, + // color: Theme.of(context).brightness == Brightness.dark + // ? AppConfig.primaryColorLight + // : AppConfig.primaryColor, + // ), ], ), ); diff --git a/lib/pangea/widgets/igc/word_data_card.dart b/lib/pangea/widgets/igc/word_data_card.dart index 6f1492a75..ff494bb38 100644 --- a/lib/pangea/widgets/igc/word_data_card.dart +++ b/lib/pangea/widgets/igc/word_data_card.dart @@ -1,5 +1,6 @@ import 'dart:developer'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/constants/language_constants.dart'; import 'package:fluffychat/pangea/controllers/contextual_definition_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; @@ -7,8 +8,7 @@ import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; -import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; -import 'package:fluffychat/pangea/widgets/common/p_circular_loader.dart'; +import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -166,71 +166,68 @@ class WordDataCardView extends StatelessWidget { @override Widget build(BuildContext context) { if (controller.wordNetError != null) { - return CardErrorWidget(error: controller.wordNetError); + return CardErrorWidget( + error: controller.wordNetError, + maxWidth: AppConfig.toolbarMinWidth, + ); } if (controller.activeL1 == null || controller.activeL2 == null) { ErrorHandler.logError(m: "should not be here"); - return CardErrorWidget(error: controller.noLanguages); + return CardErrorWidget( + error: controller.noLanguages, + maxWidth: AppConfig.toolbarMinWidth, + ); } - final ScrollController scrollController = ScrollController(); - - return Container( - padding: const EdgeInsets.all(8), - constraints: const BoxConstraints(minHeight: minCardHeight), - alignment: Alignment.center, - child: Scrollbar( - thumbVisibility: true, - controller: scrollController, - child: SingleChildScrollView( - controller: scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (controller.widget.choiceFeedback != null) - Text( - controller.widget.choiceFeedback!, - style: BotStyle.text(context), - ), - const SizedBox(height: 5.0), - if (controller.wordData != null && - controller.wordNetError == null && - controller.activeL1 != null && - controller.activeL2 != null) - WordNetInfo( - wordData: controller.wordData!, - activeL1: controller.activeL1!, - activeL2: controller.activeL2!, - ), - if (controller.isLoadingWordNet) const PCircular(), - const SizedBox(height: 5.0), - // if (controller.widget.hasInfo && - // !controller.isLoadingContextualDefinition && - // controller.contextualDefinitionRes == null) - // Material( - // type: MaterialType.transparency, - // child: ListTile( - // leading: const BotFace( - // width: 40, expression: BotExpression.surprised), - // title: Text(L10n.of(context)!.askPangeaBot), - // onTap: controller.handleGetDefinitionButtonPress, - // ), - // ), - if (controller.isLoadingContextualDefinition) const PCircular(), - if (controller.contextualDefinitionRes != null) - Text( - controller.contextualDefinitionRes!.text, - style: BotStyle.text(context), - ), - if (controller.definitionError != null) - Text( - L10n.of(context)!.sorryNoResults, - style: BotStyle.text(context), - ), - ], - ), - ), + return Padding( + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), + child: Column( + children: [ + if (controller.widget.choiceFeedback != null) + Text( + controller.widget.choiceFeedback!, + style: BotStyle.text(context), + ), + const SizedBox(height: 5.0), + if (controller.wordData != null && + controller.wordNetError == null && + controller.activeL1 != null && + controller.activeL2 != null) + WordNetInfo( + wordData: controller.wordData!, + activeL1: controller.activeL1!, + activeL2: controller.activeL2!, + ), + if (controller.isLoadingWordNet) + const ToolbarContentLoadingIndicator(), + const SizedBox(height: 5.0), + // if (controller.widget.hasInfo && + // !controller.isLoadingContextualDefinition && + // controller.contextualDefinitionRes == null) + // Material( + // type: MaterialType.transparency, + // child: ListTile( + // leading: const BotFace( + // width: 40, expression: BotExpression.surprised), + // title: Text(L10n.of(context)!.askPangeaBot), + // onTap: controller.handleGetDefinitionButtonPress, + // ), + // ), + if (controller.isLoadingContextualDefinition) + const ToolbarContentLoadingIndicator(), + if (controller.contextualDefinitionRes != null) + Text( + controller.contextualDefinitionRes!.text, + style: BotStyle.text(context), + textAlign: TextAlign.center, + ), + if (controller.definitionError != null) + Text( + L10n.of(context)!.sorryNoResults, + style: BotStyle.text(context), + textAlign: TextAlign.center, + ), + ], ), ); } @@ -251,12 +248,14 @@ class WordNetInfo extends StatelessWidget { @override Widget build(BuildContext context) { return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ SensesForLanguage( wordData: wordData, languageType: LanguageType.target, language: activeL2, ), + const SizedBox(height: 10), SensesForLanguage( wordData: wordData, languageType: LanguageType.base, @@ -273,52 +272,6 @@ enum LanguageType { } class SensesForLanguage extends StatelessWidget { - const SensesForLanguage({ - super.key, - required this.wordData, - required this.languageType, - required this.language, - }); - - final LanguageModel language; - final LanguageType languageType; - final WordData wordData; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(7, 0, 0, 0), - child: LanguageFlag( - language: language, - ), - ), - Expanded( - child: PartOfSpeechBlock( - wordData: wordData, - languageType: languageType, - ), - ), - ], - ), - ); - } -} - -class PartOfSpeechBlock extends StatelessWidget { - final WordData wordData; - final LanguageType languageType; - - const PartOfSpeechBlock({ - super.key, - required this.wordData, - required this.languageType, - }); - String get exampleSentence => languageType == LanguageType.target ? wordData.targetExampleSentence : wordData.baseExampleSentence; @@ -336,70 +289,76 @@ class PartOfSpeechBlock extends StatelessWidget { return "$word (${wordData.formattedPartOfSpeech(languageType)})"; } + const SensesForLanguage({ + super.key, + required this.wordData, + required this.languageType, + required this.language, + }); + + final LanguageModel language; + final LanguageType languageType; + final WordData wordData; + @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - formattedTitle(context), - style: BotStyle.text(context, italics: true, bold: false), - ), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.only(left: 14.0, bottom: 10.0), - child: Align( - alignment: Alignment.centerLeft, - child: Column( - children: [ - if (definition.isNotEmpty) - RichText( - text: TextSpan( - style: BotStyle.text( - context, - italics: false, - bold: false, - ), - children: [ - TextSpan( - text: "${L10n.of(context)!.definition}: ", - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: definition), - ], - ), - ), - const SizedBox(height: 10), - if (exampleSentence.isNotEmpty) - RichText( - text: TextSpan( - style: BotStyle.text( - context, - italics: false, - bold: false, - ), - children: [ - TextSpan( - text: "${L10n.of(context)!.exampleSentence}: ", - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - TextSpan(text: exampleSentence), - ], - ), - ), - ], + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LanguageFlag(language: language), + const SizedBox(width: 10), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + formattedTitle(context), + style: BotStyle.text(context, italics: true, bold: false), ), - ), + const SizedBox(height: 4), + if (definition.isNotEmpty) + RichText( + text: TextSpan( + style: BotStyle.text( + context, + italics: false, + bold: false, + ), + children: [ + TextSpan( + text: "${L10n.of(context)!.definition}: ", + style: const TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan(text: definition), + ], + ), + ), + const SizedBox(height: 4), + if (exampleSentence.isNotEmpty) + RichText( + text: TextSpan( + style: BotStyle.text( + context, + italics: false, + bold: false, + ), + children: [ + TextSpan( + text: "${L10n.of(context)!.exampleSentence}: ", + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + TextSpan(text: exampleSentence), + ], + ), + ), + ], ), - ], - ), + ), + ], ); } } diff --git a/lib/pangea/widgets/practice_activity/no_more_practice_card.dart b/lib/pangea/widgets/practice_activity/no_more_practice_card.dart index d4844ac21..12a087d97 100644 --- a/lib/pangea/widgets/practice_activity/no_more_practice_card.dart +++ b/lib/pangea/widgets/practice_activity/no_more_practice_card.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; import 'package:flutter/material.dart'; @@ -71,18 +72,21 @@ class GamifiedTextWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: [ - const StarAnimationWidget(), - const SizedBox(height: 10), - Text( - userMessage, - style: BotStyle.text(context), - textAlign: TextAlign.center, - ), - ], + return SizedBox( + width: AppConfig.toolbarMinWidth, + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), + child: Column( + children: [ + const StarAnimationWidget(), + const SizedBox(height: 10), + Text( + userMessage, + style: BotStyle.text(context), + textAlign: TextAlign.center, + ), + ], + ), ), ); } diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index 13d22890f..c9c42b85b 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -9,13 +9,13 @@ import 'package:fluffychat/pangea/models/analytics/constructs_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_record_model.dart'; -import 'package:fluffychat/pangea/utils/bot_style.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/animations/gain_points.dart'; import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/content_issue_button.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/multiple_choice_activity.dart'; +import 'package:fluffychat/pangea/widgets/practice_activity/no_more_practice_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/target_tokens_controller.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; @@ -286,12 +286,10 @@ class PracticeActivityCardState extends State { /// If there is no current activity, the widget returns a sizedbox with a height of 80. /// If the activity type is multiple choice, the widget returns a MultipleChoiceActivity. /// If the activity type is unknown, the widget logs an error and returns a text widget with an error message. - Widget get activityWidget { - if (currentActivity == null) { - // return sizedbox with height of 80 - return const SizedBox(height: 80); - } - switch (currentActivity!.activityType) { + Widget? get activityWidget { + switch (currentActivity?.activityType) { + case null: + return null; case ActivityTypeEnum.multipleChoice: return MultipleChoiceActivity( practiceCardController: this, @@ -304,30 +302,28 @@ class PracticeActivityCardState extends State { practiceCardController: this, currentActivity: currentActivity!, ); - default: - ErrorHandler.logError( - e: Exception('Unknown activity type'), - m: 'Unknown activity type', - data: { - 'activityType': currentActivity!.activityType, - }, - ); - return Text( - L10n.of(context)!.oopsSomethingWentWrong, - style: BotStyle.text(context), - ); + // default: + // ErrorHandler.logError( + // e: Exception('Unknown activity type'), + // m: 'Unknown activity type', + // data: { + // 'activityType': currentActivity!.activityType, + // }, + // ); + // return Text( + // L10n.of(context)!.oopsSomethingWentWrong, + // style: BotStyle.text(context), + // ); } } @override Widget build(BuildContext context) { - // if (!fetchingActivity && currentActivity == null) { - // return GamifiedTextWidget( - // userMessage: L10n.of(context)!.noActivitiesFound, - // ); - // } - - return const ToolbarContentLoadingIndicator(); + if (!fetchingActivity && currentActivity == null) { + return GamifiedTextWidget( + userMessage: L10n.of(context)!.noActivitiesFound, + ); + } return Stack( alignment: Alignment.center, @@ -336,16 +332,15 @@ class PracticeActivityCardState extends State { const Positioned( child: PointsGainedAnimation(), ), - Padding( - padding: const EdgeInsets.fromLTRB(8, 20, 8, 8), - child: activityWidget, - ), + if (activityWidget != null) + Padding( + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), + child: activityWidget, + ), // Conditionally show the darkening and progress indicator based on the loading state if (!savoringTheJoy && fetchingActivity) ...[ // Circular progress indicator in the center - const Center( - child: CircularProgressIndicator(), - ), + const ToolbarContentLoadingIndicator(), ], // Flag button in the top right corner Positioned( diff --git a/lib/pangea/widgets/select_to_define.dart b/lib/pangea/widgets/select_to_define.dart index 556cc7f94..968eaa147 100644 --- a/lib/pangea/widgets/select_to_define.dart +++ b/lib/pangea/widgets/select_to_define.dart @@ -10,18 +10,11 @@ class SelectToDefine extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.all(8), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Text( - L10n.of(context)!.selectToDefine, - style: BotStyle.text(context), - textAlign: TextAlign.center, - ), - ), - ], + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), + child: Text( + L10n.of(context)!.selectToDefine, + style: BotStyle.text(context), + textAlign: TextAlign.center, ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 076a0ed49..f8f00ee8f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.22.3+3553 +version: 1.22.4+3554 environment: sdk: ">=3.0.0 <4.0.0" From 4b5602b2374ad360a9e2f87e4189c5867b91ed5e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 13:42:22 -0400 Subject: [PATCH 17/21] added x button back to card error header --- lib/config/app_config.dart | 2 +- lib/pangea/widgets/igc/card_error_widget.dart | 30 ++++++++-------- lib/pangea/widgets/igc/card_header.dart | 35 ++++++++++--------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 418244fb9..ab05ffd99 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -24,7 +24,7 @@ abstract class AppConfig { static const bool enableRegistration = true; static const double toolbarMaxHeight = 300.0; static const double toolbarMinHeight = 70.0; - static const double toolbarMinWidth = 250.0; + static const double toolbarMinWidth = 270.0; // #Pangea // static const Color primaryColor = Color(0xFF5625BA); // static const Color primaryColorLight = Color(0xFFCCBDEA); diff --git a/lib/pangea/widgets/igc/card_error_widget.dart b/lib/pangea/widgets/igc/card_error_widget.dart index 52f66f5a0..8c810391b 100644 --- a/lib/pangea/widgets/igc/card_error_widget.dart +++ b/lib/pangea/widgets/igc/card_error_widget.dart @@ -27,26 +27,26 @@ class CardErrorWidget extends StatelessWidget { constraints: maxWidth != null ? BoxConstraints(maxWidth: maxWidth!) : const BoxConstraints(), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CardHeader( - text: errorCopy.title, - botExpression: BotExpression.addled, - onClose: () => choreographer?.onMatchError( - cursorOffset: offset, - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CardHeader( + text: errorCopy.title, + botExpression: BotExpression.addled, + onClose: () => choreographer?.onMatchError( + cursorOffset: offset, ), - const SizedBox(height: 12.0), - Text( + ), + const SizedBox(height: 12.0), + Padding( + padding: const EdgeInsets.all(12), + child: Text( errorCopy.body, style: BotStyle.text(context), textAlign: TextAlign.center, ), - ], - ), + ), + ], ), ); } diff --git a/lib/pangea/widgets/igc/card_header.dart b/lib/pangea/widgets/igc/card_header.dart index 270314f72..1816cc214 100644 --- a/lib/pangea/widgets/igc/card_header.dart +++ b/lib/pangea/widgets/igc/card_header.dart @@ -1,4 +1,6 @@ +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import '../common/bot_face_svg.dart'; @@ -20,13 +22,12 @@ class CardHeader extends StatelessWidget { return Padding( padding: const EdgeInsets.only(bottom: 5.0), child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.only(top: 3.0), - child: BotFace( - width: 50.0, - expression: botExpression, - ), + BotFace( + width: 50.0, + expression: botExpression, ), const SizedBox(width: 12.0), Flexible( @@ -36,17 +37,17 @@ class CardHeader extends StatelessWidget { softWrap: true, ), ), - // const SizedBox(width: 5.0), - // IconButton( - // icon: const Icon(Icons.close_outlined), - // onPressed: () { - // if (onClose != null) onClose!(); - // MatrixState.pAnyState.closeOverlay(); - // }, - // color: Theme.of(context).brightness == Brightness.dark - // ? AppConfig.primaryColorLight - // : AppConfig.primaryColor, - // ), + const SizedBox(width: 5.0), + IconButton( + icon: const Icon(Icons.close_outlined), + onPressed: () { + if (onClose != null) onClose!(); + MatrixState.pAnyState.closeOverlay(); + }, + color: Theme.of(context).brightness == Brightness.dark + ? AppConfig.primaryColorLight + : AppConfig.primaryColor, + ), ], ), ); From dc79a50fda7606140a485bcf67b29794c27c8ab0 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 13:44:32 -0400 Subject: [PATCH 18/21] only init one instance of ttscontroller, don't stop tts twice --- .../widgets/chat/message_audio_card.dart | 8 +++---- .../chat/message_selection_overlay.dart | 8 +++++-- lib/pangea/widgets/chat/message_toolbar.dart | 5 ++++ lib/pangea/widgets/chat/tts_controller.dart | 5 ++-- .../multiple_choice_activity.dart | 8 ++++++- .../practice_activity_card.dart | 5 ++++ .../practice_activity/word_audio_button.dart | 24 ++++--------------- pubspec.yaml | 6 ++--- 8 files changed, 37 insertions(+), 32 deletions(-) diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index 97ffe36d5..e66e69477 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -21,11 +21,13 @@ class MessageAudioCard extends StatefulWidget { final PangeaMessageEvent messageEvent; final MessageOverlayController overlayController; final PangeaTokenText? selection; + final TtsController tts; const MessageAudioCard({ super.key, required this.messageEvent, required this.overlayController, + required this.tts, this.selection, }); @@ -40,8 +42,6 @@ class MessageAudioCardState extends State { int? sectionStartMS; int? sectionEndMS; - TtsController tts = TtsController(); - @override void initState() { super.initState(); @@ -68,7 +68,7 @@ class MessageAudioCardState extends State { final PangeaTokenText selection = widget.selection!; final tokenText = selection.content; - await tts.speak(tokenText); + await widget.tts.speak(tokenText); } void setSectionStartAndEnd(int? start, int? end) => mounted @@ -204,7 +204,7 @@ class MessageAudioCardState extends State { color: Theme.of(context).colorScheme.onPrimaryContainer, ), - tts.missingVoiceButton, + widget.tts.missingVoiceButton, ], ) : const CardErrorWidget( diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index 5cf9e70b5..dbce6f2b8 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -17,6 +17,7 @@ import 'package:fluffychat/pangea/widgets/chat/message_toolbar_buttons.dart'; import 'package:fluffychat/pangea/widgets/chat/overlay_footer.dart'; import 'package:fluffychat/pangea/widgets/chat/overlay_header.dart'; import 'package:fluffychat/pangea/widgets/chat/overlay_message.dart'; +import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; @@ -61,11 +62,11 @@ class MessageOverlayController extends State /// The number of activities that need to be completed before the toolbar is unlocked /// If we don't have any good activities for them, we'll decrease this number static const int neededActivities = 3; - int activitiesLeftToComplete = neededActivities; - PangeaMessageEvent get pangeaMessageEvent => widget._pangeaMessageEvent; + final TtsController tts = TtsController(); + @override void initState() { super.initState(); @@ -98,6 +99,7 @@ class MessageOverlayController extends State ).listen((_) => setState(() {})); setInitialToolbarMode(); + tts.setupTTS(); } /// We need to check if the setState call is safe to call immediately @@ -359,6 +361,7 @@ class MessageOverlayController extends State void dispose() { _animationController.dispose(); _reactionSubscription?.cancel(); + tts.dispose(); super.dispose(); } @@ -455,6 +458,7 @@ class MessageOverlayController extends State MessageToolbar( pangeaMessageEvent: widget._pangeaMessageEvent, overLayController: this, + tts: tts, ), SizedBox( height: adjustedMessageHeight, diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index cf4192691..2f2f2b736 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; import 'package:fluffychat/pangea/widgets/chat/message_speech_to_text_card.dart'; import 'package:fluffychat/pangea/widgets/chat/message_translation_card.dart'; import 'package:fluffychat/pangea/widgets/chat/message_unsubscribed_card.dart'; +import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/practice_activity_card.dart'; import 'package:fluffychat/pangea/widgets/select_to_define.dart'; @@ -22,11 +23,13 @@ const double minCardHeight = 70; class MessageToolbar extends StatelessWidget { final PangeaMessageEvent pangeaMessageEvent; final MessageOverlayController overLayController; + final TtsController tts; const MessageToolbar({ super.key, required this.pangeaMessageEvent, required this.overLayController, + required this.tts, }); Widget get toolbarContent { @@ -50,6 +53,7 @@ class MessageToolbar extends StatelessWidget { messageEvent: pangeaMessageEvent, overlayController: overLayController, selection: overLayController.selectedSpan, + tts: tts, ); case MessageMode.speechToText: return MessageSpeechToTextCard( @@ -87,6 +91,7 @@ class MessageToolbar extends StatelessWidget { return PracticeActivityCard( pangeaMessageEvent: pangeaMessageEvent, overlayController: overLayController, + tts: tts, ); default: debugger(when: kDebugMode); diff --git a/lib/pangea/widgets/chat/tts_controller.dart b/lib/pangea/widgets/chat/tts_controller.dart index 225d7a04e..c98cb6220 100644 --- a/lib/pangea/widgets/chat/tts_controller.dart +++ b/lib/pangea/widgets/chat/tts_controller.dart @@ -23,7 +23,8 @@ class TtsController { } onError(dynamic message) => ErrorHandler.logError( - m: 'TTS error', + e: message, + m: (message.toString().isNotEmpty) ? message.toString() : 'TTS error', data: { 'message': message, }, @@ -82,13 +83,11 @@ class TtsController { debugger(when: kDebugMode); ErrorHandler.logError(e: e, s: s); } - await tts.stop(); } Future speak(String text) async { try { stop(); - targetLanguage ??= MatrixState.pangeaController.languageController.userL2?.langCode; diff --git a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart index ee892837b..e76021000 100644 --- a/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart +++ b/lib/pangea/widgets/practice_activity/multiple_choice_activity.dart @@ -6,6 +6,7 @@ import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart'; import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_record_model.dart'; +import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/practice_activity_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/word_audio_button.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -16,11 +17,13 @@ import 'package:flutter/material.dart'; class MultipleChoiceActivity extends StatefulWidget { final PracticeActivityCardState practiceCardController; final PracticeActivityModel currentActivity; + final TtsController tts; const MultipleChoiceActivity({ super.key, required this.practiceCardController, required this.currentActivity, + required this.tts, }); @override @@ -112,7 +115,10 @@ class MultipleChoiceActivityState extends State { // #freeze-activity if (practiceActivity.activityType == ActivityTypeEnum.wordFocusListening) - WordAudioButton(text: practiceActivity.content.answer), + WordAudioButton( + text: practiceActivity.content.answer, + ttsController: widget.tts, + ), ChoicesArray( isLoading: false, uniqueKeyForLayerLink: (index) => "multiple_choice_$index", diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index c9c42b85b..dbb98de73 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -13,6 +13,7 @@ import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/animations/gain_points.dart'; import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; +import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/pangea/widgets/content_issue_button.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/multiple_choice_activity.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/no_more_practice_card.dart'; @@ -28,11 +29,13 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; class PracticeActivityCard extends StatefulWidget { final PangeaMessageEvent pangeaMessageEvent; final MessageOverlayController overlayController; + final TtsController tts; const PracticeActivityCard({ super.key, required this.pangeaMessageEvent, required this.overlayController, + required this.tts, }); @override @@ -294,6 +297,7 @@ class PracticeActivityCardState extends State { return MultipleChoiceActivity( practiceCardController: this, currentActivity: currentActivity!, + tts: widget.tts, ); case ActivityTypeEnum.wordFocusListening: // return WordFocusListeningActivity( @@ -301,6 +305,7 @@ class PracticeActivityCardState extends State { return MultipleChoiceActivity( practiceCardController: this, currentActivity: currentActivity!, + tts: widget.tts, ); // default: // ErrorHandler.logError( diff --git a/lib/pangea/widgets/practice_activity/word_audio_button.dart b/lib/pangea/widgets/practice_activity/word_audio_button.dart index 24835fcb2..2f56299c8 100644 --- a/lib/pangea/widgets/practice_activity/word_audio_button.dart +++ b/lib/pangea/widgets/practice_activity/word_audio_button.dart @@ -4,10 +4,12 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; class WordAudioButton extends StatefulWidget { final String text; + final TtsController ttsController; const WordAudioButton({ super.key, required this.text, + required this.ttsController, }); @override @@ -17,22 +19,6 @@ class WordAudioButton extends StatefulWidget { class WordAudioButtonState extends State { bool _isPlaying = false; - TtsController ttsController = TtsController(); - - @override - void initState() { - // TODO: implement initState - debugPrint('initState WordAudioButton'); - super.initState(); - ttsController.setupTTS().then((value) => setState(() {})); - } - - @override - void dispose() { - ttsController.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { debugPrint('build WordAudioButton'); @@ -54,7 +40,7 @@ class WordAudioButtonState extends State { _isPlaying ? L10n.of(context)!.stop : L10n.of(context)!.playAudio, onPressed: () async { if (_isPlaying) { - await ttsController.tts.stop(); + await widget.ttsController.tts.stop(); if (mounted) { setState(() => _isPlaying = false); } @@ -62,7 +48,7 @@ class WordAudioButtonState extends State { if (mounted) { setState(() => _isPlaying = true); } - await ttsController.speak(widget.text); + await widget.ttsController.speak(widget.text); if (mounted) { setState(() => _isPlaying = false); } @@ -70,7 +56,7 @@ class WordAudioButtonState extends State { }, // Disable button if language isn't supported ), // #freeze-activity - ttsController.missingVoiceButton, + widget.ttsController.missingVoiceButton, ], ); } diff --git a/pubspec.yaml b/pubspec.yaml index f8f00ee8f..25403c0ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.22.4+3554 +version: 1.22.5+3555 environment: sdk: ">=3.0.0 <4.0.0" @@ -162,8 +162,8 @@ flutter: # #Pangea # uncomment this to enable mobile builds # causes error with github actions - # - .env - # - assets/.env + - .env + - assets/.env - assets/pangea/ - assets/pangea/bot_faces/ # Pangea# From a3845eb13ab33ba085e50041d25ddfb6da66db10 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 13:46:20 -0400 Subject: [PATCH 19/21] comment out env file paths in pubspec --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 25403c0ec..377087387 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -162,8 +162,8 @@ flutter: # #Pangea # uncomment this to enable mobile builds # causes error with github actions - - .env - - assets/.env + # - .env + # - assets/.env - assets/pangea/ - assets/pangea/bot_faces/ # Pangea# From 9e3111f97c68c347cc5aa67cf6df197e3a63bb0a Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 14:16:39 -0400 Subject: [PATCH 20/21] don't play token text if null message audio is playing --- lib/pages/chat/events/audio_player.dart | 11 +++++++++-- lib/pangea/widgets/chat/message_audio_card.dart | 6 +++++- .../widgets/chat/message_selection_overlay.dart | 15 ++++++++++++--- lib/pangea/widgets/chat/message_toolbar.dart | 1 + pubspec.yaml | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 4a4f6fac9..c79fc9cb3 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -21,6 +21,7 @@ class AudioPlayerWidget extends StatefulWidget { final Event? event; final PangeaAudioFile? matrixFile; final bool autoplay; + final Function(bool)? setIsPlayingAudio; // Pangea# static String? currentId; @@ -41,6 +42,7 @@ class AudioPlayerWidget extends StatefulWidget { this.autoplay = false, this.sectionStartMS, this.sectionEndMS, + this.setIsPlayingAudio, // Pangea# super.key, }); @@ -204,8 +206,13 @@ class AudioPlayerState extends State { if (max == null || max == Duration.zero) return; setState(() => maxPosition = max.inMilliseconds.toDouble()); }); - onPlayerStateChanged ??= - audioPlayer.playingStream.listen((_) => setState(() {})); + onPlayerStateChanged ??= audioPlayer.playingStream.listen( + (isPlaying) => setState(() { + // #Pangea + widget.setIsPlayingAudio?.call(isPlaying); + // Pangea# + }), + ); final audioFile = this.audioFile; if (audioFile != null) { audioPlayer.setFilePath(audioFile.path); diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index e66e69477..47cb41af8 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -22,12 +22,14 @@ class MessageAudioCard extends StatefulWidget { final MessageOverlayController overlayController; final PangeaTokenText? selection; final TtsController tts; + final Function(bool) setIsPlayingAudio; const MessageAudioCard({ super.key, required this.messageEvent, required this.overlayController, required this.tts, + required this.setIsPlayingAudio, this.selection, }); @@ -56,7 +58,7 @@ class MessageAudioCardState extends State { @override void didUpdateWidget(covariant oldWidget) { - if (oldWidget.selection != widget.selection) { + if (oldWidget.selection != widget.selection && widget.selection != null) { debugPrint('selection changed'); setSectionStartAndEndFromSelection(); playSelectionAudio(); @@ -65,6 +67,7 @@ class MessageAudioCardState extends State { } Future playSelectionAudio() async { + if (widget.selection == null) return; final PangeaTokenText selection = widget.selection!; final tokenText = selection.content; @@ -203,6 +206,7 @@ class MessageAudioCardState extends State { sectionEndMS: sectionEndMS, color: Theme.of(context).colorScheme.onPrimaryContainer, + setIsPlayingAudio: widget.setIsPlayingAudio, ), widget.tts.missingVoiceButton, ], diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index dbce6f2b8..a8022b1cc 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -66,6 +66,7 @@ class MessageOverlayController extends State PangeaMessageEvent get pangeaMessageEvent => widget._pangeaMessageEvent; final TtsController tts = TtsController(); + bool isPlayingAudio = false; @override void initState() { @@ -200,9 +201,10 @@ class MessageOverlayController extends State PangeaToken token, ) { if ([ - MessageMode.practiceActivity, - // MessageMode.textToSpeech - ].contains(toolbarMode)) { + MessageMode.practiceActivity, + // MessageMode.textToSpeech + ].contains(toolbarMode) || + isPlayingAudio) { return; } @@ -273,6 +275,13 @@ class MessageOverlayController extends State double get reactionsHeight => hasReactions ? 28 : 0; double get belowMessageHeight => toolbarButtonsHeight + reactionsHeight; + void setIsPlayingAudio(bool isPlaying) { + if (mounted) { + setState(() => isPlayingAudio = isPlaying); + debugPrint("IS PLAYING AUDIO: $isPlaying"); + } + } + @override void didChangeDependencies() { super.didChangeDependencies(); diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index 2f2f2b736..071a99f69 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -54,6 +54,7 @@ class MessageToolbar extends StatelessWidget { overlayController: overLayController, selection: overLayController.selectedSpan, tts: tts, + setIsPlayingAudio: overLayController.setIsPlayingAudio, ); case MessageMode.speechToText: return MessageSpeechToTextCard( diff --git a/pubspec.yaml b/pubspec.yaml index 377087387..80906d77c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.22.5+3555 +version: 1.22.6+3556 environment: sdk: ">=3.0.0 <4.0.0" From 1a151e90b7ec7d82f012c3b10a43fe2a98be7aac Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 24 Oct 2024 14:33:25 -0400 Subject: [PATCH 21/21] removed print statement --- lib/pangea/widgets/chat/message_selection_overlay.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index a8022b1cc..bd5b3da00 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -278,7 +278,6 @@ class MessageOverlayController extends State void setIsPlayingAudio(bool isPlaying) { if (mounted) { setState(() => isPlayingAudio = isPlaying); - debugPrint("IS PLAYING AUDIO: $isPlaying"); } }