BLoC Pattern Event In Flutter :
This flutter tutorial post is BLoC pattern event in flutter.
Screenshot :






blocs package contain 4 packages
blocs package
- login
- promoter
- user : Login successfull after save the data. For example username, email etc.
- viewmodel : Constant data save. For example List.
- common_state.dart : Check the Api call or not
Every bloc pattern 3 class contains
1) state
2) event
3) bloc
For example:
Login state
- username, password is input.
- loading, loaded, error api call to response
Login event
- input username, password
- callback get the from api
Login bloc
- userNameInput, passwordInput input data.
- login is call user press button login then. That is call login_page.dart onRegisterDevice().
pubspec.yaml
yaml file use to flutter name and decscription of application, sdk version, dependencies, assets, fonts.
This application 6 dependencies add
1) cupertino_icons: ^0.1.2
2) shared_preferences:
3) intl:
4) font_awesome_flutter:
5) flutter_bloc:
6) provider:
pubspec.yaml
name: block_pattern_event description: A new Flutter application. version: 1.0.0+1 environment: sdk: ">=2.5.0 <3.0.0" dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.2 shared_preferences: intl: font_awesome_flutter: flutter_bloc: provider: dev_dependencies: flutter_test: sdk: flutter flutter: uses-material-design: true assets: - assets/images/ fonts: - family: Quicksand fonts: - asset: assets/fonts/quicksand_medium.ttf style: normal - asset: assets/fonts/quicksand_bold.otf weight: 700 - family: Raleway fonts: - asset: assets/fonts/raleway_regular.ttf style: normal - asset: assets/fonts/raleway_medium.ttf
BLoC Package :
– Login Package :
login_bloc.dart
import 'package:bloc/bloc.dart'; import 'package:block_pattern_event/models/login.dart'; import 'login_event.dart'; import 'login_state.dart'; class LoginBloc extends Bloc<LoginEvent, LoginState> { void userNameInput(mobileEmail) { dispatch(UserNameInput(username: mobileEmail)); } void passwordInput(passwordInput) { dispatch(PasswordInput(password: passwordInput)); } void login(callback) { dispatch(Login(callback: callback)); } @override LoginState get initialState => LoginState.initial(); @override Stream<LoginState> mapEventToState(LoginEvent event) async* { if (event is UserNameInput) { yield currentState.copyWith(username: event.username); } if (event is PasswordInput) { yield currentState.copyWith(password: event.password); } if (event is Login) { yield currentState.copyWith(loading: true); try { yield currentState.copyWith( loaded: true, loading: false, error: {}, ); event.callback(new LoginResponse( mobile: '', id: 1, code: '200', firstName: 'admin', lastName: 'admin', username: 'Flutter Tutorial')); } catch (e) { yield currentState.copyWith( loaded: true, loading: false, error: {"error": "Error, Something bad happened."}, ); } } } }
login_event.dart
abstract class LoginEvent {} class UserNameInput extends LoginEvent { final String username; UserNameInput({this.username}); } class PasswordInput extends LoginEvent { final String password; PasswordInput({this.password}); } class Login extends LoginEvent { Function callback; Login({this.callback}); }
login_state.dart
import 'package:meta/meta.dart'; import '../common_state.dart'; class LoginState extends CommonState { final String username; final String password; bool loading; bool loaded; Map error; LoginState({ @required this.username, @required this.password, bool loading, bool loaded, Map error, }) : super( loading: loading, loaded: loaded, error: error, ); factory LoginState.initial() { return LoginState( username: "", password: "", ); } LoginState copyWith( {bool loading, bool loaded, Map error, String username, String uid, String password}) { return LoginState( username: username ?? this.username, password: password ?? this.password, ); } }
– Promoter Package
promoter_bloc.dart
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:block_pattern_event/blocs/viewmodel/promoter_data.dart'; import 'promoter_event.dart'; import 'promoter_state.dart'; class PromoterBloc extends Bloc<PromoterEvent, PromoterState> { void callPromoter() { dispatch(GetPromoter()); } @override PromoterState get initialState => PromoterState.initial(); @override Stream<PromoterState> mapEventToState(PromoterEvent event) async* { if (event is GetPromoter) { final promoterViewModel = PromoterViewModel(); yield currentState.copyWith(promoters: promoterViewModel.promoterList()); } } }
promoter_event.dart
abstract class PromoterEvent {} class GetPromoter extends PromoterEvent {}
promoter_state.dart
import 'package:block_pattern_event/models/promoter.dart'; class PromoterState { final List<PromoterResponse> promoters; PromoterState({ this.promoters, }); factory PromoterState.initial() { return PromoterState( promoters: List<PromoterResponse>(), ); } PromoterState copyWith({ List<PromoterResponse> promoters }) { return PromoterState( promoters: promoters ?? this.promoters, ); } }
– User Package
user_bloc.dart
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'user_event.dart'; import 'user_state.dart'; class UserBloc extends Bloc<UserEvent, UserState> { SharedPreferences pref; void saveUserName(username) { dispatch(SaveUserName(username: username)); } void saveId(id) { dispatch(SaveId(id: id)); } void saveAuthToken(token) { dispatch(SaveToken(token: token)); } void saveEmail(email) { dispatch(SaveEmail(email: email)); } void saveMobile(mobile) { dispatch(SaveMobile(mobile: mobile)); } void getLoginDetails() { dispatch(GetLoginDetails()); } @override UserState get initialState => UserState.initial(); @override Stream<UserState> mapEventToState( UserEvent event, ) async* { if (event is SaveUserName) { pref.setString("username", event.username); } if (event is SaveId) { pref = await SharedPreferences.getInstance(); pref.setString("id", event.id); } if (event is SaveEmail) { pref = await SharedPreferences.getInstance(); pref.setString("email", event.email); } if (event is SaveToken) { pref = await SharedPreferences.getInstance(); pref.setString("token", event.token); } if (event is RemoveToken) { pref = await SharedPreferences.getInstance(); pref.remove("token"); } if (event is SaveMobile) { pref = await SharedPreferences.getInstance(); pref.setString("mobile", event.mobile); } //GET LOGIN DETAILS if (event is GetLoginDetails) { pref = await SharedPreferences.getInstance(); yield currentState.copyWith(mobile: pref.getString('mobile'), userName: pref.getString('username')); } } }
user_event.dart
abstract class UserEvent {} class GetLoginDetails extends UserEvent {} class SaveUserName extends UserEvent { final String username; SaveUserName({this.username}); } class SaveId extends UserEvent { final String id; SaveId({this.id}); } class SaveToken extends UserEvent { final String token; SaveToken({this.token}); } class RemoveToken extends UserEvent { final String token; RemoveToken({this.token}); } class SaveEmail extends UserEvent { final String email; SaveEmail({this.email}); } class SaveMobile extends UserEvent { final String mobile; SaveMobile({this.mobile}); }
user_state.dart
import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; class UserState { final bool loading, loaded; final Map error; final String userName, mobile; UserState({ @required this.loading, @required this.loaded, @required this.error, @required this.userName, @required this.mobile, }); factory UserState.initial() { return UserState( loading: false, loaded: false, error: null, userName: null, mobile: null, ); } UserState copyWith({ bool loading, bool loaded, Map error, String userName, String mobile, }) { return UserState( loading: loading ?? this.loading, loaded: loaded ?? this.loaded, error: error ?? this.error, userName: userName ?? this.userName, mobile: mobile ?? this.mobile); } }
– Viewmodel Package
promoter_data.dart
import 'package:block_pattern_event/models/promoter.dart'; class PromoterViewModel { List<PromoterResponse> promoterItems; PromoterViewModel({this.promoterItems}); promoterList() => <PromoterResponse>[ PromoterResponse(promoterId: 1, promoterName: 'Admin'), PromoterResponse(promoterId: 1, promoterName: 'User'), PromoterResponse(promoterId: 1, promoterName: 'Local'), PromoterResponse(promoterId: 1, promoterName: 'Others'), ]; }
common_state.dart
abstract class CommonState { bool loading = false; bool loaded= false; Map error; CommonState({ this.loading, this.loaded, this.error, }); Map<String, dynamic> toMap() => { 'loading': loading, 'loaded': loaded, 'error': error, }; }
– Models Package
login.dart
class LoginResponse { final double id; final String firstName, lastName, mobile, username, code; LoginResponse({ this.id, this.firstName, this.lastName, this.username, this.code, this.mobile, }); LoginResponse copyWith(Map<String, dynamic> json) { return LoginResponse( id: json["ID"] ?? this.id, firstName: json["FNAME"] ?? this.firstName, lastName: json["LNAME"] ?? this.lastName, username: json["RETAILERNAME"] ?? this.username, code: json["RETAILERCODE"] ?? this.code, mobile: json["MOBILENO"] ?? this.mobile); } LoginResponse.fromJson(Map<String, dynamic> json) : id = json["ID"], firstName = json["FNAME"], lastName = json["LNAME"], username = json["RETAILERNAME"], code = json["RETAILERCODE"], mobile = json["MOBILENO"]; }
promoter.dart
class PromoterResponse { final double promoterId; final String promoterName; PromoterResponse({this.promoterId, this.promoterName}); }
– Screens Package
screen package inside 2 package
- pages : View
- widgets : Custom widgets
– Pages Package
home_page.dart
import 'package:block_pattern_event/blocs/promoter/promoter_bloc.dart'; import 'package:block_pattern_event/blocs/promoter/promoter_state.dart'; import 'package:block_pattern_event/models/promoter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class HomePage extends StatefulWidget { @override _HomeState createState() => _HomeState(); } class _HomeState extends State<HomePage> { PromoterBloc promoterBloc; @override void initState() { super.initState(); promoterBloc = BlocProvider.of<PromoterBloc>(context); promoterBloc.callPromoter(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text('Promoter List'), ), body: Container( child: BlocBuilder( bloc: promoterBloc, builder: (context, PromoterState state) { return ListView.builder( padding: EdgeInsets.only(top: 1.0), physics: BouncingScrollPhysics(), itemCount: state.promoters.length, itemBuilder: (BuildContext context, int index) { PromoterResponse promoter = state.promoters[index]; return Material( child: Ink( color: Colors.white, child: ListTile( title: Text(promoter.promoterName, style: TextStyle( color: Colors.black87, fontSize: 17)), leading: Container( width: 40, height: 40, child: Align( alignment: Alignment.center, child: Text( promoter.promoterName .substring(0, 1), style: TextStyle( color: Colors.black54, fontSize: 20))), decoration: BoxDecoration( color: Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(40.0))), onTap: () {}))); }); }))); } }
login_page.dart
import 'package:block_pattern_event/blocs/login/login_bloc.dart'; import 'package:block_pattern_event/blocs/login/login_state.dart'; import 'package:block_pattern_event/blocs/user/user_bloc.dart'; import 'package:block_pattern_event/models/login.dart'; import 'package:block_pattern_event/screens/widgets/common_dialogs.dart'; import 'package:block_pattern_event/utils/validator.dart'; import 'package:block_pattern_event/utils/vars.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class LoginPage extends StatefulWidget { @override _LoginState createState() => _LoginState(); } class _LoginState extends State<LoginPage> { final GlobalKey<FormState> _key = new GlobalKey(); final TextEditingController _usernameController = new TextEditingController(); final TextEditingController _passwordController = new TextEditingController(); final scaffoldKey = new GlobalKey<ScaffoldState>(); LoginBloc loginBloc; UserBloc userBloc; bool _validate = false; @override void initState() { super.initState(); loginBloc = BlocProvider.of<LoginBloc>(context); userBloc = BlocProvider.of<UserBloc>(context); } @override Widget build(BuildContext context) { return Scaffold( key: scaffoldKey, backgroundColor: Colors.white, body: ListView(children: <Widget>[ Column(children: <Widget>[ Padding( padding: const EdgeInsets.only(top: 57.0, left: 10, right: 10), child: Text('Flutter BLoC Pattern Event', style: TextStyle(fontSize: 28), textAlign: TextAlign.center), ), new Form(key: _key, autovalidate: _validate, child: _bottomSheet()), ]) ])); } Widget _bottomSheet() { return Container( margin: EdgeInsets.only(top: MediaQuery.of(context).size.height / 10), decoration: BoxDecoration( borderRadius: BorderRadius.only( topLeft: Radius.circular(24), topRight: Radius.circular(24), ), color: Colors.orange.withOpacity(0.1), ), alignment: Alignment.bottomCenter, padding: EdgeInsets.all(25), height: MediaQuery.of(context).size.height / 1.4, child: Column(children: <Widget>[ Text('LOGIN', textAlign: TextAlign.center, style: TextStyle( fontFamily: ralewayFont, color: Colors.orange.withOpacity(0.8), fontSize: 20, fontWeight: FontWeight.bold)), _userNameTextField(), _passwordTextField(), _signInButton(), ])); } _userNameTextField() => BlocBuilder( bloc: loginBloc, builder: (BuildContext context, LoginState state) { return Padding( padding: const EdgeInsets.only(top: 32.0), child: TextFormField( validator: Validator.validUserName, controller: _usernameController, keyboardType: TextInputType.text, textAlign: TextAlign.left, onChanged: loginBloc.userNameInput, style: TextStyle( color: Colors.black54, fontFamily: 'quickFont', fontSize: 18, letterSpacing: 0.5), decoration: InputDecoration( focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), border: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade200, width: 2)), errorStyle: TextStyle(color: Colors.black54), hintStyle: TextStyle( color: Colors.black54, fontFamily: 'quickFont', fontSize: 15, ), labelStyle: TextStyle(color: Colors.grey, fontSize: 12), labelText: 'Username', hintText: 'Username'))); }); _passwordTextField() => BlocBuilder( bloc: loginBloc, builder: (BuildContext context, LoginState state) { return Padding( padding: const EdgeInsets.only(top: 15.0), child: TextFormField( validator: Validator.validatePassword, controller: _passwordController, keyboardType: TextInputType.emailAddress, textAlign: TextAlign.left, onChanged: loginBloc.passwordInput, style: TextStyle( color: Colors.black54, fontFamily: 'quickFont', fontSize: 18, letterSpacing: 0.5), decoration: InputDecoration( focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), border: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey)), focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red.shade200, width: 2)), errorStyle: TextStyle(color: Colors.black54), hintStyle: TextStyle( color: Colors.black54, fontFamily: 'quickFont', fontSize: 15, ), labelStyle: TextStyle(color: Colors.grey, fontSize: 12), labelText: 'Password', hintText: 'Password'))); }); buttonChild() { return Text("Login", style: TextStyle( fontFamily: quickFont, color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500)); } void onRegisterDevice() async { showProgress(context); loginBloc.login((results) { hideProgress(context); if (results is LoginResponse) { clearData(); LoginResponse loginResponse = results; userBloc.saveAuthToken(''); userBloc.saveUserName(loginResponse.username); userBloc.saveId(loginResponse.code); userBloc.saveMobile(loginResponse.mobile); Navigator.pushNamed(context, '/homepage'); } else {} }); } _signInButton() => BlocBuilder( bloc: loginBloc, builder: (BuildContext context, LoginState state) { if (state.error != null && state.error.containsKey('error')) {} return new Padding( padding: const EdgeInsets.only(top: 20.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ SizedBox( width: 150, height: 36, child: RaisedButton( color: Colors.orange, onPressed: () { sendToServer(); }, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), elevation: 1, child: buttonChild())) ])); }); sendToServer() { if (_key.currentState.validate()) { _key.currentState.save(); onRegisterDevice(); } else { setState(() { _validate = true; }); } } clearData() { _usernameController.clear(); _passwordController.clear(); } }
– Widgets Package
common_dialogs.dart
import 'package:block_pattern_event/utils/vars.dart'; import 'package:flutter/material.dart'; /*toast(String msg) { Fluttertoast.showToast( msg: msg, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, backgroundColor: Colors.white, textColor: Colors.black); }*/ showSuccess(BuildContext context, String message, IconData icon) { showDialog( context: context, builder: (context) => Center( child: Material( borderRadius: BorderRadius.circular(8.0), color: Colors.black, elevation: 5.0, child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[ Icon( icon, color: Colors.green, ), SizedBox( height: 10.0, ), Text( message, style: TextStyle( fontFamily: '$ralewayFont', color: Colors.white), ) ], ), ), ), )); } showProgress(BuildContext context) { showDialog( context: context, barrierDismissible: false, builder: (context) => Center( child: CircularProgressIndicator() )); } hideProgress(BuildContext context) { Navigator.pop(context); }
– Utils Package
validator.dart
class Validator { static String validateMobile(String value) { String pattern = r'(^[0-9]*$)'; RegExp regExp = new RegExp(pattern); if (value.replaceAll(" ", "").isEmpty) { return 'Mobile is required'; } else if (value.replaceAll(" ", "").length != 10) { return 'Mobile number must 10 digits'; } else if (!regExp.hasMatch(value.replaceAll(" ", ""))) { return 'Mobile number must be digits'; } return null; } static String validUserName(String value) { String pattern = r'(^[a-zA-Z ]*$)'; RegExp regExp = new RegExp(pattern); if (value.isEmpty) { return 'Username is required'; } else if (!regExp.hasMatch(value)) { return 'Username must be a-z and A-Z'; } return null; } static String validateEmail(String value) { String pattern = r'^(([^<>()[\]\\.,;:\[email protected]\"]+(\.[^<>()[\]\\.,;:\[email protected]\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; RegExp regExp = new RegExp(pattern); if (value.isEmpty) { return 'Email is required'; } else if (!regExp.hasMatch(value)) { return 'Invalid email'; } else { return null; } } static String validatePassword(String value) { if (value.isEmpty) { return 'Password is required'; } else if (value.length < 4) { return 'Password must be at least 4 characters'; } return null; } static String validateConfirmPassword(String value) { if (value.isEmpty) { return 'Confirm password is required'; } else if (value.length < 4) { return 'Confirm password must be at least 4 characters'; } return null; } static bool validationEqual(String currentValue, String checkValue) { if (currentValue == checkValue) { return true; } else { return false; } } static String address(String value) { if (value.isEmpty) { return 'Address is required'; } return null; } static String state(String value) { if (value.isEmpty) { return 'State is required'; } return null; } static String flatNoHouseNo(String value) { if (value.isEmpty) { return 'Flat No. / House No. is required'; } return null; } static String city(String value) { if (value.isEmpty) { return 'City is required'; } return null; } }
vars.dart
String appName = "MileStone"; String quickFont = 'Quicksand'; String ralewayFont = 'Raleway'; String quickBoldFont = 'quicksand_bold.otf'; String quickNormalFont = 'quicksand_book.otf'; String quickLightFont = 'quicksand_light.otf'; String homeRoute = '/homepage'; int ok200 = 200;
This file contains
- Start of application
- BlocProvider
- Theme
- Route
main.dart
import 'package:block_pattern_event/blocs/promoter/promoter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'blocs/login/login_bloc.dart'; import 'blocs/user/user_bloc.dart'; import 'screens/pages/login_page.dart'; import 'screens/pages/home_page.dart'; import 'utils/vars.dart'; void main() { runApp(StartApp()); } class StartApp extends StatelessWidget { @override Widget build(BuildContext context) { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle.dark.copyWith( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light), ); return BlocProvider( builder: (context) => UserBloc(), child: BlocProvider( builder: (context) => LoginBloc(), child: BlocProvider( builder: (context) => PromoterBloc(), child: MaterialApp( theme: ThemeData( //buttonColor: Colors.white, brightness: Brightness.light, accentColor: Colors.orange, primaryColor: Colors.orangeAccent, primarySwatch: Colors.orange, fontFamily: quickFont), initialRoute: '/', debugShowCheckedModeBanner: false, routes: <String, WidgetBuilder>{ '/': (context) => LoginPage(), '/homepage': (context) => HomePage()//LoginPage })))); } }
The flutter tutorial is a website that bring you the latest and amazing resources of code. All the languages codes are included in this website. The languages like flutter, android, java,kotlin etc.with the help of this languages any user can develop the beautiful application
For more information about Flutter. visit www.fluttertutorial.in