From 29c61b2b2d951e92e8c507640764ee60123ae054 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 26 Jun 2025 13:25:14 -0400 Subject: [PATCH 01/10] chore: if user closes invite dialog without declining, don't leave invited space --- lib/pages/chat_list/chat_list.dart | 1 - lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 091c6e8b0..519ff9218 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -46,7 +46,6 @@ import '../../widgets/matrix.dart'; import 'package:fluffychat/utils/tor_stub.dart' if (dart.library.html) 'package:tor_detector_web/tor_detector_web.dart'; - enum PopupMenuAction { settings, invite, diff --git a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart index 428567a27..72839b716 100644 --- a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart +++ b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart @@ -31,8 +31,9 @@ Future showInviteDialog(Room room, BuildContext context) async { room.isSpace ? "/rooms?spaceId=${room.id}" : "/rooms/${room.id}", ); return room.id; + } else if (acceptInvite == OkCancelResult.cancel) { + await room.leave(); } - await room.leave(); }, ); From 687fd4a03e1dd4d79730ffd15ecd9adaf54a35b8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 26 Jun 2025 13:48:04 -0400 Subject: [PATCH 02/10] chore: fix overflow in overlay for other user's audio messages on small screens --- .../toolbar/widgets/overlay_message.dart | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/pangea/toolbar/widgets/overlay_message.dart b/lib/pangea/toolbar/widgets/overlay_message.dart index a5dda244c..fc0543395 100644 --- a/lib/pangea/toolbar/widgets/overlay_message.dart +++ b/lib/pangea/toolbar/widgets/overlay_message.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -20,6 +22,7 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart import 'package:fluffychat/pangea/toolbar/widgets/stt_transcript_tokens.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/file_description.dart'; +import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; // @ggurdin be great to explain the need/function of a widget like this @@ -150,8 +153,13 @@ class OverlayMessage extends StatelessWidget { final transcription = showTranscription ? Container( - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 1.5, + constraints: BoxConstraints( + maxWidth: min( + FluffyThemes.columnWidth * 1.5, + MediaQuery.of(context).size.width - + (ownMessage ? 0 : Avatar.defaultSize) - + 24.0, + ), ), child: Padding( padding: const EdgeInsets.all(12.0), @@ -230,8 +238,13 @@ class OverlayMessage extends StatelessWidget { final translation = showTranslation || showSpeechTranslation ? Container( - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 1.5, + constraints: BoxConstraints( + maxWidth: min( + FluffyThemes.columnWidth * 1.5, + MediaQuery.of(context).size.width - + (ownMessage ? 0 : Avatar.defaultSize) - + 24.0, + ), ), child: Padding( padding: const EdgeInsets.fromLTRB( From 3586fb75fd4f6bc85df5d0a7ecd511374721e7c2 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Thu, 26 Jun 2025 15:51:13 -0400 Subject: [PATCH 03/10] If there are no activities after loading finishes, display error message --- .../activity_suggestions/activity_suggestions_area.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pangea/activity_suggestions/activity_suggestions_area.dart b/lib/pangea/activity_suggestions/activity_suggestions_area.dart index b4ce264a0..82d0ca74b 100644 --- a/lib/pangea/activity_suggestions/activity_suggestions_area.dart +++ b/lib/pangea/activity_suggestions/activity_suggestions_area.dart @@ -221,7 +221,7 @@ class ActivitySuggestionsAreaState extends State { ), AnimatedSize( duration: FluffyThemes.animationDuration, - child: _timeout + child: (_timeout || !_loading && cards.isEmpty) ? Padding( padding: const EdgeInsets.all(8.0), child: RichText( @@ -236,8 +236,10 @@ class ActivitySuggestionsAreaState extends State { ), const TextSpan(text: " "), TextSpan( - text: - L10n.of(context).activitySuggestionTimeoutMessage, + text: _timeout + ? L10n.of(context) + .activitySuggestionTimeoutMessage + : L10n.of(context).oopsSomethingWentWrong, ), ], ), From 32b5de675c40d851b559010c61a5f78b632f2924 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 27 Jun 2025 08:48:02 -0400 Subject: [PATCH 04/10] chore: set fetch audio error --- lib/pangea/toolbar/widgets/select_mode_buttons.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pangea/toolbar/widgets/select_mode_buttons.dart b/lib/pangea/toolbar/widgets/select_mode_buttons.dart index 238fec5f9..f2f561361 100644 --- a/lib/pangea/toolbar/widgets/select_mode_buttons.dart +++ b/lib/pangea/toolbar/widgets/select_mode_buttons.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -202,12 +201,10 @@ class SelectModeButtonsState extends State { File? file; file = File('${tempDir.path}/${_audioBytes!.name}'); await file.writeAsBytes(_audioBytes!.bytes); - setState(() => _audioFile = file); + _audioFile = file; } - - if (mounted) setState(() => _isLoadingAudio = false); } catch (e, s) { - debugger(when: kDebugMode); + _audioError = e.toString(); ErrorHandler.logError( e: e, s: s, @@ -217,6 +214,7 @@ class SelectModeButtonsState extends State { messageEvent?.messageDisplayLangCode, }, ); + } finally { if (mounted) setState(() => _isLoadingAudio = false); } } @@ -289,7 +287,7 @@ class SelectModeButtonsState extends State { } TtsController.stop(); - matrix?.audioPlayer?.play(); + await matrix?.audioPlayer?.play(); } catch (e, s) { setState(() => _audioError = e.toString()); ErrorHandler.logError( From e6d2a6834871ddf7caa6cda223301a39498a4160 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 27 Jun 2025 10:40:39 -0400 Subject: [PATCH 05/10] chore: don't interupt message audio with button click sound --- lib/pages/chat/events/audio_player.dart | 43 +++++++++++-------- .../toolbar/widgets/overlay_message.dart | 4 +- .../toolbar/widgets/select_mode_buttons.dart | 2 +- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 6728e69c0..ebecd12c0 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -209,28 +209,37 @@ class AudioPlayerState extends State { // #Pangea // if (!kIsWeb) { - if (!kIsWeb && matrixFile != null) { - // Pangea# - final tempDir = await getTemporaryDirectory(); - final fileName = Uri.encodeComponent( - // #Pangea - // widget.event.attachmentOrThumbnailMxcUrl()!.pathSegments.last, - widget.event!.attachmentOrThumbnailMxcUrl()!.pathSegments.last, + if (!kIsWeb) { + if (matrixFile != null) { // Pangea# - ); - file = File('${tempDir.path}/${fileName}_${matrixFile.name}'); + final tempDir = await getTemporaryDirectory(); + final fileName = Uri.encodeComponent( + // #Pangea + // widget.event.attachmentOrThumbnailMxcUrl()!.pathSegments.last, + widget.event!.attachmentOrThumbnailMxcUrl()!.pathSegments.last, + // Pangea# + ); + file = File('${tempDir.path}/${fileName}_${matrixFile.name}'); - await file.writeAsBytes(matrixFile.bytes); + await file.writeAsBytes(matrixFile.bytes); - if (Platform.isIOS && - matrixFile.mimeType.toLowerCase() == 'audio/ogg') { - Logs().v('Convert ogg audio file for iOS...'); - final convertedFile = File('${file.path}.caf'); - if (await convertedFile.exists() == false) { - OpusCaf().convertOpusToCaf(file.path, convertedFile.path); + if (Platform.isIOS && + matrixFile.mimeType.toLowerCase() == 'audio/ogg') { + Logs().v('Convert ogg audio file for iOS...'); + final convertedFile = File('${file.path}.caf'); + if (await convertedFile.exists() == false) { + OpusCaf().convertOpusToCaf(file.path, convertedFile.path); + } + file = convertedFile; } - file = convertedFile; + // #Pangea + } else if (widget.matrixFile != null) { + final tempDir = await getTemporaryDirectory(); + + file = File('${tempDir.path}/${widget.matrixFile!.name}'); + await file.writeAsBytes(widget.matrixFile!.bytes); } + // Pangea# } setState(() { diff --git a/lib/pangea/toolbar/widgets/overlay_message.dart b/lib/pangea/toolbar/widgets/overlay_message.dart index fc0543395..e678ac1ad 100644 --- a/lib/pangea/toolbar/widgets/overlay_message.dart +++ b/lib/pangea/toolbar/widgets/overlay_message.dart @@ -206,8 +206,8 @@ class OverlayMessage extends StatelessWidget { text: overlayController .transcription!.transcript.text, textLanguage: PLanguageStore.byLangCode( - pangeaMessageEvent! - .messageDisplayLangCode, + overlayController + .transcription!.langCode, ) ?? LanguageModel.unknown, style: AppConfig.messageTextStyle( diff --git a/lib/pangea/toolbar/widgets/select_mode_buttons.dart b/lib/pangea/toolbar/widgets/select_mode_buttons.dart index f2f561361..97e334bfb 100644 --- a/lib/pangea/toolbar/widgets/select_mode_buttons.dart +++ b/lib/pangea/toolbar/widgets/select_mode_buttons.dart @@ -492,7 +492,7 @@ class SelectModeButtonsState extends State { borderRadius: BorderRadius.circular(20), color: Theme.of(context).colorScheme.primaryContainer, onPressed: () => _updateMode(mode), - playSound: true, + playSound: mode != SelectMode.audio, colorFactor: Theme.of(context).brightness == Brightness.light ? 0.55 : 0.3, From 15ae6844ca02e4923c5773eb8f9abc92f441ff81 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 27 Jun 2025 12:03:52 -0400 Subject: [PATCH 06/10] Simplify audio button error behavior, remove audio error reset on clear, remove tooltip on error --- lib/pangea/toolbar/widgets/select_mode_buttons.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pangea/toolbar/widgets/select_mode_buttons.dart b/lib/pangea/toolbar/widgets/select_mode_buttons.dart index f2f561361..fcc43c81a 100644 --- a/lib/pangea/toolbar/widgets/select_mode_buttons.dart +++ b/lib/pangea/toolbar/widgets/select_mode_buttons.dart @@ -125,7 +125,8 @@ class SelectModeButtonsState extends State { void _clear() { setState(() { - _audioError = null; + // Audio errors do not go away when I switch modes and back + // Is there any reason to wipe error records on clear? _translationError = null; _speechTranslationError = null; }); @@ -148,8 +149,10 @@ class SelectModeButtonsState extends State { } setState( - () => _selectedMode = - _selectedMode == mode && mode != SelectMode.audio ? null : mode, + () => _selectedMode = _selectedMode == mode && + (mode != SelectMode.audio || _audioError != null) + ? null + : mode, ); if (_selectedMode == SelectMode.audio) { @@ -486,7 +489,7 @@ class SelectModeButtonsState extends State { children: [ for (final mode in modes) Tooltip( - message: mode.tooltip(context), + message: _isError ? null : mode.tooltip(context), child: PressableButton( depressed: mode == _selectedMode, borderRadius: BorderRadius.circular(20), From 9a0f5682ef52306a1e420fe562d1c9c4bdb0681e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 27 Jun 2025 12:19:47 -0400 Subject: [PATCH 07/10] chore: send all message / constructs from the level to request for construct summary, show loading and error messages when needed --- .../get_analytics_controller.dart | 52 ++- lib/pangea/analytics_misc/level_up.dart | 296 ++++++++++-------- 2 files changed, 203 insertions(+), 145 deletions(-) diff --git a/lib/pangea/analytics_misc/get_analytics_controller.dart b/lib/pangea/analytics_misc/get_analytics_controller.dart index dcdcafd65..5f8997a7d 100644 --- a/lib/pangea/analytics_misc/get_analytics_controller.dart +++ b/lib/pangea/analytics_misc/get_analytics_controller.dart @@ -477,8 +477,8 @@ class GetAnalyticsController extends BaseController { // generate level up analytics as a construct summary ConstructSummary summary; try { - final int maxXP = constructListModel.calculateXpWithLevel(upperLevel); - final int minXP = constructListModel.calculateXpWithLevel(lowerLevel); + final int minXP = constructListModel.calculateXpWithLevel(upperLevel); + final int maxXP = constructListModel.calculateXpWithLevel(lowerLevel); int diffXP = maxXP - minXP; if (diffXP < 0) diffXP = 0; @@ -492,23 +492,41 @@ class GetAnalyticsController extends BaseController { } // extract construct use message bodies for analytics - List? constructUseMessageContentBodies = []; + final Map> useEventIds = {}; for (final use in constructUseOfCurrentLevel) { - try { - final useMessage = await use.getEvent(_client); - final useMessageBody = useMessage?.content["body"]; - if (useMessageBody is String) { - constructUseMessageContentBodies.add(useMessageBody); - } else { - constructUseMessageContentBodies.add(null); - } - } catch (e) { - constructUseMessageContentBodies.add(null); - } + if (use.metadata.roomId == null) continue; + if (use.metadata.eventId == null) continue; + useEventIds[use.metadata.roomId!] ??= {}; + useEventIds[use.metadata.roomId!]!.add(use.metadata.eventId!); } - if (constructUseMessageContentBodies.length != - constructUseOfCurrentLevel.length) { - constructUseMessageContentBodies = null; + + final List constructUseMessageContentBodies = []; + for (final entry in useEventIds.entries) { + final String roomId = entry.key; + final room = _client.getRoomById(roomId); + if (room == null) continue; + final List messageBodies = []; + for (final eventId in entry.value) { + try { + final Event? event = await room.getEventById(eventId); + if (event?.content["body"] is! String) continue; + final String body = event?.content["body"] as String; + if (body.isEmpty) continue; + messageBodies.add(body); + } catch (e, s) { + debugPrint("Error getting event by ID: $e"); + ErrorHandler.logError( + e: e, + s: s, + data: { + 'roomId': roomId, + 'eventId': eventId, + }, + ); + continue; + } + } + constructUseMessageContentBodies.addAll(messageBodies); } final request = ConstructSummaryRequest( diff --git a/lib/pangea/analytics_misc/level_up.dart b/lib/pangea/analytics_misc/level_up.dart index ab57cd03d..6e348aa13 100644 --- a/lib/pangea/analytics_misc/level_up.dart +++ b/lib/pangea/analytics_misc/level_up.dart @@ -91,6 +91,7 @@ class LevelUpBannerState extends State ConstructSummary? _constructSummary; String? _error; + bool _loading = true; @override void initState() { @@ -143,6 +144,7 @@ class LevelUpBannerState extends State Future _setConstructSummary() async { try { + setState(() => _loading = true); _constructSummary = await MatrixState.pangeaController.getAnalytics .generateLevelUpAnalytics( widget.level, @@ -150,6 +152,10 @@ class LevelUpBannerState extends State ); } catch (e) { _error = e.toString(); + } finally { + if (mounted) { + setState(() => _loading = false); + } } } @@ -364,144 +370,178 @@ class LevelUpBannerState extends State borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.all(16), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 24.0, - children: [ - Table( - columnWidths: const { - 0: IntrinsicColumnWidth(), - 1: FlexColumnWidth(), - 2: IntrinsicColumnWidth(), - }, - defaultVerticalAlignment: - TableCellVerticalAlignment.middle, - children: [ - ...LearningSkillsEnum.values - .where( - (v) => - v.isVisible && _skillsPoints(v) > -1, + child: _loading + ? const Center( + child: CircularProgressIndicator.adaptive(), + ) + : _error != null + ? Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon( + Icons.error, + color: Theme.of(context) + .colorScheme + .error, + ), + const SizedBox(width: 8.0), + Text( + L10n.of(context) + .oopsSomethingWentWrong, + ), + ], ) - .map((skill) { - return TableRow( + : SingleChildScrollView( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + spacing: 24.0, children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 9.0, - horizontal: 18.0, - ), - child: Icon( - skill.icon, - size: 25, - color: Colors.white, - ), + Table( + columnWidths: const { + 0: IntrinsicColumnWidth(), + 1: FlexColumnWidth(), + 2: IntrinsicColumnWidth(), + }, + defaultVerticalAlignment: + TableCellVerticalAlignment + .middle, + children: [ + ...LearningSkillsEnum.values + .where( + (v) => + v.isVisible && + _skillsPoints(v) > -1, + ) + .map((skill) { + return TableRow( + children: [ + Padding( + padding: const EdgeInsets + .symmetric( + vertical: 9.0, + horizontal: 18.0, + ), + child: Icon( + skill.icon, + size: 25, + color: Colors.white, + ), + ), + Padding( + padding: const EdgeInsets + .symmetric( + vertical: 9.0, + horizontal: 18.0, + ), + child: Text( + skill.tooltip(context), + style: const TextStyle( + fontSize: 16, + fontWeight: + FontWeight.w600, + color: Colors.white, + ), + textAlign: + TextAlign.center, + ), + ), + Padding( + padding: const EdgeInsets + .symmetric( + vertical: 9.0, + horizontal: 18.0, + ), + child: Text( + "+ ${_skillsPoints(skill)} XP", + style: const TextStyle( + fontSize: 16, + fontWeight: + FontWeight.w600, + color: Colors.white, + ), + textAlign: + TextAlign.center, + ), + ), + ], + ); + }), + ], ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 9.0, - horizontal: 18.0, - ), - child: Text( - skill.tooltip(context), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white, + CachedNetworkImage( + imageUrl: + "${AppConfig.assetsBaseURL}/${LevelUpConstants.dinoLevelUPFileName}", + width: 400, + fit: BoxFit.cover, + ), + if (_constructSummary?.textSummary != + null) + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .secondaryContainer, + borderRadius: + BorderRadius.circular(8), ), - textAlign: TextAlign.center, - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - vertical: 9.0, - horizontal: 18.0, - ), - child: Text( - "+ ${_skillsPoints(skill)} XP", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white, + child: Text( + _constructSummary!.textSummary, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context) + .colorScheme + .onSecondaryContainer, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, ), + const SizedBox( + height: 24, ), + // Share button, currently no functionality + // ElevatedButton( + // onPressed: () { + // // Add share functionality + // }, + // style: ElevatedButton.styleFrom( + // backgroundColor: Colors.white, + // foregroundColor: Colors.black, + // padding: const EdgeInsets.symmetric( + // vertical: 12, + // horizontal: 24, + // ), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // child: const Row( + // mainAxisSize: MainAxisSize + // .min, + // children: [ + // Text( + // "Share with Friends", + // style: TextStyle( + // fontSize: 16, + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox( + // width: 8, + // ), + // Icon( + // Icons.ios_share, + // size: 20, + // ), + // ), + // ), + // ), ], - ); - }), - ], - ), - CachedNetworkImage( - imageUrl: - "${AppConfig.assetsBaseURL}/${LevelUpConstants.dinoLevelUPFileName}", - width: 400, - fit: BoxFit.cover, - ), - if (_constructSummary?.textSummary != null) - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondaryContainer, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - _constructSummary!.textSummary, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Theme.of(context) - .colorScheme - .onSecondaryContainer, ), - textAlign: TextAlign.center, ), - ), - const SizedBox( - height: 24, - ), - // Share button, currently no functionality - // ElevatedButton( - // onPressed: () { - // // Add share functionality - // }, - // style: ElevatedButton.styleFrom( - // backgroundColor: Colors.white, - // foregroundColor: Colors.black, - // padding: const EdgeInsets.symmetric( - // vertical: 12, - // horizontal: 24, - // ), - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // child: const Row( - // mainAxisSize: MainAxisSize - // .min, - // children: [ - // Text( - // "Share with Friends", - // style: TextStyle( - // fontSize: 16, - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox( - // width: 8, - // ), - // Icon( - // Icons.ios_share, - // size: 20, - // ), - // ), - // ), - // ), - ], - ), - ), ), ), ], From 678e32a80f2730467071300fee94ee0e2e844799 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 27 Jun 2025 12:32:11 -0400 Subject: [PATCH 08/10] Use tooltipvisibility, don't mess with tooltips for non-selected modes --- .../toolbar/widgets/select_mode_buttons.dart | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/pangea/toolbar/widgets/select_mode_buttons.dart b/lib/pangea/toolbar/widgets/select_mode_buttons.dart index 0025ff800..1a5ff426b 100644 --- a/lib/pangea/toolbar/widgets/select_mode_buttons.dart +++ b/lib/pangea/toolbar/widgets/select_mode_buttons.dart @@ -488,25 +488,28 @@ class SelectModeButtonsState extends State { spacing: 4.0, children: [ for (final mode in modes) - Tooltip( - message: _isError ? null : mode.tooltip(context), - child: PressableButton( - depressed: mode == _selectedMode, - borderRadius: BorderRadius.circular(20), - color: Theme.of(context).colorScheme.primaryContainer, - onPressed: () => _updateMode(mode), - playSound: mode != SelectMode.audio, - colorFactor: Theme.of(context).brightness == Brightness.light - ? 0.55 - : 0.3, - child: Container( - height: buttonSize, - width: buttonSize, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primaryContainer, - shape: BoxShape.circle, + TooltipVisibility( + visible: (!_isError || mode != _selectedMode), + child: Tooltip( + message: mode.tooltip(context), + child: PressableButton( + depressed: mode == _selectedMode, + borderRadius: BorderRadius.circular(20), + color: Theme.of(context).colorScheme.primaryContainer, + onPressed: () => _updateMode(mode), + playSound: mode != SelectMode.audio, + colorFactor: Theme.of(context).brightness == Brightness.light + ? 0.55 + : 0.3, + child: Container( + height: buttonSize, + width: buttonSize, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + shape: BoxShape.circle, + ), + child: icon(mode), ), - child: icon(mode), ), ), ), From 8714f05aa86888831c20e81531b2d40e0cdeddf2 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 27 Jun 2025 12:38:18 -0400 Subject: [PATCH 09/10] chore: always set playback speech variable when toggling audio speed --- lib/pages/chat/events/audio_player.dart | 27 +++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index ebecd12c0..0831047f4 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -323,22 +323,19 @@ class AudioPlayerState extends State { final audioPlayer = matrix.audioPlayer; // #Pangea // if (audioPlayer == null) return; - if (audioPlayer == null || - matrix.voiceMessageEventId.value != widget.eventId) { - switch (playbackSpeed) { - case 1.0: - setState(() => playbackSpeed = 0.75); - case 0.75: - setState(() => playbackSpeed = 0.5); - case 0.5: - setState(() => playbackSpeed = 1.25); - case 1.25: - setState(() => playbackSpeed = 1.5); - default: - setState(() => playbackSpeed = 1.0); - } - return; + switch (playbackSpeed) { + case 1.0: + setState(() => playbackSpeed = 0.75); + case 0.75: + setState(() => playbackSpeed = 0.5); + case 0.5: + setState(() => playbackSpeed = 1.25); + case 1.25: + setState(() => playbackSpeed = 1.5); + default: + setState(() => playbackSpeed = 1.0); } + if (audioPlayer == null) return; // Pangea# switch (audioPlayer.speed) { // #Pangea From d42347201960db71ac9ad938f4ea5c32b6ab3dbb Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 27 Jun 2025 13:49:45 -0400 Subject: [PATCH 10/10] chore: wait for language change updates in sync --- .../learning_settings/pages/settings_learning.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/pangea/learning_settings/pages/settings_learning.dart b/lib/pangea/learning_settings/pages/settings_learning.dart index 340b79597..304beebe6 100644 --- a/lib/pangea/learning_settings/pages/settings_learning.dart +++ b/lib/pangea/learning_settings/pages/settings_learning.dart @@ -125,9 +125,12 @@ class SettingsLearningController extends State { if (formKey.currentState!.validate()) { await showFutureLoadingDialog( context: context, - future: () async => pangeaController.userController.updateProfile( - (_) => _profile, - ), + future: () async => pangeaController.userController + .updateProfile( + (_) => _profile, + waitForDataInSync: true, + ) + .timeout(const Duration(seconds: 15)), ); Navigator.of(context).pop(); }