Browse Source

take photo and recording video with plugin camera

master
daivph 5 years ago
parent
commit
a660de8819
7 changed files with 475 additions and 13 deletions
  1. +12
    -0
      ios/Podfile.lock
  2. +10
    -1
      lib/main.dart
  3. +386
    -0
      lib/presentation/custom_widgets/camera_helper.dart
  4. +20
    -6
      lib/presentation/custom_widgets/widget_media_helper.dart
  5. +11
    -1
      lib/presentation/screens/login/view/login_page.dart
  6. +27
    -4
      pubspec.lock
  7. +9
    -1
      pubspec.yaml

+ 12
- 0
ios/Podfile.lock View File

- Flutter - Flutter
- MTBBarcodeScanner - MTBBarcodeScanner
- SwiftProtobuf - SwiftProtobuf
- camera (0.0.1):
- Flutter
- Firebase/CoreOnly (6.26.0): - Firebase/CoreOnly (6.26.0):
- FirebaseCore (= 6.7.2) - FirebaseCore (= 6.7.2)
- Firebase/Messaging (6.26.0): - Firebase/Messaging (6.26.0):
- nanopb/encode (1.30906.0) - nanopb/encode (1.30906.0)
- package_info (0.0.1): - package_info (0.0.1):
- Flutter - Flutter
- path_provider (0.0.1):
- Flutter
- PromisesObjC (1.2.10) - PromisesObjC (1.2.10)
- Protobuf (3.13.0) - Protobuf (3.13.0)
- shared_preferences (0.0.1): - shared_preferences (0.0.1):


