sura_flutter
A flutter package for custom widgets and utility function.
Migrate from 0.2.x to 0.3.x
-
BREAKING CHANGE:
- remove FutureManager, AsyncSubjectManager, FutureManagerBuilder
- All manager class now has a separate package
dependencies: sura_manager: ^1.5.0
Installation
Add this to pubspec.yaml
dependencies:
sura_flutter: ^1.4.2
Widgets
Widget | Description |
---|---|
ConditionalWidget | Build a widget base on a boolean condition |
Divider0 | Divider with 0 height |
EllipsisText | Nullable Text with Ellipsis as default overflow |
KeyboardDismiss | Dismiss keyboard on tap |
LoadingOverlay | Create an overlay loading that cover entire screen and disable input |
LoadingOverlayPopScope | prevent or allow user from pop the screen when LoadingOverlay is displaying |
SpaceX | SizedBox with only width |
SpaceY | SizedBox with only height |
SuraAccordion | Custom ExpansionTile |
SuraActionSheet | Custom CupertinoActionSheet for option selector |
SuraAsyncButton | Fully customize Material ElevatedButton for asynchronous onPressed callback |
SuraAsyncIconButton | SuraIconButton with asynchronous onPressed callback |
SuraBadge | Small badge like notification |
SuraConfirmationDialog | Platform adaptive AlertDialog with cancel and confirm action |
SuraExpandable | Similar to SuraAccordion but with different use case |
SuraFlatButton | Custom TextButton or FlatButton |
SuraFutureHandler | FutureBuilder with less boilerplate code |
SuraIconButton | Custom IconButton |
SuraListTile | Custom ListTile |
SuraLoadingDialog | Create and manage Loading Dialog, Deprecated and shouldn't be use. Consider using LoadingOverlay instead |
SuraNotifier | Custom ValueListenableBuilder |
SuraPaginatedGrid | GridView with pagination support |
SuraPaginatedList | ListView with pagination support |
SuraPlatformChecker | Platform adaptive widget |
SuraProvider | A provider for SuraFlutter global setting |
SuraRaisedButton | Custom ElevatedButton with loading notifier |
SuraSimpleDialog | Simple platform adaptive AlertDialog |
SuraStreamHandler | A StreamBuilder with less boilerplate code |
SuraToolbar | Custom ToolBar or AppBar |
ValueNotifierWrapper | Wrapper with ValueNotifier when using StatelessWidget |
WidgetDisposer | Provide a dispose callback when using StatelessWidget |
Mixin
AfterBuildMixin
Create an override method that will call after the build method has been called
class _HomePageState extends State<NewPage> with AfterBuildMixin {
//this method will call after widget has been build
@override
void afterBuild(BuildContext context) {
}
@override
Widget build(BuildContext context) {
return Container();
}
}
SuraFormMixin
Provide some property and method when working with Form
field and attribute
- formKey: a key for form
- loadingNotifier: a bool ValueNotifier
- passwordObscureNotifier: a bool ValueNotifier for toggling password obscure field
- isFormValidated: a bool return by validate formKey
method
- toggleLoading: toggle loadingNotifier
- togglePasswordObscure: toggle passwordObscureNotifier
class _HomePageState extends State<NewPage> with SuraFormMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Form(key: formKey, child: child)
);
}
}
BoolNotifierMixin
Provider a ValueNotifier
- boolNotifier: a bool ValueNotifier
method
- toggleValue: toggle loadingNotifier
class _HomePageState extends State<NewPage> with BoolNotifierMixin {
@override
Widget build(BuildContext context) {
return Container();
}
}
Extension
BuildContext extension
Size screenSize = context.screenSize;
Color primaryColor = context.primaryColor;
Color accentColor = context.accentColor;
TextThemeData textTheme = context.textTheme;
Theme theme = context.theme;
MediaQueryData data = context.mediaQuery;
//
context.hideKeyboard();
TextStyle Extension
Text("Hello Flutter", style: TextStyle().normal)
Text("Hello Flutter", style: TextStyle().medium)
Text("Hello Flutter", style: TextStyle().bold)
Text("Hello Flutter", style: TextStyle().semiBold)
Text("Hello Flutter", style: TextStyle().white)
Text("Hello Flutter", style: TextStyle().black)
Text("Hello Flutter", style: TextStyle().red)
Text("Hello Flutter", style: TextStyle().green)
Text("Hello Flutter", style: TextStyle().grey)
Text("Hello Flutter", style: TextStyle().underline)
Text("Hello Flutter", style: TextStyle().setColor(Colors.white))
Text("Hello Flutter", style: TextStyle().setFontSize(24))
///This responsive font size is configure as following using SuraResponsive value:
/// tablet: value + 4
/// desktop: value + 6
/// small mobile: value - 2
Text("Hello Flutter", style: TextStyle().responsiveFontSize(24))
DateTime extension
DateTime.now().format(format: "dd mmm yyyy", locale: context.locale)
DateTime.now().isTheSameDay(DateTime.now())
DateTime.now().formatToLocalDate(format: "dd mmm yyyy", locale: context.locale)
List and map extension
///Filter list
List<int> adult = [2,24,12,18].filter((age)=> age >= 18);
///Add age to Map if age isn't null
Map<String, int> data = {};
int? age = 20;
data.addIfNotNull("age",age);
///Return null if age doesn't exist
data.getIfExist("age");
Widget's Extension
Text("Hello Flutter").padding(EdgeInsets.all(16.0)) // default value is EdgeInsets.all(8.0)
Text("Hello Flutter").margin(EdgeInsets.all(16.0)) // default value is EdgeInsets.all(8.0)
///As a value
Text("Hello Flutter").marginValue(all: 12)
Text("Hello Flutter").paddingValue(horizontal: 12, vertical: 8)
Text("Hello Flutter").cssSpacing(margin: [10,10], padding:[16])
//css margin and padding rule
Text("Hello Flutter").rotate(45)
///Rotate 45 degree
Text("Hello Flutter").flexible
Text("Hello Flutter").expanded
Text("Hello Flutter").clipOval
Text("Hello Flutter").opacity(0.5)
String extension
String name = "chunlee".capitalize() // => Chunlee
Utility and Style
DotTabIndicator
TabBar(
...
indicator: DotTabIndicator(
color: Colors.blue,
dotAlignment: TabAlignment.bottom,
)
...
)
SmallUnderlineTabIndicator
TabBar(
...
isScrollable: true, //This indicator work best with scrollable tab bar
indicator: SmallUnderlineTabIndicator(
color: Colors.blue,
paddingLeft: 16,
alignment: TabAlignment.bottom,
)
...
)
ShadowInputBorder
This input border solve a problem that TextField doesn't have a default elevation.
TextFormField(
...
decoration: InputDecoration(
border: ShadowInputBorder(
elevation: 2.0, //required
fillColor: Colors.white, //required
borderRadius: SuraDecoration.radius(),
shadowColor: Colors.black87,
),
)
...
)
SuraColor
//Get Color from hex string
Color green = SuraColor.fromCode("42f545")
//Get Color from RGB without Alpha or Opacity
Color newColor = SuraColor.fromRGB(8, 182, 155)
//Convert color to MaterialColor
MaterialColor newMaterialColor = SuraColor.toMaterial(0xFF869CF4)
SuraUtils
//Ping to google to check for internet connection
bool isConnected = await SuraUtils.checkConnection();
//Convert degree to radian value
double radian = SuraUtils.degreeToRadian(90);
//Future.delayed base on millisecond value
await SuraUtils.wait(200);
//Get random image from unsplash
String carUrlImage = SuraUtils.unsplashImage(width: 200, height: 200, category: "car");
//Get byte from asset bundle
Future<Uint8List> imageByte = await SuraUtils.getBytesFromAsset("image asset path", 200); //200 is an image width
//Get random image from unsplash
String carUrlImage = SuraUtils.unsplashImage(width: 200, height: 200, category: "car");
//Get random from picsum with provided: width and height
String randomUrlImage = SuraUtils.picsumImage(200,300);
SuraFormValidator
Provide some field validation
///Validate
TextFormField(
validator: (value) => SuraFormValidator.validateField(value, field: "username"),
),
TextFormField(
validator: (value) => SuraFormValidator.isNumber(value, field: "age"),
),
TextFormField(
validator: (value) => SuraFormValidator.validateEmail(value, field: "email"),
)
SuraPageNavigator and SuraNavigator
PageNavigator support push, pushReplacement and pushAndRemove method
///use name param to provide RouteSetting's routeName
SuraPageNavigator.push(context, DetailPage(), name: "detail-page");
///Also support RouteSetting
SuraPageNavigator.pushReplacement(context, HomePage(), settings: RouteSetting());
///Remove all
SuraPageNavigator.pushAndRemove(context, RootPage());
SuraNavigator also support push, pushReplacement, pushAndRemove without providing a context but you need to add SuraNavigator.navigatorKey to MaterialApp
MaterialApp(
...
navigatorKey: SuraNavigator.navigatorKey,
...
home: MyHomePage(),
)
SuraNavigator.push(DetailPage());
SuraNavigator.pushReplacement(HomePage());
SuraNavigator.pushAndRemove(RootPage());
SuraNavigator also can show dialog without providing a context
var result = await SuraNavigator.dialog(MyDialog());
SuraDecoration
RoundedRectangleBorder roundRectangle = SuraDecoration.roundRect(12); //default value is 8
BorderRadius radius = SuraDecoration.radius(12); //default value is 8
SuraResponsiveSize
A responsive tool to help define a value base on screen size
- Wrap your Home widget in MaterialApp with SuraResponsiveBuilder
Example:
// Only required first parameter
//set value 20 for mobile size
//set value 24 for tablet size
//set value 28 for desktop size
//set value 16 for small mobile size
//If context isn't null, it will react to MediaQuery change
double width = SuraResponsive.value(20,24,28,16,context);
///Auto value base on provided rule
///-4 for small phone, +8 for tablet and +16 for Desktop if using add rule
///-25% for small phone, x2 for tablet and x3 for Desktop if using multiply rule
double width = SuraResponsive.auto(20,SuraResponsiveRule.add);
Widget child = SuraResponsive.builder(
mobile: ()=> MobileWidget(), ///required
tablet: ()=> TabletWidget(), ///required
desktop: ()=> DesktopWidget(), ///Optional, using tablet widget if value is null
mobileSmall: ()=> MobileSmallWidget(), ///Optional, using mobile widget if value is null
);