diff --git a/lib/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart b/lib/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart new file mode 100644 index 000000000..2cb2e7663 --- /dev/null +++ b/lib/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart @@ -0,0 +1,12 @@ +import 'package:core/core.dart'; +import 'package:flutter/material.dart'; + +class ScrollToTopButtonWidgetStyles { + static const double defaultLimitIndicator = 50.0; + static const double defaultElevation = 5.0; + static const Color defaultColor = AppColor.colorLabelCancelButton; + static const double defaultButtonRadius = 44.0; + static const double buttonPadding = 16.0; + static const double iconWidth = 28.0; + static const double iconHeight = 28.0; +} \ No newline at end of file diff --git a/lib/features/thread/presentation/widgets/scroll_to_top_button_widget.dart b/lib/features/thread/presentation/widgets/scroll_to_top_button_widget.dart new file mode 100644 index 000000000..d340c9cb8 --- /dev/null +++ b/lib/features/thread/presentation/widgets/scroll_to_top_button_widget.dart @@ -0,0 +1,94 @@ +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart'; + +class ScrollToTopButtonWidget extends StatefulWidget { + final ScrollController scrollController; + final GestureTapCallback onTap; + final ResponsiveUtils responsiveUtils; + final double? limitIndicator; + final double? elevation; + final Color? colorButton; + final double? buttonRadius; + final Widget? icon; + + const ScrollToTopButtonWidget({ + Key? key, + required this.scrollController, + required this.onTap, + required this.responsiveUtils, + this.limitIndicator = ScrollToTopButtonWidgetStyles.defaultLimitIndicator, + this.elevation = ScrollToTopButtonWidgetStyles.defaultElevation, + this.colorButton = ScrollToTopButtonWidgetStyles.defaultColor, + this.buttonRadius = ScrollToTopButtonWidgetStyles.defaultButtonRadius, + this.icon, + }) : super(key: key); + + @override + State createState() => _ScrollToTopButtonWidgetState(); +} + +class _ScrollToTopButtonWidgetState extends State { + bool _isVisible = false; + + @override + void initState() { + super.initState(); + _handleScroll(); + } + + @override + void dispose() { + widget.scrollController.removeListener(() {}); + super.dispose(); + } + + void _handleScroll() { + ScrollController scrollController = widget.scrollController; + scrollController.addListener(() { + if (scrollController.position.pixels > widget.limitIndicator!) { + if (mounted) { + setState(() { + _isVisible = true; + }); + } + } else if (scrollController.position.pixels <= widget.limitIndicator!) { + if (mounted) { + setState(() { + _isVisible = false; + }); + } + } + }); + } + + @override + Widget build(BuildContext context) { + if (widget.responsiveUtils.isWebDesktop(context)) { + return const SizedBox.shrink(); + } + + return Align( + alignment: AlignmentDirectional.bottomEnd, + child: Visibility( + visible: _isVisible, + child: Card( + elevation: widget.elevation, + shape: const CircleBorder(), + child: InkWell( + borderRadius: BorderRadius.circular(widget.buttonRadius!), + onTap: widget.onTap, + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(widget.buttonRadius!), + color: widget.colorButton, + ), + padding: const EdgeInsets.all(ScrollToTopButtonWidgetStyles.buttonPadding), + child: widget.icon, + ) + ), + ) + ), + ); + } +} \ No newline at end of file