| @@ -1,6 +1,19 @@ | |||
| { | |||
| "id": 1578, | |||
| "times": 20, | |||
| "activityExecuteDate": "2020-08-20T11:53:20Z", | |||
| "isExceedLimit": false | |||
| "id": 1, | |||
| "qrCode": "QRLO01", | |||
| "code": "LO01", | |||
| "areaM2": 1000.0, | |||
| "type": 0, | |||
| "startDate": "2020-08-20T02:34:18Z", | |||
| "endDate": "2020-08-20T02:34:18Z", | |||
| "status": "STATUS_ARE_ACTIVE", | |||
| "description": "", | |||
| "ageDayStartAt": 3, | |||
| "tbSuppliesId": 1, | |||
| "suppliesName": "Rau muống", | |||
| "tbGuidelineId": 2, | |||
| "netHouseId": 26, | |||
| "netHouseName": "T01", | |||
| "areaId": 3, | |||
| "area": "Khu C" | |||
| } | |||
| @@ -4,13 +4,26 @@ part 'Plot.g.dart'; | |||
| @JsonSerializable() | |||
| class Plot { | |||
| Plot(); | |||
| Plot(); | |||
| num id; | |||
| num times; | |||
| String activityExecuteDate; | |||
| bool isExceedLimit; | |||
| factory Plot.fromJson(Map<String, dynamic> json) => _$PlotFromJson(json); | |||
| Map<String, dynamic> toJson() => _$PlotToJson(this); | |||
| num id; | |||
| String qrCode; | |||
| String code; | |||
| num areaM2; | |||
| num type; | |||
| String startDate; | |||
| String endDate; | |||
| String status; | |||
| String description; | |||
| num ageDayStartAt; | |||
| num tbSuppliesId; | |||
| String suppliesName; | |||
| num tbGuidelineId; | |||
| num netHouseId; | |||
| String netHouseName; | |||
| num areaId; | |||
| String area; | |||
| factory Plot.fromJson(Map<String,dynamic> json) => _$PlotFromJson(json); | |||
| Map<String, dynamic> toJson() => _$PlotToJson(this); | |||
| } | |||
| @@ -9,14 +9,40 @@ part of 'Plot.dart'; | |||
| Plot _$PlotFromJson(Map<String, dynamic> json) { | |||
| return Plot() | |||
| ..id = json['id'] as num | |||
| ..times = json['times'] as num | |||
| ..activityExecuteDate = json['activityExecuteDate'] as String | |||
| ..isExceedLimit = json['isExceedLimit'] as bool; | |||
| ..qrCode = json['qrCode'] as String | |||
| ..code = json['code'] as String | |||
| ..areaM2 = json['areaM2'] as num | |||
| ..type = json['type'] as num | |||
| ..startDate = json['startDate'] as String | |||
| ..endDate = json['endDate'] as String | |||
| ..status = json['status'] as String | |||
| ..description = json['description'] as String | |||
| ..ageDayStartAt = json['ageDayStartAt'] as num | |||
| ..tbSuppliesId = json['tbSuppliesId'] as num | |||
| ..suppliesName = json['suppliesName'] as String | |||
| ..tbGuidelineId = json['tbGuidelineId'] as num | |||
| ..netHouseId = json['netHouseId'] as num | |||
| ..netHouseName = json['netHouseName'] as String | |||
| ..areaId = json['areaId'] as num | |||
| ..area = json['area'] as String; | |||
| } | |||
| Map<String, dynamic> _$PlotToJson(Plot instance) => <String, dynamic>{ | |||
| 'id': instance.id, | |||
| 'times': instance.times, | |||
| 'activityExecuteDate': instance.activityExecuteDate, | |||
| 'isExceedLimit': instance.isExceedLimit, | |||
| 'qrCode': instance.qrCode, | |||
| 'code': instance.code, | |||
| 'areaM2': instance.areaM2, | |||
| 'type': instance.type, | |||
| 'startDate': instance.startDate, | |||
| 'endDate': instance.endDate, | |||
| 'status': instance.status, | |||
| 'description': instance.description, | |||
| 'ageDayStartAt': instance.ageDayStartAt, | |||
| 'tbSuppliesId': instance.tbSuppliesId, | |||
| 'suppliesName': instance.suppliesName, | |||
| 'tbGuidelineId': instance.tbGuidelineId, | |||
| 'netHouseId': instance.netHouseId, | |||
| 'netHouseName': instance.netHouseName, | |||
| 'areaId': instance.areaId, | |||
| 'area': instance.area | |||
| }; | |||
| @@ -1,2 +1,3 @@ | |||
| export 'Plot.dart'; | |||
| export 'ResourceHelper.dart'; | |||
| export 'Supply.dart' ; | |||
| export 'Plot.dart' ; | |||
| export 'ResourceHelper.dart' ; | |||
| @@ -3,10 +3,14 @@ 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/screens/plot/widget_search.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'; | |||
| import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| import 'bloc/plot_bloc.dart'; | |||
| @@ -77,21 +81,27 @@ class _InfinityViewState extends State<InfinityView> { | |||
| if (state.items.isEmpty) { | |||
| return Center(child: Text(label_list_empty)); | |||
| } | |||
| return RefreshIndicator( | |||
| child: ListView.builder( | |||
| 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 Column( | |||
| children: <Widget>[ | |||
| WidgetSearch(), | |||
| Expanded( | |||
| child: RefreshIndicator( | |||
| child: ListView.builder( | |||
| 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(), | |||
| @@ -116,19 +126,28 @@ class ItemInfinityWidget extends StatelessWidget { | |||
| Widget build(BuildContext context) { | |||
| return GestureDetector( | |||
| child: Card( | |||
| color: item.id % 3 == 0 ? Colors.white : Colors.greenAccent[100], | |||
| child: Container( | |||
| padding: EdgeInsets.all(8.0), | |||
| child: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| children: <Widget>[ | |||
| Text("Ngày giờ: " + item.activityExecuteDate.toString()), | |||
| SizedBox( | |||
| height: 8.0, | |||
| ), | |||
| Text("Thời gian: " + item.id.toString() + " giây"), | |||
| ], | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? Colors.white | |||
| : COLOR_CONST.DEFAULT, | |||
| child: ListTile( | |||
| title: Text( | |||
| item.code.toString() + " - " + item.suppliesName.toString(), | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white), | |||
| ), | |||
| subtitle: Text(item.startDate.format_DDMMYY_HHmm().toString(), | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white)), | |||
| trailing: Text( | |||
| item.areaM2.formatNumtoStringDecimal().toString() + " m\u00B2", | |||
| style: TextStyle( | |||
| color: item.status == "STATUS_ARE_ACTIVE" | |||
| ? COLOR_CONST.DEFAULT | |||
| : Colors.white)), | |||
| ), | |||
| ), | |||
| onTap: () {}); | |||
| @@ -0,0 +1,82 @@ | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| class WidgetSearch extends StatefulWidget { | |||
| @override | |||
| _WidgetSearchState createState() => _WidgetSearchState(); | |||
| } | |||
| class _WidgetSearchState extends State<WidgetSearch> { | |||
| BuildContext _blocContext; | |||
| TextEditingController _searchController = TextEditingController(); | |||
| @override | |||
| void initState() { | |||
| super.initState(); | |||
| _searchController.addListener(() { | |||
| final keyword = _searchController.text; | |||
| if (keyword.isNotEmpty) { | |||
| //search when text change | |||
| } | |||
| }); | |||
| } | |||
| Widget getSearchBarUI() { | |||
| _searchController.text = ""; | |||
| return Padding( | |||
| padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 0), | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Padding( | |||
| padding: const EdgeInsets.only(right: 8, top: 8, bottom: 0), | |||
| child: Container( | |||
| decoration: BoxDecoration( | |||
| color: Colors.white, | |||
| borderRadius: const BorderRadius.all( | |||
| Radius.circular(38.0), | |||
| ), | |||
| boxShadow: <BoxShadow>[ | |||
| BoxShadow( | |||
| color: Colors.grey.withOpacity(0.2), | |||
| offset: const Offset(0, 2), | |||
| blurRadius: 8.0), | |||
| ], | |||
| ), | |||
| child: Padding( | |||
| padding: const EdgeInsets.only( | |||
| left: 16, right: 16, top: 4, bottom: 4), | |||
| child: TextField( | |||
| textInputAction: TextInputAction.done, | |||
| controller: _searchController, | |||
| onChanged: (String txt) {}, | |||
| cursorColor: COLOR_CONST.GRAY1, | |||
| decoration: InputDecoration( | |||
| border: InputBorder.none, | |||
| hintText: 'Tìm kiếm ...', | |||
| ), | |||
| onSubmitted: (value) { | |||
| FocusScope.of(context).requestFocus(FocusNode()); | |||
| }, | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| _blocContext = context; | |||
| return Container(child: getSearchBarUI()); | |||
| } | |||
| @override | |||
| void dispose() { | |||
| _searchController.dispose(); | |||
| super.dispose(); | |||
| } | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| import 'package:farm_tpf/presentation/screens/control_device/sc_control_device.dart'; | |||
| import 'package:farm_tpf/presentation/screens/home/home.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart'; | |||
| import 'package:farm_tpf/presentation/screens/profile/sc_update_profile.dart'; | |||
| import 'package:farm_tpf/presentation/screens/scan_barcode/sc_scan_barcode.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| @@ -57,7 +58,7 @@ class _NavigationHomeScreenState extends State<NavigationHomeScreen> { | |||
| drawerIndex = drawerIndexdata; | |||
| if (drawerIndex == DrawerIndex.Home) { | |||
| setState(() { | |||
| screenView = HomePage(); | |||
| screenView = PlotListScreen(); | |||
| }); | |||
| } else if (drawerIndex == DrawerIndex.ControlDevice) { | |||
| setState(() { | |||
| @@ -2,6 +2,44 @@ import 'dart:developer'; | |||
| import 'package:intl/intl.dart'; | |||
| extension ddMM_HHmm on String { | |||
| //"2020-08-13T02:11:32Z" => 13/08 02:11 | |||
| // convert utc to local timezone | |||
| String format_DDMM_HHmm() { | |||
| try { | |||
| final str = this.toString(); | |||
| var dateFromString = | |||
| DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(str, true).toLocal(); | |||
| return DateFormat("dd/MM HH:mm").format(dateFromString); | |||
| } catch (_) { | |||
| return ""; | |||
| } | |||
| } | |||
| String format_DDMMYY_HHmm() { | |||
| try { | |||
| final str = this.toString(); | |||
| var dateFromString = | |||
| DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(str, true).toLocal(); | |||
| return DateFormat("dd/MM/yyyy HH:mm").format(dateFromString); | |||
| } catch (_) { | |||
| return ""; | |||
| } | |||
| } | |||
| } | |||
| extension numToString on num { | |||
| String formatNumtoStringDecimal() { | |||
| try { | |||
| var numWithLocalSeparator = new NumberFormat.decimalPattern("vi_VN"); | |||
| final str = numWithLocalSeparator.format(this); | |||
| return str; | |||
| } catch (_) { | |||
| return ""; | |||
| } | |||
| } | |||
| } | |||
| extension HHmm on Duration { | |||
| String formatHHmm() { | |||
| //1:34:00.000000 | |||
| @@ -18,7 +56,14 @@ extension HHmm on Duration { | |||
| extension FormatNumber on int { | |||
| String formatDecimalThousand() { | |||
| //1403 -> 1,403 | |||
| var f = new NumberFormat.decimalPattern("en_US"); | |||
| var f = new NumberFormat.decimalPattern("vi_VN"); | |||
| return f.format(this); | |||
| } | |||
| } | |||
| extension FormatNumberToDecimal on double { | |||
| String formatDecimalThousand() { | |||
| var f = new NumberFormat.decimalPattern("vi_VN"); | |||
| return f.format(this); | |||
| } | |||
| } | |||
| @@ -32,21 +77,16 @@ extension FormatDate on int { | |||
| extension DoubleParsing on String { | |||
| double parseDoubleThousand() { | |||
| var newValue = this.replaceAll(",", ""); | |||
| //TODO: CHECK again | |||
| if (newValue.endsWith(".0")) { | |||
| newValue = newValue.substring(0, newValue.length - 2); | |||
| } | |||
| return double.tryParse(newValue); | |||
| var newValue = this.replaceAll(".", ""); | |||
| var changeToServerFormat = newValue.replaceAll(",", "."); | |||
| return double.tryParse(changeToServerFormat); | |||
| } | |||
| } | |||
| extension IntParsing on String { | |||
| int parseIntThousand() { | |||
| var newValue = this.replaceAll(",", ""); | |||
| if (newValue.endsWith(".0")) { | |||
| newValue = newValue.substring(0, newValue.length - 2); | |||
| } | |||
| return int.tryParse(newValue); | |||
| var newValue = this.replaceAll(".", ""); | |||
| var changeToServerFormat = newValue.replaceAll(",", "."); | |||
| return int.tryParse(changeToServerFormat); | |||
| } | |||
| } | |||
| @@ -400,7 +400,7 @@ packages: | |||
| name: json_serializable | |||
| url: "https://pub.dartlang.org" | |||
| source: hosted | |||
| version: "3.4.0" | |||
| version: "3.4.1" | |||
| keyboard_dismisser: | |||
| dependency: "direct main" | |||
| description: | |||
| @@ -589,7 +589,7 @@ packages: | |||
| name: retrofit_generator | |||
| url: "https://pub.dartlang.org" | |||
| source: hosted | |||
| version: "1.3.7+5" | |||
| version: "1.3.7+6" | |||
| rxdart: | |||
| dependency: "direct main" | |||
| description: | |||