diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e96bbbf20..68422ad70 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4767,5 +4767,6 @@ "video": "Video", "voiceMessage": "Voice message", "nan": "Not applicable", - "activityPlannerOverviewInstructionsBody": "Choose a topic, mode, learning objective and generate an activity for the chat!" + "activityPlannerOverviewInstructionsBody": "Choose a topic, mode, learning objective and generate an activity for the chat!", + "completeActivitiesToUnlock": "Complete the highlighted word activities to unlock" } \ No newline at end of file diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index b3ab2e38a..690756a8b 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -31,17 +31,20 @@ abstract class AppConfig { static const double defaultFooterHeight = 48.0; static const double toolbarSpacing = 8.0; static TextStyle messageTextStyle( - Event event, + Event? event, Color textColor, ) { final fontSize = messageFontSize * fontSizeFactor; - final bigEmotes = - event.onlyEmotes && event.numberEmotes > 0 && event.numberEmotes <= 10; + final bigEmotes = event != null && + event.onlyEmotes && + event.numberEmotes > 0 && + event.numberEmotes <= 10; return TextStyle( color: textColor, fontSize: bigEmotes ? fontSize * 5 : fontSize, - decoration: event.redacted ? TextDecoration.lineThrough : null, + decoration: + (event?.redacted ?? false) ? TextDecoration.lineThrough : null, height: 1.3, ); } diff --git a/lib/pangea/toolbar/widgets/message_mode_locked_card.dart b/lib/pangea/toolbar/widgets/message_mode_locked_card.dart new file mode 100644 index 000000000..64272cfff --- /dev/null +++ b/lib/pangea/toolbar/widgets/message_mode_locked_card.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +import 'package:fluffychat/config/app_config.dart'; + +class MessageModeLockedCard extends StatelessWidget { + const MessageModeLockedCard({super.key}); + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: AppConfig.toolbarMinWidth, + maxHeight: AppConfig.toolbarMaxHeight, + ), + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 20, 16, 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.lock_outline, + size: 40, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(height: 16), + Text( + L10n.of(context).completeActivitiesToUnlock, + style: AppConfig.messageTextStyle( + null, + Theme.of(context).colorScheme.primary, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pangea/toolbar/widgets/message_toolbar.dart b/lib/pangea/toolbar/widgets/message_toolbar.dart index 9db07e5c8..c26df8d07 100644 --- a/lib/pangea/toolbar/widgets/message_toolbar.dart +++ b/lib/pangea/toolbar/widgets/message_toolbar.dart @@ -9,6 +9,7 @@ import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dar import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart'; import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_audio_card.dart'; +import 'package:fluffychat/pangea/toolbar/widgets/message_mode_locked_card.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_speech_to_text_card.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_translation_card.dart'; @@ -57,6 +58,15 @@ class MessageToolbar extends StatelessWidget { return const ToolbarContentLoadingIndicator(); } + final unlocked = overlayController.toolbarMode.isUnlocked( + overlayController.pangeaMessageEvent!.proportionOfActivitiesCompleted, + overlayController.isPracticeComplete, + ); + + if (!unlocked) { + return const MessageModeLockedCard(); + } + switch (overlayController.toolbarMode) { case MessageMode.translation: return MessageTranslationCard( diff --git a/lib/pangea/toolbar/widgets/toolbar_button.dart b/lib/pangea/toolbar/widgets/toolbar_button.dart index 7fa310dcd..929674c9e 100644 --- a/lib/pangea/toolbar/widgets/toolbar_button.dart +++ b/lib/pangea/toolbar/widgets/toolbar_button.dart @@ -4,7 +4,6 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pangea/common/widgets/pressable_button.dart'; import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/toolbar_button_and_progress_row.dart'; class ToolbarButton extends StatelessWidget { final MessageMode mode; @@ -39,11 +38,9 @@ class ToolbarButton extends StatelessWidget { children: [ PressableButton( borderRadius: BorderRadius.circular(20), - depressed: !enabled || mode == overlayController.toolbarMode, + depressed: mode == overlayController.toolbarMode, color: color(context), - onPressed: enabled - ? () => overlayController.updateToolbarMode(mode) - : null, + onPressed: () => overlayController.updateToolbarMode(mode), playSound: true, child: AnimatedContainer( duration: FluffyThemes.animationDuration, @@ -61,7 +58,6 @@ class ToolbarButton extends StatelessWidget { ), ), ), - if (!enabled) const DisabledAnimation(), ], ), ); diff --git a/lib/pangea/toolbar/widgets/toolbar_button_and_progress_row.dart b/lib/pangea/toolbar/widgets/toolbar_button_and_progress_row.dart index cc513b36f..455954fb1 100644 --- a/lib/pangea/toolbar/widgets/toolbar_button_and_progress_row.dart +++ b/lib/pangea/toolbar/widgets/toolbar_button_and_progress_row.dart @@ -1,8 +1,6 @@ import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:matrix/matrix.dart'; @@ -108,80 +106,3 @@ class ToolbarButtonAndProgressRow extends StatelessWidget { ); } } - -class DisabledAnimation extends StatefulWidget { - final double size; - - const DisabledAnimation({ - this.size = 40.0, - super.key, - }); - - @override - DisabledAnimationState createState() => DisabledAnimationState(); -} - -class DisabledAnimationState extends State - with SingleTickerProviderStateMixin { - late final AnimationController _controller; - late final Animation _animation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 1000), - vsync: this, - ); - - _animation = TweenSequence([ - TweenSequenceItem( - tween: Tween(begin: 0, end: 0.9), - weight: 1.0, - ), - TweenSequenceItem( - tween: Tween(begin: 0.9, end: 0.9), - weight: 1.0, - ), - TweenSequenceItem( - tween: Tween(begin: 0.9, end: 0), - weight: 1.0, - ), - ]).animate(_controller); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return AnimatedBuilder( - animation: _animation, - builder: (context, _) { - return GestureDetector( - onTap: () { - _controller.forward().then((_) => _controller.reset()); - if (!kIsWeb) { - HapticFeedback.mediumImpact(); - } - }, - child: SizedBox( - width: widget.size, - height: widget.size, - child: Opacity( - opacity: _animation.value, - child: const Icon( - Icons.lock, - color: AppConfig.primaryColor, - size: 28, - ), - ), - ), - ); - }, - ); - } -}