Skip to content

Instantly share code, notes, and snippets.

@mhassanist
Created February 27, 2023 18:17
Show Gist options
  • Save mhassanist/1a7ace0d8d3a511a237698a317f57071 to your computer and use it in GitHub Desktop.
Save mhassanist/1a7ace0d8d3a511a237698a317f57071 to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:camera/camera.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart';
import 'package:geocoding/geocoding.dart';
import 'package:intl/intl.dart';
import 'package:location/location.dart' as location;
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:skycap/data/models/job_site_model.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart';
import 'package:video_player/video_player.dart';
import '../../data/models/manual_classify_upload_item.dart';
import '../../providers/manual_classify_bloc.dart';
import '../../providers/shared_preference_provider.dart';
import '../../utils/ui_utils.dart';
import '../screens/manual_classification/upload_screen_bottom_bar.dart';
import 'compass_widget.dart';
class JobSiteCamera extends StatefulWidget {
final List<CameraDescription> cameras;
final JobSite? project;
JobSiteCamera(this.cameras, this.project);
@override
_JobSiteCameraState createState() {
return _JobSiteCameraState();
}
}
void logError(String code, String? message) {
if (message != null) {
print('Error: $code\nError Message: $message');
} else {
print('Error: $code');
}
}
class _JobSiteCameraState extends State<JobSiteCamera>
with WidgetsBindingObserver, TickerProviderStateMixin {
CameraController? controller;
XFile? imageOrVideoFile;
File? fileWithNewDirectory;
List<XFile> filesList = [];
List<File> filesWithNewDirectoryList = [];
VideoPlayerController? videoController;
VoidCallback? videoPlayerListener;
bool enableAudio = false;
late AnimationController _flashModeControlRowAnimationController;
late Animation<double> _flashModeControlRowAnimation;
late AnimationController _exposureModeControlRowAnimationController;
late AnimationController _focusModeControlRowAnimationController;
double _minAvailableZoom = 1.0;
double _maxAvailableZoom = 1.0;
double _currentScale = 1.0;
double _baseScale = 1.0;
bool isVideo = false;
List<ManualClassifyUploadItem> manualClassifyItemList = [];
ManualClassifyUploadItem? manualClassifyUploadItem;
String azimuth = '';
// Counting pointers (number of user fingers on screen)
int _pointers = 0;
location.LocationData? _locationData;
location.LocationData? _locationData2;
Placemark? address;
location.Location _location = location.Location();
ConnectivityResult? _connectivityResult;
late StreamSubscription _connectivitySubscription;
Color whiteColor = Colors.white;
location.PermissionStatus? _permissionGranted;
Future<Placemark> getAddressFromLatAndLong(location.LocationData position)async {
List<Placemark> placeMark = await placemarkFromCoordinates(position.latitude!, position.longitude!);
return placeMark[0];
}
Future<void> _showExitCameraDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Warning'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('Captured files will be deleted.'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('upload'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Delete'),
onPressed: () {
_deleteFiles();
Navigator.of(context).pop();
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _deleteFiles(){
for(var xFile in filesList){
final dir = Directory(xFile.path);
dir.deleteSync(recursive: true);
}
for(var file in filesWithNewDirectoryList){
final dir = Directory(file.path);
dir.deleteSync(recursive: true);
}
}
final StopWatchTimer _stopWatchTimer = StopWatchTimer(
mode: StopWatchMode.countUp,
onChange: (value) => print('onChange $value'),
onChangeRawSecond: (value) => print('onChangeRawSecond $value'),
onChangeRawMinute: (value) => print('onChangeRawMinute $value'),
);
void getLocationPermission()async{
_permissionGranted = await location.Location().hasPermission();
if (_permissionGranted == location.PermissionStatus.denied) {
_permissionGranted = await location.Location().requestPermission();
if (_permissionGranted != location.PermissionStatus.granted) {
return;
}
}
}
@override
void initState() {
super.initState();
onNewCameraSelected(widget.cameras.first);
_ambiguate(WidgetsBinding.instance)?.addObserver(this);
_flashModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_flashModeControlRowAnimation = CurvedAnimation(
parent: _flashModeControlRowAnimationController,
curve: Curves.easeInCubic,
);
_exposureModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_focusModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_connectivitySubscription = Connectivity().onConnectivityChanged.listen((
ConnectivityResult result
) {
_connectivityResult = result;
});
_stopWatchTimer.rawTime.listen((value) =>
print('rawTime $value ${StopWatchTimer.getDisplayTime(value)}'));
_stopWatchTimer.minuteTime.listen((value) => print('minuteTime $value'));
_stopWatchTimer.secondTime.listen((value) => print('secondTime $value'));
_stopWatchTimer.records.listen((value) => print('records $value'));
}
@override
void dispose() async{
_ambiguate(WidgetsBinding.instance)?.removeObserver(this);
_flashModeControlRowAnimationController.dispose();
_exposureModeControlRowAnimationController.dispose();
controller!.dispose();
_connectivitySubscription.cancel();
await _stopWatchTimer.dispose();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
final CameraController? cameraController = controller;
// App state changed before we got the chance to initialize.
if (cameraController == null || !cameraController.value.isInitialized) {
return;
}
if (state == AppLifecycleState.inactive) {
cameraController.dispose();
} else if (state == AppLifecycleState.resumed) {
onNewCameraSelected(cameraController.description);
}
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: ()async{
if(filesList.isEmpty){
Navigator.of(context).pop();
}else{
_showExitCameraDialog();
}
return true;
},
child: SafeArea(
child: Material(
color: Colors.transparent,
child: Stack(
children: [
_cameraPreviewWidget(),
_buildLocationAndCompassInfo(),
_buildCameraControlSetting(),
_buildVideoTimerCountField(),
BackButton(
color: whiteColor,
onPressed: (){
if(filesList.isEmpty){
Navigator.of(context).pop();
}else{
_showExitCameraDialog();
}
},
),
],
),
),
),
);
}
_buildCameraControlSetting() {
return Container(
color: Colors.transparent,
padding: EdgeInsets.only(left: 10.0, right: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
_captureControlRowWidget(),
//_modeControlRowWidget(),
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_cameraTogglesRowWidget(),
_buildSubmitButton(),
//_thumbnailWidget(),
],
),
),
],
),
);
}
_buildLocationAndCompassInfo() {
return Align(
alignment: Alignment.topCenter,
child: Container(
color: Colors.black26,
height: 140,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Center(
child: _buildJobSiteIdText(),
),
SizedBox(height: 10.0,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StreamBuilder(
stream: _location.onLocationChanged,
builder: (context, snapShot) {
if (snapShot.hasData) {
_locationData = snapShot.data as location.LocationData?;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_locationData == null
? ""
: "lat: ${_locationData!.latitude}",
style: TextStyle(color: whiteColor, fontSize: 18),
),
Text(
_locationData == null
? ""
: "long: ${_locationData!.longitude}",
style: TextStyle(color: whiteColor, fontSize: 18),
),
FutureBuilder(
future: getAddressFromLatAndLong(_locationData!),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasData){
address = snapshot.data as Placemark?;
return Container(
width: MediaQuery.of(context).size.width/2,
child: Text('Address: ${address!.street},'
'${address!.administrativeArea},'
'${address!.isoCountryCode}',maxLines: 2,overflow: TextOverflow.clip,
style: TextStyle(color: whiteColor,
fontSize: 18,)),
);
}
}
return Text('');
}
)
],
);
}
return Text('');
}),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
CompassWidget(_getAzimuthValue),
StreamBuilder(
stream: _location.onLocationChanged,
builder: (context, snapshot) {
if(snapshot.hasData){
_locationData2 = snapshot.data as location.LocationData?;
return Text(
_locationData2 == null
? ""
: "Elevation: ${_locationData2!.altitude!.toStringAsFixed(2)}'",
style: TextStyle(
color: whiteColor, fontSize: 18),
);
}else{
return Text('');
}
})
],
),
),
],
),
],
),
),
),
);
}
/// Display the preview from the camera (or a message if the preview is not available).
Widget _cameraPreviewWidget() {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
return Center(
child: Text(
'Tap a camera',
style: TextStyle(
color: whiteColor,
fontSize: 24.0,
fontWeight: FontWeight.w900,
),
),
);
} else {
return Listener(
onPointerDown: (_) => _pointers++,
onPointerUp: (_) => _pointers--,
child: CameraPreview(
controller!,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
getLocationPermission();
return GestureDetector(
behavior: HitTestBehavior.opaque,
onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate,
onTapDown: (TapDownDetails details) =>
onViewFinderTap(details, constraints),
);
}),
),
);
}
}
void _handleScaleStart(ScaleStartDetails details) {
_baseScale = _currentScale;
}
Future<void> _handleScaleUpdate(ScaleUpdateDetails details) async {
// When there are not exactly two fingers on screen don't scale
if (controller == null || _pointers != 2) {
return;
}
_currentScale = (_baseScale * details.scale)
.clamp(_minAvailableZoom, _maxAvailableZoom);
await controller!.setZoomLevel(_currentScale);
}
/// Display a bar with buttons to change the flash and exposure modes
Widget _flashModeControlRowWidget() {
return SizeTransition(
sizeFactor: _flashModeControlRowAnimation,
child: ClipRect(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: const Icon(Icons.flash_off),
color: controller?.value.flashMode == FlashMode.off
? Colors.orange
: whiteColor,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.off)
: null,
),
IconButton(
icon: const Icon(Icons.flash_auto),
color: controller?.value.flashMode == FlashMode.auto
? Colors.orange
: whiteColor,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.auto)
: null,
),
IconButton(
icon: const Icon(Icons.flash_on),
color: controller?.value.flashMode == FlashMode.always
? Colors.orange
: whiteColor,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.always)
: null,
),
IconButton(
icon: const Icon(Icons.highlight),
color: controller?.value.flashMode == FlashMode.torch
? Colors.orange
: whiteColor,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.torch)
: null,
),
],
),
),
);
}
/// Display the control bar with buttons to take pictures and record videos.
Widget _captureControlRowWidget() {
final CameraController? cameraController = controller;
return Column(
children: [
cameraController != null &&
cameraController.value.isPreviewPaused
? IconButton(
icon: Icon(
Icons.cancel,
color: whiteColor,
),
iconSize: 80,
onPressed: ()async{
filesList.remove(imageOrVideoFile);
filesWithNewDirectoryList.remove(fileWithNewDirectory);
manualClassifyItemList.remove(manualClassifyUploadItem);
final dir = Directory(imageOrVideoFile!.path);
dir.deleteSync(recursive: true);
final newDir = Directory(fileWithNewDirectory!.path);
newDir.deleteSync(recursive: true);
imageOrVideoFile = null;
fileWithNewDirectory = null;
manualClassifyUploadItem = null;
await cameraController.resumePreview();
},
) : SizedBox(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: const Icon(Icons.flash_on, size: 30),
color: whiteColor,
onPressed: controller != null ? onFlashModeButtonPressed : null,
),
isVideo == true
? Expanded(
child: Stack(
alignment: Alignment.topCenter,
children: [
Center(
child: IconButton(
icon: Icon(
cameraController != null &&
cameraController.value.isInitialized &&
cameraController.value.isRecordingVideo
? Icons.stop_circle_outlined
: Icons.circle,
color: cameraController != null &&
cameraController.value.isInitialized &&
cameraController.value.isRecordingVideo
? Colors.red
: whiteColor,
),
iconSize: 80,
onPressed: cameraController != null &&
cameraController.value.isInitialized
? !cameraController.value.isRecordingVideo
? onVideoRecordButtonPressed
: onStopButtonPressed
: null,
),
),
Padding(
padding: EdgeInsets.only(left: 60),
child: Text(
filesList.length == 0
? ""
: filesList.length.toString(),
style: TextStyle(color: whiteColor,fontSize: 18),
)),
],
),
)
: cameraController != null &&
cameraController.value.isPreviewPaused
? Expanded(
child: IconButton(
iconSize: 80,
icon: const Icon(Icons.check_circle),
color: whiteColor,
onPressed: cameraController.value.isInitialized
? onPausePreviewButtonPressed
: null,
),
)
: Expanded(
child: Stack(
alignment: Alignment.topCenter,
children: [
Center(
child: IconButton(
icon: Icon(
Icons.circle,
color: whiteColor,
),
iconSize: 80,
onPressed: cameraController != null &&
cameraController.value.isInitialized &&
!cameraController.value.isRecordingVideo
? onTakePictureButtonPressed
: null,
),
),
Padding(
padding: EdgeInsets.only(left: 60),
child: Text(
filesList.length == 0
? ""
: filesList.length.toString(),
style: TextStyle(color: whiteColor,fontSize: 18),
)),
],
),
),
_buildCameraChangeLens(),
],
),
_flashModeControlRowWidget(),
],
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget() {
Widget toggles = Container();
if (widget.cameras.isEmpty) {
return const Text('No camera found');
} else {
toggles = Row(
children: [
Icon(
Icons.camera_alt,
size: 30,
color: whiteColor,
),
Switch(
onChanged: (bool value) {
setState(() {
isVideo = !isVideo;
});
},
value: isVideo,
),
Icon(
Icons.videocam,
size: 30,
color: whiteColor,
)
],
);
}
return toggles;
}
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
void showInSnackBar(String message) {
// ignore: deprecated_member_use
_scaffoldKey.currentState?.showSnackBar(SnackBar(content: Text(message)));
}
void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) {
if (controller == null) {
return;
}
final CameraController cameraController = controller!;
final Offset offset = Offset(
details.localPosition.dx / constraints.maxWidth,
details.localPosition.dy / constraints.maxHeight,
);
cameraController.setExposurePoint(offset);
cameraController.setFocusPoint(offset);
}
Future<void> onNewCameraSelected(CameraDescription cameraDescription) async {
if (controller != null) {
await controller!.dispose();
}
final CameraController cameraController = CameraController(
cameraDescription,
ResolutionPreset.high,
enableAudio: enableAudio,
imageFormatGroup: ImageFormatGroup.jpeg,
);
controller = cameraController;
// If the controller is updated then update the UI.
cameraController.addListener(() {
if (mounted) {
setState(() {});
}
if (cameraController.value.hasError) {
showInSnackBar(
'Camera error ${cameraController.value.errorDescription}');
}
});
try {
await cameraController.initialize();
await Future.wait(<Future<Object?>>[
// The exposure mode is currently not supported on the web.
cameraController
.getMaxZoomLevel()
.then((double value) => _maxAvailableZoom = value),
cameraController
.getMinZoomLevel()
.then((double value) => _minAvailableZoom = value),
]);
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
void onTakePictureButtonPressed() {
takePicture().then((XFile? file) async {
if (mounted) {
setState(() {
imageOrVideoFile = file;
videoController?.dispose();
videoController = null;
});
if (file != null) {
if(Platform.isAndroid){
Uint8List exportImage = await file.readAsBytes();
Directory? directory = (await getExternalStorageDirectory());
Directory d = await Directory('${directory!.path}/Sky-cap/'
'${widget.project!.site!.code! + " " + widget.project!.site!.name!}'
'/${DateFormat('yyyy-MM-dd').format(DateTime.now())}/').create(recursive: true).catchError(
(e){
print(e);
});
final fullPath = '${d.path}${file.name}';
final imgFile = File('$fullPath');
try{
imgFile.writeAsBytesSync(exportImage);
}catch(e){
print(e);
}
fileWithNewDirectory = imgFile;
filesList.add(file);
filesWithNewDirectoryList.add(imgFile);
manualClassifyUploadItem = _putManualClassifyItem(imgFile);
manualClassifyItemList.add(manualClassifyUploadItem!);
showInSnackBar('Picture saved to ${file.path}');
}
}
}
onPausePreviewButtonPressed();
});
}
void onFlashModeButtonPressed() {
if (_flashModeControlRowAnimationController.value == 1) {
_flashModeControlRowAnimationController.reverse();
} else {
_flashModeControlRowAnimationController.forward();
_exposureModeControlRowAnimationController.reverse();
_focusModeControlRowAnimationController.reverse();
}
}
void onSetFlashModeButtonPressed(FlashMode mode) {
setFlashMode(mode).then((_) {
if (mounted) {
setState(() {});
}
showInSnackBar('Flash mode set to ${mode.toString().split('.').last}');
});
}
void onVideoRecordButtonPressed() {
_stopWatchTimer.onExecute
.add(StopWatchExecute.start);
startVideoRecording().then((_) {
if (mounted) {
setState(() {});
}
});
}
void onStopButtonPressed() {
_stopWatchTimer.onExecute
.add(StopWatchExecute.reset);
stopVideoRecording().then((XFile? file) async {
if (mounted) {
setState(() {});
}
if (file != null) {
if (Platform.isAndroid) {
Uint8List exportImage = await file.readAsBytes();
Directory? directory = (await getExternalStorageDirectory());
Directory d = await Directory(
'${directory!.path}/Sky-cap/'
'${widget.project!.site!.code! + " " + widget.project!.site!.name!}'
'/${DateFormat('yyyy-MM-dd').format(DateTime.now())}/')
.create(recursive: true)
.catchError((e) {
print(e);
});
final fullPath = '${d.path}${file.name}';
final imgFile = File('$fullPath');
try {
imgFile.writeAsBytesSync(exportImage);
} catch (e) {
print(e);
}
setState(() {
filesList.add(file);
imageOrVideoFile = file;
filesWithNewDirectoryList.add(imgFile);
fileWithNewDirectory = imgFile;
manualClassifyUploadItem = _putManualClassifyItem(imgFile);
manualClassifyItemList.add(manualClassifyUploadItem!);
});
showInSnackBar('Video recorded to ${file.path}');
}
//_startVideoPlayer();
}
});
}
Future<void> onPausePreviewButtonPressed() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return;
}
if (cameraController.value.isPreviewPaused) {
await cameraController.resumePreview();
} else {
await cameraController.pausePreview();
}
if (mounted) {
setState(() {});
}
}
Future<void> startVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return;
}
if (cameraController.value.isRecordingVideo) {
// A recording is already started, do nothing.
return;
}
try {
await cameraController.startVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return;
}
}
Future<XFile?> stopVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isRecordingVideo) {
return null;
}
try {
return cameraController.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
Future<void> setFlashMode(FlashMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setFlashMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setExposureMode(ExposureMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setExposureMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setFocusMode(FocusMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setFocusMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<XFile?> takePicture() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return null;
}
if (cameraController.value.isTakingPicture) {
// A capture is already pending, do nothing.
return null;
}
try {
final XFile file = await cameraController.takePicture();
return file;
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
void _showCameraException(CameraException e) {
logError(e.code, e.description);
showInSnackBar('Error: ${e.code}\n${e.description}');
}
_buildSubmitButton() {
return Expanded(
child: Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
onPressed: () async {
if(manualClassifyItemList.isNotEmpty){
for (var item in manualClassifyItemList) {
ManualClassifyUploadBloc().uploadSink.add(item);
}
if(_connectivityResult == ConnectivityResult.wifi
|| _connectivityResult == ConnectivityResult.mobile){
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => UploadScreenBottomBar(widget.project!)));
}else{
Navigator.pop(context);
}
}
}, child: Text('Finish'))),
);
}
_buildCameraChangeLens() {
if(widget.cameras.first == CameraDescription(name: '0', lensDirection: CameraLensDirection.back, sensorOrientation: 90)
&& widget.cameras[1] == CameraDescription(name: '1', lensDirection: CameraLensDirection.front, sensorOrientation: 90)){
return IconButton(
color: whiteColor,
onPressed: (){
onNewCameraSelected((controller!.description.lensDirection == CameraLensDirection.back)
? widget.cameras[1] : widget.cameras[0]);
},
icon: Icon((controller!.description.lensDirection == CameraLensDirection.back)
? Icons.camera_front : Icons.camera_rear),
iconSize: 30,);
}else{
return Container();
}
}
_buildJobSiteIdText() {
return Text('Job Site: '+widget.project!.site!.code! + " " + widget.project!.site!.name!,
style: TextStyle(color: whiteColor, fontSize: 18,fontWeight: FontWeight.bold));
}
void _getAzimuthValue(String value){
azimuth = value;
}
ManualClassifyUploadItem _putManualClassifyItem(File file) {
ManualClassifyUploadItem item = ManualClassifyUploadItem(
jobSiteIdValue: widget.project!.id!,
localFilePath: file.path,
fileSize: filesize(file.lengthSync()),
name: path.basename(file.path),
uniqueNameIdentifier:
Utils.prepFootageFileName(path.basename(file.path), null, null),
footageType:
Utils().getFootageType(fileExtension: path.extension(file.path)),
status: UploadStatus.notStarted,
uploader: LocalDataProvider().getLoggedInUser(),
uploadedAt: null,
queuedAt: DateTime.now(),
uploadProgress: "0",
latitude: _locationData!.latitude.toString(),
longitude: _locationData!.longitude.toString(),
elevation: _locationData2!.altitude.toString(),
azimuth: azimuth,
address: '${address!.street},'
'${address!.administrativeArea},'
'${address!.isoCountryCode}',
captureDate: Timestamp.fromDate(DateTime.now())
);
return item;
}
_buildVideoTimerCountField() {
return Positioned(
top: 145,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StreamBuilder<int>(
stream: _stopWatchTimer.rawTime,
initialData: _stopWatchTimer.rawTime.value,
builder: (context, snap) {
final value = snap.data!;
final displayTime = StopWatchTimer.getDisplayTime(value,
hours: false, milliSecond: false);
if (displayTime == '00:00') {
return Container();
} else {
return Row(
children: <Widget>[
Icon(
Icons.fiber_manual_record,
color: Colors.red,
),
Text(
displayTime,
style: const TextStyle(
fontSize: 20,
fontFamily: 'Helvetica',
color: Colors.red,
fontWeight: FontWeight.bold),
),
],
);
}
},
),
));
}
}
T? _ambiguate<T>(T? value) => value;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment