Commit 9d608f3e by Rizal Hermawan

feat (alert & accordion): add alert & accordion widget and implement alert &…

feat (alert & accordion): add alert & accordion widget and implement alert & accordion on example project. Story #1
parent d7d1ef94
......@@ -3,7 +3,7 @@
#
# For more info see: https://dart.dev/go/dot-packages-deprecation
#
# Generated by pub on 2021-04-29 12:30:25.427215.
# Generated by pub on 2021-06-03 17:24:23.151930.
async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib/
boolean_selector:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/
characters:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/characters-1.1.0/lib/
......@@ -12,6 +12,7 @@ clock:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/clock-1
collection:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/
fake_async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/
flutter:file:///D:/flutter/2.0.4-stable/packages/flutter/lib/
flutter_sequence_animation_null_safety:file:///D:/flutter/2.0.4-stable/.pub-cache/git/flutter_sequence_animation_null_safety-773d67311fed31fae22214b385265ae275854495/lib/
flutter_test:file:///D:/flutter/2.0.4-stable/packages/flutter_test/lib/
matcher:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.10/lib/
meta:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/meta-1.3.0/lib/
......
......@@ -3,7 +3,7 @@
#
# For more info see: https://dart.dev/go/dot-packages-deprecation
#
# Generated by pub on 2021-06-02 14:09:44.544419.
# Generated by pub on 2021-06-04 15:07:16.298304.
async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/async-2.5.0/lib/
bloc:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/bloc-7.0.0/lib/
boolean_selector:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/
......@@ -16,6 +16,7 @@ equatable:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/equ
fake_async:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/
flutter:file:///D:/flutter/2.0.4-stable/packages/flutter/lib/
flutter_bloc:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/flutter_bloc-7.0.1/lib/
flutter_sequence_animation_null_safety:file:///D:/flutter/2.0.4-stable/.pub-cache/git/flutter_sequence_animation_null_safety-773d67311fed31fae22214b385265ae275854495/lib/
flutter_test:file:///D:/flutter/2.0.4-stable/packages/flutter_test/lib/
font_awesome_flutter:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/font_awesome_flutter-9.0.0/lib/
http:file:///D:/flutter/2.0.4-stable/.pub-cache/hosted/pub.dartlang.org/http-0.12.2/lib/
......
......@@ -15,14 +15,18 @@ class RouteGenerator {
return MaterialPageRoute(builder: (_) => StandardsButtonPage());
case LabelPage.routeName:
return MaterialPageRoute(builder: (_) => LabelPage());
case ListTilePage.routeName:
return MaterialPageRoute(builder: (_) => ListTilePage());
case TilesPage.routeName:
return MaterialPageRoute(builder: (_) => TilesPage());
case RoundedButtonPage.routeName:
return MaterialPageRoute(builder: (_) => RoundedButtonPage());
case SquareButtonPage.routeName:
return MaterialPageRoute(builder: (_) => SquareButtonPage());
case ButtonsPageDynamic.routeName:
return MaterialPageRoute(builder: (_) => ButtonsPageDynamic());
case AccordionPage.routeName:
return MaterialPageRoute(builder: (_) => AccordionPage());
case AlertPage.routeName:
return MaterialPageRoute(builder: (_) => AlertPage());
case TestStatePage.routeName:
return MaterialPageRoute(builder: (_) => TestStatePage());
default:
......@@ -35,7 +39,7 @@ class RouteGenerator {
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'In Progress.',
'In Progress. Sabar yah :)',
style: TextStyle(fontSize: 20),
),
const SizedBox(
......
part of 'pages.dart';
class AccordionPage extends StatefulWidget {
const AccordionPage({ Key? key }) : super(key: key);
static const routeName = '/accordion_page';
@override
_AccordionPageState createState() => _AccordionPageState();
}
class _AccordionPageState extends State<AccordionPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: LLSColors.PRIMARY,
leading: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(
CupertinoIcons.back,
color: LLSColors.WHITE,
),
),
title: const Text(
'Accordion',
style: TextStyle(fontSize: 17),
),
centerTitle: true,
),
body: ListView(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Basic Accordion',
type: LLSLabelType.typo4,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
LLSAccordion(
titleBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
titleExpandedBorderRadius: BorderRadius.only(
topRight: Radius.circular(8),
topLeft: Radius.circular(8)
),
titleCollapsedBorderRadius: BorderRadius.all(Radius.circular(8)),
contentBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
contentBorderRadius: BorderRadius.only(
bottomRight: Radius.circular(8),
bottomLeft: Radius.circular(8)
),
title: 'What is Locator Logic?',
content:
'Locator Logic is a powerful and unique analytic tool, created based on Indonesian market demand. Becoming and remaining successful in a constantly changing environment, requires more and better data.'),
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Accordion with Text',
type: LLSLabelType.typo5,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
LLSAccordion(
titleBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
titleExpandedBorderRadius: BorderRadius.only(
topRight: Radius.circular(8),
topLeft: Radius.circular(8)
),
titleCollapsedBorderRadius: BorderRadius.all(Radius.circular(8)),
contentBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
contentBorderRadius: BorderRadius.only(
bottomRight: Radius.circular(8),
bottomLeft: Radius.circular(8)
),
title: 'What is Locator Logic?',
content:
'Locator Logic is a powerful and unique analytic tool, created based on Indonesian market demand. Becoming and remaining successful in a constantly changing environment, requires more and better data.',
collapsedIcon: const Text('Show'),
expandedIcon: const Text(
'Hide',
style: TextStyle(color: Colors.red),
)),
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Accordion with Icon',
type: LLSLabelType.typo5,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
LLSAccordion(
titleBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
titleExpandedBorderRadius: BorderRadius.only(
topRight: Radius.circular(8),
topLeft: Radius.circular(8)
),
titleCollapsedBorderRadius: BorderRadius.all(Radius.circular(8)),
contentBorder: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
bottom: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
left: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
right: BorderSide(
color: Colors.black.withOpacity(0.2), width: 0.5),
),
contentBorderRadius: BorderRadius.only(
bottomRight: Radius.circular(8),
bottomLeft: Radius.circular(8)
),
title: 'What is Locator Logic?',
content:
'Locator Logic is a powerful and unique analytic tool, created based on Indonesian market demand. Becoming and remaining successful in a constantly changing environment, requires more and better data.',
collapsedIcon: Icon(Icons.add_circle_outline),
expandedIcon: Icon(
Icons.remove_circle_outline,
color: Colors.red,
),
),
],
),
);
}
}
\ No newline at end of file
part of 'pages.dart';
class AlertPage extends StatefulWidget {
static const routeName = '/alert_page';
@override
_AlertPageState createState() => _AlertPageState();
}
class _AlertPageState extends State<AlertPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: LLSColors.PRIMARY,
leading: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(
CupertinoIcons.back,
color: LLSColors.WHITE,
),
),
title: const Text(
'Alert',
style: TextStyle(fontSize: 17),
),
centerTitle: true,
),
body: ListView(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Basic Alert',
type: LLSLabelType.typo4,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
Column(
children: [
LLSButton(
onPressed: () {
LLSAlert.show(context, title: "Data Berhasil disimpan");
},
shape: LLSButtonShape.rounded,
child: Text(
'Tap to View'
),
color: LLSColors.PRIMARY
),
],
),
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Alert with title and subtitle',
type: LLSLabelType.typo5,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
Column(
children: [
LLSButton(
onPressed: () {
LLSAlert.show(context, title: "Success", subtitle: "Data Berhasil disimpan");
},
shape: LLSButtonShape.rounded,
child: Text(
'Tap to View'
),
color: LLSColors.PRIMARY
),
],
),
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Confirm Dialog',
type: LLSLabelType.typo5,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
Column(
children: [
LLSButton(
onPressed: () {
LLSAlert.show(context,
title: "Hey you!",
subtitle: "Are you sure you want to log out?",
style: LLSAlertStyle.confirm,
showCancelButton: true,
onPress: (bool isConfirm) {
if (isConfirm) {
LLSAlert.show(context, style: LLSAlertStyle.success , title: "Success!");
return false;
}
return true;
}
);
},
shape: LLSButtonShape.rounded,
child: Text(
'Tap to View'
),
color: LLSColors.PRIMARY
),
],
),
const Padding(
padding: EdgeInsets.only(left: 15, top: 30),
child: LLSLabel(
text: 'Confirm Dialog with Loading',
type: LLSLabelType.typo5,
dividerWidth: 25,
dividerColor: LLSColors.SECONDARY,
),
),
Column(
children: [
LLSButton(
onPressed: () {
LLSAlert.show(context,
subtitle: "Do you want to delete this data?",
style: LLSAlertStyle.confirm,
showCancelButton: true,
onPress: (bool isConfirm) {
if (isConfirm) {
LLSAlert.show(context, subtitle: "Loading...", style: LLSAlertStyle.loading);
Future.delayed(Duration(seconds: 2),() {
LLSAlert.show(context, subtitle: "Success!", style: LLSAlertStyle.success);
});
return false;
}
return true;
}
);
},
shape: LLSButtonShape.rounded,
child: Text(
'Tap to View'
),
color: LLSColors.PRIMARY
),
],
),
],
),
);
}
}
\ No newline at end of file
part of '../pages.dart';
part of 'pages.dart';
class LabelPage extends StatefulWidget {
static const routeName = '/label_page/label_page';
static const routeName = '/label_page';
@override
_LabelPageState createState() => _LabelPageState();
......
......@@ -10,27 +10,88 @@ class MainPage extends StatefulWidget {
class _MainPageState extends State<MainPage> {
List components = [
{
'title': 'Accordion',
'route': '/accordion_page',
'route_dynamic': '/accordion_page_dynamic'
},
{
'title': 'Alert',
'route': '/alert_page',
'route_dynamic': '/alert_page_dynamic'
},
{
'title': 'App Bar',
'route': '/appbar_page',
'route_dynamic': '/appbar_page_dynamic'
},
{
'title': 'Avatar',
'route': '/avatar_page',
'route_dynamic': '/avatar_page_dynamic'
},
{
'title': 'Badges',
'route': '/badges_page',
'route_dynamic': '/badges_page_dynamic'
},
{
'title': 'Buttons',
'route': '/buttons_page/buttons_page',
'route_dynamic': '/buttons_page/buttons_page_dynamic'
},
{
'title': 'Cards',
'route': '/cards_page/cards_page',
'route_dynamic': '/cards_page/cards_page_dynamic'
},
{
'title': 'Carousels',
'route': '/carousels_page',
'route_dynamic': '/carousels_page_dynamic'
},
{
'title': 'Label',
'route': '/label_page/label_page',
'route_dynamic': '/label_page/label_page_dynamic'
'route': '/label_page',
'route_dynamic': '/label_page_dynamic'
},
{
'title': 'Loading',
'route': '/loading_page',
'route_dynamic': '/loading_page_dynamic'
},
{
'title': 'Tabs',
'route': '/tabs_page/tabs_page',
'route_dynamic': '/tabs_page/tabs_page_dynamic'
},
{
'title': 'Test State & API',
'route': '',
'route_dynamic': '/test_state_page'
}
'title': 'Tiles',
'route': '/tiles_page',
'route_dynamic': '/tiles_page_dynamic'
},
{
'title': 'Toast',
'route': '/toast_page',
'route_dynamic': '/toast_page_dynamic'
},
{
'title': 'Toggle',
'route': '/toggle_page',
'route_dynamic': '/toggle_page_dynamic'
},
];
// {
// 'title': 'Test State & API',
// 'route': '',
// 'route_dynamic': '/test_state_page'
// }
Widget buildSquareTile(String title, String route, String routeDynamic) => InkWell(
onTap: () {
ActionSheet.material(
context,
"Choose how the widget will be rendered",
"Choose how the component/widget will be rendered",
() {
Navigator.of(context).pop();
Navigator.of(context).pushNamed(
......
......@@ -11,8 +11,11 @@ part 'main_page.dart';
part 'buttons_page/buttons_page.dart';
part 'buttons_page/buttons_page_dynamic.dart';
part 'buttons_page/standards_button_page.dart';
part 'label_page/label_page.dart';
part 'list_tile_page/list_tile_page.dart';
part 'label_page.dart';
part 'tiles_page.dart';
part 'buttons_page/rounded_button_page.dart';
part 'buttons_page/square_button_page.dart';
part 'test_state_page.dart';
\ No newline at end of file
part 'test_state_page.dart';
part 'accordion_page.dart';
part 'alert_page.dart';
part 'appbar_page/appbar_page.dart';
\ No newline at end of file
part of '../pages.dart';
part of 'pages.dart';
class ListTilePage extends StatefulWidget {
static const routeName = '/list_tile_page/list_tile_page';
class TilesPage extends StatefulWidget {
static const routeName = '/tiles_page';
@override
_ListTilePageState createState() => _ListTilePageState();
_TilesPageState createState() => _TilesPageState();
}
class _ListTilePageState extends State<ListTilePage> {
class _TilesPageState extends State<TilesPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
......@@ -25,7 +25,7 @@ class _ListTilePageState extends State<ListTilePage> {
),
),
title: const Text(
'List Tile',
'List Tiles',
style: TextStyle(fontSize: 17),
),
centerTitle: true,
......@@ -57,7 +57,7 @@ class _ListTilePageState extends State<ListTilePage> {
child: LLSListTile(
color: LLSColors.SECONDARY,
title: const Text(
'Standards Buttons',
'Text Online',
style: TextStyle(color: LLSColors.WHITE),
),
icon: Icon(
......
......@@ -83,6 +83,15 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.1"
flutter_sequence_animation_null_safety:
dependency: transitive
description:
path: "."
ref: "773d67311fed31fae22214b385265ae275854495"
resolved-ref: "773d67311fed31fae22214b385265ae275854495"
url: "https://git.locatorlogic.com/hermawan/flutter_sequence_animation_null_safety"
source: git
version: "3.0.1"
flutter_test:
dependency: "direct dev"
description: flutter
......
......@@ -33,4 +33,8 @@ export 'package:llswidget/src/components/label/type/lls_label_type.dart';
//exports card
export 'package:llswidget/src/components/card/lls_card.dart';
//exports image overlay
export 'package:llswidget/src/components/image/lls_image_overlay.dart';
\ No newline at end of file
export 'package:llswidget/src/components/image/lls_image_overlay.dart';
//exports accordion
export 'package:llswidget/src/components/accordion/lls_accordion.dart';
//exports alert
export 'package:llswidget/src/components/alert/lls_alert.dart';
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:llswidget/llswidget.dart';
class LLSAccordion extends StatefulWidget {
const LLSAccordion(
{Key? key,
this.title,
this.content,
this.titleChild,
this.contentChild,
this.collapsedTitleBackgroundColor = LLSColors.WHITE,
this.expandedTitleBackgroundColor = const Color(0xFFE0E0E0),
this.collapsedIcon = const Icon(Icons.keyboard_arrow_down),
this.expandedIcon = const Icon(Icons.keyboard_arrow_up),
this.textStyle = const TextStyle(color: Colors.black, fontSize: 16),
this.titlePadding = const EdgeInsets.all(10),
this.contentBackgroundColor,
this.contentPadding = const EdgeInsets.all(10),
this.titleBorder = const Border(),
this.contentBorder = const Border(),
this.margin,
this.showAccordion = false,
this.onToggleCollapsed,
this.titleCollapsedBorderRadius = const BorderRadius.all(Radius.circular(0)),
this.titleExpandedBorderRadius = const BorderRadius.all(Radius.circular(0)),
this.contentBorderRadius = const BorderRadius.all(Radius.circular(0))})
: super(key: key);
final bool showAccordion;
final Widget? titleChild;
final String? content;
final Widget? contentChild;
final Color collapsedTitleBackgroundColor;
final Color expandedTitleBackgroundColor;
final Widget collapsedIcon;
final Widget expandedIcon;
final String? title;
final TextStyle textStyle;
final EdgeInsets titlePadding;
final EdgeInsets contentPadding;
final Color? contentBackgroundColor;
final EdgeInsets? margin;
final Border titleBorder;
final Border contentBorder;
final BorderRadius titleCollapsedBorderRadius;
final BorderRadius titleExpandedBorderRadius;
final BorderRadius contentBorderRadius;
final Function(bool)? onToggleCollapsed;
@override
_LLSAccordionState createState() => _LLSAccordionState();
}
class _LLSAccordionState extends State<LLSAccordion> with TickerProviderStateMixin {
late AnimationController animationController;
late AnimationController controller;
late Animation<Offset> offset;
late bool showAccordion;
@override
void initState() {
showAccordion = widget.showAccordion;
animationController = AnimationController(duration: const Duration(seconds: 2), vsync: this);
controller = AnimationController(duration: const Duration(milliseconds: 300), vsync: this);
offset = Tween(
begin: const Offset(0, -0.06),
end: Offset.zero,
).animate(
CurvedAnimation(
parent: controller,
curve: Curves.fastOutSlowIn,
),
);
super.initState();
}
@override
void dispose() {
animationController.dispose();
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Container(
margin: widget.margin ?? const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: _toggleCollapsed,
child: Container(
decoration: BoxDecoration(
borderRadius: showAccordion ? widget.titleExpandedBorderRadius : widget.titleCollapsedBorderRadius,
border: widget.titleBorder,
color: showAccordion
? widget.expandedTitleBackgroundColor
: widget.collapsedTitleBackgroundColor,
),
padding: widget.titlePadding,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: widget.title != null
? Text(widget.title!, style: widget.textStyle)
: (widget.titleChild ?? Container()),
),
showAccordion ? widget.expandedIcon : widget.collapsedIcon
],
),
),
),
showAccordion
? Container(
decoration: BoxDecoration(
borderRadius: widget.contentBorderRadius,
border: widget.contentBorder,
color: widget.contentBackgroundColor ?? Colors.white70,
),
width: MediaQuery.of(context).size.width,
padding: widget.contentPadding,
child: SlideTransition(
position: offset,
child: widget.content != null
? Text(widget.content!)
: (widget.contentChild ?? Container()),
))
: Container()
],
),
);
void _toggleCollapsed() {
setState(() {
switch (controller.status) {
case AnimationStatus.completed:
controller.forward(from: 0);
break;
case AnimationStatus.dismissed:
controller.forward();
break;
default:
}
showAccordion = !showAccordion;
if (widget.onToggleCollapsed != null) {
widget.onToggleCollapsed!(showAccordion);
}
});
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'view/cancel.dart';
import 'view/confirm.dart';
import 'view/success.dart';
import '../../../llswidget.dart';
//Return false to keey dialog showing
typedef bool LLSAlertOnPress(bool isConfirm);
enum LLSAlertStyle { success, error, confirm, loading }
class LLSAlertOptions {
final String? title;
final String? subtitle;
final LLSAlertOnPress? onPress;
final Color? confirmButtonColor;
final Color? cancelButtonColor;
final String? confirmButtonText;
final String? cancelButtonText;
final bool showCancelButton;
final LLSAlertStyle style;
LLSAlertOptions(
{this.showCancelButton: false,
this.title,
this.subtitle,
this.onPress,
this.cancelButtonColor,
this.cancelButtonText,
this.confirmButtonColor,
this.confirmButtonText,
this.style = LLSAlertStyle.success});
}
class LLSAlertDialog extends StatefulWidget {
final Curve? curve;
final LLSAlertOptions? options;
LLSAlertDialog({
this.curve,
this.options,
}) : assert(options != null);
@override
_LLSAlertDialogState createState() => _LLSAlertDialogState();
}
class _LLSAlertDialogState extends State<LLSAlertDialog> with SingleTickerProviderStateMixin, LLSAlert {
AnimationController? controller;
Animation<double>? tween;
LLSAlertOptions? _options;
@override
void initState() {
_options = widget.options;
controller = AnimationController(vsync: this);
tween = Tween(begin: 0.0, end: 1.0).animate(controller!);
controller!.animateTo(1.0,
duration: Duration(milliseconds: 300),
curve: widget.curve ?? LLSAlert.showCurve);
LLSAlert._state = this;
super.initState();
}
@override
void dispose() {
controller?.dispose();
LLSAlert._state = null;
super.dispose();
}
@override
void didUpdateWidget(LLSAlertDialog oldWidget) {
super.didUpdateWidget(oldWidget);
}
void confirm() {
if (_options!.onPress != null && _options!.onPress!(true) == false)
return;
Navigator.pop(context);
}
void cancel() {
if (_options!.onPress != null && _options!.onPress!(false) == false)
return;
Navigator.pop(context);
}
void update(LLSAlertOptions options) {
setState(() {
_options = options;
});
}
@override
Widget build(BuildContext context) {
List<Widget> listOfChildren = [];
switch (_options!.style) {
case LLSAlertStyle.success:
listOfChildren.add(SizedBox(
width: 64.0,
height: 64.0,
child: SuccessView(),
));
break;
case LLSAlertStyle.confirm:
listOfChildren.add(SizedBox(
width: 64.0,
height: 64.0,
child: ConfirmView(),
));
break;
case LLSAlertStyle.error:
listOfChildren.add(SizedBox(
width: 64.0,
height: 64.0,
child: CancelView(),
));
break;
case LLSAlertStyle.loading:
listOfChildren.add(SizedBox(
width: 64.0,
height: 64.0,
child: Center(
child: CircularProgressIndicator(),
),
));
break;
}
if (_options!.title != null) {
listOfChildren.add(Padding(
padding: EdgeInsets.only(top: 24.0),
child: Text(
_options!.title!,
style: TextStyle(fontSize: 25.0, color: Color(0xff575757)),
),
));
}
if (_options!.subtitle != null) {
double paddingTop = 10.0;
if (_options!.title == null) {
paddingTop = 24.0;
}
listOfChildren.add(Padding(
padding: EdgeInsets.only(top: paddingTop),
child: Text(
_options!.subtitle!,
style: TextStyle(fontSize: 16.0, color: Color(0xff797979)),
),
));
}
if (_options!.style != LLSAlertStyle.loading) {
if (_options!.showCancelButton) {
listOfChildren.add(Padding(
padding: EdgeInsets.only(top: 18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LLSButton(
onPressed: cancel,
shape: LLSButtonShape.rounded,
child: Text(
_options!.cancelButtonText ?? LLSAlert.cancelText,
),
color: _options!.cancelButtonColor ?? LLSColors.WARNING
),
SizedBox(
width: 10.0,
),
LLSButton(
onPressed: confirm,
shape: LLSButtonShape.rounded,
child: Text(
_options!.confirmButtonText ?? LLSAlert.confirmText,
),
color: _options!.confirmButtonColor ?? LLSColors.SUCCESS
)
],
),
));
} else {
listOfChildren.add(Padding(
padding: EdgeInsets.only(top: 18.0),
child: LLSButton(
onPressed: confirm,
shape: LLSButtonShape.rounded,
child: Text(
_options!.confirmButtonText ?? LLSAlert.successText
),
color: _options!.confirmButtonColor ?? LLSColors.SUCCESS
)
));
}
} else {
listOfChildren.add(SizedBox(height: 18.0));
}
return Center(
child: AnimatedBuilder(
animation: controller!,
builder: (c, w) {
return ScaleTransition(
scale: tween!,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
child: Container(
color: Colors.white,
width: double.infinity,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: listOfChildren,
),
)),
),
);
}
)
);
}
}
abstract class LLSAlert {
static String successText = "OK";
static String confirmText = "Confirm";
static String cancelText = "Cancel";
static Curve showCurve = Curves.bounceOut;
static _LLSAlertDialogState? _state;
static void show(BuildContext context,
{Curve? curve,
String? title,
String? subtitle,
bool showCancelButton: false,
LLSAlertOnPress? onPress,
Color? cancelButtonColor,
Color? confirmButtonColor,
String? cancelButtonText,
String? confirmButtonText,
LLSAlertStyle style: LLSAlertStyle.success}) {
LLSAlertOptions options = LLSAlertOptions(
showCancelButton: showCancelButton,
title: title,
subtitle: subtitle,
style: style,
onPress: onPress,
confirmButtonColor: confirmButtonColor,
confirmButtonText: confirmButtonText,
cancelButtonText: cancelButtonText,
cancelButtonColor: confirmButtonColor);
if (_state != null){
_state!.update(options);
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return Container(
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.all(40.0),
child: Scaffold(
backgroundColor: Colors.transparent,
body: LLSAlertDialog(
curve: curve,
options: options
),
),
),
);
}
);
}
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:llswidget/src/lls_color.dart';
import 'package:vector_math/vector_math_64.dart' as math;
import 'dart:ui';
import 'package:flutter_sequence_animation_null_safety/flutter_sequence_animation_null_safety.dart';
class CancelView extends StatefulWidget {
const CancelView({ Key? key }) : super(key: key);
@override
_CancelViewState createState() => _CancelViewState();
}
class _CancelViewState extends State<CancelView> with SingleTickerProviderStateMixin {
AnimationController? animationController;
SequenceAnimation? sequenceAnimation;
@override
void initState() {
animationController = AnimationController(vsync: this);
sequenceAnimation = SequenceAnimationBuilder()
.addAnimatable(
animatable: Tween(begin: 90.0, end: 0.0),
from: Duration(milliseconds: 0),
to: Duration(milliseconds: 300),
tag: "rotation")
.addAnimatable(
animatable: Tween(begin: 0.3, end: 1.0),
from: Duration(milliseconds: 600),
to: Duration(milliseconds: 900),
tag: "fade",
curve: Curves.bounceOut)
.addAnimatable(
animatable: Tween(begin: 32.0 / 5.0, end: 32.0 / 2.0),
from: Duration(milliseconds: 600),
to: Duration(milliseconds: 900),
tag: "fact",
curve: Curves.bounceOut)
.animate(animationController);
//delay
Future.delayed(Duration(milliseconds: 200)).then((_) {
forward();
});
super.initState();
}
void forward() {
animationController!
.animateTo(1.0,
duration: Duration(milliseconds: 600), curve: Curves.ease)
.then((_) {});
}
@override
void dispose() {
animationController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animationController!,
builder: (c, w) {
return Transform(
transform: Matrix4.rotationX(
math.radians(sequenceAnimation!['rotation']!.value)),
origin: Offset(0.0, 32.0),
child: CustomPaint(
painter: CancelViewPainter(
color: LLSColors.DANGER,
fade: sequenceAnimation!['fade']!.value,
factor: sequenceAnimation!['fact']!.value
),
),
);
});
}
}
class CancelViewPainter extends CustomPainter {
Paint _paint = new Paint();
Color? color;
double _r = 32.0;
final double? fade;
final double? factor;
CancelViewPainter({this.color, this.fade, this.factor}) {
_paint.strokeCap = StrokeCap.round;
_paint.style = PaintingStyle.stroke;
_paint.strokeWidth = 4.0;
_paint.color = color!;
}
@override
void paint(Canvas canvas, Size size) {
Path path = new Path();
_paint.color = color!;
path.addArc(Rect.fromCircle(center: Offset(_r, _r), radius: _r),
0.0, math.radians(360.0));
canvas.drawPath(path, _paint);
_paint.color =
Color(color!.value & 0x00FFFFFF + ((0xff * fade!).toInt() << 24));
path.moveTo(_r - factor!, _r - factor!);
path.lineTo(_r + factor!, _r + factor!);
path.moveTo(_r + factor!, _r - factor!);
path.lineTo(_r - factor!, _r + factor!);
canvas.drawPath(path, _paint);
}
@override
bool shouldRepaint(CancelViewPainter oldDelegate) {
return color != oldDelegate.color || fade != oldDelegate.fade;
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as math;
import 'dart:ui';
class ConfirmView extends StatefulWidget {
const ConfirmView({ Key? key }) : super(key: key);
@override
_ConfirmViewState createState() => _ConfirmViewState();
}
class _ConfirmViewState extends State<ConfirmView> with SingleTickerProviderStateMixin {
AnimationController? animationController;
Animation<Color?>? animation;
@override
void initState() {
animationController = AnimationController(vsync: this);
animation = ColorTween(begin: Color(0xffF7D58B), end: Color(0xffF2A665)).animate(animationController!);
Future.delayed(Duration(milliseconds: 200)).then((_) {
forward();
});
super.initState();
}
void forward() {
animationController!
.animateTo(1.0,
duration: Duration(milliseconds: 600), curve: Curves.ease)
.then((_) {
backward();
});
}
void backward() {
animationController!
.animateTo(0.0,
duration: Duration(milliseconds: 600), curve: Curves.ease)
.then((_) {
forward();
});
}
@override
void dispose() {
animationController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animationController!,
builder: (c, w) {
return CustomPaint(
painter: ConfirmViewPainter(color: animation!.value),
);
}
);
}
}
class ConfirmViewPainter extends CustomPainter {
Paint _paint = new Paint();
Color? color;
double _r = 32.0;
double factor = 0.96;
ConfirmViewPainter({this.color}) {
_paint.strokeCap = StrokeCap.round;
_paint.style = PaintingStyle.stroke;
_paint.strokeWidth = 4.0;
_paint.color = color!;
}
@override
void paint(Canvas canvas, Size size) {
Path path = new Path();
path.addArc(Rect.fromCircle(center: Offset(_r, _r), radius: _r),
0.0, math.radians(360.0));
double factor = 64 / 1.5;
path.moveTo(_r, 15.0);
path.lineTo(_r, factor);
path.moveTo(_r, factor + 10.0);
path.addArc(
Rect.fromCircle(center: Offset(_r, factor + 10.0), radius: 1.0),
0.0,
math.radians(360.0)
);
canvas.drawPath(path, _paint);
}
@override
bool shouldRepaint(ConfirmViewPainter oldDelegate) {
return color != oldDelegate.color;
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as math;
import 'dart:ui';
import 'package:flutter_sequence_animation_null_safety/flutter_sequence_animation_null_safety.dart';
class SuccessView extends StatefulWidget {
const SuccessView({ Key? key }) : super(key: key);
@override
_SuccessViewState createState() => _SuccessViewState();
}
class _SuccessViewState extends State<SuccessView> with SingleTickerProviderStateMixin {
AnimationController? animationController;
SequenceAnimation? sequenceAnimation;
@override
void initState() {
int factor = 50;
animationController = AnimationController(vsync: this);
sequenceAnimation = SequenceAnimationBuilder()
.addAnimatable(
animatable: Tween(begin: 0.0, end: 0.70),
from: Duration(milliseconds: 3 * factor),
to: Duration(milliseconds: 10 * factor),
tag: "start")
.addAnimatable(
animatable: Tween(begin: 0.0, end: 1.0),
from: Duration(milliseconds: 0),
to: Duration(milliseconds: 10 * factor),
tag: "end",
curve: Curves.easeOut)
.animate(animationController);
Future.delayed(Duration(milliseconds: 200)).then((_) {
animationController!.forward();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animationController!,
builder: (c, w) {
return CustomPaint(
painter: SuccessViewPainter(strokeStart: sequenceAnimation!['start']!.value, strokeEnd: sequenceAnimation!['end']!.value),
);
}
);
}
}
class SuccessViewPainter extends CustomPainter {
Paint _paint = Paint();
double _r = 32.0;
double factor = 0.96;
double? strokeStart;
double? strokeEnd;
double total = 0;
double? _strokeStart;
double? _strokeEnd;
SuccessViewPainter({this.strokeEnd, this.strokeStart}) {
_paint.strokeCap = StrokeCap.round;
_paint.style = PaintingStyle.stroke;
_paint.strokeWidth = 4.0;
Path path = createPath();
PathMetrics metrics = path.computeMetrics();
for (PathMetric pathMetric in metrics) {
total += pathMetric.length;
}
_strokeStart = strokeStart! * total;
_strokeEnd = strokeEnd! * total;
}
Path createPath() {
Path path = new Path();
path.addArc(Rect.fromCircle(center: Offset(_r, _r), radius: _r),
math.radians(60.0 - 30.0), math.radians(-200.0));
path.lineTo(24.0, 46.0);
path.lineTo(49.0, 18.0);
return path;
}
@override
void paint(Canvas canvas, Size size) {
Path path = new Path();
path.addArc(Rect.fromCircle(center: Offset(_r, _r), radius: _r),
0.0, math.radians(360.0));
_paint.color = Color(0x4096d873);
canvas.drawPath(path, _paint);
_paint.color = Color(0xff96d873);
path = createPath();
PathMetrics metrics = path.computeMetrics();
for (PathMetric pathMetric in metrics) {
canvas.drawPath(pathMetric.extractPath(_strokeStart!, _strokeEnd!), _paint);
}
}
@override
bool shouldRepaint(SuccessViewPainter oldDelegate) {
return strokeStart != oldDelegate.strokeStart || strokeEnd != oldDelegate.strokeEnd;
}
}
\ No newline at end of file
......@@ -55,6 +55,15 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_sequence_animation_null_safety:
dependency: "direct main"
description:
path: "."
ref: "773d67311fed31fae22214b385265ae275854495"
resolved-ref: "773d67311fed31fae22214b385265ae275854495"
url: "https://git.locatorlogic.com/hermawan/flutter_sequence_animation_null_safety"
source: git
version: "3.0.1"
flutter_test:
dependency: "direct dev"
description: flutter
......
......@@ -4,6 +4,8 @@ version: 0.0.1
author: Rizal Hermawan
homepage: https://locatorlogic.com
publish_to: none
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.17.0"
......@@ -11,6 +13,10 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_sequence_animation_null_safety:
git:
url: https://git.locatorlogic.com/hermawan/flutter_sequence_animation_null_safety
ref: 773d67311fed31fae22214b385265ae275854495
dev_dependencies:
flutter_test:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment