Browse Source

show plot detail

master
daivph 5 years ago
parent
commit
ba93672b77
13 changed files with 322 additions and 51 deletions
  1. +6
    -0
      lib/data/api/rest_client.dart
  2. +20
    -0
      lib/data/api/rest_client.g.dart
  3. +5
    -0
      lib/data/repository/repository.dart
  4. +1
    -1
      lib/models/Crop.g.dart
  5. +1
    -1
      lib/models/HistoryAction.g.dart
  6. +2
    -1
      lib/presentation/screens/plot/sc_plot.dart
  7. +68
    -0
      lib/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart
  8. +18
    -0
      lib/presentation/screens/plot_detail/bloc/plot_detail_event.dart
  9. +35
    -0
      lib/presentation/screens/plot_detail/bloc/plot_detail_state.dart
  10. +109
    -6
      lib/presentation/screens/plot_detail/sc_plot_action.dart
  11. +8
    -1
      lib/presentation/screens/plot_detail/sc_plot_detail.dart
  12. +46
    -39
      pubspec.lock
  13. +3
    -2
      pubspec.yaml

+ 6
- 0
lib/data/api/rest_client.dart View File

@@ -44,4 +44,10 @@ abstract class RestClient {
{@Path() int page = 0, @Path() int size = 20, @Path() String query = ""});
@GET("/api/listActivityTypesOther")
Future<List<ActionType>> getActionTypes();

//Crop
@GET(
"/api/tb-crops-detail/{cropId}?page={page}&size={size}&sort=executeDate,DESC")
Future<Crop> getCropDetail(@Path() int cropId,
{@Path() int page = 0, @Path() int size = 20});
}

+ 20
- 0
lib/data/api/rest_client.g.dart View File

@@ -205,4 +205,24 @@ class _RestClient implements RestClient {
.toList();
return value;
}

@override
getCropDetail(cropId, {page = 0, size = 20}) async {
ArgumentError.checkNotNull(cropId, 'cropId');
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
queryParameters.removeWhere((k, v) => v == null);
final _data = <String, dynamic>{};
final Response<Map<String, dynamic>> _result = await _dio.request(
'/api/tb-crops-detail/$cropId?page=$page&size=$size&sort=executeDate,DESC',
queryParameters: queryParameters,
options: RequestOptions(
method: 'GET',
headers: <String, dynamic>{},
extra: _extra,
baseUrl: baseUrl),
data: _data);
final value = Crop.fromJson(_result.data);
return value;
}
}

+ 5
- 0
lib/data/repository/repository.dart View File

@@ -16,6 +16,11 @@ class Repository {
return client.getActionTypes();
}

Future<Crop> getPlotDetail(int cropId, {int page, int size}) {
final client = RestClient(dio);
return client.getCropDetail(cropId, page: page, size: size);
}

Future<List<Plot>> getPlots({int page, int size, String searchString}) {
final client = RestClient(dio);
return client.getPlots(page: page, size: size, query: searchString);

+ 1
- 1
lib/models/Crop.g.dart View File

@@ -26,5 +26,5 @@ Map<String, dynamic> _$CropToJson(Crop instance) => <String, dynamic>{
'seedIncubationTime': instance.seedIncubationTime,
'numberPlants': instance.numberPlants,
'numberCurrentPlants': instance.numberCurrentPlants,
'endOfFarmingDate': instance.endOfFarmingDate
'endOfFarmingDate': instance.endOfFarmingDate,
};

+ 1
- 1
lib/models/HistoryAction.g.dart View File

@@ -25,5 +25,5 @@ Map<String, dynamic> _$HistoryActionToJson(HistoryAction instance) =>
'executeDate': instance.executeDate,
'description': instance.description,
'activityTypeId': instance.activityTypeId,
'activityTypeName': instance.activityTypeName
'activityTypeName': instance.activityTypeName,
};

+ 2
- 1
lib/presentation/screens/plot/sc_plot.dart View File

@@ -164,7 +164,8 @@ class ItemInfinityWidget extends StatelessWidget {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => PlotDetailScreen()));
builder: (BuildContext context) =>
PlotDetailScreen(cropId: item.id)));
});
}
}

+ 68
- 0
lib/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart View File

@@ -0,0 +1,68 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:farm_tpf/data/api/app_exception.dart';
import 'package:farm_tpf/data/repository/repository.dart';
import 'package:meta/meta.dart';

part 'plot_detail_event.dart';
part 'plot_detail_state.dart';

