Browse Source

widget media helper

master
daivph 5 years ago
parent
commit
e796bfbdbf
5 changed files with 400 additions and 32 deletions
  1. +0
    -6
      ios/Podfile.lock
  2. +360
    -0
      lib/presentation/custom_widgets/widget_media_helper.dart
  3. +2
    -3
      lib/presentation/screens/plot_detail/sc_plot_information.dart
  4. +27
    -23
      lib/presentation/screens/slide_menu/home_drawer.dart
  5. +11
    -0
      lib/utils/const_string.dart

+ 0
- 6
ios/Podfile.lock View File

@@ -3,8 +3,6 @@ PODS:
- Flutter
- MTBBarcodeScanner
- SwiftProtobuf
- camera (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_plugin_android_lifecycle (0.0.1):
- Flutter
@@ -29,7 +27,6 @@ PODS:

DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- camera (from `.symlinks/plugins/camera/ios`)
- Flutter (from `Flutter`)
- flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
@@ -49,8 +46,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
barcode_scan:
:path: ".symlinks/plugins/barcode_scan/ios"
camera:
:path: ".symlinks/plugins/camera/ios"
Flutter:
:path: Flutter
flutter_plugin_android_lifecycle:
@@ -74,7 +69,6 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
camera: a0ca5080336f7af47b88436e5e26da3dee5568f0
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09

+ 360
- 0
lib/presentation/custom_widgets/widget_media_helper.dart View File

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

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

class WidgetMediaHelper extends StatefulWidget {
@override
_WidgetMediaHelperState createState() => _WidgetMediaHelperState();
}

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

final ImagePicker _picker = ImagePicker();

@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
_actionButton(),
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()),
],
));
}

Widget viewResult() {
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,
);
}
}
},
);
}

Widget multipleChoice() {
return CupertinoAlertDialog(
title: Text(label_title_select_media),
actions: <Widget>[
CupertinoDialogAction(
child: const Text(label_select_image_from_library),
onPressed: () {
Navigator.pop(context, 'Discard');
isVideo = false;
_onImageButtonPressed(ImageSource.gallery, context: context);
}),
CupertinoDialogAction(
child: const Text(label_take_photo),
onPressed: () {
Navigator.pop(context, 'Discard');
isVideo = false;
_onImageButtonPressed(ImageSource.camera, context: context);
}),
CupertinoDialogAction(
child: const Text(label_select_video_from_library),
onPressed: () {
Navigator.pop(context, 'Discard');
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
}),
CupertinoDialogAction(
child: const Text(label_record_video),
onPressed: () {
Navigator.pop(context, 'Discard');
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
}),
CupertinoDialogAction(
child: const Text(label_cancel),
textStyle: TextStyle(fontWeight: FontWeight.bold),
isDefaultAction: true,
onPressed: () {
Navigator.pop(context, 'Cancel');
}),
],
);
}

Widget _actionButton() {
return SizedBox(
width: double.infinity,
height: 55,
child: FlatButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Opacity(
child: multipleChoice(),
opacity: 1,
));
},
color: COLOR_CONST.DEFAULT,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(7.0),
),
child: Row(
children: <Widget>[
Icon(Icons.image),
Text(
button_add_media,
style: TextStyle(
fontWeight: FontWeight.bold, color: COLOR_CONST.WHITE),
)
],
),
),
);
}

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();
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), width: 100, height: 100);
} 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;
}
}

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

Future<void> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
onPick(null, null, null);
}
}

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 Container(
width: 100,
height: 100,
child: AspectRatio(
aspectRatio: controller.value?.aspectRatio,
child: VideoPlayer(controller),
),
);
} else {
return Container();
}
}
}

+ 2
- 3
lib/presentation/screens/plot_detail/sc_plot_information.dart View File

@@ -1,3 +1,4 @@
import 'package:farm_tpf/presentation/custom_widgets/widget_media_helper.dart';
import 'package:flutter/material.dart';

class PlotInformationScreen extends StatefulWidget {
@@ -8,8 +9,6 @@ class PlotInformationScreen extends StatefulWidget {
class _PlotInformationScreenState extends State<PlotInformationScreen> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("Thông tin lô"),
);
return Container(width: 200, child: WidgetMediaHelper());
}
}

+ 27
- 23
lib/presentation/screens/slide_menu/home_drawer.dart View File

@@ -132,30 +132,34 @@ class _HomeDrawerState extends State<HomeDrawer> {
height: 1,
color: COLOR_CONST.GRAY1,
),
Column(
children: <Widget>[
ListTile(
title: Text(
'Đăng xuất',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
),
textAlign: TextAlign.left,
),
trailing: Icon(
Icons.power_settings_new,
color: Colors.red,
),
onTap: () {
_clickSignOut();
},
),
SizedBox(
height: MediaQuery.of(context).padding.bottom,
)
],
Container(
child: Text("ss"),
width: 40,
),
// Column(
// children: <Widget>[
// ListTile(
// title: Text(
// 'Đăng xuất',
// style: TextStyle(
// fontWeight: FontWeight.w600,
// fontSize: 16,
// ),
// textAlign: TextAlign.left,
// ),
// trailing: Icon(
// Icons.power_settings_new,
// color: Colors.red,
// ),
// onTap: () {
// _clickSignOut();
// },
// ),
// SizedBox(
// height: MediaQuery.of(context).padding.bottom,
// )
// ],
// ),
],
),
);

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

@@ -10,3 +10,14 @@ 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";

//Common

const String label_title_select_media = "Chọn hoạt động";
const String button_add_media = "Thêm ảnh hoặc video";
const String label_select_image_from_library = "Chọn ảnh từ thư viện";
const String label_take_photo = "Chụp ảnh";
const String label_select_video_from_library = "Chọn video từ thư viện";
const String label_record_video = "Quay video";

const String label_cancel = "Huỷ";

Loading…
Cancel
Save