Merge pull request #927 from pangeachat/pressable-messages

don't rely on fixed dimensions to render pressable buttons, animate i…
pull/1476/head
ggurdin 1 year ago committed by GitHub
commit 889dba298c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -35,6 +35,7 @@ abstract class AppConfig {
static const Color activeToggleColor = Color(0xFF33D057); static const Color activeToggleColor = Color(0xFF33D057);
static const Color success = Color(0xFF33D057); static const Color success = Color(0xFF33D057);
static const Color warning = Color.fromARGB(255, 210, 124, 12); static const Color warning = Color.fromARGB(255, 210, 124, 12);
static const int overlayAnimationDuration = 250;
// static String _privacyUrl = // static String _privacyUrl =
// 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md'; // 'https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md';
static String _privacyUrl = "https://www.pangeachat.com/privacy"; static String _privacyUrl = "https://www.pangeachat.com/privacy";

@ -1699,7 +1699,7 @@ class ChatController extends State<ChatPageWithRoom>
context: context, context: context,
child: overlayEntry, child: overlayEntry,
transformTargetId: "", transformTargetId: "",
backgroundColor: const Color.fromRGBO(0, 0, 0, 1).withAlpha(150), backgroundColor: Colors.black,
closePrevOverlay: closePrevOverlay:
MatrixState.pangeaController.subscriptionController.isSubscribed, MatrixState.pangeaController.subscriptionController.isSubscribed,
position: OverlayPositionEnum.centered, position: OverlayPositionEnum.centered,

@ -1,6 +1,7 @@
import 'dart:developer'; import 'dart:developer';
import 'dart:ui'; import 'dart:ui';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/utils/any_state_holder.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart';
import 'package:fluffychat/pangea/widgets/common_widgets/overlay_container.dart'; import 'package:fluffychat/pangea/widgets/common_widgets/overlay_container.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -219,7 +220,7 @@ class OverlayUtil {
static bool get isOverlayOpen => MatrixState.pAnyState.entries.isNotEmpty; static bool get isOverlayOpen => MatrixState.pAnyState.entries.isNotEmpty;
} }
class TransparentBackdrop extends StatelessWidget { class TransparentBackdrop extends StatefulWidget {
final Color? backgroundColor; final Color? backgroundColor;
final Function? onDismiss; final Function? onDismiss;
final bool blurBackground; final bool blurBackground;
@ -231,34 +232,91 @@ class TransparentBackdrop extends StatelessWidget {
this.blurBackground = false, this.blurBackground = false,
}); });
@override
TransparentBackdropState createState() => TransparentBackdropState();
}
class TransparentBackdropState extends State<TransparentBackdrop>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _opacityTween;
late Animation<double> _blurTween;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration:
const Duration(milliseconds: AppConfig.overlayAnimationDuration),
vsync: this,
);
_opacityTween = Tween<double>(begin: 0.0, end: 0.8).animate(
CurvedAnimation(
parent: _controller,
curve: FluffyThemes.animationCurve,
),
);
_blurTween = Tween<double>(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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return AnimatedBuilder(
borderOnForeground: false, animation: _opacityTween,
color: backgroundColor ?? Colors.transparent, builder: (context, _) {
clipBehavior: Clip.antiAlias, return Material(
child: InkWell( borderOnForeground: false,
hoverColor: Colors.transparent, color: widget.backgroundColor?.withOpacity(_opacityTween.value) ??
splashColor: Colors.transparent, Colors.transparent,
focusColor: Colors.transparent, clipBehavior: Clip.antiAlias,
highlightColor: Colors.transparent, child: InkWell(
onTap: () { hoverColor: Colors.transparent,
if (onDismiss != null) { splashColor: Colors.transparent,
onDismiss!(); focusColor: Colors.transparent,
} highlightColor: Colors.transparent,
MatrixState.pAnyState.closeOverlay(); onTap: () {
}, if (widget.onDismiss != null) {
child: BackdropFilter( widget.onDismiss!();
filter: blurBackground }
? ImageFilter.blur(sigmaX: 2.5, sigmaY: 2.5) MatrixState.pAnyState.closeOverlay();
: ImageFilter.blur(sigmaX: 0, sigmaY: 0), },
child: Container( child: AnimatedBuilder(
height: double.infinity, animation: _blurTween,
width: double.infinity, builder: (context, _) {
color: Colors.transparent, 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,
),
);
},
),
), ),
), // ),
), );
},
); );
} }
} }

