Skip to content
This repository was archived by the owner on May 27, 2025. It is now read-only.

Commit d9b3331

Browse files
committed
Added Upload Images Feature
1 parent 5ade6ed commit d9b3331

File tree

3 files changed

+182
-116
lines changed

3 files changed

+182
-116
lines changed

flutter-app/lib/camera.dart

Lines changed: 137 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
2020
import 'package:firebase_storage/firebase_storage.dart';
2121
import 'package:flutter/material.dart';
2222
import 'package:path_provider/path_provider.dart';
23+
import 'package:multi_media_picker/multi_media_picker.dart';
2324

2425
import 'countdown_timer.dart';
2526
import 'models.dart';
@@ -38,14 +39,21 @@ class Camera extends StatefulWidget {
3839
final String label;
3940
final String labelKey;
4041
final UserModel userModel;
41-
42-
Camera(this.dataset, this.label, this.labelKey, this.userModel);
42+
final bool isUploading;
43+
List<File> resultList;
44+
Camera(this.dataset, this.label, this.labelKey, this.userModel,
45+
this.isUploading);
4346

4447
Future init() async {
45-
try {
46-
cameras = await availableCameras();
47-
} on CameraException catch (e) {
48-
logError(e.code, e.description);
48+
if (!isUploading) {
49+
try {
50+
cameras = await availableCameras();
51+
} on CameraException catch (e) {
52+
logError(e.code, e.description);
53+
}
54+
} else {
55+
resultList =
56+
await MultiMediaPicker.pickImages(source: ImageSource.gallery);
4957
}
5058
}
5159

@@ -67,12 +75,14 @@ class _CameraState extends State<Camera> {
6775
@override
6876
void initState() {
6977
super.initState();
70-
WidgetsBinding.instance.addPostFrameCallback((_) {
71-
for (CameraDescription cameraDescription in cameras) {
72-
if (cameraDescription.lensDirection == CameraLensDirection.back)
73-
onNewCameraSelected(cameraDescription);
74-
}
75-
});
78+
if (!widget.isUploading) {
79+
WidgetsBinding.instance.addPostFrameCallback((_) {
80+
for (CameraDescription cameraDescription in cameras) {
81+
if (cameraDescription.lensDirection == CameraLensDirection.back)
82+
onNewCameraSelected(cameraDescription);
83+
}
84+
});
85+
}
7686
}
7787

7888
@override
@@ -83,54 +93,74 @@ class _CameraState extends State<Camera> {
8393

8494
@override
8595
Widget build(BuildContext context) {
96+
if (widget.isUploading && widget.resultList != null) {
97+
widget.resultList
98+
.forEach((eachImage) => {uploadImageToStorage(eachImage.path)});
99+
}
86100
return Scaffold(
87101
key: _scaffoldKey,
88102
appBar: AppBar(
89103
backgroundColor: Theme.of(context).accentColor,
90104
title: Text('Capture sample for ${widget.label}'),
91105
),
92-
body: Container(
93-
decoration: new BoxDecoration(color: Colors.black),
94-
child: Column(
95-
children: <Widget>[
96-
Expanded(
97-
child: Container(
98-
child: Padding(
99-
padding: const EdgeInsets.all(1.0),
100-
child: Center(
101-
child: _cameraPreviewWidget(),
102-
),
103-
),
104-
decoration: BoxDecoration(
105-
color: Colors.black,
106-
border: Border.all(
107-
color:
108-
controller != null && controller.value.isRecordingVideo
109-
? Colors.redAccent
110-
: Colors.black45,
111-
width: 2.0,
112-
),
113-
),
106+
body: widget.isUploading
107+
? Center(
108+
child: Column(
109+
mainAxisAlignment: MainAxisAlignment.center,
110+
crossAxisAlignment: CrossAxisAlignment.center,
111+
children: <Widget>[
112+
Text('Uploading Images in the background'),
113+
MaterialButton(
114+
onPressed: () {
115+
Navigator.pop(context);
116+
},
117+
child: Text('OK'),
118+
)
119+
],
114120
),
115-
),
116-
new CameraControlWidget(
117-
controller: controller,
118-
onRecordingStart: onVideoRecordButtonPressed,
119-
onRecordingStop: onStopButtonPressed,
120-
onPictureTaken: onTakePictureButtonPressed,
121-
),
122-
Padding(
123-
padding: const EdgeInsets.all(5.0),
124-
child: Row(
125-
mainAxisAlignment: MainAxisAlignment.start,
121+
)
122+
: Container(
123+
decoration: new BoxDecoration(color: Colors.black),
124+
child: Column(
126125
children: <Widget>[
127-
_thumbnailWidget(),
126+
Expanded(
127+
child: Container(
128+
child: Padding(
129+
padding: const EdgeInsets.all(1.0),
130+
child: Center(
131+
child: _cameraPreviewWidget(),
132+
),
133+
),
134+
decoration: BoxDecoration(
135+
color: Colors.black,
136+
border: Border.all(
137+
color: controller != null &&
138+
controller.value.isRecordingVideo
139+
? Colors.redAccent
140+
: Colors.black45,
141+
width: 2.0,
142+
),
143+
),
144+
),
145+
),
146+
new CameraControlWidget(
147+
controller: controller,
148+
onRecordingStart: onVideoRecordButtonPressed,
149+
onRecordingStop: onStopButtonPressed,
150+
onPictureTaken: onTakePictureButtonPressed,
151+
),
152+
Padding(
153+
padding: const EdgeInsets.all(5.0),
154+
child: Row(
155+
mainAxisAlignment: MainAxisAlignment.start,
156+
children: <Widget>[
157+
_thumbnailWidget(),
158+
],
159+
),
160+
),
128161
],
129162
),
130163
),
131-
],
132-
),
133-
),
134164
);
135165
}
136166

@@ -200,60 +230,7 @@ class _CameraState extends State<Camera> {
200230

201231
void onTakePictureButtonPressed() async {
202232
final filePath = await takePicture();
203-
final automlStorage = InheritedStorage.of(context).autoMlStorage;
204-
205-
if (mounted) {
206-
setState(() {
207-
imagePath = filePath;
208-
});
209-
210-
final filename =
211-
new DateTime.now().millisecondsSinceEpoch.toString() + '.jpg';
212-
213-
// upload to storage and firestore
214-
final StorageReference ref = automlStorage
215-
.ref()
216-
.child('datasets')
217-
.child(widget.dataset.name)
218-
.child(widget.label)
219-
.child(filename);
220-
221-
final File file = File(filePath).absolute;
222-
// upload the file
223-
StorageUploadTask uploadTask = ref.putFile(
224-
file,
225-
StorageMetadata(
226-
contentType: 'image/jpeg',
227-
customMetadata: <String, String>{'activity': 'imgUpload'},
228-
),
229-
);
230-
231-
final snapshot = await uploadTask.onComplete;
232-
final downloadUrl = await snapshot.ref.getDownloadURL();
233-
234-
Firestore.instance.collection('images').add({
235-
'parent_key': widget.labelKey,
236-
'dataset_parent_key': widget.dataset.id,
237-
'type': toString(SampleType
238-
.TRAIN), // newly created images are categorized as training.
239-
'filename': filename,
240-
'uploadPath':
241-
'datasets/${widget.dataset.name}/${widget.label}/$filename',
242-
'gcsURI': downloadUrl,
243-
'uploader': widget.userModel.user.email,
244-
});
245-
246-
final labelRef =
247-
Firestore.instance.collection('labels').document(widget.labelKey);
248-
249-
// increment count for the label
250-
await Firestore.instance.runTransaction((Transaction tx) async {
251-
DocumentSnapshot snapshot = await tx.get(labelRef);
252-
await tx.update(labelRef, <String, dynamic>{
253-
'total_images': snapshot.data['total_images'] + 1
254-
});
255-
});
256-
}
233+
uploadImageToStorage(filePath);
257234
}
258235

259236
void onVideoRecordButtonPressed() {
@@ -375,6 +352,63 @@ class _CameraState extends State<Camera> {
375352
logError(e.code, e.description);
376353
showInSnackBar('Error: ${e.code}\n${e.description}');
377354
}
355+
356+
void uploadImageToStorage(String filePath) async {
357+
final automlStorage = InheritedStorage.of(context).autoMlStorage;
358+
359+
if (mounted) {
360+
setState(() {
361+
imagePath = filePath;
362+
});
363+
364+
final filename =
365+
new DateTime.now().millisecondsSinceEpoch.toString() + '.jpg';
366+
367+
// upload to storage and firestore
368+
final StorageReference ref = automlStorage
369+
.ref()
370+
.child('datasets')
371+
.child(widget.dataset.name)
372+
.child(widget.label)
373+
.child(filename);
374+
375+
final File file = File(filePath).absolute;
376+
// upload the file
377+
StorageUploadTask uploadTask = ref.putFile(
378+
file,
379+
StorageMetadata(
380+
contentType: 'image/jpeg',
381+
customMetadata: <String, String>{'activity': 'imgUpload'},
382+
),
383+
);
384+
385+
final snapshot = await uploadTask.onComplete;
386+
final downloadUrl = await snapshot.ref.getDownloadURL();
387+
388+
Firestore.instance.collection('images').add({
389+
'parent_key': widget.labelKey,
390+
'dataset_parent_key': widget.dataset.id,
391+
'type': toString(SampleType
392+
.TRAIN), // newly created images are categorized as training.
393+
'filename': filename,
394+
'uploadPath':
395+
'datasets/${widget.dataset.name}/${widget.label}/$filename',
396+
'gcsURI': downloadUrl,
397+
'uploader': widget.userModel.user.email,
398+
});
399+
400+
final labelRef =
401+
Firestore.instance.collection('labels').document(widget.labelKey);
402+
403+
// increment count for the label
404+
await Firestore.instance.runTransaction((Transaction tx) async {
405+
DocumentSnapshot snapshot = await tx.get(labelRef);
406+
await tx.update(labelRef, <String, dynamic>{
407+
'total_images': snapshot.data['total_images'] + 1
408+
});
409+
});
410+
}
411+
}
378412
}
379413

380414
/// Widget to control start / stop of camera

flutter-app/lib/label_samples_grid.dart

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,51 @@ class ListLabelSamples extends StatelessWidget {
6565
preferredSize: new AppBar().preferredSize,
6666
),
6767
floatingActionButton: model.isLoggedIn()
68-
? new FloatingActionButton.extended(
69-
icon: const Icon(Icons.add_a_photo),
70-
label: const Text('Add Images'),
71-
onPressed: () async {
72-
final c = Camera(dataset, labelName, labelKey, model);
73-
await c.init();
74-
Navigator.push(
75-
context,
76-
MaterialPageRoute(
77-
builder: (context) => c,
68+
? Align(
69+
alignment: Alignment.bottomRight,
70+
child: Column(
71+
mainAxisAlignment: MainAxisAlignment.start,
72+
mainAxisSize: MainAxisSize.min,
73+
children: <Widget>[
74+
new FloatingActionButton.extended(
75+
icon: const Icon(Icons.add_a_photo),
76+
heroTag: 1,
77+
label: const Text('Add Images'),
78+
onPressed: () async {
79+
final c =
80+
Camera(dataset, labelName, labelKey, model, false);
81+
await c.init();
82+
Navigator.push(
83+
context,
84+
MaterialPageRoute(
85+
builder: (context) => c,
86+
),
87+
);
88+
},
7889
),
79-
);
80-
},
90+
Padding(
91+
padding: const EdgeInsets.all(4.0),
92+
),
93+
new FloatingActionButton.extended(
94+
icon: const Icon(Icons.file_upload),
95+
heroTag: 2,
96+
label: const Text('Upload Images'),
97+
onPressed: () async {
98+
final c =
99+
Camera(dataset, labelName, labelKey, model, true);
100+
await c.init();
101+
if (c.resultList != null && c.resultList.isNotEmpty) {
102+
Navigator.push(
103+
context,
104+
MaterialPageRoute(
105+
builder: (context) => c,
106+
),
107+
);
108+
}
109+
},
110+
),
111+
],
112+
),
81113
)
82114
: Container(),
83115
// body of the screen

flutter-app/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ dependencies:
4141
intro_slider: ^1.2.0
4242
url_launcher: ^5.0.2
4343
shared_preferences: ^0.5.2
44-
44+
multi_media_picker: ^0.2.3
4545
# The following adds the Cupertino Icons font to your application.
4646
# Use with the CupertinoIcons class for iOS style icons.
4747
cupertino_icons: ^0.1.2

0 commit comments

Comments
 (0)