Screenshot :

BLoC Pattern Event using Rest API Call in Flutter
main.dart
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'blocs/country/country_bloc.dart'; import 'blocs/user/user_bloc.dart'; import 'screens/pages/home_page.dart'; import 'service/di/dependency_injection.dart'; import 'utils/vars.dart'; void main() { Injector.configure(Flavor.Network); 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) => CountryBloc(), 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) => HomePage() }))); } }
pubspec.yaml
name: flutter_app description: A new Flutter application. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: flutter: sdk: flutter cupertino_icons: shared_preferences: intl: font_awesome_flutter: flutter_bloc: provider: rxdart: http: dev_dependencies: flutter_test: sdk: flutter flutter: uses-material-design: true 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
Models Package
country.dart
class CountryResponse { final String name; CountryResponse({this.name}); CountryResponse copyWith(Map<String, dynamic> json) { return CountryResponse( name: json["name"] ?? this.name); } CountryResponse.fromJson(Map<String, dynamic> json) : name = json["name"]; }
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"]; }
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;
Screens Package
- pages Package
- widgets Package
-Pages
home_page.dart
import 'package:flutter/material.dart'; import 'package:flutter_app/blocs/country/country_state.dart'; import 'package:flutter_app/blocs/country/country_bloc.dart'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class HomePage extends StatefulWidget { @override _HomeState createState() => _HomeState(); } class _HomeState extends State<HomePage> { CountryBloc countryBloc; @override void initState() { super.initState(); countryBloc = BlocProvider.of<CountryBloc>(context); countryBloc.callCountry(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text('Country List'), ), body: Container( child: BlocBuilder( bloc: countryBloc, builder: (context, CountryState state) { return state.loading? Center( child: CircularProgressIndicator() ) : ListView.builder( padding: EdgeInsets.only(top: 1.0), physics: BouncingScrollPhysics(), itemCount: state.country.length, itemBuilder: (BuildContext context, int index) { CountryResponse promoter = state.country[index]; return Material( child: Ink( color: Colors.white, child: ListTile( title: Text(promoter.name, style: TextStyle( color: Colors.black87, fontSize: 17)), leading: Container( width: 40, height: 40, child: Align( alignment: Alignment.center, child: Text( promoter.name .substring(0, 1), style: TextStyle( color: Colors.black54, fontSize: 20))), decoration: BoxDecoration( color: Colors.grey.withOpacity(0.1), borderRadius: BorderRadius.circular(40.0))), onTap: () {}))); }); }))); } }
-widgets
common_dialogs.dart
import 'package:flutter/material.dart'; import 'package:flutter_app/utils/vars.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); }
Bloc Package
- country Package
- user Package
- viewmodel Package
- common_state.dart
Bloc Package
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, }; }
-country Package
country_bloc.dart
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter_app/blocs/viewmodel/api_provider.dart'; import 'package:flutter_app/blocs/viewmodel/country_data.dart'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_app/utils/vars.dart'; import 'country_event.dart'; import 'country_state.dart'; class CountryBloc extends Bloc<CountryEvent, CountryState> { final ApiProvider apiProvider = ApiProvider(); void callCountry() { dispatch(GetCountry()); } @override CountryState get initialState => CountryState.initial(); @override Stream<CountryState> mapEventToState(CountryEvent event) async* { if (event is GetCountry) { yield currentState.copyWith(loading: true); try { await apiProvider.getCountry(); List<CountryResponse> brandList; if (apiProvider.apiResult != null) { brandList = apiProvider.apiResult.response; if (brandList.isNotEmpty) { yield currentState.copyWith( loading: false, country: brandList ); } else { yield currentState.copyWith( error: {"error": 'Data not found'}, loaded: false, loading: false, ); } } } catch (e) { yield currentState.copyWith( error: {"error": "Error, Something bad happened."}, loaded: false, loading: false, ); } } } }
country_event.dart
abstract class CountryEvent {} class GetCountry extends CountryEvent {}
country_state.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter_app/models/country.dart'; class CountryState { final List<CountryResponse> country; final bool loading; final Map error; CountryState({ @required this.loading, @required this.error, this.country, }); factory CountryState.initial() { return CountryState( loading: false, error: null, country: const [], ); } CountryState copyWith({ bool loading, bool loaded, Map error, List<CountryResponse> country }) { return CountryState( loading: loading ?? this.loading, error: error ?? this.error, country: country ?? this.country, ); } }
-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
api_provider.dart
import 'dart:async'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_app/service/abstract/api_service.dart'; import 'package:flutter_app/service/di/dependency_injection.dart'; import 'package:flutter_app/service/network_service_response.dart'; class ApiProvider { NetworkServiceResponse apiResult; APIService apiService = new Injector().flavor; Future<Null> getCountry() async { NetworkServiceResponse<List<CountryResponse>> result = await apiService.country(); this.apiResult = result; } }
country_data.dart
import 'package:flutter_app/models/country.dart'; class CountryViewModel { List<CountryResponse> promoterItems; CountryViewModel({this.promoterItems}); countryList() => <CountryResponse>[ CountryResponse(name: 'India'), ]; }
service Package
- abstract Package
- di Package
- mock Package
- network Package
- network_service_response.dart
- network_type.dart
- restclient.dart
service Package
network_service_response.dart
class NetworkServiceResponse<T> { T response; int responseCode; NetworkServiceResponse({this.response, this.responseCode}); } class MappedNetworkServiceResponse<T> { dynamic mappedResult; NetworkServiceResponse<T> networkServiceResponse; MappedNetworkServiceResponse( {this.mappedResult, this.networkServiceResponse}); }
network_type.dart
import 'package:flutter_app/service/restclient.dart'; abstract class NetworkType { RestClient rest; NetworkType(this.rest); }
restclient.dart
import 'dart:async'; import 'package:flutter_app/utils/vars.dart'; import 'package:http/http.dart' as http; import 'network_service_response.dart'; class RestClient { Future<MappedNetworkServiceResponse<T>> get<T>(String url, {Map headers}) async{ try { var response = await http.get(url, headers: headers); return processResponse<T>(response); } catch(e) { return new MappedNetworkServiceResponse<T>( networkServiceResponse: new NetworkServiceResponse<T>( responseCode: 0)); } } Future<MappedNetworkServiceResponse<T>> post<T>(String url, {Map headers, body, encoding}) async{ try { var response = await http.post(url, headers: headers, body: body, encoding: encoding); return processResponse<T>(response); } catch(e) { return new MappedNetworkServiceResponse<T>( networkServiceResponse: new NetworkServiceResponse<T>( responseCode: 0)); } } MappedNetworkServiceResponse<T> processResponse<T>(http.Response response) { if ((response.statusCode > ok200)) { return new MappedNetworkServiceResponse<T>( networkServiceResponse: new NetworkServiceResponse<T>( responseCode: response.statusCode)); } else { return new MappedNetworkServiceResponse<T>( mappedResult: response.body, networkServiceResponse: new NetworkServiceResponse<T>(responseCode: response.statusCode)); } } }
-abstract Package
api_service.dart
import 'dart:async'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_app/models/login.dart'; import '../network_service_response.dart'; abstract class APIService { Future<NetworkServiceResponse<List<CountryResponse>>> country(); }
-di Package
dependency_injection.dart
import 'package:flutter_app/service/abstract/api_service.dart'; import 'package:flutter_app/service/mock/mock_service.dart'; import 'package:flutter_app/service/network/network_service.dart'; import 'package:flutter_app/service/restclient.dart'; enum Flavor {Testing, Network} //Simple DI class Injector { static final Injector _singleton = new Injector._internal(); static Flavor _flavor; static void configure(Flavor flavor) async { _flavor = flavor; } factory Injector() => _singleton; Injector._internal(); APIService get flavor { switch (_flavor) { case Flavor.Testing: return MockService(); default: return NetworkService(new RestClient()); } } }
-mock Package
mock_service.dart
import 'dart:async'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_app/models/login.dart'; import 'package:flutter_app/service/abstract/api_service.dart'; import 'package:flutter_app/service/network_service_response.dart'; import 'package:flutter_app/utils/vars.dart'; class MockService implements APIService { @override Future<NetworkServiceResponse<LoginResponse>> login( String phoneNumber, String password) async { await Future.delayed(Duration(seconds: 2)); return Future.value(NetworkServiceResponse( responseCode: ok200, response: LoginResponse( ))); } @override Future<NetworkServiceResponse<List<CountryResponse>>> country() { return null; } }
-network Package
network_service.dart
import 'dart:async'; import 'dart:convert'; import 'package:flutter_app/models/country.dart'; import 'package:flutter_app/models/login.dart'; import 'package:flutter_app/service/abstract/api_service.dart'; import '../network_service_response.dart'; import '../network_type.dart'; import '../restclient.dart'; class NetworkService extends NetworkType implements APIService { static final _baseURL = 'https://restcountries.eu/rest/v2/'; static final _loginUrl = ''; final _countryUrl = _baseURL + 'all'; Map<String, String> headers = { "Content-Type": "application/x-www-form-urlencoded" }; NetworkService(RestClient rest) : super(rest); @override Future<NetworkServiceResponse<LoginResponse>> login(String phoneNumber, String password) async { var result = await rest.get<LoginResponse>( '$_loginUrl?MobileNo=$phoneNumber&Password=$password&EmailId=""'); if (result.mappedResult != null) { var res = LoginResponse.fromJson(json.decode(result.mappedResult)); return new NetworkServiceResponse( response: res, responseCode: result.networkServiceResponse.responseCode); } return new NetworkServiceResponse( responseCode: result.networkServiceResponse.responseCode); } @override Future<NetworkServiceResponse<List<CountryResponse>>> country() async{ var result = await rest.get<CountryResponse>('$_countryUrl'); if (result.networkServiceResponse.responseCode == 200) { List<CountryResponse> list = (json.decode(result.mappedResult) as List) .map((data) => new CountryResponse.fromJson(data)) .toList(); return new NetworkServiceResponse( response: list, responseCode: result.networkServiceResponse.responseCode ); } return new NetworkServiceResponse( responseCode: result.networkServiceResponse.responseCode); } }
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