From cdfc8b831edde5c1c4df983d0e1da9d3a5602209 Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:55:05 -0500 Subject: [PATCH] feat: added widget to make dialog full screen on mobile with constraints on web (#1499) --- .../morph_analytics_popup.dart | 42 ++-- .../vocab_analytics_popup.dart | 46 ++-- .../conversation_bot_settings.dart | 219 +++++++++--------- .../common/widgets/full_width_dialog.dart | 36 +++ .../pages/settings_learning_view.dart | 26 +-- 5 files changed, 185 insertions(+), 184 deletions(-) create mode 100644 lib/pangea/common/widgets/full_width_dialog.dart diff --git a/lib/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_popup.dart b/lib/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_popup.dart index 75f285c56..8cfe3fdee 100644 --- a/lib/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_popup.dart +++ b/lib/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_popup.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart' import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart'; import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart'; import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_xp_tile.dart'; +import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; class MorphAnalyticsPopup extends StatefulWidget { @@ -123,33 +124,26 @@ class MorphAnalyticsPopupState extends State { ); } - return Dialog( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 400, - maxHeight: 600, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20.0), - child: Scaffold( - appBar: AppBar( - title: Text(widget.type.indicator.tooltip(context)), - leading: IconButton( - icon: selectedCategory == null - ? const Icon(Icons.close) - : const Icon(Icons.chevron_left_outlined), - onPressed: selectedCategory == null - ? Navigator.of(context).pop - : () => setSelectedCategory(null), - ), - ), - body: Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: dialogContent, - ), + return FullWidthDialog( + dialogContent: Scaffold( + appBar: AppBar( + title: Text(widget.type.indicator.tooltip(context)), + leading: IconButton( + icon: selectedCategory == null + ? const Icon(Icons.close) + : const Icon(Icons.chevron_left_outlined), + onPressed: selectedCategory == null + ? Navigator.of(context).pop + : () => setSelectedCategory(null), ), ), + body: Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: dialogContent, + ), ), + maxWidth: 600, + maxHeight: 800, ); } } diff --git a/lib/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_analytics_popup.dart b/lib/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_analytics_popup.dart index 2cfd91808..1f4bcd81b 100644 --- a/lib/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_analytics_popup.dart +++ b/lib/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_analytics_popup.dart @@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart'; import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart'; import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart'; import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_definition_popup.dart'; +import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; /// Displays vocab analytics, sorted into categories @@ -159,8 +160,21 @@ class VocabAnalyticsPopupState extends State { final Widget greens = dialogWidget(LemmaCategoryEnum.greens, greenLemmas); final Widget seeds = dialogWidget(LemmaCategoryEnum.seeds, seedLemmas); - return ListView( - children: [flowers, greens, seeds], + return Scaffold( + appBar: AppBar( + title: Text(ProgressIndicatorEnum.wordsUsed.tooltip(context)), + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: Navigator.of(context).pop, + ), + // TODO: add search and training buttons? + ), + body: Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: ListView( + children: [flowers, greens, seeds], + ), + ), ); } @@ -238,30 +252,10 @@ class VocabAnalyticsPopupState extends State { @override Widget build(BuildContext context) { - return Dialog( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 400, - maxHeight: 600, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20.0), - child: Scaffold( - appBar: AppBar( - title: Text(ProgressIndicatorEnum.wordsUsed.tooltip(context)), - leading: IconButton( - icon: const Icon(Icons.close), - onPressed: Navigator.of(context).pop, - ), - // TODO: add search and training buttons? - ), - body: Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: dialogContent, - ), - ), - ), - ), + return FullWidthDialog( + dialogContent: dialogContent, + maxWidth: 600, + maxHeight: 800, ); } } diff --git a/lib/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings.dart index 1dcf44916..1cfe32abd 100644 --- a/lib/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings.dart +++ b/lib/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings.dart @@ -14,6 +14,7 @@ import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/conversation_bot/conversation_bot_no_permission_dialog.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/conversation_bot/conversation_bot_settings_form.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -175,135 +176,125 @@ class ConversationBotSettingsDialogState Widget build(BuildContext context) { final dialogContent = Form( key: formKey, - child: Container( + child: Padding( padding: const EdgeInsets.all(16), - constraints: kIsWeb - ? const BoxConstraints( - maxWidth: 450, - maxHeight: 725, - ) - : null, - child: ClipRRect( - borderRadius: BorderRadius.circular(20.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.symmetric( - vertical: 12, - ), - child: Text( - L10n.of(context).botConfig, - style: Theme.of(context).textTheme.titleLarge, - ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12, ), - IconButton( - icon: const Icon(Icons.close), - onPressed: () => Navigator.of(context).pop(null), + child: Text( + L10n.of(context).botConfig, + style: Theme.of(context).textTheme.titleLarge, ), - ], - ), - InkWell( - onTap: hasPermission - ? null - : () => showNoPermissionDialog(context), - child: SwitchListTile( - title: Text( - L10n.of(context).conversationBotStatus, - ), - value: addBot, - onChanged: hasPermission - ? (bool value) { - setState(() => addBot = value); - } - : null, // Keeps the switch disabled - contentPadding: const EdgeInsets.all(4), ), + IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(null), + ), + ], + ), + InkWell( + onTap: + hasPermission ? null : () => showNoPermissionDialog(context), + child: SwitchListTile( + title: Text( + L10n.of(context).conversationBotStatus, + ), + value: addBot, + onChanged: hasPermission + ? (bool value) { + setState(() => addBot = value); + } + : null, // Keeps the switch disabled + contentPadding: const EdgeInsets.all(4), ), - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - children: [ - const SizedBox(height: 20), - AnimatedOpacity( - duration: FluffyThemes.animationDuration, - opacity: addBot ? 1.0 : 0.5, - child: ConversationBotSettingsForm( - botOptions: botOptions, - discussionKeywordsController: - discussionKeywordsController, - discussionTopicController: - discussionTopicController, - customSystemPromptController: - customSystemPromptController, - hasPermission: hasPermission, - enabled: addBot, - hasUpdatedMode: hasUpdatedMode, - onUpdateBotMode: onUpdateChatMode, - onUpdateBotLanguage: onUpdateBotLanguage, - onUpdateBotVoice: onUpdateBotVoice, - onUpdateBotLanguageLevel: onUpdateBotLanguageLevel, - ), + ), + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + children: [ + const SizedBox(height: 20), + AnimatedOpacity( + duration: FluffyThemes.animationDuration, + opacity: addBot ? 1.0 : 0.5, + child: ConversationBotSettingsForm( + botOptions: botOptions, + discussionKeywordsController: + discussionKeywordsController, + discussionTopicController: discussionTopicController, + customSystemPromptController: + customSystemPromptController, + hasPermission: hasPermission, + enabled: addBot, + hasUpdatedMode: hasUpdatedMode, + onUpdateBotMode: onUpdateChatMode, + onUpdateBotLanguage: onUpdateBotLanguage, + onUpdateBotVoice: onUpdateBotVoice, + onUpdateBotLanguageLevel: onUpdateBotLanguageLevel, ), - ], - ), + ), + ], ), ), ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (hasPermission) - TextButton( - onPressed: () { - Navigator.of(context).pop(null); - }, - child: Text(L10n.of(context).cancel), - ), - const SizedBox(width: 20), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (hasPermission) TextButton( - onPressed: () async { - if (!hasPermission) { - Navigator.of(context).pop(null); - return; - } - final isValid = formKey.currentState!.validate(); - if (!isValid) return; - - updateFromTextControllers(); - botOptions.targetLanguage ??= MatrixState - .pangeaController.languageController.userL2?.langCode; - - Navigator.of(context).pop(botOptions); - - final bool isBotRoomMember = - await widget.room.botIsInRoom; - if (addBot && !isBotRoomMember) { - await widget.room.invite(BotName.byEnvironment); - } else if (!addBot && isBotRoomMember) { - await widget.room.kick(BotName.byEnvironment); - } + onPressed: () { + Navigator.of(context).pop(null); }, - child: hasPermission - ? Text(L10n.of(context).confirm) - : Text(L10n.of(context).close), + child: Text(L10n.of(context).cancel), ), - ], - ), - ], - ), + const SizedBox(width: 20), + TextButton( + onPressed: () async { + if (!hasPermission) { + Navigator.of(context).pop(null); + return; + } + final isValid = formKey.currentState!.validate(); + if (!isValid) return; + + updateFromTextControllers(); + botOptions.targetLanguage ??= MatrixState + .pangeaController.languageController.userL2?.langCode; + + Navigator.of(context).pop(botOptions); + + final bool isBotRoomMember = await widget.room.botIsInRoom; + if (addBot && !isBotRoomMember) { + await widget.room.invite(BotName.byEnvironment); + } else if (!addBot && isBotRoomMember) { + await widget.room.kick(BotName.byEnvironment); + } + }, + child: hasPermission + ? Text(L10n.of(context).confirm) + : Text(L10n.of(context).close), + ), + ], + ), + ], ), ), ); - return kIsWeb - ? Dialog(child: dialogContent) - : Dialog.fullscreen(child: dialogContent); + return FullWidthDialog( + dialogContent: dialogContent, + maxWidth: 450, + maxHeight: 725, + ); } } diff --git a/lib/pangea/common/widgets/full_width_dialog.dart b/lib/pangea/common/widgets/full_width_dialog.dart new file mode 100644 index 000000000..a13a5b752 --- /dev/null +++ b/lib/pangea/common/widgets/full_width_dialog.dart @@ -0,0 +1,36 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class FullWidthDialog extends StatelessWidget { + final Widget dialogContent; + final double maxWidth; + final double maxHeight; + + const FullWidthDialog({ + required this.dialogContent, + required this.maxWidth, + required this.maxHeight, + super.key, + }); + + @override + Widget build(BuildContext context) { + final content = ConstrainedBox( + constraints: kIsWeb + ? BoxConstraints( + maxWidth: maxWidth, + maxHeight: maxHeight, + ) + : BoxConstraints( + maxWidth: MediaQuery.of(context).size.width, + maxHeight: MediaQuery.of(context).size.height, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20.0), + child: dialogContent, + ), + ); + + return kIsWeb ? Dialog(child: content) : Dialog.fullscreen(child: content); + } +} diff --git a/lib/pangea/learning_settings/pages/settings_learning_view.dart b/lib/pangea/learning_settings/pages/settings_learning_view.dart index ee6c6e26e..7fbec574a 100644 --- a/lib/pangea/learning_settings/pages/settings_learning_view.dart +++ b/lib/pangea/learning_settings/pages/settings_learning_view.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -7,6 +6,7 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/common/constants/model_keys.dart'; +import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart'; import 'package:fluffychat/pangea/learning_settings/widgets/country_picker_tile.dart'; import 'package:fluffychat/pangea/learning_settings/widgets/language_tile.dart'; @@ -125,25 +125,11 @@ class SettingsLearningView extends StatelessWidget { ), ); - return kIsWeb - ? Dialog( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 600, - maxHeight: 600, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20.0), - child: dialogContent, - ), - ), - ) - : Dialog.fullscreen( - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 600), - child: dialogContent, - ), - ); + return FullWidthDialog( + dialogContent: dialogContent, + maxWidth: 600, + maxHeight: 600, + ); }, ); }