| @PUT("/api/update-fcmToken") | @PUT("/api/update-fcmToken") | ||||
| Future<void> updateFcmToken(@Body() String token); | 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 = ""}); | |||||
| } | } |
| } | } | ||||
| @override | @override | ||||
| getPlots({page = 0, size = 20}) async { | |||||
| getPlots({page = 0, size = 20, query = ""}) async { | |||||
| const _extra = <String, dynamic>{}; | const _extra = <String, dynamic>{}; | ||||
| final queryParameters = <String, dynamic>{}; | final queryParameters = <String, dynamic>{}; | ||||
| queryParameters.removeWhere((k, v) => v == null); | queryParameters.removeWhere((k, v) => v == null); | ||||
| final _data = <String, dynamic>{}; | final _data = <String, dynamic>{}; | ||||
| final Response<List<dynamic>> _result = await _dio.request( | 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, | queryParameters: queryParameters, | ||||
| options: RequestOptions( | options: RequestOptions( | ||||
| method: 'GET', | method: 'GET', |
| class Repository { | class Repository { | ||||
| final dio = DioProvider.instance(); | 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); | 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) { | Future<User> signInWithCredentials(String username, String password) { |
| 'netHouseId': instance.netHouseId, | 'netHouseId': instance.netHouseId, | ||||
| 'netHouseName': instance.netHouseName, | 'netHouseName': instance.netHouseName, | ||||
| 'areaId': instance.areaId, | 'areaId': instance.areaId, | ||||
| 'area': instance.area | |||||
| 'area': instance.area, | |||||
| }; | }; |
| class PlotBloc extends Bloc<PlotEvent, PlotState> { | class PlotBloc extends Bloc<PlotEvent, PlotState> { | ||||
| final Repository repository; | final Repository repository; | ||||
| PlotBloc({@required this.repository}) : super(PlotInitial()); | PlotBloc({@required this.repository}) : super(PlotInitial()); | ||||
| static int pageSize = 4; | |||||
| static int pageSize = 20; | |||||
| @override | @override | ||||
| Stream<PlotState> mapEventToState( | Stream<PlotState> mapEventToState( | ||||
| !(state is PlotSuccess && (state as PlotSuccess).hasReachedMax)) { | !(state is PlotSuccess && (state as PlotSuccess).hasReachedMax)) { | ||||
| try { | try { | ||||
| if (state is PlotInitial) { | if (state is PlotInitial) { | ||||
| yield PlotLoading(); | |||||
| final response = await repository.getPlots(page: 0, size: pageSize); | final response = await repository.getPlots(page: 0, size: pageSize); | ||||
| yield PlotSuccess( | yield PlotSuccess( | ||||
| items: response, | items: response, | ||||
| if (state is PlotSuccess) { | if (state is PlotSuccess) { | ||||
| final currentState = state as PlotSuccess; | final currentState = state as PlotSuccess; | ||||
| int page = currentState.page + 1; | int page = currentState.page + 1; | ||||
| yield PlotLoading(); | |||||
| final response = | final response = | ||||
| await repository.getPlots(page: page, size: pageSize); | await repository.getPlots(page: page, size: pageSize); | ||||
| yield response.isEmpty | yield response.isEmpty | ||||
| } | } | ||||
| if (event is OnRefresh) { | if (event is OnRefresh) { | ||||
| try { | try { | ||||
| yield PlotLoading(); | |||||
| final response = await repository.getPlots(page: 0, size: pageSize); | final response = await repository.getPlots(page: 0, size: pageSize); | ||||
| yield PlotSuccess( | yield PlotSuccess( | ||||
| items: response, | items: response, | ||||
| } catch (e) { | } catch (e) { | ||||
| yield PlotFailure(errorString: AppException.handleError(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)); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| class DataFetched extends PlotEvent {} | class DataFetched extends PlotEvent {} | ||||
| class OnRefresh extends PlotEvent {} | class OnRefresh extends PlotEvent {} | ||||
| class OnSearch extends PlotEvent { | |||||
| final String searchString; | |||||
| OnSearch({@required this.searchString}); | |||||
| } |
| class PlotInitial extends PlotState {} | class PlotInitial extends PlotState {} | ||||
| class PlotLoading extends PlotState {} | |||||
| class PlotFailure extends PlotState { | class PlotFailure extends PlotState { | ||||
| final String errorString; | final String errorString; | ||||
| PlotFailure({@required this.errorString}); | PlotFailure({@required this.errorString}); |
| import 'package:dio/dio.dart'; | |||||
| import 'package:farm_tpf/data/repository/repository.dart'; | import 'package:farm_tpf/data/repository/repository.dart'; | ||||
| import 'package:farm_tpf/models/Plot.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/bottom_loader.dart'; | ||||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.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/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_color.dart'; | ||||
| import 'package:farm_tpf/utils/const_enum.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
| import 'package:farm_tpf/utils/const_string.dart'; | import 'package:farm_tpf/utils/const_string.dart'; | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | 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(), | |||||
| ); | |||||
| }, | |||||
| )) | |||||
| ], | |||||
| ); | ); | ||||
| } | } | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | 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( | return GestureDetector( | ||||
| child: Card( | child: Card( | ||||
| color: item.status == "STATUS_ARE_ACTIVE" | |||||
| ? Colors.white | |||||
| : COLOR_CONST.DEFAULT, | |||||
| color: backgroundColor, | |||||
| child: ListTile( | child: ListTile( | ||||
| title: Text( | 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(), | 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( | trailing: Text( | ||||
| item.areaM2.formatNumtoStringDecimal().toString() + " m\u00B2", | 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())); | |||||
| }); | |||||
| } | } | ||||
| } | } |
| import 'package:farm_tpf/utils/const_color.dart'; | import 'package:farm_tpf/utils/const_color.dart'; | ||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
| import 'bloc/plot_bloc.dart'; | |||||
| class WidgetSearch extends StatefulWidget { | class WidgetSearch extends StatefulWidget { | ||||
| @override | @override | ||||
| Widget getSearchBarUI() { | Widget getSearchBarUI() { | ||||
| _searchController.text = ""; | _searchController.text = ""; | ||||
| return Padding( | 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( | child: Row( | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| Expanded( | Expanded( | ||||
| ), | ), | ||||
| onSubmitted: (value) { | onSubmitted: (value) { | ||||
| FocusScope.of(context).requestFocus(FocusNode()); | FocusScope.of(context).requestFocus(FocusNode()); | ||||
| BlocProvider.of<PlotBloc>(_blocContext) | |||||
| .add(OnSearch(searchString: value)); | |||||
| }, | }, | ||||
| ), | ), | ||||
| ), | ), |
| class _PlotInformationScreenState extends State<PlotInformationScreen> { | class _PlotInformationScreenState extends State<PlotInformationScreen> { | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Container(width: 200, child: WidgetMediaHelper()); | |||||
| return Container(); | |||||
| } | } | ||||
| } | } |
| @override | @override | ||||
| void initState() { | void initState() { | ||||
| drawerIndex = DrawerIndex.Home; | drawerIndex = DrawerIndex.Home; | ||||
| screenView = HomePage(); | |||||
| screenView = PlotListScreen(); | |||||
| super.initState(); | super.initState(); | ||||
| } | } | ||||