diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index bec1df519..548e0a90a 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -35,6 +35,7 @@ abstract class AppConfig { static const Color activeToggleColor = Color(0xFF33D057); static const Color success = Color(0xFF33D057); static const Color warning = Color.fromARGB(255, 210, 124, 12); + static const int overlayAnimationDuration = 250; // static String _privacyUrl = // 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md'; static String _privacyUrl = "https://www.pangeachat.com/privacy"; diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 203186116..091b35047 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1699,7 +1699,7 @@ class ChatController extends State context: context, child: overlayEntry, transformTargetId: "", - backgroundColor: const Color.fromRGBO(0, 0, 0, 1).withAlpha(150), + backgroundColor: Colors.black, closePrevOverlay: MatrixState.pangeaController.subscriptionController.isSubscribed, position: OverlayPositionEnum.centered, diff --git a/lib/pangea/utils/overlay.dart b/lib/pangea/utils/overlay.dart index ef7a16b80..49ef48851 100644 --- a/lib/pangea/utils/overlay.dart +++ b/lib/pangea/utils/overlay.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'dart:ui'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart'; import 'package:fluffychat/pangea/widgets/common_widgets/overlay_container.dart'; import 'package:flutter/foundation.dart'; @@ -219,7 +220,7 @@ class OverlayUtil { static bool get isOverlayOpen => MatrixState.pAnyState.entries.isNotEmpty; } -class TransparentBackdrop extends StatelessWidget { +class TransparentBackdrop extends StatefulWidget { final Color? backgroundColor; final Function? onDismiss; final bool blurBackground; @@ -231,34 +232,91 @@ class TransparentBackdrop extends StatelessWidget { this.blurBackground = false, }); + @override + TransparentBackdropState createState() => TransparentBackdropState(); +} + +class TransparentBackdropState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _opacityTween; + late Animation _blurTween; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: + const Duration(milliseconds: AppConfig.overlayAnimationDuration), + vsync: this, + ); + _opacityTween = Tween(begin: 0.0, end: 0.8).animate( + CurvedAnimation( + parent: _controller, + curve: FluffyThemes.animationCurve, + ), + ); + _blurTween = Tween(begin: 0.0, end: 2.5).animate( + CurvedAnimation( + parent: _controller, + curve: FluffyThemes.animationCurve, + ), + ); + + Future.delayed(const Duration(milliseconds: 100), () { + if (mounted) _controller.forward(); + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return Material( - borderOnForeground: false, - color: backgroundColor ?? Colors.transparent, - clipBehavior: Clip.antiAlias, - child: InkWell( - hoverColor: Colors.transparent, - splashColor: Colors.transparent, - focusColor: Colors.transparent, - highlightColor: Colors.transparent, - onTap: () { - if (onDismiss != null) { - onDismiss!(); - } - MatrixState.pAnyState.closeOverlay(); - }, - child: BackdropFilter( - filter: blurBackground - ? ImageFilter.blur(sigmaX: 2.5, sigmaY: 2.5) - : ImageFilter.blur(sigmaX: 0, sigmaY: 0), - child: Container( - height: double.infinity, - width: double.infinity, - color: Colors.transparent, + return AnimatedBuilder( + animation: _opacityTween, + builder: (context, _) { + return Material( + borderOnForeground: false, + color: widget.backgroundColor?.withOpacity(_opacityTween.value) ?? + Colors.transparent, + clipBehavior: Clip.antiAlias, + child: InkWell( + hoverColor: Colors.transparent, + splashColor: Colors.transparent, + focusColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: () { + if (widget.onDismiss != null) { + widget.onDismiss!(); + } + MatrixState.pAnyState.closeOverlay(); + }, + child: AnimatedBuilder( + animation: _blurTween, + builder: (context, _) { + return BackdropFilter( + filter: widget.blurBackground + ? ImageFilter.blur( + sigmaX: _blurTween.value, + sigmaY: _blurTween.value, + ) + : ImageFilter.blur(sigmaX: 0, sigmaY: 0), + child: Container( + height: double.infinity, + width: double.infinity, + color: Colors.transparent, + ), + ); + }, + ), ), - ), - ), + // ), + ); + }, ); } } diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index baa84ccc7..80263c62f 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -80,7 +80,8 @@ class MessageOverlayController extends State super.initState(); _animationController = AnimationController( vsync: this, - duration: FluffyThemes.animationDuration, + duration: + const Duration(milliseconds: AppConfig.overlayAnimationDuration), ); activitiesLeftToComplete = activitiesLeftToComplete - @@ -372,7 +373,8 @@ class MessageOverlayController extends State widget.chatController.scrollController.animateTo( widget.chatController.scrollController.offset - scrollOffset, - duration: FluffyThemes.animationDuration, + duration: + const Duration(milliseconds: AppConfig.overlayAnimationDuration), curve: FluffyThemes.animationCurve, ); _animationController.forward(); diff --git a/lib/pangea/widgets/chat/message_toolbar_buttons.dart b/lib/pangea/widgets/chat/message_toolbar_buttons.dart index 12c71e736..2ddd3c29d 100644 --- a/lib/pangea/widgets/chat/message_toolbar_buttons.dart +++ b/lib/pangea/widgets/chat/message_toolbar_buttons.dart @@ -94,8 +94,6 @@ class ToolbarButtons extends StatelessWidget { return Tooltip( message: mode.tooltip(context), child: PressableButton( - width: buttonSize, - height: buttonSize, borderRadius: BorderRadius.circular(20), enabled: enabled, depressed: !enabled || mode == overlayController.toolbarMode, diff --git a/lib/pangea/widgets/chat/overlay_message.dart b/lib/pangea/widgets/chat/overlay_message.dart index c0a362fc3..db6ba8424 100644 --- a/lib/pangea/widgets/chat/overlay_message.dart +++ b/lib/pangea/widgets/chat/overlay_message.dart @@ -75,7 +75,8 @@ class OverlayMessage extends StatelessWidget { ); final displayEvent = pangeaMessageEvent.event.getDisplayEvent(timeline); - var color = theme.colorScheme.surfaceContainerHighest; + // ignore: deprecated_member_use + var color = theme.colorScheme.surfaceVariant; if (ownMessage) { color = displayEvent.status.isError ? Colors.redAccent diff --git a/lib/pangea/widgets/pressable_button.dart b/lib/pangea/widgets/pressable_button.dart index 596511adf..5c4a32a7d 100644 --- a/lib/pangea/widgets/pressable_button.dart +++ b/lib/pangea/widgets/pressable_button.dart @@ -4,21 +4,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class PressableButton extends StatefulWidget { - final double width; - final double height; final BorderRadius borderRadius; final double buttonHeight; - final bool enabled; final bool depressed; - final Color color; final Widget child; final void Function()? onPressed; const PressableButton({ - required this.width, - required this.height, required this.borderRadius, required this.child, required this.onPressed, @@ -53,6 +47,7 @@ class PressableButtonState extends State void _onTapDown(TapDownDetails details) { if (!widget.enabled) return; _animationCompleter = Completer(); + if (!mounted) return; _controller.forward().then((_) { _animationCompleter?.complete(); _animationCompleter = null; @@ -61,17 +56,17 @@ class PressableButtonState extends State Future _onTapUp(TapUpDetails details) async { if (!widget.enabled) return; + widget.onPressed?.call(); if (_animationCompleter != null) { await _animationCompleter!.future; } - _controller.reverse(); - widget.onPressed?.call(); + if (mounted) _controller.reverse(); HapticFeedback.mediumImpact(); } void _onTapCancel() { if (!widget.enabled) return; - _controller.reverse(); + if (mounted) _controller.reverse(); } @override @@ -86,28 +81,31 @@ class PressableButtonState extends State onTapDown: _onTapDown, onTapUp: _onTapUp, onTapCancel: _onTapCancel, - child: Stack( - alignment: Alignment.bottomCenter, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, children: [ - Container( - width: widget.width, - height: widget.height, - decoration: BoxDecoration( - color: Color.alphaBlend( - Colors.black.withOpacity(0.25), - widget.color, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + AnimatedBuilder( + animation: _tweenAnimation, + builder: (context, _) { + return Container( + padding: EdgeInsets.only(bottom: _tweenAnimation.value), + decoration: BoxDecoration( + color: Color.alphaBlend( + Colors.black.withOpacity(0.25), + widget.color, + ), + borderRadius: widget.borderRadius, + ), + child: widget.child, + ); + }, ), - borderRadius: widget.borderRadius, - ), - ), - AnimatedBuilder( - animation: _tweenAnimation, - builder: (context, _) { - return Positioned( - bottom: widget.depressed ? 0 : _tweenAnimation.value, - child: widget.child, - ); - }, + ], ), ], ),