Browse Source

view action

master
daivph 5 years ago
parent
commit
c6b84bdc86
16 changed files with 749 additions and 13 deletions
  1. +2
    -2
      android/app/build.gradle
  2. +2
    -1
      android/app/src/main/AndroidManifest.xml
  3. +1
    -0
      android/settings_aar.gradle
  4. +30
    -0
      ios/Podfile.lock
  5. +4
    -4
      ios/Runner.xcodeproj/project.pbxproj
  6. +7
    -4
      ios/Runner/Info.plist
  7. +52
    -0
      lib/presentation/custom_widgets/widget_rounded_rect_indicator.dart
  8. +360
    -0
      lib/presentation/screens/actions/nursery/sc_nursery.dart
  9. +23
    -0
      lib/presentation/screens/actions/plant/sc_plant.dart
  10. +21
    -2
      lib/presentation/screens/home/view/home_page.dart
  11. +112
    -0
      lib/presentation/screens/plot_detail/sc_plot_action.dart
  12. +54
    -0
      lib/presentation/screens/plot_detail/sc_plot_detail.dart
  13. +15
    -0
      lib/presentation/screens/plot_detail/sc_plot_information.dart
  14. +11
    -0
      lib/utils/const_string.dart
  15. +49
    -0
      pubspec.lock
  16. +6
    -0
      pubspec.yaml

+ 2
- 2
android/app/build.gradle View File

apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"


