Last active
May 14, 2020 20:16
-
-
Save pkozlovskiy/bbe976d6b571890a02a91b21df105ba1 to your computer and use it in GitHub Desktop.
This file contains 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 ProjectsPage extends StatefulWidget { | |
static const String route = '/projects'; | |
const ProjectsPage({Key key}) : super(key: key); | |
@override | |
_ProjectsPageState createState() => _ProjectsPageState(); | |
} | |
class _ProjectsPageState extends State<ProjectsPage> { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Center(child: Text(S.of(context).projectsPageTitle))), | |
body: ProjectsListView(context), | |
); | |
} | |
} | |
class ProjectsListView extends StatefulWidget { | |
ProjectsListView(BuildContext context); | |
@override | |
_ProjectsListViewState createState() => _ProjectsListViewState(); | |
} | |
class _ProjectsListViewState extends State<ProjectsListView> { | |
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = | |
new GlobalKey<RefreshIndicatorState>(); | |
@override | |
void initState() { | |
super.initState(); | |
Provider.of<ProjectsBloc>(context, listen: false) | |
.add(FetchData(ProjectsParams())); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return StreamBuilder( | |
stream: Provider.of<ProjectsBloc>(context), | |
builder: (context, snapshot) { | |
final state = snapshot.data as DataState; | |
if (state is DataLoadingState) { | |
WidgetsBinding.instance.addPostFrameCallback( | |
(_) => _refreshIndicatorKey.currentState.show()); | |
} | |
if (state is LoadDataErrorState) { | |
WidgetsBinding.instance.addPostFrameCallback((_) async => { | |
await PlatformExceptionAlertDialog( | |
title: S.of(context).error, | |
exception: PlatformException(code: '', message: ''), | |
).show(context) | |
}); | |
} | |
final List dataList = state?.lastData ?? []; | |
return RefreshIndicator( | |
key: _refreshIndicatorKey, | |
onRefresh: | |
Provider.of<ProjectsBloc>(context, listen: false).refresh, | |
child: Stack( | |
children: <Widget>[ | |
ListView.builder( | |
itemCount: dataList.length, | |
itemBuilder: (context, index) => GestureDetector( | |
onTap: () => Navigator.of(context).pushNamed( | |
ProjectPage.route, | |
arguments: dataList[index]), | |
child: ProjectListItem(dataList[index])), | |
), | |
Visibility( | |
visible: state is DataLoadedState && dataList.isEmpty, | |
child: Center( | |
child: Text(S.of(context).emptyProjects), | |
), | |
), | |
], | |
)); | |
}, | |
); | |
} | |
} | |
class ProjectListItem extends StatelessWidget { | |
final Project project; | |
ProjectListItem(this.project); | |
@override | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Row( | |
children: <Widget>[ | |
Text('${project.title}'), | |
], | |
), | |
); | |
} | |
} |
This file contains 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:bloc/bloc.dart'; | |
import '../error/exceptions.dart'; | |
import 'data_event.dart'; | |
import 'data_state.dart'; | |
import 'data_usecase.dart'; | |
abstract class DataBloc<Type, Params extends DataParams> | |
extends Bloc<DataEvent, DataState> with FailureMapper { | |
final DataUseCase _useCase; | |
Type lastData; | |
Params lastParams; | |
DataBloc(this._useCase); | |
@override | |
DataState get initialState => DataInitState<Type>(lastData); | |
@override | |
Stream<DataState> mapEventToState(DataEvent event) async* { | |
if (event is FetchData) { | |
if (lastParams != event.params) { | |
lastData = null; | |
} | |
lastParams = event.params; | |
yield DataLoadingState<Type>(lastData); | |
final result = await _useCase(event.params); | |
yield result.fold( | |
(failure) => | |
LoadDataErrorState<Type>(lastData, mapFailureToMessage(failure)), | |
(data) { | |
lastData = data; | |
return DataLoadedState<Type>(lastData); | |
}); | |
} | |
} | |
Future<void> refresh({Params params}) async { | |
var dataState = await first; | |
if (dataState is DataLoadingState) return Future.value(null); | |
add(FetchData(params ?? lastParams)); | |
return skip(1).firstWhere((state) => state is! DataLoadingState); | |
} | |
} |
This file contains 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 'data_usecase.dart'; | |
abstract class DataEvent {} | |
class FetchData<Params extends DataParams> extends DataEvent { | |
final Params params; | |
FetchData(this.params); | |
} |
This file contains 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:equatable/equatable.dart'; | |
import 'package:meta/meta.dart'; | |
@immutable | |
abstract class DataState<Type> extends Equatable { | |
final Type lastData; | |
DataState(this.lastData); | |
@override | |
List<Object> get props => [lastData]; | |
@override | |
String toString() { | |
return super.toString() + 'Data = $lastData'; | |
} | |
} | |
class DataInitState<Type> extends DataState<Type> { | |
DataInitState(Type lastData) : super(lastData); | |
} | |
class DataLoadingState<Type> extends DataState<Type> { | |
DataLoadingState(Type lastData) : super(lastData); | |
} | |
class DataLoadedState<Type> extends DataState<Type> { | |
DataLoadedState(Type lastData) : super(lastData); | |
} | |
class LoadDataErrorState<Type> extends DataState<Type> { | |
final String message; | |
LoadDataErrorState(Type lastData, this.message) : super(lastData); | |
@override | |
List<Object> get props => [message, lastData]; | |
} |
This file contains 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:dartz/dartz.dart'; | |
import 'package:equatable/equatable.dart'; | |
import '../error/failures.dart'; | |
import '../usecases/usecase.dart'; | |
abstract class DataUseCase<Type, Params extends DataParams> | |
extends UseCase<Type, Params> { | |
@override | |
Future<Either<Failure, Type>> call(Params params) async { | |
return getData(params); | |
} | |
Future<Either<Failure, Type>> getData(Params params); | |
} | |
class DataParams extends Equatable { | |
final bool forceRefresh; | |
DataParams(this.forceRefresh); | |
@override | |
List get props => [forceRefresh]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment