diff --git a/.gitignore b/.gitignore index 1f62091d..1978a178 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,8 @@ .pub/ build/ web/ +getflutter-app-kit +getflutter-web-kit # Android related **/android/**/gradle-wrapper.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index d9b8506a..3b6ff8dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog + +## 1.0.0-dev.8 - 2020-01-16 + +### Fixed +* ListTile re-implemeted. + ## 1.0.0-dev.3 - 2020-01-15 ### Fixed diff --git a/example/lib/main.dart b/example/lib/main.dart index 5234dea5..4cfbcf93 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -173,6 +173,76 @@ class _MyHomePageState extends State mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + GFCard( + content: Column( + children: [ + GFTypography( + text: 'Toast', + type: GFTypographyType.typo6, + ), + SizedBox( + height: 10, + ), + GFToast( + text: 'Happy New Year', + button: GFButton( + onPressed: () { + print("dfr"); + }, + text: 'OK', + type: GFType.outline, + color: GFColor.warning, + ), + ), + ], + ), + ), + + GFCard( + content: Column( + children: [ + GFTypography( + text: 'Floating Toast', + type: GFTypographyType.typo6, + ), + GFFloatingWidget( + verticalPosition: 80, + child: showToast + ? GFToast( + width: 300, + text: 'Happy New Year', + button: GFButton( + onPressed: () { + print("df"); + }, + text: 'OK', + type: GFType.outline, + color: GFColor.warning, + ), + ) + : Container(), + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment.center, + child: GFButton( + onPressed: () { + setState(() { + showToast = !showToast; + }); + }, + text: 'Click to View the toast', + type: GFType.outline, + color: GFColor.warning, + ), + ) + ], + )) + ], + ), + ), + // Container( // height: 130.0, // width: 105.0, @@ -187,6 +257,7 @@ class _MyHomePageState extends State // ])), // ), // + // GFCard( // content: Column( // children: [ @@ -263,7 +334,49 @@ class _MyHomePageState extends State // ), // ), // ), -// + + GFButtonBar( + alignment: WrapAlignment.spaceEvenly, + children: [ + GFButton( + onPressed: null, + child: Text("dshsc"), + icon: Icon(Icons.access_time), + ), + GFButton( + onPressed: null, + child: Text("dszndc"), + icon: Icon(Icons.warning), + ), + GFButtonBadge( + onPressed: null, + text: "djvhcfdscc", + icon: Icon(Icons.label), + ), + GFButton( + onPressed: null, + child: Text("gcnjd"), + ), + GFButton( + onPressed: null, + child: Text("dsqdsc"), + icon: Icon(Icons.favorite), + ), + GFButton( + onPressed: null, + child: Text("gcd"), + ), + GFButton( + onPressed: null, + child: Text("dascdsc"), + ), + GFButton( + onPressed: null, + child: Text("gtgcd"), + ), + ], + ), + // GFCard( // content: Column( // crossAxisAlignment: CrossAxisAlignment.center, @@ -324,7 +437,8 @@ class _MyHomePageState extends State // dividerWidth: 20, // ), // ], -// )), +// ) +// ), // GFButton( // onPressed: (){}, @@ -338,11 +452,11 @@ class _MyHomePageState extends State // ), GFListTile( -// padding: EdgeInsets.all(8.0), -// color: Colors.redAccent, -// avatar: GFAvatar( -// child: Text("tb"), -// ), + padding: EdgeInsets.all(8.0), + color: Colors.redAccent, + avatar: GFAvatar( + child: Text("tb"), + ), title: Text('title'), subTitle: Text('subtitle'), description: Text('A page view that displays the widget which ' @@ -481,42 +595,42 @@ class _MyHomePageState extends State // // ), // -// GFButton( -//// icon: GFBadge( -//// child: Text("12"), -//// color: GFColor.dark, -////// shape: GFBadgeShape.circle, -////// size: GFSize.small, -////// border: BorderSide(color: Colors.pink, width: 1.0, style: BorderStyle.solid), -////// textColor: GFColor.white, -////// textStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 8.0), -//// ), -// text: 'goodies', -// onPressed: (){}, -//// textColor: GFColor.danger, -//// icon: Icon(Icons.access_alarms), -//// hoverColor: GFColor.dark, -// color: GFColor.secondary, -//// focusColor: GFColor.danger, -// type: GFType.solid, -// shape: GFButtonShape.pills, -// buttonBoxShadow: true, -//// boxShadow: BoxShadow( -//// color: Colors.pink, -//// blurRadius: 2.0, -//// spreadRadius: 1.0, -//// offset: Offset.zero, -//// ), -//// splashColor: GFColor.warning, -//// highlightColor: GFColor.alt, -//// size: GFSize.large, -//// disabledColor: GFColor.dark, -//// disabledTextColor: GFColor.light, -// blockButton: true, -//// fullWidthButton: true, -//// borderSide: BorderSide(color: Colors.pink, width: 1.0, style: BorderStyle.solid), -//// borderShape: RoundedRectangleBorder(side: BorderSide(color: Colors.pink, width: 2.0, style: BorderStyle.solid), borderRadius: BorderRadius.zero), -// ), + GFButton( +// icon: GFBadge( +// child: Text("12"), +// color: GFColor.dark, +//// shape: GFBadgeShape.circle, +//// size: GFSize.small, +//// border: BorderSide(color: Colors.pink, width: 1.0, style: BorderStyle.solid), +//// textColor: GFColor.white, +//// textStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 8.0), +// ), + text: 'goodies', + onPressed: () {}, +// textColor: GFColor.danger, +// icon: Icon(Icons.access_alarms), +// hoverColor: GFColor.dark, + color: GFColor.secondary, +// focusColor: GFColor.danger, + type: GFType.solid, + shape: GFButtonShape.pills, + buttonBoxShadow: true, +// boxShadow: BoxShadow( +// color: Colors.pink, +// blurRadius: 2.0, +// spreadRadius: 1.0, +// offset: Offset.zero, +// ), +// splashColor: GFColor.warning, +// highlightColor: GFColor.alt, +// size: GFSize.large, +// disabledColor: GFColor.dark, +// disabledTextColor: GFColor.light, + blockButton: true, +// fullWidthButton: true, +// borderSide: BorderSide(color: Colors.pink, width: 1.0, style: BorderStyle.solid), +// borderShape: RoundedRectangleBorder(side: BorderSide(color: Colors.pink, width: 2.0, style: BorderStyle.solid), borderRadius: BorderRadius.zero), + ), // // GFIconButton( // onPressed: null, @@ -553,54 +667,30 @@ class _MyHomePageState extends State // ), GFSegmentTabs( - tabController: tabController, - height: 36.0, -// width: 180.0, - initialIndex: 0, - length: 3, - tabs: [ - Text( - "Gelatin", - ), - Tab( - child: Text( - "Donuts", - ), - ), - Tab( - child: Text( - "Pastry", - ), - ), - ], - tabBarColor: Colors.grey, - indicatorSize: TabBarIndicatorSize.tab, - indicatorColor: Colors.greenAccent, - labelColor: Colors.greenAccent, - unselectedLabelColor: Colors.white, - indicator: BoxDecoration( - color: Colors.black, - border: Border( - bottom: BorderSide( - color: Colors.greenAccent, - width: 2.0, - ), - ), -// borderRadius: BorderRadius.circular(2.0) + tabController: tabController, + initialIndex: 0, + length: 3, + tabs: [ + Text( + "Tab1", ), - indicatorPadding: EdgeInsets.all(8.0), - indicatorWeight: 2.0, - border: Border.all(color: Colors.white, width: 2.0), - borderRadius: BorderRadius.circular(2.0)), + Text( + "Tab2", + ), + Text( + "Tab3", + ), + ], + ), - GFTabBarView( - controller: tabController, - height: 400.0, - children: [ - Container(color: Colors.red), - Container(color: Colors.green), - Container(color: Colors.blue) - ]), +// GFTabBarView( +// controller: tabController, +// children: [ +// Container(color: Colors.red), +// Container(color: Colors.green), +// Container(color: Colors.blue) +// ] +// ), // GFItemsCarousel( // rowCount: 3, @@ -649,85 +739,37 @@ class _MyHomePageState extends State // }, // ), +// // GFTabs( -//// height: 100.0, -//// tabBarHeight: 52.0, // initialIndex: 0, // length: 3, // tabs: [ -// GFButton( -// onPressed: null, -// child: Text("share"), -// icon: Icon(Icons.share), -// buttonBoxShadow: true, +// Tab( +// icon: Icon(Icons.directions_bike), +// child: Text( +// "Tab1", +// ), // ), // Tab( -// icon: Icon(Icons.error), +// icon: Icon(Icons.directions_bus), // child: Text( -// "Orders", +// "Tab2", // ), // ), // Tab( +// icon: Icon(Icons.directions_railway), // child: Text( -// "Pastry", +// "Tab3", // ), // ), // ], // tabBarView: GFTabBarView( // children: [ -// Container( -// color: Colors.red, -// child: Column( -// mainAxisAlignment: MainAxisAlignment.center, -// crossAxisAlignment: CrossAxisAlignment.center, -// children: [ -// -// GFToast( -// child: Text("sdc"), -// backgroundColor: Colors.pink, -// button: GFButton( -// text: 'dsx', -// onPressed: (){ -// print("fdsc"); -// }, -// ), -// ), -// RawMaterialButton( -// onPressed: null, -// child: Text("fv"), -// ), -// FlatButton(onPressed: null, child: Text("cds")), -// Icon(Icons.directions_railway), -// GFButton( -// onPressed: null, -// child: Text("share"), -// icon: Icon(Icons.share), -// shape: GFButtonShape.pills, -// type: GFType.transparent, -// ), -// ], -// ), -// ), -// Icon(Icons.directions_car), -// Icon(Icons.directions_transit), +// Container(child: Icon(Icons.directions_bike), color: Colors.red,), +// Container(child: Icon(Icons.directions_bus), color: Colors.blue,), +// Container(child: Icon(Icons.directions_railway), color: Colors.orange,), // ], // ), -// indicatorColor: Colors.teal, -// indicatorSize: TabBarIndicatorSize.label, -// labelColor: Colors.lightGreen, -// unselectedLabelColor: Colors.black, -// labelStyle: TextStyle( -// fontWeight: FontWeight.w500, -// fontSize: 13.0, -// color: Colors.deepOrange, -// fontFamily: 'OpenSansBold', -// ), -// unselectedLabelStyle: TextStyle( -// fontWeight: FontWeight.w500, -// fontSize: 13.0, -// color: Colors.black, -// fontFamily: 'OpenSansBold', -// ), // ), // // GFCarousel( @@ -1033,31 +1075,31 @@ class _MyHomePageState extends State ], ), ), - bottomNavigationBar: GFTabBar( - initialIndex: 0, - length: 3, - controller: tabController, - tabs: [ - Tab( - icon: Icon(Icons.directions_bike), - child: Text( - "Tab1", - ), - ), - Tab( - icon: Icon(Icons.directions_bus), - child: Text( - "Tab2", - ), - ), - Tab( - icon: Icon(Icons.directions_railway), - child: Text( - "Tab3", - ), - ), - ], -// indicatorColor: Colors.teal, +// bottomNavigationBar: GFTabBar( +// initialIndex: 0, +// length: 3, +// controller: tabController, +// tabs: [ +// Tab( +// icon: Icon(Icons.directions_bike), +// child: Text( +// "Tab1", +// ), +// ), +// Tab( +// icon: Icon(Icons.directions_bus), +// child: Text( +// "Tab2", +// ), +// ), +// Tab( +// icon: Icon(Icons.directions_railway), +// child: Text( +// "Tab3", +// ), +// ), +// ], +// indicatorColor: Colors.white, //// indicatorSize: TabBarIndicatorSize.label, // labelColor: Colors.lightGreen, // labelPadding: EdgeInsets.all(8.0), @@ -1075,7 +1117,7 @@ class _MyHomePageState extends State // color: Colors.black, // fontFamily: 'OpenSansBold', // ), - ), +// ), ); } } diff --git a/example/pubspec.lock b/example/pubspec.lock index ab9c5288..cbece1ef 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -80,7 +80,7 @@ packages: path: ".." relative: true source: path - version: "1.0.0-dev.3" + version: "1.0.0-dev.8" image: dependency: transitive description: diff --git a/lib/components/appbar/gf_appbar.dart b/lib/components/appbar/gf_appbar.dart index c3cfb533..a3a7af0d 100644 --- a/lib/components/appbar/gf_appbar.dart +++ b/lib/components/appbar/gf_appbar.dart @@ -202,8 +202,9 @@ class GFAppBar extends StatefulWidget implements PreferredSizeWidget { return false; case TargetPlatform.iOS: return trailing == null || trailing.length < 2; + default: + return false; } - return null; } @override @@ -294,6 +295,8 @@ class _GFAppBarState extends State { break; case TargetPlatform.iOS: break; + default: + break; } title = DefaultTextStyle( style: centerStyle, diff --git a/lib/components/button/gf_button_bar.dart b/lib/components/button/gf_button_bar.dart index 922ba9b7..b8b0ef33 100644 --- a/lib/components/button/gf_button_bar.dart +++ b/lib/components/button/gf_button_bar.dart @@ -1,22 +1,159 @@ import 'package:flutter/material.dart'; import 'package:getflutter/components/button/gf_button.dart'; import 'package:getflutter/components/button/gf_icon_button.dart'; +import 'package:flutter/rendering.dart'; class GFButtonBar extends StatelessWidget { /// Create buttons bar for all types of buttons. /// check [GFButton] and [GFIconButton] const GFButtonBar({ Key key, - this.alignment = MainAxisAlignment.end, - this.mainAxisSize = MainAxisSize.max, + this.direction = Axis.horizontal, + this.alignment = WrapAlignment.center, + this.spacing = 8.0, + this.runAlignment = WrapAlignment.start, + this.runSpacing = 0.0, + this.crossAxisAlignment = WrapCrossAlignment.start, + this.textDirection, + this.verticalDirection = VerticalDirection.down, this.children = const [], + this.padding = const EdgeInsets.all(0.0), }) : super(key: key); - /// How the children should be placed along the horizontal axis. - final MainAxisAlignment alignment; + /// The empty space that surrounds the buttonBar. Default's to padding.zero + final EdgeInsetsGeometry padding; - /// How much horizontal space is available. See [Row.mainAxisSize]. - final MainAxisSize mainAxisSize; + /// The direction to use as the main axis. + /// + /// For example, if [direction] is [Axis.horizontal], the default, the + /// children are placed adjacent to one another in a horizontal run until the + /// available horizontal space is consumed, at which point a subsequent + /// children are placed in a new run vertically adjacent to the previous run. + final Axis direction; + + /// How the children within a run should be placed in the main axis. + /// + /// For example, if [alignment] is [WrapAlignment.center], the children in + /// each run are grouped together in the center of their run in the main axis. + /// + /// Defaults to [WrapAlignment.start]. + /// + /// See also: + /// + /// * [runAlignment], which controls how the runs are placed relative to each + /// other in the cross axis. + /// * [crossAxisAlignment], which controls how the children within each run + /// are placed relative to each other in the cross axis. + final WrapAlignment alignment; + + /// How much space to place between children in a run in the main axis. + /// + /// For example, if [spacing] is 10.0, the children will be spaced at least + /// 10.0 logical pixels apart in the main axis. + /// + /// If there is additional free space in a run (e.g., because the wrap has a + /// minimum size that is not filled or because some runs are longer than + /// others), the additional free space will be allocated according to the + /// [alignment]. + /// + /// Defaults to 0.0. + final double spacing; + + /// How the runs themselves should be placed in the cross axis. + /// + /// For example, if [runAlignment] is [WrapAlignment.center], the runs are + /// grouped together in the center of the overall [Wrap] in the cross axis. + /// + /// Defaults to [WrapAlignment.start]. + /// + /// See also: + /// + /// * [alignment], which controls how the children within each run are placed + /// relative to each other in the main axis. + /// * [crossAxisAlignment], which controls how the children within each run + /// are placed relative to each other in the cross axis. + final WrapAlignment runAlignment; + + /// How much space to place between the runs themselves in the cross axis. + /// + /// For example, if [runSpacing] is 10.0, the runs will be spaced at least + /// 10.0 logical pixels apart in the cross axis. + /// + /// If there is additional free space in the overall [Wrap] (e.g., because + /// the wrap has a minimum size that is not filled), the additional free space + /// will be allocated according to the [runAlignment]. + /// + /// Defaults to 0.0. + final double runSpacing; + + /// How the children within a run should be aligned relative to each other in + /// the cross axis. + /// + /// For example, if this is set to [WrapCrossAlignment.end], and the + /// [direction] is [Axis.horizontal], then the children within each + /// run will have their bottom edges aligned to the bottom edge of the run. + /// + /// Defaults to [WrapCrossAlignment.start]. + /// + /// See also: + /// + /// * [alignment], which controls how the children within each run are placed + /// relative to each other in the main axis. + /// * [runAlignment], which controls how the runs are placed relative to each + /// other in the cross axis. + final WrapCrossAlignment crossAxisAlignment; + + /// Determines the order to lay children out horizontally and how to interpret + /// `start` and `end` in the horizontal direction. + /// + /// Defaults to the ambient [Directionality]. + /// + /// If the [direction] is [Axis.horizontal], this controls order in which the + /// children are positioned (left-to-right or right-to-left), and the meaning + /// of the [alignment] property's [WrapAlignment.start] and + /// [WrapAlignment.end] values. + /// + /// If the [direction] is [Axis.horizontal], and either the + /// [alignment] is either [WrapAlignment.start] or [WrapAlignment.end], or + /// there's more than one child, then the [textDirection] (or the ambient + /// [Directionality]) must not be null. + /// + /// If the [direction] is [Axis.vertical], this controls the order in which + /// runs are positioned, the meaning of the [runAlignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the + /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and + /// [WrapCrossAlignment.end] values. + /// + /// If the [direction] is [Axis.vertical], and either the + /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the + /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or + /// [WrapCrossAlignment.end], or there's more than one child, then the + /// [textDirection] (or the ambient [Directionality]) must not be null. + final TextDirection textDirection; + + /// Determines the order to lay children out vertically and how to interpret + /// `start` and `end` in the vertical direction. + /// + /// If the [direction] is [Axis.vertical], this controls which order children + /// are painted in (down or up), the meaning of the [alignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values. + /// + /// If the [direction] is [Axis.vertical], and either the [alignment] + /// is either [WrapAlignment.start] or [WrapAlignment.end], or there's + /// more than one child, then the [verticalDirection] must not be null. + /// + /// If the [direction] is [Axis.horizontal], this controls the order in which + /// runs are positioned, the meaning of the [runAlignment] property's + /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the + /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and + /// [WrapCrossAlignment.end] values. + /// + /// If the [direction] is [Axis.horizontal], and either the + /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the + /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or + /// [WrapCrossAlignment.end], or there's more than one child, then the + /// [verticalDirection] must not be null. + final VerticalDirection verticalDirection; /// The buttons to arrange horizontally. /// Typically [RaisedButton] or [GFButton] or [GFIconButton] widgets. @@ -24,37 +161,21 @@ class GFButtonBar extends StatelessWidget { @override Widget build(BuildContext context) { - final ButtonThemeData buttonTheme = ButtonTheme.of(context); - // We divide by 4.0 because we want half of the average of the left and right padding. - final double paddingUnit = buttonTheme.padding.horizontal / 4.0; - final Widget child = Row( - mainAxisAlignment: alignment, - mainAxisSize: mainAxisSize, - children: children.map((Widget child) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: paddingUnit), - child: child, - ); - }).toList(), + return Padding( + padding: padding, + child: Wrap( + direction: direction, + alignment: alignment, + spacing: spacing, + runAlignment: runAlignment, + runSpacing: runSpacing, + crossAxisAlignment: crossAxisAlignment, + textDirection: textDirection, + verticalDirection: verticalDirection, + children: children.map((Widget child) { + return child; + }).toList(), + ), ); - switch (buttonTheme.layoutBehavior) { - case ButtonBarLayoutBehavior.padded: - return Padding( - padding: EdgeInsets.symmetric( - vertical: 2.0 * paddingUnit, - horizontal: paddingUnit, - ), - child: child, - ); - case ButtonBarLayoutBehavior.constrained: - return Container( - padding: EdgeInsets.symmetric(horizontal: paddingUnit), - constraints: const BoxConstraints(minHeight: 52.0), - alignment: Alignment.center, - child: child, - ); - } - assert(false); - return null; } } diff --git a/lib/components/drawer/gf_drawer.dart b/lib/components/drawer/gf_drawer.dart index 2b3d919a..cd2fa757 100644 --- a/lib/components/drawer/gf_drawer.dart +++ b/lib/components/drawer/gf_drawer.dart @@ -116,6 +116,9 @@ class GFDrawer extends StatelessWidget { case TargetPlatform.android: case TargetPlatform.fuchsia: label = semanticLabel ?? MaterialLocalizations.of(context)?.drawerLabel; + break; + default: + break; } return Semantics( scopesRoute: true, diff --git a/lib/components/list_tile/gf_list_tile.dart b/lib/components/list_tile/gf_list_tile.dart index 5b06e3bd..19258c96 100644 --- a/lib/components/list_tile/gf_list_tile.dart +++ b/lib/components/list_tile/gf_list_tile.dart @@ -28,6 +28,8 @@ class GFListTile extends StatelessWidget { /// The icon to display inside the [GFListTile]. see [Icon] final Widget icon; + final EdgeInsets padding; + /// Creates ListTile with leading, title, trailing, image widget for almost every type of ListTile design. const GFListTile({ Key key, @@ -39,13 +41,14 @@ class GFListTile extends StatelessWidget { this.subTitle, this.description, this.icon, + this.padding = const EdgeInsets.all(8.0), }) : super(key: key); @override Widget build(BuildContext context) { return Container( constraints: BoxConstraints(minHeight: 50), - padding: EdgeInsets.all(8), + padding: padding, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.all(Radius.circular(5)), diff --git a/lib/components/toast/gf_floating_widget.dart b/lib/components/toast/gf_floating_widget.dart index b6fa7076..8afd436e 100644 --- a/lib/components/toast/gf_floating_widget.dart +++ b/lib/components/toast/gf_floating_widget.dart @@ -40,10 +40,14 @@ class _GFFloatingWidgetState extends State { child: widget.body ?? Container(), ), Positioned( - top: widget.horizontalPosition != null + top: + widget.verticalPosition != null ? widget.verticalPosition : 0.0, + left: widget.horizontalPosition != null ? widget.horizontalPosition - : 0, - left: widget.verticalPosition != null ? widget.verticalPosition : 0, + : 0.0, + right: widget.horizontalPosition != null + ? widget.horizontalPosition + : 0.0, child: Container( width: MediaQuery.of(context).size.width, child: widget.child ?? Container(), diff --git a/pubspec.yaml b/pubspec.yaml index 9e414623..18a05613 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,12 @@ name: getflutter description: GetFlutter is open source libraries that come with pre-build 1000+ UI components. It makes development faster & more enjoyable. You can customize the component as per your need. -version: 1.0.0-dev.3 +version: 1.0.0-dev.8 #author: GetFlutter homepage: https://github.com/ionicfirebaseapp/getflutter environment: - sdk: ">=2.1.0 <3.0.0" + # sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.2.2 <3.0.0" dependencies: flutter: