| { | |||||
| "id": 1, | |||||
| "name": "Rau muống", | |||||
| "sku": "SKURAUMUONG", | |||||
| "manufacturer": "Bộ nông nghiệp", | |||||
| "unit": "g", | |||||
| "tbSuppliesTypeId": 1, | |||||
| "tbCustomerId": 1 | |||||
| } |
| import 'package:dio/dio.dart'; | import 'package:dio/dio.dart'; | ||||
| import 'package:farm_tpf/models/Supply.dart'; | |||||
| import 'package:farm_tpf/models/account.dart'; | import 'package:farm_tpf/models/account.dart'; | ||||
| import 'package:farm_tpf/models/index.dart'; | |||||
| import 'package:farm_tpf/models/password.dart'; | import 'package:farm_tpf/models/password.dart'; | ||||
| import 'package:farm_tpf/models/user.dart'; | import 'package:farm_tpf/models/user.dart'; | ||||
| import 'package:farm_tpf/models/user_request.dart'; | import 'package:farm_tpf/models/user_request.dart'; | ||||
| @PUT("/api/update-my-profile") | @PUT("/api/update-my-profile") | ||||
| Future<Account> updateProfile(@Body() Account account); | Future<Account> updateProfile(@Body() Account account); | ||||
| @GET("/api/tb-supplies-by-type/{type}") | |||||
| Future<List<Supply>> getSupplies(@Path() String type); | |||||
| } | } |
| final value = Account.fromJson(_result.data); | final value = Account.fromJson(_result.data); | ||||
| return value; | return value; | ||||
| } | } | ||||
| @override | |||||
| getSupplies(type) async { | |||||
| ArgumentError.checkNotNull(type, 'type'); | |||||
| const _extra = <String, dynamic>{}; | |||||
| final queryParameters = <String, dynamic>{}; | |||||
| final _data = <String, dynamic>{}; | |||||
| final Response<List<dynamic>> _result = await _dio.request( | |||||
| '/api/tb-supplies-by-type/$type', | |||||
| queryParameters: queryParameters, | |||||
| options: RequestOptions( | |||||
| method: 'GET', | |||||
| headers: <String, dynamic>{}, | |||||
| extra: _extra, | |||||
| baseUrl: baseUrl), | |||||
| data: _data); | |||||
| var value = _result.data | |||||
| .map((dynamic i) => Supply.fromJson(i as Map<String, dynamic>)) | |||||
| .toList(); | |||||
| return value; | |||||
| } | |||||
| } | } |
| import 'package:farm_tpf/data/api/rest_client.dart'; | import 'package:farm_tpf/data/api/rest_client.dart'; | ||||
| import 'package:farm_tpf/models/PagedResult.dart'; | import 'package:farm_tpf/models/PagedResult.dart'; | ||||
| import 'package:farm_tpf/models/Plot.dart'; | import 'package:farm_tpf/models/Plot.dart'; | ||||
| import 'package:farm_tpf/models/Supply.dart'; | |||||
| import 'package:farm_tpf/models/index.dart'; | |||||
| import 'package:farm_tpf/models/user.dart'; | import 'package:farm_tpf/models/user.dart'; | ||||
| import 'package:farm_tpf/models/user_request.dart'; | import 'package:farm_tpf/models/user_request.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | import 'package:farm_tpf/utils/const_common.dart'; | ||||
| return value; | return value; | ||||
| } | } | ||||
| Future<List<Supply>> getSupplies(String type) async { | |||||
| final client = RestClient(dio); | |||||
| return client.getSupplies(type); | |||||
| } | |||||
| Object getInstanceClass() { | Object getInstanceClass() { | ||||
| var instanceClass; | var instanceClass; | ||||
| if (1 == 1) { | if (1 == 1) { |
| 'id': instance.id, | 'id': instance.id, | ||||
| 'times': instance.times, | 'times': instance.times, | ||||
| 'activityExecuteDate': instance.activityExecuteDate, | 'activityExecuteDate': instance.activityExecuteDate, | ||||
| 'isExceedLimit': instance.isExceedLimit | |||||
| 'isExceedLimit': instance.isExceedLimit, | |||||
| }; | }; |
| 'id': instance.id, | 'id': instance.id, | ||||
| 'name': instance.name, | 'name': instance.name, | ||||
| 'description': instance.description, | 'description': instance.description, | ||||
| 'isSelected': instance.isSelected | |||||
| 'isSelected': instance.isSelected, | |||||
| }; | }; |
| import 'package:json_annotation/json_annotation.dart'; | |||||
| part 'Supply.g.dart'; | |||||
| @JsonSerializable() | |||||
| class Supply { | |||||
| Supply(); | |||||
| num id; | |||||
| String name; | |||||
| String sku; | |||||
| String manufacturer; | |||||
| String unit; | |||||
| num tbSuppliesTypeId; | |||||
| num tbCustomerId; | |||||
| bool isSelected = false; | |||||
| factory Supply.fromJson(Map<String, dynamic> json) => _$SupplyFromJson(json); | |||||
| Map<String, dynamic> toJson() => _$SupplyToJson(this); | |||||
| } |
| // GENERATED CODE - DO NOT MODIFY BY HAND | |||||
| part of 'Supply.dart'; | |||||
| // ************************************************************************** | |||||
| // JsonSerializableGenerator | |||||
| // ************************************************************************** | |||||
| Supply _$SupplyFromJson(Map<String, dynamic> json) { | |||||
| return Supply() | |||||
| ..id = json['id'] as num | |||||
| ..name = json['name'] as String | |||||
| ..sku = json['sku'] as String | |||||
| ..manufacturer = json['manufacturer'] as String | |||||
| ..unit = json['unit'] as String | |||||
| ..tbSuppliesTypeId = json['tbSuppliesTypeId'] as num | |||||
| ..tbCustomerId = json['tbCustomerId'] as num | |||||
| ..isSelected = false; | |||||
| } | |||||
| Map<String, dynamic> _$SupplyToJson(Supply instance) => <String, dynamic>{ | |||||
| 'id': instance.id, | |||||
| 'name': instance.name, | |||||
| 'sku': instance.sku, | |||||
| 'manufacturer': instance.manufacturer, | |||||
| 'unit': instance.unit, | |||||
| 'tbSuppliesTypeId': instance.tbSuppliesTypeId, | |||||
| 'tbCustomerId': instance.tbCustomerId, | |||||
| }; |
| export 'Plot.dart' ; | |||||
| export 'ResourceHelper.dart' ; | |||||
| export 'Plot.dart'; | |||||
| export 'ResourceHelper.dart'; |
| import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart'; | import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | ||||
| import 'package:farm_tpf/presentation/screens/resources/sc_resource_helper.dart'; | import 'package:farm_tpf/presentation/screens/resources/sc_resource_helper.dart'; | ||||
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| class HomePage extends StatelessWidget { | class HomePage extends StatelessWidget { | ||||
| Navigator.of(context) | Navigator.of(context) | ||||
| .push(MaterialPageRoute( | .push(MaterialPageRoute( | ||||
| builder: (_) => ResourceHelperScreen( | builder: (_) => ResourceHelperScreen( | ||||
| resourceName: "test", | |||||
| selectedPlotId: 1531, | |||||
| titleName: "phân bón", | |||||
| type: ConstCommon.supplyTypeDung, | |||||
| selectedId: 3, | |||||
| ), | ), | ||||
| fullscreenDialog: false)) | fullscreenDialog: false)) | ||||
| .then((value) { | .then((value) { |
| import 'dart:async'; | |||||
| import 'package:bloc/bloc.dart'; | |||||
| import 'package:equatable/equatable.dart'; | |||||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||||
| import 'package:farm_tpf/models/Supply.dart'; | |||||
| import 'package:farm_tpf/utils/bloc/infinity_scroll_bloc.dart'; | |||||
| import 'package:meta/meta.dart'; | |||||
| part 'supply_event.dart'; | |||||
| part 'supply_state.dart'; | |||||
| class SupplyBloc extends Bloc<SupplyEvent, SupplyState> { | |||||
| final Repository repository; | |||||
| SupplyBloc({@required this.repository}) : super(SupplyInitial()); | |||||
| @override | |||||
| Stream<SupplyState> mapEventToState( | |||||
| SupplyEvent event, | |||||
| ) async* { | |||||
| if (event is DataFetched) { | |||||
| try { | |||||
| final response = await repository.getSupplies(event.type); | |||||
| List<Supply> supplies = response.map((supply) { | |||||
| if (supply.id == event.selectedId) { | |||||
| supply.isSelected = true; | |||||
| } | |||||
| return supply; | |||||
| }).toList(); | |||||
| yield SupplySuccess(items: supplies); | |||||
| } catch (_) { | |||||
| yield SupplyFailure(); | |||||
| } | |||||
| } else if (event is OnRefresh) { | |||||
| try { | |||||
| final response = await repository.getSupplies(event.type); | |||||
| List<Supply> supplies = response.map((supply) { | |||||
| if (supply.id == event.selectedId) { | |||||
| supply.isSelected = true; | |||||
| } | |||||
| return supply; | |||||
| }).toList(); | |||||
| yield SupplySuccess(items: supplies); | |||||
| } catch (_) { | |||||
| yield SupplyFailure(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| part of 'supply_bloc.dart'; | |||||
| abstract class SupplyEvent extends Equatable { | |||||
| const SupplyEvent(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class DataFetched extends SupplyEvent { | |||||
| final int selectedId; | |||||
| final String type; | |||||
| DataFetched({this.selectedId, @required this.type}); | |||||
| } | |||||
| class OnRefresh extends SupplyEvent { | |||||
| final int selectedId; | |||||
| final String type; | |||||
| OnRefresh({this.selectedId, @required this.type}); | |||||
| } |
| part of 'supply_bloc.dart'; | |||||
| abstract class SupplyState extends Equatable { | |||||
| const SupplyState(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class SupplyInitial extends SupplyState {} | |||||
| class SupplyFailure extends SupplyState {} | |||||
| class SupplySuccess<T> extends SupplyState { | |||||
| final List<T> items; | |||||
| const SupplySuccess({this.items}); | |||||
| SupplySuccess copyWith({List<T> items}) { | |||||
| return SupplySuccess(items: items ?? this.items); | |||||
| } | |||||
| @override | |||||
| List<Object> get props => [items]; | |||||
| } |
| import 'package:farm_tpf/data/repository/repository.dart'; | import 'package:farm_tpf/data/repository/repository.dart'; | ||||
| import 'package:farm_tpf/models/Supply.dart'; | |||||
| import 'package:farm_tpf/models/index.dart'; | import 'package:farm_tpf/models/index.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/utils/bloc/infinity_scroll_bloc.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/resources/bloc/supply_bloc.dart'; | |||||
| import 'package:farm_tpf/utils/const_string.dart'; | import 'package:farm_tpf/utils/const_string.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'; | ||||
| class ResourceHelperScreen extends StatefulWidget { | class ResourceHelperScreen extends StatefulWidget { | ||||
| final String resourceName; | |||||
| final int selectedPlotId; | |||||
| final String type; | |||||
| final int selectedId; | |||||
| final String titleName; | |||||
| ResourceHelperScreen( | ResourceHelperScreen( | ||||
| {@required this.resourceName, @required this.selectedPlotId}); | |||||
| {@required this.type, | |||||
| @required this.selectedId, | |||||
| @required this.titleName}); | |||||
| @override | @override | ||||
| _ResourceHelperScreenState createState() => _ResourceHelperScreenState(); | _ResourceHelperScreenState createState() => _ResourceHelperScreenState(); | ||||
| } | } | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return BlocProvider( | return BlocProvider( | ||||
| create: (context) => | |||||
| InfinityScrollBloc(repository: Repository())..add(DataFetched()), | |||||
| create: (context) => SupplyBloc(repository: Repository()) | |||||
| ..add(DataFetched(type: widget.type, selectedId: widget.selectedId)), | |||||
| child: HoldInfinityWidget( | child: HoldInfinityWidget( | ||||
| selectedPlotId: widget.selectedPlotId, | |||||
| selectedId: widget.selectedId, | |||||
| type: widget.type, | |||||
| titleName: widget.titleName, | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| class HoldInfinityWidget extends StatelessWidget { | class HoldInfinityWidget extends StatelessWidget { | ||||
| final int selectedPlotId; | |||||
| HoldInfinityWidget({@required this.selectedPlotId}); | |||||
| final int selectedId; | |||||
| final String type; | |||||
| final String titleName; | |||||
| HoldInfinityWidget( | |||||
| {@required this.selectedId, | |||||
| @required this.type, | |||||
| @required this.titleName}); | |||||
| final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); | final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Scaffold( | return Scaffold( | ||||
| key: _scaffoldKey, | key: _scaffoldKey, | ||||
| appBar: AppBar(title: Text("Chọn danh sách")), | |||||
| appBar: AppBar(title: Text("Chọn $titleName")), | |||||
| body: InfinityView( | body: InfinityView( | ||||
| selectedPlotId: selectedPlotId, | |||||
| selectedId: selectedId, | |||||
| type: type, | |||||
| )); | )); | ||||
| } | } | ||||
| } | } | ||||
| class InfinityView extends StatefulWidget { | class InfinityView extends StatefulWidget { | ||||
| final int selectedPlotId; | |||||
| InfinityView({@required this.selectedPlotId}); | |||||
| final int selectedId; | |||||
| final String type; | |||||
| InfinityView({@required this.selectedId, @required this.type}); | |||||
| @override | @override | ||||
| _InfinityViewState createState() => _InfinityViewState(); | _InfinityViewState createState() => _InfinityViewState(); | ||||
| } | } | ||||
| class _InfinityViewState extends State<InfinityView> { | class _InfinityViewState extends State<InfinityView> { | ||||
| final _scrollController = ScrollController(); | |||||
| final _scrollThreshold = 250.0; | |||||
| InfinityScrollBloc _infinityScrollBloc; | |||||
| SupplyBloc _supplyBloc; | |||||
| @override | @override | ||||
| void initState() { | void initState() { | ||||
| _scrollController.addListener(() { | |||||
| final maxScroll = _scrollController.position.maxScrollExtent; | |||||
| final currentScroll = _scrollController.position.pixels; | |||||
| if (maxScroll - currentScroll < _scrollThreshold) { | |||||
| _infinityScrollBloc.add(DataFetched()); | |||||
| } | |||||
| }); | |||||
| _infinityScrollBloc = BlocProvider.of<InfinityScrollBloc>(context); | |||||
| _supplyBloc = BlocProvider.of<SupplyBloc>(context); | |||||
| _supplyBloc | |||||
| .add(DataFetched(type: widget.type, selectedId: widget.selectedId)); | |||||
| super.initState(); | super.initState(); | ||||
| } | } | ||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return BlocBuilder<InfinityScrollBloc, InfinityScrollState>( | |||||
| return BlocBuilder<SupplyBloc, SupplyState>( | |||||
| builder: (context, state) { | builder: (context, state) { | ||||
| if (state is InfinityScrollFailure) { | |||||
| if (state is SupplyFailure) { | |||||
| return Center(child: Text(label_error_get_data)); | return Center(child: Text(label_error_get_data)); | ||||
| } | } | ||||
| if (state is InfinityScrollSuccess) { | |||||
| if (state is SupplySuccess) { | |||||
| if (state.items.isEmpty) { | if (state.items.isEmpty) { | ||||
| return Center(child: Text(label_list_empty)); | return Center(child: Text(label_list_empty)); | ||||
| } | } | ||||
| Plot selectedPlot; | |||||
| List<Plot> plots = state.items.map((e) => e as Plot).toList(); | |||||
| plots.forEach((plot) { | |||||
| plot.id == widget.selectedPlotId ? selectedPlot = plot : Plot(); | |||||
| }); | |||||
| return RefreshIndicator( | return RefreshIndicator( | ||||
| child: ListView.builder( | child: ListView.builder( | ||||
| itemBuilder: (BuildContext context, int index) { | |||||
| return index >= state.items.length | |||||
| ? BottomLoader() | |||||
| : ItemInfinityWidget( | |||||
| item: state.items[index], | |||||
| selectedPlot: selectedPlot, | |||||
| ); | |||||
| }, | |||||
| itemCount: state.hasReachedMax | |||||
| ? state.items.length | |||||
| : state.items.length + 1, | |||||
| controller: _scrollController, | |||||
| ), | |||||
| itemBuilder: (BuildContext context, int index) { | |||||
| return index >= state.items.length | |||||
| ? BottomLoader() | |||||
| : ItemInfinityWidget(item: state.items[index]); | |||||
| }, | |||||
| itemCount: state.items.length), | |||||
| onRefresh: () async { | onRefresh: () async { | ||||
| _infinityScrollBloc.add(OnRefresh()); | |||||
| _supplyBloc.add(OnRefresh( | |||||
| type: widget.type, selectedId: widget.selectedId)); | |||||
| }); | }); | ||||
| } | } | ||||
| return Center( | return Center( | ||||
| @override | @override | ||||
| void dispose() { | void dispose() { | ||||
| _scrollController.dispose(); | |||||
| super.dispose(); | super.dispose(); | ||||
| } | } | ||||
| } | } | ||||
| class ItemInfinityWidget extends StatelessWidget { | class ItemInfinityWidget extends StatelessWidget { | ||||
| final Plot item; | |||||
| final Plot selectedPlot; | |||||
| final Supply item; | |||||
| const ItemInfinityWidget({Key key, @required this.item, this.selectedPlot}) | |||||
| : super(key: key); | |||||
| const ItemInfinityWidget({Key key, @required this.item}) : super(key: key); | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return GestureDetector( | return GestureDetector( | ||||
| child: Card( | child: Card( | ||||
| color: item.id % 3 == 0 ? Colors.white : Colors.greenAccent[100], | |||||
| child: Material( | child: Material( | ||||
| child: RadioListTile( | |||||
| title: Text(item.activityExecuteDate.toString()), | |||||
| subtitle: Text(item.id.toString()), | |||||
| value: item, | |||||
| groupValue: selectedPlot, | |||||
| onChanged: (Plot value) { | |||||
| print("selected value: ${value.id}"); | |||||
| Navigator.of(context).pop(value.id); | |||||
| }), | |||||
| )), | |||||
| child: RadioListTile( | |||||
| title: Text(item.name.toString()), | |||||
| subtitle: Text(item.manufacturer.toString()), | |||||
| value: item, | |||||
| groupValue: item.isSelected ? item : null, | |||||
| onChanged: (Supply value) { | |||||
| print("selected value: ${value.id}"); | |||||
| Navigator.of(context).pop(value.id); | |||||
| }), | |||||
| )), | |||||
| onTap: () {}); | onTap: () {}); | ||||
| } | } | ||||
| } | } |
| class ConstCommon { | class ConstCommon { | ||||
| static int kExpiredTime = 12 * 60 * 60 * 1000; //24h | static int kExpiredTime = 12 * 60 * 60 * 1000; //24h | ||||
| static const String baseUrl = "https://aquaman.aztrace.vn"; | |||||
| static const String baseUrl = "https://ironman.aztrace.vn"; | |||||
| static const String supplyTypeSeed = "GIONG"; | |||||
| static const String supplyTypeDung = "PHANBON"; | |||||
| static const String supplyTypeSubStrate = "GIATHE"; | |||||
| static const String supplyTypeProtectPlant = "THUOCBVTV"; | |||||
| } | } |