TF-248 Change floating button compose email
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.8233 5.22705L14.7725 8.17622L7.58679 15.3629C6.94241 16.0072 6.14959 16.4833 5.27805 16.7494L2.8593 17.4878C2.7124 17.5326 2.55696 17.4499 2.51212 17.303C2.49596 17.2501 2.49596 17.1935 2.51212 17.1406L3.25045 14.7221C3.51657 13.8504 3.99282 13.0575 4.63732 12.413L11.8233 5.22705ZM15.9492 2.86975L17.1311 4.05164C17.5888 4.50925 17.6174 5.23347 17.217 5.72444L17.1311 5.81937L15.6567 7.29288L12.7067 4.34288L14.1814 2.86971C14.6696 2.38163 15.4611 2.38165 15.9492 2.86975Z" fill="#007AFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 608 B |
@@ -41,6 +41,7 @@ export 'presentation/views/dialog/loading_dialog_builder.dart';
|
||||
export 'presentation/views/dialog/downloading_file_dialog_builder.dart';
|
||||
export 'presentation/views/background/background_widget_builder.dart';
|
||||
export 'presentation/views/html_viewer/html_content_viewer_widget.dart';
|
||||
export 'presentation/views/floating_button/scrolling_floating_button_animated.dart';
|
||||
|
||||
// Resources
|
||||
export 'presentation/resources/assets_paths.dart';
|
||||
|
||||
@@ -50,6 +50,7 @@ class ImagePaths {
|
||||
String get icChevronDown => _getImagePath('ic_chevron_down.svg');
|
||||
String get icFilter => _getImagePath('ic_filter.svg');
|
||||
String get icSearchBar => _getImagePath('ic_search_bar.svg');
|
||||
String get icCompose => _getImagePath('ic_compose.svg');
|
||||
|
||||
String _getImagePath(String imageName) {
|
||||
return AssetsPaths.images + imageName;
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
/// Widget to animate the button when scroll down
|
||||
class ScrollingFloatingButtonAnimated extends StatefulWidget {
|
||||
/// Function to use when press the button
|
||||
final GestureTapCallback? onPress;
|
||||
|
||||
/// Double value to set the button elevation
|
||||
final double? elevation;
|
||||
|
||||
/// Double value to set the button width
|
||||
final double? width;
|
||||
|
||||
/// Double value to set the button height
|
||||
final double? height;
|
||||
|
||||
/// Value to set the duration for animation
|
||||
final Duration? duration;
|
||||
|
||||
/// Widget to use as button icon
|
||||
final Widget? icon;
|
||||
|
||||
/// Widget to use as button text when button is expanded
|
||||
final Widget? text;
|
||||
|
||||
/// Value to set the curve for animation
|
||||
final Curve? curve;
|
||||
|
||||
/// ScrollController to use to determine when user is on top or not
|
||||
final ScrollController? scrollController;
|
||||
|
||||
/// Double value to set the boundary value when scroll animation is triggered
|
||||
final double? limitIndicator;
|
||||
|
||||
/// Color to set the button background color
|
||||
final Color? color;
|
||||
|
||||
/// Value to indicate if animate or not the icon
|
||||
final bool? animateIcon;
|
||||
|
||||
ScrollingFloatingButtonAnimated(
|
||||
{Key? key,
|
||||
required this.icon,
|
||||
required this.text,
|
||||
required this.onPress,
|
||||
required this.scrollController,
|
||||
this.elevation = 5.0,
|
||||
this.width = 120.0,
|
||||
this.height = 60.0,
|
||||
this.duration = const Duration(milliseconds: 250),
|
||||
this.curve,
|
||||
this.limitIndicator = 10.0,
|
||||
this.color = Colors.blueAccent,
|
||||
this.animateIcon = true})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_ScrollingFloatingButtonAnimatedState createState() =>
|
||||
_ScrollingFloatingButtonAnimatedState();
|
||||
}
|
||||
|
||||
class _ScrollingFloatingButtonAnimatedState
|
||||
extends State<ScrollingFloatingButtonAnimated>
|
||||
with SingleTickerProviderStateMixin {
|
||||
/// Boolean value to indicate when scroll view is on top
|
||||
bool _onTop = true;
|
||||
|
||||
/// Value to indicate when to show the child widget
|
||||
bool _visibleText = false;
|
||||
|
||||
/// Controller for icon animation
|
||||
late AnimationController _animationController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_animationController = new AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 250),
|
||||
reverseDuration: Duration(milliseconds: 250),
|
||||
animationBehavior: AnimationBehavior.normal,
|
||||
lowerBound: 0,
|
||||
upperBound: 120,
|
||||
);
|
||||
super.initState();
|
||||
_handleScroll();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.scrollController!.removeListener(() {});
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Function to add listener for scroll
|
||||
void _handleScroll() {
|
||||
ScrollController _scrollController = widget.scrollController!;
|
||||
_scrollController.addListener(() {
|
||||
print(_scrollController.position.userScrollDirection);
|
||||
if (_scrollController.position.pixels > widget.limitIndicator! &&
|
||||
_scrollController.position.userScrollDirection ==
|
||||
ScrollDirection.reverse) {
|
||||
if (widget.animateIcon!) _animationController.forward();
|
||||
setState(() {
|
||||
_onTop = false;
|
||||
});
|
||||
} else if (_scrollController.position.pixels <= widget.limitIndicator! &&
|
||||
_scrollController.position.userScrollDirection ==
|
||||
ScrollDirection.forward) {
|
||||
if (widget.animateIcon!) _animationController.reverse();
|
||||
setState(() {
|
||||
_onTop = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: widget.elevation,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(widget.height! / 2))),
|
||||
child: AnimatedContainer(
|
||||
curve: widget.curve ?? Curves.easeInOut,
|
||||
duration: widget.duration!,
|
||||
height: widget.height,
|
||||
width: _onTop ? widget.width : widget.height,
|
||||
onEnd: () {
|
||||
setState(() {
|
||||
_visibleText = !_visibleText;
|
||||
});
|
||||
},
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(widget.height! / 2))),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.all(Radius.circular(widget.height! / 2)),
|
||||
onTap: widget.onPress,
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(widget.height! / 2)),
|
||||
color: widget.color),
|
||||
child: Row(
|
||||
mainAxisAlignment: _onTop ? MainAxisAlignment.spaceEvenly : MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 16, right: _onTop ? 10 : 16),
|
||||
child: AnimatedBuilder(
|
||||
child: widget.icon!,
|
||||
animation: _animationController,
|
||||
builder: (BuildContext context, Widget? _widget) {
|
||||
return Transform.rotate(
|
||||
angle: (_animationController.value * 3 * math.pi) / 180,
|
||||
child: _widget!,
|
||||
);
|
||||
}),
|
||||
),
|
||||
...(_onTop
|
||||
? [
|
||||
Expanded(
|
||||
child: AnimatedOpacity(
|
||||
opacity: !_visibleText ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
child: widget.text!,
|
||||
),
|
||||
)
|
||||
]
|
||||
: []),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -68,11 +68,20 @@ class ThreadView extends GetWidget<ThreadController> {
|
||||
)
|
||||
),
|
||||
floatingActionButton: Obx(() => !controller.isSearchActive()
|
||||
? FloatingActionButton(
|
||||
? ScrollingFloatingButtonAnimated(
|
||||
icon: SvgPicture.asset(imagePaths.icCompose, width: 20, height: 20, fit: BoxFit.fill),
|
||||
text: Padding(
|
||||
padding: EdgeInsets.only(right: 10),
|
||||
child: Text(
|
||||
AppLocalizations.of(context).compose,
|
||||
style: TextStyle(color: AppColor.colorTextButton, fontSize: 15.0, fontWeight: FontWeight.w500))
|
||||
),
|
||||
onPress: () => controller.composeEmailAction(),
|
||||
scrollController: controller.listEmailController,
|
||||
color: Colors.white,
|
||||
elevation: 4.0,
|
||||
child: new Icon(Icons.add),
|
||||
backgroundColor: AppColor.appColor,
|
||||
onPressed: () => controller.composeEmailAction())
|
||||
width: 140,
|
||||
animateIcon: false)
|
||||
: SizedBox.shrink())
|
||||
),
|
||||
);
|
||||
|
||||
@@ -470,5 +470,11 @@ class AppLocalizations {
|
||||
'Search for emails and files',
|
||||
name: 'hint_search_emails');
|
||||
}
|
||||
|
||||
String get compose {
|
||||
return Intl.message(
|
||||
'Compose',
|
||||
name: 'compose');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user