| 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 |
| <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" |
| include ':app' |
| - 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 | ||||
| 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 = ( |
| <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> |
| 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); | |||||
| } | |||||
| } |
| 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(); | |||||
| } | |||||
| } | |||||
| } |
| 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"), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } |
| 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())); | |||||
| }), | |||||
| ], | ], | ||||
| ), | ), | ||||
| ), | ), |
| 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; | |||||
| } | |||||
| } |
| 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), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ))); | |||||
| } | |||||
| } |
| 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ô"), | |||||
| ); | |||||
| } | |||||
| } |
| 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"; |
| 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: |
| 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: |