class PlotDetailBloc extends Bloc<PlotDetailEvent, PlotDetailState> {
final Repository repository;
PlotDetailBloc({@required this.repository}) : super(PlotDetailInitial());
static int pageSize = 20;

@override
Stream<PlotDetailState> mapEventToState(
PlotDetailEvent event,
) async* {
if (event is DataFetched &&
!(state is PlotDetailSuccess &&
(state as PlotDetailSuccess).hasReachedMax)) {
try {
if (state is PlotDetailInitial) {
yield PlotDetailLoading();
final response = await repository.getPlotDetail(event.cropId,
page: 0, size: pageSize);
yield PlotDetailSuccess(
items: response.activities,
page: 0,
hasReachedMax:
response.activities.length < pageSize ? true : false);
}
if (state is PlotDetailSuccess) {
final currentState = state as PlotDetailSuccess;
int page = currentState.page + 1;
yield PlotDetailLoading();
final response = await repository.getPlotDetail(event.cropId,
page: page, size: pageSize);
yield response.activities.isEmpty
? currentState.copyWith(hasReachedMax: true)
: PlotDetailSuccess(
items: currentState.items + response.activities,
page: currentState.page + 1,
hasReachedMax: false);
}
} catch (e) {
var errorString = AppException.handleError(e);
yield PlotDetailFailure(errorString: errorString);
}
}
if (event is OnRefresh) {
try {
yield PlotDetailLoading();
final response = await repository.getPlotDetail(event.cropId,
page: 0, size: pageSize);
yield PlotDetailSuccess(
items: response.activities,
page: 0,
hasReachedMax:
response.activities.length < pageSize ? true : false);
} catch (e) {
yield PlotDetailFailure(errorString: AppException.handleError(e));
}
}
}
}

+ 18
- 0
lib/presentation/screens/plot_detail/bloc/plot_detail_event.dart View File

@@ -0,0 +1,18 @@
part of 'plot_detail_bloc.dart';

abstract class PlotDetailEvent extends Equatable {
const PlotDetailEvent();

@override
List<Object> get props => [];
}

class DataFetched extends PlotDetailEvent {
final int cropId;
DataFetched(this.cropId);
}

class OnRefresh extends PlotDetailEvent {
final int cropId;
OnRefresh(this.cropId);
}

+ 35
- 0
lib/presentation/screens/plot_detail/bloc/plot_detail_state.dart View File

@@ -0,0 +1,35 @@
part of 'plot_detail_bloc.dart';

abstract class PlotDetailState extends Equatable {
const PlotDetailState();

@override
List<Object> get props => [];
}

class PlotDetailInitial extends PlotDetailState {}

class PlotDetailLoading extends PlotDetailState {}

class PlotDetailFailure extends PlotDetailState {
final String errorString;
PlotDetailFailure({@required this.errorString});
}

class PlotDetailSuccess<T> extends PlotDetailState {
final List<T> items;
final int page;
final bool hasReachedMax;

const PlotDetailSuccess({this.items, this.page, this.hasReachedMax});

PlotDetailSuccess copyWith({List<T> items, int page, bool hasReachedMax}) {
return PlotDetailSuccess(
items: items ?? this.items,
page: page ?? this.page,
hasReachedMax: hasReachedMax ?? this.hasReachedMax);
}

@override
List<Object> get props => [items, hasReachedMax];
}

+ 109
- 6
lib/presentation/screens/plot_detail/sc_plot_action.dart View File

@@ -1,10 +1,19 @@
import 'package:farm_tpf/data/repository/repository.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/loading_list_page.dart';
import 'package:farm_tpf/presentation/screens/actions/other/sc_edit_action_other.dart';
import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart';
import 'package:farm_tpf/utils/const_color.dart';
import 'package:farm_tpf/utils/const_string.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:farm_tpf/utils/formatter.dart';

class PlotActionScreen extends StatefulWidget {
final int cropId;
PlotActionScreen({@required this.cropId});
@override
_PlotActionScreenState createState() => _PlotActionScreenState();
}
@@ -140,18 +149,112 @@ class _PlotActionScreenState extends State<PlotActionScreen> {
))
]))
],
body: RefreshIndicator(
backgroundColor: Colors.white,
onRefresh: () async {},
child: ListView.builder(
itemBuilder: (context, index) => ListTile(title: Text("Text $index")),
itemCount: 20,
body: BlocProvider(
create: (context) => PlotDetailBloc(repository: Repository())
..add(DataFetched(widget.cropId)),
child: HoldInfinityWidget(
cropId: widget.cropId,
),
),
);
}
}

class HoldInfinityWidget extends StatelessWidget {
final int cropId;
HoldInfinityWidget({@required this.cropId});
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(key: _scaffoldKey, body: InfinityView(cropId: cropId));
}
}

class InfinityView extends StatefulWidget {
final int cropId;
InfinityView({@required this.cropId});
@override
_InfinityViewState createState() => _InfinityViewState();
}