DEPENDENCIES: DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`) - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- camera (from `.symlinks/plugins/camera/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- image_picker (from `.symlinks/plugins/image_picker/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`) - package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`) - video_player (from `.symlinks/plugins/video_player/ios`)


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"
firebase_core: firebase_core:
:path: ".symlinks/plugins/firebase_core/ios" :path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging: firebase_messaging:
:path: ".symlinks/plugins/image_picker/ios" :path: ".symlinks/plugins/image_picker/ios"
package_info: package_info:
:path: ".symlinks/plugins/package_info/ios" :path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
shared_preferences: shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios" :path: ".symlinks/plugins/shared_preferences/ios"
video_player: video_player:


SPEC CHECKSUMS: SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479 barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
camera: a0ca5080336f7af47b88436e5e26da3dee5568f0
Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6 Firebase: 7cf5f9c67f03cb3b606d1d6535286e1080e57eb6
firebase_core: 3134fe79d257d430f163b558caf52a10a87efe8a firebase_core: 3134fe79d257d430f163b558caf52a10a87efe8a
firebase_messaging: 6061cbdfe4463502a0d4d7049820c25d1757a095 firebase_messaging: 6061cbdfe4463502a0d4d7049820c25d1757a095
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151 PromisesObjC: b14b1c6b68e306650688599de8a45e49fae81151
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748 Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d

+ 10
- 1
lib/main.dart View File

import 'package:barcode_scan/barcode_scan.dart'; import 'package:barcode_scan/barcode_scan.dart';
import 'package:camera/camera.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart'; import 'package:farm_tpf/presentation/screens/plot_detail/bloc/plot_detail_bloc.dart';
import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'data/repository/authentication_repository.dart'; import 'data/repository/authentication_repository.dart';
import 'data/repository/repository.dart'; import 'data/repository/repository.dart';


void main() {
List<CameraDescription> cameras = [];
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
} on CameraException catch (e) {
print(e.description);
}
runApp(App(authenticationRepository: AuthenticationRepository())); runApp(App(authenticationRepository: AuthenticationRepository()));
} }



+ 386
- 0
lib/presentation/custom_widgets/camera_helper.dart View File

import 'dart:io';

import 'package:camera/camera.dart';
import 'package:farm_tpf/main.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:path_provider/path_provider.dart';

class CameraHelper extends StatefulWidget {
@override
_CameraHelperState createState() => _CameraHelperState();
}

/// Returns a suitable camera icon for [direction].
IconData getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return Icons.camera_rear;
case CameraLensDirection.front:
return Icons.camera_front;
case CameraLensDirection.external:
return Icons.camera;
}
throw ArgumentError('Unknown lens direction');
}

void logError(String code, String message) =>
print('Error: $code\nError Message: $message');

class _CameraHelperState extends State<CameraHelper>
with WidgetsBindingObserver {
CameraController controller;
String imagePath;
String videoPath;
VideoPlayerController videoController;
VoidCallback videoPlayerListener;
bool enableAudio = true;
int indexCamera = 0;

@override
void initState() {
super.initState();
controller =
CameraController(cameras[indexCamera], ResolutionPreset.medium);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
WidgetsBinding.instance.addObserver(this);
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// App state changed before we got the chance to initialize.
if (controller == null || !controller.value.isInitialized) {
return;
}
if (state == AppLifecycleState.inactive) {
controller?.dispose();
} else if (state == AppLifecycleState.resumed) {
if (controller != null) {
onNewCameraSelected(controller.description);
}
}
}

final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: SafeArea(
top: false,
bottom: false,
child: Column(
children: <Widget>[
Expanded(
child: Container(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Center(
child: _cameraPreviewWidget(),
),
),
decoration: BoxDecoration(
color: Colors.black,
border: Border.all(
color:
controller != null && controller.value.isRecordingVideo
? Colors.redAccent
: Colors.grey,
width:
controller != null && controller.value.isRecordingVideo
? 1.0
: 0.0,
),
),
),
),
_captureControlRowWidget(),
],
),
),
);
}

/// Display the preview from the camera (or a message if the preview is not available).
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Đang mở camera ....',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
} else {
return AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
);
}
}

/// Display the control bar with buttons to take pictures and record videos.
Widget _captureControlRowWidget() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Get.back();
}),
_cameraTogglesRowWidget(),
IconButton(
icon: const Icon(Icons.camera_alt),
color: Colors.blue,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo
? onTakePictureButtonPressed
: null,
),
IconButton(
icon: const Icon(Icons.videocam),
color: Colors.blue,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo
? onVideoRecordButtonPressed
: null,
),
IconButton(
icon: controller != null && controller.value.isRecordingPaused
? Icon(Icons.play_arrow)
: Icon(Icons.pause),
color: Colors.blue,
onPressed: controller != null &&
controller.value.isInitialized &&
controller.value.isRecordingVideo
? (controller != null && controller.value.isRecordingPaused
? onResumeButtonPressed
: onPauseButtonPressed)
: null,
),
IconButton(
icon: const Icon(Icons.stop),
color: Colors.red,
onPressed: controller != null &&
controller.value.isInitialized &&
controller.value.isRecordingVideo
? onStopButtonPressed
: null,
)
],
);
}

/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget() {
if (cameras.isEmpty) {
return const Text('Không có camera');
} else {
bool disableSwitch =
controller != null && controller.value.isRecordingVideo;
if (indexCamera == cameras.length - 1) {
indexCamera = 0;
} else {
indexCamera++;
}
return IconButton(
icon: Icon(
Icons.switch_camera,
color: Colors.green,
),
onPressed: disableSwitch == true
? null
: () {
onNewCameraSelected(cameras[indexCamera]);
});
}
}

String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

void showInSnackBar(String message) {
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message)));
}

void onNewCameraSelected(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = CameraController(
cameraDescription,
ResolutionPreset.medium,
enableAudio: enableAudio,
);

// If the controller is updated then update the UI.
controller.addListener(() {
if (mounted) setState(() {});
if (controller.value.hasError) {
showInSnackBar('Lỗi camera: ${controller.value.errorDescription}');
}
});

try {
await controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}

if (mounted) {
setState(() {});
}
}

void onTakePictureButtonPressed() {
takePicture().then((String filePath) {
if (mounted) {
setState(() {
imagePath = filePath;
videoController?.dispose();
videoController = null;
});
if (filePath != null) print('Picture saved to $filePath');
}
});
}

void onVideoRecordButtonPressed() {
startVideoRecording().then((String filePath) {
if (mounted) setState(() {});
if (filePath != null) print('Saving video to $filePath');
});
}

void onStopButtonPressed() {
stopVideoRecording().then((_) {
if (mounted) setState(() {});
print('Video recorded to: $videoPath');
});
}

void onPauseButtonPressed() {
pauseVideoRecording().then((_) {
if (mounted) setState(() {});
print('Video recording paused');
});
}

void onResumeButtonPressed() {
resumeVideoRecording().then((_) {
if (mounted) setState(() {});
print('Video recording resumed');
});
}

Future<String> startVideoRecording() async {
if (!controller.value.isInitialized) {
showInSnackBar('Vui lòng chọn camera');
return null;
}

final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/Movies/tpf';
await Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.mp4';

if (controller.value.isRecordingVideo) {
// A recording is already started, do nothing.
return null;
}

try {
videoPath = filePath;
await controller.startVideoRecording(filePath);
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
return filePath;
}

Future<void> stopVideoRecording() async {
if (!controller.value.isRecordingVideo) {
return null;
}

try {
await controller.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}

Future<void> pauseVideoRecording() async {
if (!controller.value.isRecordingVideo) {
return null;
}

try {
await controller.pauseVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}

Future<void> resumeVideoRecording() async {
if (!controller.value.isRecordingVideo) {
return null;
}

try {
await controller.resumeVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}

Future<String> takePicture() async {
if (!controller.value.isInitialized) {
showInSnackBar('Vui lòng chọn camera');
return null;
}
final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/Pictures/tpf';
await Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';

if (controller.value.isTakingPicture) {
// A capture is already pending, do nothing.
return null;
}

try {
await controller.takePicture(filePath);
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
return filePath;
}

void _showCameraException(CameraException e) {
logError(e.code, e.description);
showInSnackBar('Lỗi: ${e.code}\n${e.description}');
}
}

+ 20
- 6
lib/presentation/custom_widgets/widget_media_helper.dart View File

), ),
defaultTargetPlatform == TargetPlatform.android defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>( ? FutureBuilder<void>(
future: retrieveLostData(),
future: retrieveLostData(context),
builder: (BuildContext context, builder: (BuildContext context,
AsyncSnapshot<void> snapshot) { AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) { switch (snapshot.connectionState) {
Future<void> _playVideo(PickedFile file) async { Future<void> _playVideo(PickedFile file) async {
if (file != null && mounted) { if (file != null && mounted) {
await _disposeVideoController(); await _disposeVideoController();
File f = File(file.path);
_controller = VideoPlayerController.file(File(file.path)); _controller = VideoPlayerController.file(File(file.path));
await _controller.setVolume(1.0); await _controller.setVolume(1.0);
await _controller.initialize(); await _controller.initialize();
await _controller.setLooping(true);
await _controller.setLooping(false);
await _controller.play(); await _controller.play();
} }
} }
await _controller.setVolume(0.0); await _controller.setVolume(0.0);
} }
if (isVideo) { if (isVideo) {
final PickedFile file = await _picker.getVideo(
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
// final video = await FilePicker.getFile(type: FileType.video);
final PickedFile pickedFile = await _picker.getVideo(source: source);
Get.find<ChangeImageController>().updateFile(pickedFile);
Media newMedia = Media()
..isVideo = false
..isServerFile = false
..pathFile = pickedFile.path;
currentItems.add(newMedia);
print(pickedFile.path);
files.add(pickedFile.path);
_playVideo(pickedFile);
// BlocProvider.of<MediaHelperBloc>(context)
// ..add(ChangeListMedia(items: currentItems));
// widget.onChangeFiles(files);
} else { } else {
await _displayPickImageDialog(context, await _displayPickImageDialog(context,
(double maxWidth, double maxHeight, int quality) async { (double maxWidth, double maxHeight, int quality) async {
}); });
} }


Future<void> retrieveLostData() async {
Future<void> retrieveLostData(
BuildContext context,
) async {
final LostData response = await _picker.getLostData(); final LostData response = await _picker.getLostData();
if (response.isEmpty) { if (response.isEmpty) {
return; return;

+ 11
- 1
lib/presentation/screens/login/view/login_page.dart View File

import 'package:farm_tpf/data/repository/authentication_repository.dart'; import 'package:farm_tpf/data/repository/authentication_repository.dart';
import 'package:farm_tpf/presentation/custom_widgets/camera_helper.dart';
import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart'; import 'package:farm_tpf/presentation/screens/login/bloc/login_bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:keyboard_dismisser/keyboard_dismisser.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart';


import 'login_form.dart'; import 'login_form.dart';
); );
}, },
child: ListView( child: ListView(
children: <Widget>[WidgetTopWelcome(), LoginForm()],
children: <Widget>[
WidgetTopWelcome(),
LoginForm(),
IconButton(
icon: Icon(Icons.cake),
onPressed: () {
Get.to(CameraHelper());
})
],
), ),
), ),
), ),

+ 27
- 4
pubspec.lock View File

url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "7.1.0" version: "7.1.0"
camera:
dependency: "direct main"
description:
name: camera
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.8+5"
change_app_package_name: change_app_package_name:
dependency: "direct main" dependency: "direct main"
description: description:
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.7+7"
path: "packages/image_picker/image_picker"
ref: "9cac5347d9ab9d111a918a8154fb060565b1bf31"
resolved-ref: "9cac5347d9ab9d111a918a8154fb060565b1bf31"
url: "https://github.com/miguelpruivo/plugins"
source: git
version: "0.6.7+5"
image_picker_platform_interface: image_picker_platform_interface:
dependency: transitive dependency: transitive
description: description:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.7.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.14"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.1+2" version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+4"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:

+ 9
- 1
pubspec.yaml View File

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.7+7
#https://github.com/flutter/plugins/pull/2860
image_picker:
git:
url: https://github.com/miguelpruivo/plugins
ref: 9cac5347d9ab9d111a918a8154fb060565b1bf31
path: packages/image_picker/image_picker
video_player: ^0.10.11+2 video_player: ^0.10.11+2
flutter_plugin_android_lifecycle: ^1.0.4 flutter_plugin_android_lifecycle: ^1.0.4
shimmer: ^1.1.1 shimmer: ^1.1.1
http_parser: ^3.1.4 http_parser: ^3.1.4
rflutter_alert: ^1.1.0 rflutter_alert: ^1.1.0


camera: ^0.5.8+5
path_provider: ^1.6.14

dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

Loading…
Cancel
Save