@ -80,7 +80,8 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
super.initState(); super.initState();
_animationController = AnimationController( _animationController = AnimationController(
vsync: this, vsync: this,
duration: FluffyThemes.animationDuration, duration:
const Duration(milliseconds: AppConfig.overlayAnimationDuration),
); );
activitiesLeftToComplete = activitiesLeftToComplete - activitiesLeftToComplete = activitiesLeftToComplete -
@ -372,7 +373,8 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
widget.chatController.scrollController.animateTo( widget.chatController.scrollController.animateTo(
widget.chatController.scrollController.offset - scrollOffset, widget.chatController.scrollController.offset - scrollOffset,
duration: FluffyThemes.animationDuration, duration:
const Duration(milliseconds: AppConfig.overlayAnimationDuration),
curve: FluffyThemes.animationCurve, curve: FluffyThemes.animationCurve,
); );
_animationController.forward(); _animationController.forward();

@ -94,8 +94,6 @@ class ToolbarButtons extends StatelessWidget {
return Tooltip( return Tooltip(
message: mode.tooltip(context), message: mode.tooltip(context),
child: PressableButton( child: PressableButton(
width: buttonSize,
height: buttonSize,
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
enabled: enabled, enabled: enabled,
depressed: !enabled || mode == overlayController.toolbarMode, depressed: !enabled || mode == overlayController.toolbarMode,

@ -75,7 +75,8 @@ class OverlayMessage extends StatelessWidget {
); );
final displayEvent = pangeaMessageEvent.event.getDisplayEvent(timeline); final displayEvent = pangeaMessageEvent.event.getDisplayEvent(timeline);
var color = theme.colorScheme.surfaceContainerHighest; // ignore: deprecated_member_use
var color = theme.colorScheme.surfaceVariant;
if (ownMessage) { if (ownMessage) {
color = displayEvent.status.isError color = displayEvent.status.isError
? Colors.redAccent ? Colors.redAccent

@ -4,21 +4,15 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class PressableButton extends StatefulWidget { class PressableButton extends StatefulWidget {
final double width;
final double height;
final BorderRadius borderRadius; final BorderRadius borderRadius;
final double buttonHeight; final double buttonHeight;
final bool enabled; final bool enabled;
final bool depressed; final bool depressed;
final Color color; final Color color;
final Widget child; final Widget child;
final void Function()? onPressed; final void Function()? onPressed;
const PressableButton({ const PressableButton({
required this.width,
required this.height,
required this.borderRadius, required this.borderRadius,
required this.child, required this.child,
required this.onPressed, required this.onPressed,
@ -53,6 +47,7 @@ class PressableButtonState extends State<PressableButton>
void _onTapDown(TapDownDetails details) { void _onTapDown(TapDownDetails details) {
if (!widget.enabled) return; if (!widget.enabled) return;
_animationCompleter = Completer<void>(); _animationCompleter = Completer<void>();
if (!mounted) return;
_controller.forward().then((_) { _controller.forward().then((_) {
_animationCompleter?.complete(); _animationCompleter?.complete();
_animationCompleter = null; _animationCompleter = null;
@ -61,17 +56,17 @@ class PressableButtonState extends State<PressableButton>
Future<void> _onTapUp(TapUpDetails details) async { Future<void> _onTapUp(TapUpDetails details) async {
if (!widget.enabled) return; if (!widget.enabled) return;
widget.onPressed?.call();
if (_animationCompleter != null) { if (_animationCompleter != null) {
await _animationCompleter!.future; await _animationCompleter!.future;
} }
_controller.reverse(); if (mounted) _controller.reverse();
widget.onPressed?.call();
HapticFeedback.mediumImpact(); HapticFeedback.mediumImpact();
} }
void _onTapCancel() { void _onTapCancel() {
if (!widget.enabled) return; if (!widget.enabled) return;
_controller.reverse(); if (mounted) _controller.reverse();
} }
@override @override
@ -86,28 +81,31 @@ class PressableButtonState extends State<PressableButton>
onTapDown: _onTapDown, onTapDown: _onTapDown,
onTapUp: _onTapUp, onTapUp: _onTapUp,
onTapCancel: _onTapCancel, onTapCancel: _onTapCancel,
child: Stack( child: Column(
alignment: Alignment.bottomCenter, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Container( Row(
width: widget.width, crossAxisAlignment: CrossAxisAlignment.end,
height: widget.height, mainAxisSize: MainAxisSize.min,
decoration: BoxDecoration( children: [
color: Color.alphaBlend( AnimatedBuilder(
Colors.black.withOpacity(0.25), animation: _tweenAnimation,
widget.color, 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,
);
},
), ),
], ],
), ),

Loading…
Cancel
Save