android { android {
compileSdkVersion 28
compileSdkVersion 29


sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.farm_tpf" applicationId "com.example.farm_tpf"
minSdkVersion 18
minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

+ 2
- 1
android/app/src/main/AndroidManifest.xml View File

<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="farm_tpf" android:label="farm_tpf"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleTop"

+ 1
- 0
android/settings_aar.gradle View File

include ':app'

+ 30
- 0
ios/Podfile.lock View File

- Flutter - Flutter
- MTBBarcodeScanner - MTBBarcodeScanner
- SwiftProtobuf - SwiftProtobuf
- camera (0.0.1):
- Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_plugin_android_lifecycle (0.0.1):
- Flutter
- image_picker (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11) - MTBBarcodeScanner (5.0.11)
- path_provider_linux (0.0.1): - path_provider_linux (0.0.1):
- Flutter - Flutter
- shared_preferences_web (0.0.1): - shared_preferences_web (0.0.1):
- Flutter - Flutter
- SwiftProtobuf (1.11.0) - SwiftProtobuf (1.11.0)
- video_player (0.0.1):
- Flutter
- video_player_web (0.0.1):
- Flutter


DEPENDENCIES: DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`) - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- camera (from `.symlinks/plugins/camera/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`)
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
- shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
- video_player_web (from `.symlinks/plugins/video_player_web/ios`)


SPEC REPOS: SPEC REPOS:
trunk: trunk:
EXTERNAL SOURCES: EXTERNAL SOURCES:
barcode_scan: barcode_scan:
:path: ".symlinks/plugins/barcode_scan/ios" :path: ".symlinks/plugins/barcode_scan/ios"
camera:
:path: ".symlinks/plugins/camera/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
flutter_plugin_android_lifecycle:
:path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
path_provider_linux: path_provider_linux:
:path: ".symlinks/plugins/path_provider_linux/ios" :path: ".symlinks/plugins/path_provider_linux/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences_macos/ios" :path: ".symlinks/plugins/shared_preferences_macos/ios"
shared_preferences_web: shared_preferences_web:
:path: ".symlinks/plugins/shared_preferences_web/ios" :path: ".symlinks/plugins/shared_preferences_web/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
video_player_web:
:path: ".symlinks/plugins/video_player_web/ios"


SPEC CHECKSUMS: SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479 barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
camera: a0ca5080336f7af47b88436e5e26da3dee5568f0
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9
SwiftProtobuf: f889fe5772f90ef7d7b8aac352d1fddf39650713 SwiftProtobuf: f889fe5772f90ef7d7b8aac352d1fddf39650713
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7


PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a



+ 4
- 4
ios/Runner.xcodeproj/project.pbxproj View File

archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 50;
objectVersion = 51;
objects = { objects = {


/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = C3DTD2JH94; DEVELOPMENT_TEAM = C3DTD2JH94;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = C3DTD2JH94; DEVELOPMENT_TEAM = C3DTD2JH94;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = C3DTD2JH94; DEVELOPMENT_TEAM = C3DTD2JH94;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (

+ 7
- 4
ios/Runner/Info.plist View File

<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSCameraUsageDescription</key>
<string>Camera permission is required for barcode scanning.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Use for record videos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Get image for upload to server</string>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<!-- Camera Permission -->
<key>NSCameraUsageDescription</key>
<string>Camera permission is required for barcode scanning.</string>
</dict> </dict>
</plist> </plist>

+ 52
- 0
lib/presentation/custom_widgets/widget_rounded_rect_indicator.dart View File

import 'package:flutter/material.dart';

class RoundedRectIndicator extends Decoration {
final BoxPainter _painter;

RoundedRectIndicator({
@required Color color,
@required double radius,
double padding = 0.0,
double weight = 3.0,
}) : _painter = _RectPainter(color, radius, padding, weight);

@override
BoxPainter createBoxPainter([onChanged]) {
return _painter;
}
}

class _RectPainter extends BoxPainter {
final Paint _paint;
final double radius;
final double padding;
final double weight;
final indicatorPaddingBottom = 4.0;

_RectPainter(Color color, this.radius, this.padding, this.weight)
: _paint = Paint()
..color = color
..isAntiAlias = true;

@override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
var width = cfg.size.width;
var height = cfg.size.height;

var left = 0.0;
var top = height - indicatorPaddingBottom;
var right = width;
var bottom = height - weight - indicatorPaddingBottom;

//calculate offset
left = left + offset.dx + padding;
right = right + offset.dx - padding;

var rect = RRect.fromLTRBAndCorners(left, top, right, bottom,
topLeft: Radius.circular(radius),
bottomLeft: Radius.circular(radius),
bottomRight: Radius.circular(radius),
topRight: Radius.circular(radius));
canvas.drawRRect(rect, _paint);
}
}

+ 360
- 0
lib/presentation/screens/actions/nursery/sc_nursery.dart View File

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';

class ActionNurseryScreen extends StatefulWidget {
@override
_ActionNurseryScreenState createState() => _ActionNurseryScreenState();
}

class _ActionNurseryScreenState extends State<ActionNurseryScreen> {
PickedFile _imageFile;
dynamic _pickImageError;
bool isVideo = false;
VideoPlayerController _controller;
VideoPlayerController _toBeDisposed;
String _retrieveDataError;

final ImagePicker _picker = ImagePicker();
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();

Future<void> _playVideo(PickedFile file) async {
if (file != null && mounted) {
await _disposeVideoController();
_controller = VideoPlayerController.file(File(file.path));
await _controller.setVolume(1.0);
await _controller.initialize();
await _controller.setLooping(true);
await _controller.play();
setState(() {});
}
}

void _onImageButtonPressed(ImageSource source, {BuildContext context}) async {
if (_controller != null) {
await _controller.setVolume(0.0);
}
if (isVideo) {
final PickedFile file = await _picker.getVideo(
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else {
await _displayPickImageDialog(context,
(double maxWidth, double maxHeight, int quality) async {
try {
final pickedFile = await _picker.getImage(
source: source,
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
);
setState(() {
_imageFile = pickedFile;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
}
}

@override
void deactivate() {
if (_controller != null) {
_controller.setVolume(0.0);
_controller.pause();
}
super.deactivate();
}

@override
void dispose() {
_disposeVideoController();
maxWidthController.dispose();
maxHeightController.dispose();
qualityController.dispose();
super.dispose();
}

Future<void> _disposeVideoController() async {
if (_toBeDisposed != null) {
await _toBeDisposed.dispose();
}
_toBeDisposed = _controller;
_controller = null;
}

Widget _previewVideo() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}

Widget _previewImage() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
return Image.file(File(_imageFile.path));
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}

Future<void> retrieveLostData() async {
final LostData response = await _picker.getLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
await _playVideo(response.file);
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
});
}
} else {
_retrieveDataError = response.exception.code;
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Test"),
),
body: Center(
//TODO : check default platform is android
child: 1 == 1
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return isVideo ? _previewVideo() : _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: (isVideo ? _previewVideo() : _previewImage()),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.gallery, context: context);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo_library),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'image1',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}

Text _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError);
_retrieveDataError = null;
return result;
}
return null;
}

Future<void> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add optional parameters'),
content: Column(
children: <Widget>[
TextField(
controller: maxWidthController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration:
InputDecoration(hintText: "Enter maxWidth if desired"),
),
TextField(
controller: maxHeightController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration:
InputDecoration(hintText: "Enter maxHeight if desired"),
),
TextField(
controller: qualityController,
keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: "Enter quality if desired"),
),
],
),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('PICK'),
onPressed: () {
double width = maxWidthController.text.isNotEmpty
? double.parse(maxWidthController.text)
: null;
double height = maxHeightController.text.isNotEmpty
? double.parse(maxHeightController.text)
: null;
int quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
onPick(width, height, quality);
Navigator.of(context).pop();
}),
],
);
});
}
}

typedef void OnPickImageCallback(
double maxWidth, double maxHeight, int quality);

class AspectRatioVideo extends StatefulWidget {
AspectRatioVideo(this.controller);

final VideoPlayerController controller;

@override
AspectRatioVideoState createState() => AspectRatioVideoState();
}

class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController get controller => widget.controller;
bool initialized = false;

void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller.value.initialized) {
initialized = controller.value.initialized;
setState(() {});
}
}

@override
void initState() {
super.initState();
controller.addListener(_onVideoControllerUpdate);
}

@override
void dispose() {
controller.removeListener(_onVideoControllerUpdate);
super.dispose();
}

@override
Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller.value?.aspectRatio,
child: VideoPlayer(controller),
),
);
} else {
return Container();
}
}
}

+ 23
- 0
lib/presentation/screens/actions/plant/sc_plant.dart View File

import 'package:farm_tpf/app.dart';
import 'package:flutter/material.dart';

class ActionPlantScreen extends StatefulWidget {
@override
_ActionPlantScreenState createState() => _ActionPlantScreenState();
}

class _ActionPlantScreenState extends State<ActionPlantScreen> {
@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Plant"),
),
);
}
}

+ 21
- 2
lib/presentation/screens/home/view/home_page.dart View File

import 'package:farm_tpf/authentication/bloc/authentication_bloc.dart';
import 'package:farm_tpf/presentation/screens/actions/nursery/sc_nursery.dart';
import 'package:farm_tpf/presentation/screens/actions/plant/sc_plant.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';


class HomePage extends StatelessWidget { class HomePage extends StatelessWidget {
static Route route() { static Route route() {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Text("logged in."), Text("logged in."),
MaterialButton(
child: Text("Nursery action"),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => ActionNurseryScreen()));
}),
MaterialButton(
child: Text("Plant action"),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => ActionPlantScreen()));
}),
MaterialButton(
child: Text("Chi tiết lô"),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => PlotDetailScreen()));
}),
], ],
), ),
), ),

+ 112
- 0
lib/presentation/screens/plot_detail/sc_plot_action.dart View File

import 'package:farm_tpf/utils/const_color.dart';
import 'package:farm_tpf/utils/const_string.dart';
import 'package:flutter/material.dart';

class PlotActionScreen extends StatefulWidget {
@override
_PlotActionScreenState createState() => _PlotActionScreenState();
}

class _PlotActionScreenState extends State<PlotActionScreen> {
List<ActionType> actions = new List<ActionType>();

@override
void initState() {
super.initState();
actions.add(ActionType(plot_action_nursery, null, null));
actions.add(ActionType(plot_action_plant, null, null));
actions.add(ActionType(plot_action_crop_status, null, null));
actions.add(ActionType(plot_action_environment_update, null, null));
actions.add(ActionType(plot_action_dung, null, null));
actions.add(ActionType(plot_action_spraying, null, null));
actions.add(ActionType(plot_action_disease, null, null));
actions.add(ActionType(plot_action_use_water, null, null));
actions.add(ActionType(plot_action_other, null, null));
actions.add(ActionType(plot_action_harvest, null, null));
actions.add(ActionType(plot_action_finish, null, null));
}

Widget _createShrimpUpdate(ActionType actionType) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => actionType.listScreen));
},
child: Container(
height: 75,
margin: EdgeInsets.all(4.0),
padding: EdgeInsets.all(0.0),
decoration: BoxDecoration(
color: COLOR_CONST.WHITE,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8.0),
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0),
topRight: Radius.circular(8.0)),
boxShadow: <BoxShadow>[
BoxShadow(
color: COLOR_CONST.GRAY1.withOpacity(0.2),
offset: Offset(1.1, 1.1),
blurRadius: 10.0),
],
),
child: Stack(
children: <Widget>[
Positioned(
top: -10,
right: -3,
child: (actionType.addScreen == null)
? Container()
: IconButton(
icon: Icon(
Icons.add_circle,
size: 40,
color: Colors.green,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => actionType.addScreen));
})),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Text(
actionType.actionName,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 16,
color: COLOR_CONST.BLACK2,
),
)),
),
],
),
));
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 2,
childAspectRatio: 16 / 6,
children: actions.map(
(item) {
return _createShrimpUpdate(item);
},
).toList()),
);
}
}

class ActionType {
Widget addScreen;
Widget listScreen;
String actionName;
ActionType(String actionName, Widget addScreen, Widget listScreen) {
this.actionName = actionName;
this.addScreen = addScreen;
this.listScreen = listScreen;
}
}

+ 54
- 0
lib/presentation/screens/plot_detail/sc_plot_detail.dart View File

import 'package:farm_tpf/presentation/custom_widgets/widget_rounded_rect_indicator.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_action.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_information.dart';
import 'package:farm_tpf/utils/const_color.dart';
import 'package:flutter/material.dart';

class PlotDetailScreen extends StatefulWidget {
@override
_PlotDetailScreenState createState() => _PlotDetailScreenState();
}

class _PlotDetailScreenState extends State<PlotDetailScreen> {
@override
Widget build(BuildContext context) {
return Container(
color: COLOR_CONST.ITEM_BG,
child: SafeArea(
top: false,
bottom: true,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Chi tiết lô"),
),
body: DefaultTabController(
length: 2,
child: new Scaffold(
backgroundColor: COLOR_CONST.ITEM_BG,
body: TabBarView(
children: [PlotInformationScreen(), PlotActionScreen()],
),
bottomNavigationBar: new TabBar(
tabs: [
Tab(
text: "Thông tin",
),
Tab(
text: "Canh tác",
),
],
labelColor: COLOR_CONST.DEFAULT,
unselectedLabelColor: COLOR_CONST.GRAY1_70,
indicatorSize: TabBarIndicatorSize.label,
indicator: RoundedRectIndicator(
color: COLOR_CONST.DEFAULT,
radius: 2,
padding: 22,
weight: 3.0),
),
),
),
)));
}
}

+ 15
- 0
lib/presentation/screens/plot_detail/sc_plot_information.dart View File

import 'package:flutter/material.dart';

class PlotInformationScreen extends StatefulWidget {
@override
_PlotInformationScreenState createState() => _PlotInformationScreenState();
}

class _PlotInformationScreenState extends State<PlotInformationScreen> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("Thông tin lô"),
);
}
}

+ 11
- 0
lib/utils/const_string.dart View File

const String app_name = "app name"; const String app_name = "app name";
const String plot_action_nursery = "Ươm";
const String plot_action_plant = "Trồng";
const String plot_action_crop_status = "Thực trạng cây trồng";
const String plot_action_environment_update = "Cập nhật môi trường";
const String plot_action_dung = "Bón phân";
const String plot_action_spraying = "Phun thuốc BVTV";
const String plot_action_disease = "Điều tra dịch hại";
const String plot_action_use_water = "Sử dụng nước";
const String plot_action_other = "Hoạt động khác";
const String plot_action_harvest = "Thu hoạch";
const String plot_action_finish = "Kết thúc canh tác";

+ 49
- 0
pubspec.lock View File

url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.0.1" version: "6.0.1"
flutter_plugin_android_lifecycle:
dependency: "direct main"
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.8"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.14.0+3" version: "0.14.0+3"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.12" version: "2.1.12"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.7+4"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
intl: intl:
dependency: transitive dependency: transitive
description: description:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.8" version: "2.0.8"
video_player:
dependency: "direct main"
description:
name: video_player
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.11+2"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
video_player_web:
dependency: transitive
description:
name: video_player_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+2"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:

+ 6
- 0
pubspec.yaml View File

environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.7.0 <3.0.0"


module:
androidX: true

dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
pattern_formatter: ^1.0.2 pattern_formatter: ^1.0.2
rxdart: ^0.23.0 rxdart: ^0.23.0
barcode_scan: ^3.0.1 barcode_scan: ^3.0.1
image_picker: ^0.6.2+3
video_player: ^0.10.11+2
flutter_plugin_android_lifecycle: ^1.0.4


dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

Loading…
Cancel
Save