Last active
December 10, 2021 05:45
-
-
Save libindev/d8dc751c07d5e97b585a319b87c35220 to your computer and use it in GitHub Desktop.
Bloc flutter sample.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_sample_api_bloc/bloc/user_bloc.dart'; | |
import 'package:flutter_sample_api_bloc/bloc/user_detail_bloc.dart'; | |
import 'package:flutter_sample_api_bloc/repository/sample_api_client.dart'; | |
import 'package:flutter_sample_api_bloc/repository/sample_api_repository.dart'; | |
import 'package:flutter_sample_api_bloc/widgets/userview.dart'; | |
import 'package:http/http.dart' as http; | |
void main() { | |
final UserRepository employeeRepository = UserRepository( | |
employeeApiClient: EmployeeApiClient( | |
httpClient: http.Client(), | |
), | |
); | |
BlocSupervisor.delegate = SimpleBlocDelegate(); | |
runApp( | |
App(employeeRepository: employeeRepository, title: "Employee App")); | |
} | |
class SimpleBlocDelegate extends BlocDelegate { | |
@override | |
void onEvent(Bloc bloc, Object event) { | |
super.onEvent(bloc, event); | |
print(event); | |
} | |
@override | |
onTransition(Bloc bloc, Transition transition) { | |
super.onTransition(bloc, transition); | |
print(transition); | |
} | |
@override | |
void onError(Bloc bloc, Object error, StackTrace stacktrace) { | |
super.onError(bloc, error, stacktrace); | |
print(error); | |
} | |
} | |
class App extends StatelessWidget { | |
final UserRepository employeeRepository; | |
final String title; | |
App({Key key, @required this.employeeRepository, @required this.title}) | |
: assert(employeeRepository != null), | |
super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return MultiBlocProvider( | |
providers: [ | |
BlocProvider<UserBloc>( | |
create: (context) => UserBloc(employeeRepository: employeeRepository )), | |
BlocProvider<UserDetailBloc>( | |
create: (context) => UserDetailBloc(userRepository: employeeRepository))], | |
child: MaterialApp( | |
title: 'Employee App', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: Scaffold( | |
appBar: AppBar( | |
title: new Text( this.title ), | |
elevation: 4.0, | |
), | |
body: UserView()))); | |
} | |
} | |
//BlocProvider(create: (context) =>EmployeeDetailBloc(employeeRepository: employeeRepository), | |
// child: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:convert'; | |
import 'package:flutter_sample_api_bloc/model/user_data.dart'; | |
import 'package:flutter_sample_api_bloc/model/user_detail.dart'; | |
import 'package:http/http.dart' as http; | |
import 'package:meta/meta.dart'; | |
class EmployeeApiClient { | |
static const baseUrl = 'https://reqres.in/api/users'; | |
final http.Client httpClient; | |
EmployeeApiClient({@required this.httpClient}) : assert(httpClient != null); | |
Future<List<User>> getAllUser() async { | |
final userUrl = '$baseUrl?page=2'; | |
final res = await this.httpClient.get( userUrl ); | |
if (res.statusCode != 200) { | |
throw Exception( 'error getting employee data'); | |
} | |
final jsonResponse = json.decode( res.body ); | |
UserResponse userResponse = UserResponse.fromJson( jsonResponse ); | |
return userResponse.user; | |
} | |
Future<UserDetail> getUserDetail(int user_id) async { | |
final slash ="/"; | |
final usersDetailUrl = '$baseUrl$slash$user_id'; | |
final res = await this.httpClient.get(usersDetailUrl); | |
if (res.statusCode != 200) { | |
throw Exception('error getting weather for location'); | |
} | |
final employeeDetailJson = jsonDecode(res.body); | |
return UserDetailResponse.fromJson(employeeDetailJson).data; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter_sample_api_bloc/model/user_data.dart'; | |
import 'package:flutter_sample_api_bloc/model/user_detail.dart'; | |
import 'package:flutter_sample_api_bloc/repository/sample_api_client.dart'; | |
import 'package:meta/meta.dart'; | |
class UserRepository { | |
final EmployeeApiClient employeeApiClient; | |
UserRepository({@required this.employeeApiClient}) | |
: assert(employeeApiClient != null); | |
Future<List<User>> getAllUsers() async { | |
return employeeApiClient.getAllUser( ); | |
} | |
Future<UserDetail> getUserDetails(int id) async { | |
return employeeApiClient.getUserDetail( id ); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter_sample_api_bloc/model/user_data.dart'; | |
import 'package:flutter_sample_api_bloc/repository/sample_api_repository.dart'; | |
import 'package:meta/meta.dart'; | |
import 'package:bloc/bloc.dart'; | |
import 'package:equatable/equatable.dart'; | |
///Event class | |
abstract class UserEvent extends Equatable { | |
const UserEvent(); | |
} | |
class FetchUserEvent extends UserEvent { | |
const FetchUserEvent() ; | |
@override | |
List<Object> get props => []; | |
} | |
class RefreshUserEvent extends UserEvent { | |
const RefreshUserEvent(); | |
@override | |
List<Object> get props => []; | |
} | |
///State Class | |
abstract class UserState extends Equatable { | |
const UserState(); | |
@override | |
List<Object> get props => []; | |
} | |
class UserEmpty extends UserState {} | |
class UserLoading extends UserState {} | |
class UserLoaded extends UserState { | |
final List<User> users; | |
const UserLoaded({@required this.users}) : assert(users != null); | |
@override | |
List<Object> get props => [users]; | |
} | |
class UserError extends UserState { | |
} | |
class UserBloc extends Bloc<UserEvent, UserState> { | |
final UserRepository employeeRepository; | |
UserBloc({@required this.employeeRepository}) | |
: assert(employeeRepository != null); | |
@override | |
UserState get initialState => UserEmpty(); | |
@override | |
Stream<UserState> mapEventToState(UserEvent event) async* { | |
if (event is FetchUserEvent) { | |
yield UserLoading(); | |
try { | |
final List<User> employees = await employeeRepository.getAllUsers(); | |
yield UserLoaded(users: employees); | |
} catch (_) { | |
yield UserError(); | |
} | |
} | |
if (event is RefreshUserEvent) { | |
yield UserLoading(); | |
try { | |
final List<User> employees = await employeeRepository.getAllUsers(); | |
yield UserLoaded(users: employees); | |
} catch (_) { | |
yield UserError(); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UserResponse { | |
int page; | |
int perPage; | |
int total; | |
int totalPages; | |
List<User> user; | |
UserResponse( | |
{this.page, this.perPage, this.total, this.totalPages, this.user}); | |
UserResponse.fromJson(Map<String, dynamic> json) { | |
page = json['page']; | |
perPage = json['per_page']; | |
total = json['total']; | |
totalPages = json['total_pages']; | |
if (json['data'] != null) { | |
user = new List<User>(); | |
json['data'].forEach((v) { | |
user.add(new User.fromJson(v)); | |
}); | |
} | |
} | |
Map<String, dynamic> toJson() { | |
final Map<String, dynamic> data = new Map<String, dynamic>(); | |
data['page'] = this.page; | |
data['per_page'] = this.perPage; | |
data['total'] = this.total; | |
data['total_pages'] = this.totalPages; | |
if (this.user != null) { | |
data['data'] = this.user.map((v) => v.toJson()).toList(); | |
} | |
return data; | |
} | |
} | |
class User { | |
int id; | |
String email; | |
String firstName; | |
String lastName; | |
String avatar; | |
User({this.id, this.email, this.firstName, this.lastName, this.avatar}); | |
User.fromJson(Map<String, dynamic> json) { | |
id = json['id']; | |
email = json['email']; | |
firstName = json['first_name']; | |
lastName = json['last_name']; | |
avatar = json['avatar']; | |
} | |
Map<String, dynamic> toJson() { | |
final Map<String, dynamic> data = new Map<String, dynamic>(); | |
data['id'] = this.id; | |
data['email'] = this.email; | |
data['first_name'] = this.firstName; | |
data['last_name'] = this.lastName; | |
data['avatar'] = this.avatar; | |
return data; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class UserDetailResponse { | |
UserDetail data; | |
UserDetailResponse({this.data}); | |
UserDetailResponse.fromJson(Map<String, dynamic> json) { | |
data = json['data'] != null ? new UserDetail.fromJson(json['data']) : null; | |
} | |
Map<String, dynamic> toJson() { | |
final Map<String, dynamic> data = new Map<String, dynamic>(); | |
if (this.data != null) { | |
data['data'] = this.data.toJson(); | |
} | |
return data; | |
} | |
} | |
class UserDetail { | |
int id; | |
String email; | |
String firstName; | |
String lastName; | |
String avatar; | |
UserDetail({this.id, this.email, this.firstName, this.lastName, this.avatar}); | |
UserDetail.fromJson(Map<String, dynamic> json) { | |
id = json['id']; | |
email = json['email']; | |
firstName = json['first_name']; | |
lastName = json['last_name']; | |
avatar = json['avatar']; | |
} | |
Map<String, dynamic> toJson() { | |
final Map<String, dynamic> data = new Map<String, dynamic>(); | |
data['id'] = this.id; | |
data['email'] = this.email; | |
data['first_name'] = this.firstName; | |
data['last_name'] = this.lastName; | |
data['avatar'] = this.avatar; | |
return data; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter_sample_api_bloc/model/user_detail.dart'; | |
import 'package:flutter_sample_api_bloc/repository/sample_api_repository.dart'; | |
import 'package:meta/meta.dart'; | |
import 'package:bloc/bloc.dart'; | |
import 'package:equatable/equatable.dart'; | |
///Event class | |
abstract class UserDetailEvent extends Equatable { | |
const UserDetailEvent(); | |
} | |
class FetchUserDetailEvent extends UserDetailEvent { | |
final int id; | |
const FetchUserDetailEvent({@required this.id}) : assert(id != null); | |
@override | |
List<Object> get props => [id]; | |
} | |
class RefreshUserDetailEvent extends UserDetailEvent { | |
final int id; | |
const RefreshUserDetailEvent({@required this.id}) : assert(id != null); | |
@override | |
List<Object> get props => [id]; | |
} | |
///State Class | |
abstract class UserDetailState extends Equatable { | |
const UserDetailState(); | |
@override | |
List<Object> get props => []; | |
} | |
class UserDetailEmpty extends UserDetailState {} | |
class UserDetailLoading extends UserDetailState {} | |
class UserDetailLoaded extends UserDetailState { | |
final UserDetail userDetail; | |
const UserDetailLoaded({@required this.userDetail}) : assert(userDetail != null); | |
@override | |
List<Object> get props => [userDetail]; | |
} | |
class UserDetailError extends UserDetailState { | |
} | |
class UserDetailBloc extends Bloc<UserDetailEvent, UserDetailState> { | |
final UserRepository userRepository; | |
UserDetailBloc({@required this.userRepository}) | |
: assert(userRepository != null); | |
@override | |
UserDetailState get initialState => UserDetailEmpty(); | |
@override | |
Stream<UserDetailState> mapEventToState(UserDetailEvent event) async* { | |
if (event is FetchUserDetailEvent) { | |
yield UserDetailLoading(); | |
try { | |
final UserDetail employees = await userRepository.getUserDetails(event.id); | |
yield UserDetailLoaded(userDetail: employees); | |
} catch (_) { | |
yield UserDetailError(); | |
} | |
} | |
if (event is RefreshUserDetailEvent) { | |
yield UserDetailLoading(); | |
try { | |
final UserDetail employees = await userRepository.getUserDetails(event.id); | |
yield UserDetailLoaded(userDetail: employees); | |
} catch (_) { | |
yield UserDetailError(); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_sample_api_bloc/bloc/user_detail_bloc.dart'; | |
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |
class UserDetailView extends StatelessWidget { | |
final int id; | |
Completer<void> _refreshCompleter; | |
final RefreshController _refreshController = RefreshController( ); | |
@override | |
void initState() { | |
_refreshCompleter = Completer<void>( ); | |
} | |
UserDetailView({@required this.id}) : assert(id != null); | |
@override | |
Widget build(BuildContext context) { | |
final UserDetailBloc employeeDetailBloc = BlocProvider.of<UserDetailBloc>(context); | |
return MaterialApp( | |
home: Scaffold( | |
appBar: AppBar( | |
// backgroundColor: Colors.red, | |
title: new Text( | |
"Employee Detail", | |
), | |
elevation: 4.0, | |
), | |
body: BlocBuilder(bloc:employeeDetailBloc,builder: (context, state) { | |
return SmartRefresher( | |
controller: _refreshController, | |
enablePullDown: true, | |
child: setList(state), | |
onRefresh: () async { | |
BlocProvider.of<UserDetailBloc>( context ).add( | |
RefreshUserDetailEvent( id: id ) ); | |
_refreshCompleter?.complete( ); | |
_refreshCompleter = Completer( ); | |
} | |
); | |
} | |
), | |
), | |
); | |
} | |
} | |
Widget setList(UserDetailState state) { | |
if (state is UserDetailLoading) { | |
return Center( child: CircularProgressIndicator( ) ); | |
} | |
if (state is UserDetailLoaded) { | |
return ListView( | |
children: <Widget>[ | |
ListTile( | |
leading: Icon( Icons.wb_sunny ), | |
title: Text( state.userDetail.email ), | |
trailing: Icon( Icons.keyboard_arrow_right ), | |
), | |
ListTile( | |
leading: Icon( Icons.brightness_3 ), | |
title: Text( state.userDetail.firstName ), | |
trailing: Icon( Icons.keyboard_arrow_right ) | |
), | |
ListTile( | |
leading: Icon( Icons.star ), | |
title: Text( state.userDetail.lastName ), | |
trailing: Icon( Icons.keyboard_arrow_right ) | |
), | |
], | |
); | |
} | |
if (state is UserDetailError) { | |
return Text( | |
'Something went wrong!', | |
style: TextStyle( color: Colors.red ), | |
); | |
} | |
return Center( child: Text( 'Pull refresh to get employee..! ' ) ); | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:flutter/cupertino.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:flutter_sample_api_bloc/bloc/user_bloc.dart'; | |
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |
import 'user_detail_view.dart'; | |
class UserView extends StatelessWidget { | |
Completer<void> _refreshCompleter; | |
@override | |
void initState() { | |
_refreshCompleter = Completer<void>(); | |
} | |
final RefreshController _refreshController = RefreshController( ); | |
@override | |
Widget build(BuildContext context) { | |
return BlocListener<UserBloc, UserState>( | |
listener: (context, state) { | |
if (state is UserLoaded) { | |
} | |
}, | |
child: BlocBuilder<UserBloc, UserState>( | |
builder: (context, state) { | |
return SmartRefresher( | |
controller: _refreshController, | |
enablePullDown: true, | |
onRefresh: () async { | |
BlocProvider.of<UserBloc>( context ).add(RefreshUserEvent()); | |
_refreshCompleter?.complete(); | |
_refreshCompleter = Completer(); | |
}, | |
child: setList(state)); | |
} | |
) | |
); | |
} | |
Widget setList(UserState state) { | |
if (state is UserLoading) { | |
return Center( child: CircularProgressIndicator( ) ); | |
} | |
if (state is UserLoaded) { | |
_refreshController.refreshCompleted(); | |
return | |
ListView.builder( | |
itemCount: state.users.length, | |
itemBuilder: (context, index) { | |
return ListTile( | |
leading: Icon( Icons.face), | |
title: Text( state.users[index].firstName ), | |
trailing: GestureDetector(child: Icon( Icons.keyboard_arrow_right ), | |
onTap:(){ | |
int id = state.users[index].id; | |
Navigator.of(context).push(MaterialPageRoute( | |
builder: (BuildContext context) { | |
return UserDetailView(id:id); | |
}, | |
), | |
); | |
}, | |
), | |
); | |
}, | |
); | |
} | |
if (state is UserError) { | |
return Text( | |
'Something went wrong!', | |
style: TextStyle( color: Colors.red ), | |
); | |
} | |
return Center( child: Text( 'Pull refresh to get employee..! ' ) ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment