| @@ -39,6 +39,7 @@ abstract class RestClient { | |||
| @PUT("/api/update-fcmToken") | |||
| Future<void> updateFcmToken(@Body() String token); | |||
| @GET("/api/tb-crops?page={page}&size={size}") | |||
| Future<List<Plot>> getPlots({@Path() int page = 0, @Path() int size = 20}); | |||
| @GET("/api/tb-crops?page={page}&size={size}&query={query}") | |||
| Future<List<Plot>> getPlots( | |||
| {@Path() int page = 0, @Path() int size = 20, @Path() String query = ""}); | |||
| } | |||
| @@ -166,13 +166,13 @@ class _RestClient implements RestClient { | |||
| } | |||
| @override | |||
| getPlots({page = 0, size = 20}) async { | |||
| getPlots({page = 0, size = 20, query = ""}) async { | |||
| const _extra = <String, dynamic>{}; | |||
| final queryParameters = <String, dynamic>{}; | |||
| queryParameters.removeWhere((k, v) => v == null); | |||
| final _data = <String, dynamic>{}; | |||
| final Response<List<dynamic>> _result = await _dio.request( | |||
| '/api/tb-crops?page=$page&size=$size', | |||
| '/api/tb-crops?page=$page&size=$size&query=$query', | |||
| queryParameters: queryParameters, | |||
| options: RequestOptions( | |||
| method: 'GET', | |||
| @@ -11,9 +11,9 @@ import 'package:farm_tpf/utils/const_common.dart'; | |||
| class Repository { | |||
| final dio = DioProvider.instance(); | |||
| Future<List<Plot>> getPlots({int page, int size}) { | |||
| Future<List<Plot>> getPlots({int page, int size, String searchString}) { | |||
| final client = RestClient(dio); | |||
| return client.getPlots(page: page, size: size); | |||
| return client.getPlots(page: page, size: size, query: searchString); | |||
| } | |||
| Future<User> signInWithCredentials(String username, String password) { | |||
| @@ -44,5 +44,5 @@ Map<String, dynamic> _$PlotToJson(Plot instance) => <String, dynamic>{ | |||
| 'netHouseId': instance.netHouseId, | |||
| 'netHouseName': instance.netHouseName, | |||
| 'areaId': instance.areaId, | |||
| 'area': instance.area | |||
| 'area': instance.area, | |||
| }; | |||
| @@ -12,7 +12,7 @@ part 'plot_state.dart'; | |||
| class PlotBloc extends Bloc<PlotEvent, PlotState> { | |||
| final Repository repository; | |||
| PlotBloc({@required this.repository}) : super(PlotInitial()); | |||
| static int pageSize = 4; | |||
| static int pageSize = 20; | |||
| @override | |||
| Stream<PlotState> mapEventToState( | |||
| @@ -22,6 +22,7 @@ class PlotBloc extends Bloc<PlotEvent, PlotState> { | |||
| !(state is PlotSuccess && (state as PlotSuccess).hasReachedMax)) { | |||
| try { | |||
| if (state is PlotInitial) { | |||
| yield PlotLoading(); | |||
| final response = await repository.getPlots(page: 0, size: pageSize); | |||
| yield PlotSuccess( | |||
| items: response, | |||
| @@ -31,6 +32,7 @@ class PlotBloc extends Bloc<PlotEvent, PlotState> { | |||
| if (state is PlotSuccess) { | |||
| final currentState = state as PlotSuccess; | |||
| int page = currentState.page + 1; | |||
| yield PlotLoading(); | |||
| final response = | |||
| await repository.getPlots(page: page, size: pageSize); | |||
| yield response.isEmpty | |||
| @@ -47,6 +49,7 @@ class PlotBloc extends Bloc<PlotEvent, PlotState> { | |||
| } | |||
| if (event is OnRefresh) { | |||
| try { | |||
| yield PlotLoading(); | |||
| final response = await repository.getPlots(page: 0, size: pageSize); | |||
| yield PlotSuccess( | |||
| items: response, | |||
| @@ -55,6 +58,18 @@ class PlotBloc extends Bloc<PlotEvent, PlotState> { | |||
| } catch (e) { | |||
| yield PlotFailure(errorString: AppException.handleError(e)); | |||
| } | |||
| } else if (event is OnSearch) { | |||
| try { | |||
| yield PlotLoading(); | |||
| final response = await repository.getPlots( | |||
| page: 0, size: pageSize, searchString: event.searchString); | |||
| yield PlotSuccess( | |||
| items: response, | |||
| page: 0, | |||
| hasReachedMax: response.length < pageSize ? true : false); | |||
| } catch (e) { | |||
| yield PlotFailure(errorString: AppException.handleError(e)); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -10,3 +10,8 @@ abstract class PlotEvent extends Equatable { | |||
| class DataFetched extends PlotEvent {} | |||
| class OnRefresh extends PlotEvent {} | |||
| class OnSearch extends PlotEvent { | |||
| final String searchString; | |||
| OnSearch({@required this.searchString}); | |||
| } | |||
| @@ -9,6 +9,8 @@ abstract class PlotState extends Equatable { | |||
| class PlotInitial extends PlotState {} | |||
| class PlotLoading extends PlotState {} | |||
| class PlotFailure extends PlotState { | |||
| final String errorString; | |||
| PlotFailure({@required this.errorString}); | |||
| @@ -1,11 +1,11 @@ | |||
| import 'package:dio/dio.dart'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/models/Plot.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot/widget_search.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:farm_tpf/utils/const_enum.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'package:farm_tpf/utils/const_string.dart'; | |||
| @@ -72,42 +72,41 @@ class _InfinityViewState extends State<InfinityView> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return BlocBuilder<PlotBloc, PlotState>( | |||
| builder: (context, state) { | |||
| if (state is PlotFailure) { | |||
| return Center(child: Text(state.errorString)); | |||
| } | |||
| if (state is PlotSuccess) { | |||
| if (state.items.isEmpty) { | |||
| return Center(child: Text(label_list_empty)); | |||
| } | |||
| return Column( | |||
| children: <Widget>[ | |||
| WidgetSearch(), | |||
| Expanded( | |||
| child: RefreshIndicator( | |||
| child: ListView.builder( | |||
| physics: AlwaysScrollableScrollPhysics(), | |||
| itemBuilder: (BuildContext context, int index) { | |||
| return index >= state.items.length | |||
| ? BottomLoader() | |||
| : ItemInfinityWidget(item: state.items[index]); | |||
| }, | |||
| itemCount: state.hasReachedMax | |||
| ? state.items.length | |||
| : state.items.length + 1, | |||
| controller: _scrollController, | |||
| ), | |||
| onRefresh: () async { | |||
| _plotBloc.add(OnRefresh()); | |||
| })) | |||
| ], | |||
| ); | |||
| } | |||
| return Center( | |||
| child: LoadingListPage(), | |||
| ); | |||
| }, | |||
| return Column( | |||
| children: <Widget>[ | |||
| WidgetSearch(), | |||
| Expanded(child: BlocBuilder<PlotBloc, PlotState>( | |||
| builder: (context, state) { | |||
| if (state is PlotFailure) { | |||
| return Center(child: Text(state.errorString)); | |||
| } | |||
| if (state is PlotSuccess) { | |||
| if (state.items.isEmpty) { | |||
| return Center(child: Text(label_list_empty)); | |||
| } | |||
| return RefreshIndicator( | |||
| child: ListView.builder( | |||
| physics: AlwaysScrollableScrollPhysics(), | |||
| itemBuilder: (BuildContext context, int index) { | |||
| return index >= state.items.length | |||
| ? BottomLoader() | |||
| : ItemInfinityWidget(item: state.items[index]); | |||
| }, | |||
| itemCount: state.hasReachedMax | |||
| ? state.items.length | |||
| : state.items.length + 1, | |||
| controller: _scrollController, | |||
| ), | |||
| onRefresh: () async { | |||
| _plotBloc.add(OnRefresh()); | |||
| }); | |||
| } | |||
| return Center( | |||
| child: LoadingListPage(), | |||
| ); | |||
| }, | |||
| )) | |||
| ], | |||
| ); | |||
| } | |||
| @@ -125,32 +124,41 @@ class ItemInfinityWidget extends StatelessWidget { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| var backgroundColor; | |||
| var textColor; | |||
| switch (item.status) { | |||
| case "STATUS_ARE_ACTIVE": | |||
| backgroundColor = Colors.white; | |||
| textColor = COLOR_CONST.DEFAULT; | |||
| break; | |||
| case "STATUS_FINISHED": | |||
| backgroundColor = COLOR_CONST.DEFAULT; | |||
| textColor = Colors.white; | |||
| break; | |||
| default: | |||
| backgroundColor = Colors.white; | |||
| textColor = Colors.black; | |||
| } | |||
| return GestureDetector( | |||
| child: Card( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? Colors.white | |||
| : COLOR_CONST.DEFAULT, | |||
| color: backgroundColor, | |||
| child: ListTile( | |||
| title: Text( | |||
| item.code.toString() + " - " + item.suppliesName.toString(), | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white), | |||
| ), | |||
| item.code.toString() + " - " + item.suppliesName.toString(), | |||
| style: TextStyle(color: textColor)), | |||
| subtitle: Text(item.startDate.format_DDMMYY_HHmm().toString(), | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white)), | |||
| style: TextStyle(color: textColor)), | |||
| trailing: Text( | |||
| item.areaM2.formatNumtoStringDecimal().toString() + " m\u00B2", | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white)), | |||
| style: TextStyle(color: textColor)), | |||
| ), | |||
| ), | |||
| onTap: () {}); | |||
| onTap: () { | |||
| Navigator.push( | |||
| context, | |||
| MaterialPageRoute( | |||
| builder: (BuildContext context) => PlotDetailScreen())); | |||
| }); | |||
| } | |||
| } | |||
| @@ -1,5 +1,8 @@ | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'bloc/plot_bloc.dart'; | |||
| class WidgetSearch extends StatefulWidget { | |||
| @override | |||
| @@ -24,7 +27,7 @@ class _WidgetSearchState extends State<WidgetSearch> { | |||
| Widget getSearchBarUI() { | |||
| _searchController.text = ""; | |||
| return Padding( | |||
| padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 0), | |||
| padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4), | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| @@ -57,6 +60,8 @@ class _WidgetSearchState extends State<WidgetSearch> { | |||
| ), | |||
| onSubmitted: (value) { | |||
| FocusScope.of(context).requestFocus(FocusNode()); | |||
| BlocProvider.of<PlotBloc>(_blocContext) | |||
| .add(OnSearch(searchString: value)); | |||
| }, | |||
| ), | |||
| ), | |||
| @@ -9,6 +9,6 @@ class PlotInformationScreen extends StatefulWidget { | |||
| class _PlotInformationScreenState extends State<PlotInformationScreen> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Container(width: 200, child: WidgetMediaHelper()); | |||
| return Container(); | |||
| } | |||
| } | |||
| @@ -25,7 +25,7 @@ class _NavigationHomeScreenState extends State<NavigationHomeScreen> { | |||
| @override | |||
| void initState() { | |||
| drawerIndex = DrawerIndex.Home; | |||
| screenView = HomePage(); | |||
| screenView = PlotListScreen(); | |||
| super.initState(); | |||
| } | |||