class _InfinityViewState extends State<InfinityView> {
final _scrollController = ScrollController();
final _scrollThreshold = 250.0;
PlotDetailBloc _plotDetailBloc;

@override
void initState() {
_scrollController.addListener(() {
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll < _scrollThreshold) {
_plotDetailBloc.add(DataFetched(widget.cropId));
}
});
_plotDetailBloc = BlocProvider.of<PlotDetailBloc>(context);
super.initState();
}

@override
Widget build(BuildContext context) {
return BlocBuilder<PlotDetailBloc, PlotDetailState>(
builder: (context, state) {
if (state is PlotDetailFailure) {
return Center(child: Text(state.errorString));
}
if (state is PlotDetailSuccess) {
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 {
_plotDetailBloc.add(OnRefresh(widget.cropId));
});
}
return Center(
child: LoadingListPage(),
);
},
);
}

@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}

class ItemInfinityWidget extends StatelessWidget {
final HistoryAction item;

const ItemInfinityWidget({Key key, @required this.item}) : super(key: key);

@override
Widget build(BuildContext context) {
return GestureDetector(
child: Card(
child: ListTile(
title: Text(item.activityTypeName),
subtitle: Text(item.executeDate.format_DDMMYY_HHmm()),
),
),
onTap: () {});
}
}

class ActionType {
Widget addScreen;
Widget listScreen;

+ 8
- 1
lib/presentation/screens/plot_detail/sc_plot_detail.dart View File

@@ -6,6 +6,8 @@ import 'package:farm_tpf/utils/const_color.dart';
import 'package:flutter/material.dart';

class PlotDetailScreen extends StatefulWidget {
final int cropId;
PlotDetailScreen({@required this.cropId});
@override
_PlotDetailScreenState createState() => _PlotDetailScreenState();
}
@@ -28,7 +30,12 @@ class _PlotDetailScreenState extends State<PlotDetailScreen> {
child: new Scaffold(
backgroundColor: COLOR_CONST.ITEM_BG,
body: TabBarView(
children: [PlotParameterScreen(), PlotActionScreen()],
children: [
PlotParameterScreen(),
PlotActionScreen(
cropId: widget.cropId,
)
],
),
bottomNavigationBar: new TabBar(
tabs: [

+ 46
- 39
pubspec.lock View File

@@ -1,13 +1,20 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
analyzer:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.0"
analyzer:
dependency: "direct main"
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.36.4"
version: "0.39.14"
archive:
dependency: transitive
description:
@@ -56,14 +63,14 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
version: "1.3.0"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.1+1"
version: "0.4.2"
build_daemon:
dependency: transitive
description:
@@ -77,21 +84,21 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.3.11"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.9"
version: "1.10.0"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
version: "5.2.0"
built_collection:
dependency: transitive
description:
@@ -127,6 +134,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
code_builder:
dependency: transitive
description:
@@ -175,7 +189,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.9"
version: "1.3.6"
dio:
dependency: "direct main"
description:
@@ -296,13 +310,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
front_end:
dependency: transitive
description:
name: front_end
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.19"
get:
dependency: "direct main"
description:
@@ -400,28 +407,14 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
json_model:
dependency: "direct dev"
description:
name: json_model
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2"
version: "3.0.1"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
kernel:
dependency: transitive
description:
name: kernel
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.19"
version: "3.4.1"
keyboard_dismisser:
dependency: "direct main"
description:
@@ -492,13 +485,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
package_resolver:
dependency: transitive
description:
name: package_resolver
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
path:
dependency: transitive
description:
@@ -604,6 +590,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
retrofit:
dependency: transitive
description:
name: retrofit
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.4"
retrofit_generator:
dependency: "direct dev"
description:
name: retrofit_generator
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.7+6"
rxdart:
dependency: "direct main"
description:
@@ -678,7 +678,7 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+4"
version: "0.9.6"
source_span:
dependency: transitive
description:
@@ -735,6 +735,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+2"
tuple:
dependency: transitive
description:
name: tuple
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
typed_data:
dependency: transitive
description:

+ 3
- 2
pubspec.yaml View File

@@ -37,14 +37,15 @@ dependencies:
get: ^3.8.0
intl: ^0.16.1
flutter_datetime_picker: ^1.3.8
analyzer: ^0.39.14

dev_dependencies:
flutter_test:
sdk: flutter
#flutter packages pub run build_runner build --delete-conflicting-outputs
# retrofit_generator: ^1.3.7
retrofit_generator: ^1.3.7
# flutter packages pub run json_model
json_model: ^0.0.2
# json_model: ^0.0.2
build_runner: any
json_serializable: any

Loading…
Cancel
Save