Related
This is a Flutter app that I wrote long ago which pushes a user-selected image to Firebase and generates output using an ML model on the server.
I want to modify the same app. It is a completely offline app, so Firebase is not an option. So there are just 4 images that the user will be using as input. The app must be hardcoded to display a predefined output depending on which image is uploaded.
The possible methods I thought of were,
Store those images as assets in the app. Compare the input image's name to that of the asset images. Display output is there is a match.
Use image comparison algorithms using packages like image_compare.
None of the above methods worked, maybe I am doing it wrong. Please help me out.
Also, sorry for the non systematic code below.
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:del04/splashscreen.dart';
import 'package:del04/page/info_page.dart';
import 'package:del04/data.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:iconsax/iconsax.dart';
import 'package:path/path.dart';
import 'package:file_picker/file_picker.dart';
import 'package:file_support/file_support.dart';
late String name, path , domain , phylum , clas , order , family , genus , species ;
File? _photo;
// ignore: prefer_typing_uninitialized_variables
var image;
File a= File('assets/images/1.jpg'), b= File('assets/images/2.jpg'), c= File('assets/images/3.jpg'), d= File('assets/images/4.jpg');
var which=-1;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const Splash_screen(),
'/home': (context) => ImageUploads(),
'/home/info_page': (context) => Info_page()
}
)
);
}
class ImageUploads extends StatefulWidget {
const ImageUploads({Key? key}) : super(key: key);
#override
// ignore: library_private_types_in_public_api
_ImageUploadsState createState() => _ImageUploadsState();
}
class _ImageUploadsState extends State<ImageUploads> {
//firebase_storage.FirebaseStorage storage = firebase_storage.FirebaseStorage.instance;
Future imgFromGallery() async {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf'],
);
setState(() {
if (result != null) {
_photo= result as File;
String? filename= FileSupport().getFileNameWithoutExtension(_photo!);
image= _photo as Image;
} else {
if (kDebugMode) {
print('No image selected.');
}
}
});
}
/* Future imgFromCamera() async {
final pickedFile = await _picker.pickImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
image= _photo;
} else {
// ignore: avoid_print
print('No image selected.');
}
});
} //from Camera
Future uploadFile() async {
//if (_photo == null) return;
//const destination = 'Abhinav/';
try {
final ref = firebase_storage.FirebaseStorage.instance
.ref(destination)
.child('file/');
await ref.putFile(_photo!);
}
catch (e) {
if (kDebugMode) {
print('Error occurred, try again.');
}
}
}*/
void _onLoading() {
/*showDialog(
context: this.context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(height: 80, width: 80),
CircularProgressIndicator(),
Text(" Analyzing..."),
],
),
);
},
);*/
//douploadingshit();
Future.delayed(const Duration(seconds: 2), () async {
if(image.readAsBytesSync().lengthInBytes != a.readAsBytesSync().lengthInBytes)which= 1;
else if(image.readAsBytesSync().lengthInBytes == b.readAsBytesSync().lengthInBytes)which= 2;
else if(image.readAsBytesSync().lengthInBytes == c.readAsBytesSync().lengthInBytes)which= 3;
else if(image.readAsBytesSync().lengthInBytes == d.readAsBytesSync().lengthInBytes)which= 4;
else which= 99;
//pop dialog
//final ref = FirebaseDatabase.instance.ref();
//final snapshot = await ref.child('/').get();
//name = (snapshot.value) as String;
const Data().setData();
//Navigator.pop(this.context); //pop dialog
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
/*if(which==99){
fetch_errorM();
}
else{
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
}*/
});
}
/* Future<void> douploadingshit() async {
uploadFile();
DatabaseReference ref = FirebaseDatabase.instance.ref("");
await ref.update({
"confirm/state": "yes",
});
}*/
void fetch_errorM() {
showDialog(
context: this.context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(height: 80, width: 30),
Text("Could not analyze sample.\nPlease Retry or try another Image."),
],
),
);
},
);
Future.delayed(const Duration(seconds: 2), () async {
Navigator.pop(this.context); //pop dialog
});
}
//----------------------------------------------------------------------------
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('\t Baclens'),
backgroundColor: Colors.blueGrey.shade900,
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
const SizedBox(height: 80,),
Text('Upload your image file', style: TextStyle(fontSize: 25, color: Colors.grey.shade800, fontWeight: FontWeight.bold),),
const SizedBox(height: 10,),
Text('File should be jpg or png only', style: TextStyle(fontSize: 15, color: Colors.grey.shade500),),
const SizedBox(height: 20,),
GestureDetector(
onTap: () {
_showPicker(context);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0),
child: DottedBorder(
borderType: BorderType.RRect,
radius: const Radius.circular(10),
dashPattern: const [10, 5],
strokeCap: StrokeCap.round,
color: Colors.grey.shade900,
child: Container(
width: double.infinity,
height: 150,
decoration: BoxDecoration(
color: Colors.blue.shade50.withOpacity(.3),
borderRadius: BorderRadius.circular(10)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Iconsax.document_upload5, color: Colors.grey.shade900, size: 40,),
const SizedBox(height: 15,),
Text('Click to choose image', style: TextStyle(fontSize: 15, color: Colors.grey.shade400),),
],
),
),
)
),
),
_photo != null
? Container(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(' Selected File:',
style: TextStyle(color: Colors.grey.shade400, fontSize: 15, ),),
const SizedBox(height:10),
Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(1),
color: Colors.transparent,
),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(2),
child: Image.file(_photo!, width: 200, height: 200, fit: BoxFit.fitWidth)
),
)
),
const SizedBox(height: 30,),
MaterialButton(
minWidth: double.infinity,
height: 50,
onPressed: () {
_onLoading();
////////////////////////////////////////////////////////////////////////////////
setState((){
const Data().setData();
Navigator.pop(this.context); //pop dialog
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
});
},
color: Colors.blueGrey.shade900,
child: const Text('Upload', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),),
)
],
))
: Container(),
const SizedBox(height: 150,),
],
),
),
);
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Wrap(
children: <Widget>[
ListTile(
leading: const Icon(Icons.photo_library),
title: const Text('Gallery'),
onTap: () {
imgFromGallery();
Navigator.of(context).pop();
}),
/*ListTile(
leading: const Icon(Icons.photo_camera),
title: const Text('Camera'),
onTap: () {
imgFromCamera();
Navigator.of(context).pop();
},
),*/
],
),
);
});
}
}
If I understood correctly (but clearly I don't) when you need a var available when you build the widget you need to call the function in the initState(). The function is 'void getDevices()'
I need var _documentsIds to build DropdownMenuItem.
var _documentsIds is docs ID from a query I make to FirebaseFirestore
How do I make _documentsIds available to be used in my Widget?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:safegaurd/constants.dart';
import 'package:flutter_time_picker_spinner/flutter_time_picker_spinner.dart';
import 'package:safegaurd/screens/log_in_page.dart';
import 'package:safegaurd/components/buttons_navigate.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'new_device_page.dart';
class DeviceSelectionPage extends StatefulWidget {
const DeviceSelectionPage({Key? key}) : super(key: key);
static const String id = 'device_selection_page';
#override
State<DeviceSelectionPage> createState() => _DeviceSelectionPageState();
}
class _DeviceSelectionPageState extends State<DeviceSelectionPage> {
final _auth = FirebaseAuth.instance;
User? loggedInUser;
final firestoreInstance = FirebaseFirestore.instance;
final String devices = 'devices';
List? _documentsIds;
bool showSpinner = false;
String? selectedValue;
final bool checkOne = false;
Color sDeviceAlways = Colors.white54;
Color sDeviceTime = Colors.white54;
FontWeight sDeviceAlwaysW = FontWeight.normal;
FontWeight sDeviceTimeW = FontWeight.normal;
#override
void initState() {
super.initState();
getCurrentUser();
getDevices();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
getDevices();
};
} catch (e) {
print(e);
}
}
void getDevices() async {
var firebaseUser = FirebaseAuth.instance.currentUser?.email;
print('firebaseUser: $firebaseUser');
var query = await firestoreInstance
.collection(devices)
.where('email', isEqualTo: '$firebaseUser')
.get();
var _documentsIds = query.docs.map((doc) => doc.id).toList();
print('_documentsIds: $_documentsIds');
}
#override
Widget build(BuildContext context) {
print('_documentsIds: $_documentsIds');
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
onPressed: () {
_auth.signOut();
Navigator.pop(context);
},
icon: Icon(Icons.close))
],
title: const Text('Device Selection page'),
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 40,
child: Text(
'SAFEGAURD',
style: kAppTextStyle,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 380,
padding: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightBlueAccent, width: 1.0),
borderRadius: kBorderRadius),
child: DropdownButtonHideUnderline(
child: DropdownButton(
hint: const Text(
'Safegaurd Devices',
style: TextStyle(color: Colors.white54, fontSize: 25),
),
style:
const TextStyle(color: Colors.orange, fontSize: 25),
borderRadius: kBorderRadius,
iconSize: 40,
elevation: 16,
onChanged: (value) {
setState(() {
selectedValue = value.toString();
setState(() {
selectedValue;
print(selectedValue);
});
});
},
value: selectedValue,
items: _documentsIds?.map((itemsList) {
return DropdownMenuItem<String>(
value: itemsList,
child: Text(itemsList),
);
}).toList(),
),
),
)
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Save Settings',
onPressed: () {},
width: 200,
),
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Claim new Device',
onPressed: () {
Navigator.pushNamed(context, NewDevicePage.id);
},
width: 200,
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Buttons_Navigate(
colour: Colors.orange,
title: 'Back',
onPressed: () {
Navigator.pushNamed(context, LogInPage.id);
},
width: 40)
],
)
],
)),
));
}
}
wall, you can use futureBuilder and show A CircularProgressBar until the query is done check the documentation here: FutureBuilder
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:safegaurd/constants.dart';
//import 'package:flutter_time_picker_spinner/flutter_time_picker_spinner.dart';
import 'package:safegaurd/screens/log_in_page.dart';
import 'package:safegaurd/components/buttons_navigate.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'new_device_page.dart';
class DeviceSelectionPage extends StatefulWidget {
const DeviceSelectionPage({Key? key}) : super(key: key);
static const String id = 'device_selection_page';
#override
State<DeviceSelectionPage> createState() => _DeviceSelectionPageState();
}
class _DeviceSelectionPageState extends State<DeviceSelectionPage> {
final _auth = FirebaseAuth.instance;
User? loggedInUser;
final firestoreInstance = FirebaseFirestore.instance;
final String devices = 'devices';
List? _documentsIds;
bool showSpinner = false;
//bool _isSelected1 = false;
//bool _isSelected2 = false;
//DateTime _dateTime = DateTime.now();
String? selectedValue;
final bool checkOne = false;
Color sDeviceAlways = Colors.white54;
Color sDeviceTime = Colors.white54;
FontWeight sDeviceAlwaysW = FontWeight.normal;
FontWeight sDeviceTimeW = FontWeight.normal;
#override
void initState() {
super.initState();
getCurrentUser();
getDevices();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
getDevices();
};
} catch (e) {
print(e);
}
}
Future<List<dynamic>> getDevices() async {
var firebaseUser = FirebaseAuth.instance.currentUser?.email;
print('firebaseUser: $firebaseUser');
var query = await firestoreInstance
.collection(devices)
.where('email', isEqualTo: '$firebaseUser')
.get();
List<String> _documentsIds = query.docs.map((doc) => doc.id).toList();
print('_documentsIds: $_documentsIds');
return _documentsIds;
}
#override
Widget build(BuildContext context) {
print('_documentsIds: $_documentsIds');
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
onPressed: () {
_auth.signOut();
Navigator.pop(context);
},
icon: Icon(Icons.close))
],
title: const Text('Device Selection page'),
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 40,
child: Text(
'SAFEGAURD',
style: kAppTextStyle,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 380,
padding: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightBlueAccent, width: 1.0),
borderRadius: kBorderRadius),
child: DropdownButtonHideUnderline(
child: FutureBuilder<List> (
future: getDevices(),
builder: (BuildContext context, AsyncSnapshot<List> snapshot){
if (!snapshot.hasData) {
return const Text('Waiting Devices',style: TextStyle(color: Colors.white54, fontSize: 25));
} else {
return DropdownButton(
hint: const Text(
'Safegaurd Devices',
style: TextStyle(color: Colors.white54, fontSize: 25),
),
style:
const TextStyle(color: Colors.orange, fontSize: 25),
borderRadius: kBorderRadius,
iconSize: 40,
elevation: 16,
onChanged: (value) {
setState(() {
selectedValue = value.toString();
setState(() {
selectedValue;
print(selectedValue);
});
});
},
value: selectedValue,
items: snapshot.data?.map((_documentsIds) =>
DropdownMenuItem<String>(
value: _documentsIds,
child: Text(_documentsIds),
)
).toList(),
);
}
}
)
),
)
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Save Settings',
onPressed: () {},
width: 200,
),
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Claim new Device',
onPressed: () {
Navigator.pushNamed(context, NewDevicePage.id);
},
width: 200,
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Buttons_Navigate(
colour: Colors.orange,
title: 'Back',
onPressed: () {
Navigator.pushNamed(context, LogInPage.id);
},
width: 40)
],
)
],
)),
));
}
Im doing an integration test in Flutter and in the application I open the camera, but I don't know how to tap on the button to do the photo, anyone know how can I search for this button?
Here is the code if the app where you can choose between pic a photo with the camera or choose one picture of your gallery
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';
import 'package:random_string/random_string.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:rosita/language/firebase_remote.dart';
import 'package:rosita/api/api_provider.dart';
import 'package:rosita/constants/common.dart';
import 'package:rosita/model/image_object.dart';
import 'package:rosita/model/senior_user.dart';
import 'package:rosita/modules/widgets/button_ui.dart';
import 'package:rosita/rosita.dart';
class AddProfileImageScreen extends StatefulWidget {
const AddProfileImageScreen({Key key, this.seniorUser}) : super(key: key);
final SeniorUser seniorUser;
#override
_AddProfileImageScreenState createState() => _AddProfileImageScreenState();
}
class _AddProfileImageScreenState extends State<AddProfileImageScreen> {
bool _isProcessing = false;
File _image;
bool _enableButton = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: ModalProgressHUD(
inAsyncCall: _isProcessing,
color: Colors.transparent,
progressIndicator: const CircularProgressIndicator(
strokeWidth: 2.0,
),
child: Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height,
minWidth: MediaQuery.of(context).size.width),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
darkSubtitleText('choose_profile_picture', context),
Expanded(
child: Center(
child: SizedBox(
width: 100,
height: 100,
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(
color: AppTheme.purpleColor,
width: 4,
),
borderRadius: BorderRadius.circular(60.0),
),
elevation: 0,
color: Theme.of(context).dividerColor,
child: _image == null
? (widget.seniorUser != null &&
widget.seniorUser.profileImage != null &&
widget.seniorUser.profileImage.imageUrl !=
'')
? CachedNetworkImage(
imageUrl:
widget.seniorUser.profileImage.imageUrl,
placeholder:
(BuildContext context, String url) =>
Image.asset(ConstantsData.appIcon),
errorWidget: (BuildContext context,
String url, error) =>
const Icon(Icons.error),
fit: BoxFit.cover,
)
: Image.asset(ConstantsData.appIcon)
: Image.file(_image),
),
),
),
),
ButtonUI(
buttonName: 'ProfilePhotoFromCameraButton',
key: const Key(Keys.cameraButton),
isTrack: true,
color: AppTheme.primaryColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('take_a_photo_with_your_camera'),
textAlign: TextAlign.center,
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
getImage(isGallery: false);
},
),
verticalSpacer(),
ButtonUI(
buttonName: 'ProfilePhotoFromGalleryButton',
key: const Key(Keys.galleryButton),
isTrack: true,
color: AppTheme.primaryColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('choose_from_gallery'),
textAlign: TextAlign.center,
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
getImage(isGallery: true);
},
),
verticalSpacer(),
if (_image != null || _enableButton)
ButtonUI(
buttonName: 'ProfilePhotoUploadButton',
key: const Key(Keys.uploadButton),
isTrack: true,
color: AppTheme.purpleColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('continue_txt'),
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
_uploadAllInformation();
},
),
],
),
),
),
),
);
}
Future<void> getImage({bool isGallery = true}) async {
await <Permission>[Permission.camera, Permission.storage].request();
if (await Permission.storage.status != PermissionStatus.granted) {
setState(() {
_enableButton = true;
});
return;
}
if (!isGallery &&
await Permission.camera.status != PermissionStatus.granted) {
setState(() {
_enableButton = true;
});
return;
}
final image = await ImagePicker.pickImage(
source: isGallery ? ImageSource.gallery : ImageSource.camera);
if (image == null) return;
final cropimage = await cropImage(image);
if (cropimage == null) return;
setState(() {
_image = cropimage;
});
}
Future<File> cropImage(File imageFile) async {
final croppedFile = await ImageCropper.cropImage(
androidUiSettings: AndroidUiSettings(
statusBarColor: Theme.of(context).primaryColor,
toolbarColor: Theme.of(context).primaryColor,
toolbarWidgetColor: Theme.of(context).backgroundColor,
),
sourcePath: imageFile.path,
cropStyle: CropStyle.circle,
aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1),
maxWidth: 420,
maxHeight: 420,
);
return croppedFile;
}
Future<void> _uploadAllInformation() async {
setState(() {
_isProcessing = true;
});
widget.seniorUser.documentId =
(await FirebaseAuth.instance.currentUser()).uid;
widget.seniorUser.referralCode =
'RO-' + randomAlphaNumeric(8).toUpperCase();
widget.seniorUser.enterReferralCode = deepLinkReferralCode;
await ApiProvider().createSeniorUserProfile(widget.seniorUser);
endRegister = true;
if (!_enableButton) {
final imageData = await updateProfilePic(widget.seniorUser);
await ApiProvider()
.updateRositaProfileImage(imageData, widget.seniorUser.documentId);
}
setState(() {
_isProcessing = false;
});
Rosita.restartApp(context);
}
Future<ImageObject> updateProfilePic(SeniorUser user) async {
final imagename = DateTime.now().millisecondsSinceEpoch.toString() + '.jpg';
final url = await ApiProvider()
.updateProfilePic('rositapics/${user.documentId}/' + imagename, _image);
final profileImage = ImageObject();
profileImage.imageUrl = url.toString();
profileImage.firebaseStoregPath =
'rositapics/${user.documentId}/' + imagename;
profileImage.imageName = imagename;
return profileImage;
}
}
my code when it found the data object it turns fine and i do not have any error. but when the data that i pass is not in the database it will return the exception. I don't know where to fix the error
exception image
this is my code. the widget.barcode is i get from another file.
modelRuangFasiliti.dart
class RuangFasiliti {
final String ruangfasiliti_id;
final String ruang_id;
final String fasiliti_id;
final String kuantiti;
final String namaruang;
final String namafasiliti;
RuangFasiliti({
this.ruangfasiliti_id,
this.ruang_id,
this.fasiliti_id,
this.kuantiti,
this.namaruang,
this.namafasiliti,
});
factory RuangFasiliti.fromJson(Map<String, dynamic> json) {
return RuangFasiliti(
ruangfasiliti_id: json['ruangfasiliti_id'],
ruang_id: json['ruang_id'],
fasiliti_id: json['fasiliti_id'],
kuantiti: json['kuantiti'],
namaruang: json['namaruang'],
namafasiliti: json['namafasiliti'],
);
}
}
borangaduan.dart
import 'dart:convert';
import 'package:eaduanfsktm/api.dart';
import 'package:eaduanfsktm/sejarahaduan.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:eaduanfsktm/model/modelRuangFasiliti.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'dart:math' as Math;
import 'package:image/image.dart' as Img;
import 'package:path_provider/path_provider.dart';
import 'dart:async';
import 'package:async/async.dart';
import 'package:path/path.dart';
class BorangAduan extends StatefulWidget {
final String idpengguna, barcode;
BorangAduan(this.idpengguna, this.barcode);
#override
_BorangAduanState createState() => _BorangAduanState();
}
class _BorangAduanState extends State<BorangAduan> {
final _key = new GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
TextEditingController controllerruang_id;
TextEditingController controllerfasiliti_id;
TextEditingController controller_namaruang;
TextEditingController controller_namafasiliti;
TextEditingController controllermaklumat = new TextEditingController();
File _image;
RuangFasiliti ruangfasiliti = new RuangFasiliti();
Future<RuangFasiliti> getruangfasiliti() async {
final response = await http.get(BaseUrl.lihatruangfasiliti(widget.barcode));
if (response.statusCode == 200) {
setState(
() {
ruangfasiliti = RuangFasiliti.fromJson(json.decode(response.body));
controllerruang_id =
new TextEditingController(text: "${ruangfasiliti.ruang_id}");
controllerfasiliti_id =
new TextEditingController(text: "${ruangfasiliti.fasiliti_id}");
controller_namaruang =
new TextEditingController(text: " ${ruangfasiliti.namaruang}");
controller_namafasiliti =
new TextEditingController(text: " ${ruangfasiliti.namafasiliti}");
},
);
}
return ruangfasiliti;
}
#override
void initState() {
super.initState();
getruangfasiliti();
}
bool isloading = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("Borang Aduan"),
),
body: isloading
? new CircularProgressIndicator()
: new ListView(
children: <Widget>[
aduanbox(),
SizedBox(height: 10.0),
],
),
),
);
}
Widget aduanbox() {
return Container(
child: Form(
key: _key,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Card(
//color: Colors.black,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: new TextFormField(
controller: controllerfasiliti_id,
readOnly: true,
decoration: InputDecoration(
labelText: "KOD FASILITI",
),
),
),
flex: 2,
),
SizedBox(width: 10.0),
Expanded(
child: Container(
child: new TextFormField(
controller: controller_namafasiliti,
readOnly: true,
decoration: InputDecoration(
labelText: "NAMA FASILITI",
),
),
),
flex: 2,
),
],
),
new Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Container(
child: new TextFormField(
controller: controllerruang_id,
readOnly: true,
decoration: InputDecoration(
labelText: "KOD LOKASI",
),
),
),
flex: 2,
),
SizedBox(width: 10.0),
Expanded(
child: Container(
child: new TextFormField(
controller: controller_namaruang,
readOnly: true,
decoration: InputDecoration(
labelText: "LOKASI",
),
),
),
flex: 2,
),
],
),
TextFormField(
controller: controllermaklumat,
validator: (value) {
if (value.isEmpty) {
return 'Masukkan Maklumat Kerosakan';
}
return null;
},
decoration: InputDecoration(
labelText: "MAKLUMAT",
hintText: "Masukkan maklumat kerosakan"),
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
RaisedButton(
child: Icon(Icons.image),
onPressed: getImageGallery,
),
SizedBox(width: 5.0),
RaisedButton(
child: Icon(Icons.camera_alt),
onPressed: getImageCamera,
),
],
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
child: _image == null
? new Text("Tiada imej !")
: new Image.file(_image),
),
SizedBox(height: 10.0),
Container(
height: 45.0,
child: GestureDetector(
onTap: () {
if (_key.currentState.validate()) {
tambahaduan(_image);
}
},
child: Material(
borderRadius: BorderRadius.circular(10.0),
color: Colors.blueAccent,
elevation: 7.0,
child: Center(
child: Text(
'HANTAR',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat'),
),
),
),
),
),
],
),
),
),
),
),
);
}
Future getImageGallery() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
int rand = new Math.Random().nextInt(100000);
Img.Image image = Img.decodeImage(imageFile.readAsBytesSync());
Img.Image smallerImg = Img.copyResize(image, width: 500);
var compressImg = new File("$path/image_$rand.jpg")
..writeAsBytesSync(Img.encodeJpg(smallerImg, quality: 85));
setState(() {
_image = compressImg;
});
}
Future getImageCamera() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
int rand = new Math.Random().nextInt(100000);
Img.Image image = Img.decodeImage(imageFile.readAsBytesSync());
Img.Image smallerImg = Img.copyResize(image, width: 500);
var compressImg = new File("$path/image_$rand.jpg")
..writeAsBytesSync(Img.encodeJpg(smallerImg, quality: 85));
setState(() {
_image = compressImg;
});
}
Future tambahaduan(File _image) async {
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
var length = await _image.length();
var uri = Uri.parse((BaseUrl.tambahaduan()));
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile("aduanimages", stream, length,
filename: basename(_image.path));
request.fields['fasiliti_id'] = controllerfasiliti_id.text;
request.fields['ruang_id'] = controllerruang_id.text;
request.fields['maklumat'] = controllermaklumat.text;
request.fields['idpengguna'] = widget.idpengguna;
request.files.add(multipartFile);
var response = await request.send();
if (response.statusCode == 200) {
print("Image Uploaded");
setState(
() {
Fluttertoast.showToast(
msg: "Aduan Berjaya",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.black,
textColor: Colors.white,
fontSize: 18.0,
);
Navigator.of(this.context).push(CupertinoPageRoute(
builder: (BuildContext context) => SejarahAduan()));
},
);
} else {
print("Upload Failed");
}
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
}
please help...
Add a check in getruangfasiliti() (in borangaduan.dart file) to verify if response.body is null or empty .you may have to add an else condition to show the user that you didn't get any data.
The main reason i want to change the design is that when i scan a product and then scan the same one i get the same product twice while it is the same one so basically i just need to increase the quantity of the product by one.
I have used Provider before but I still can't manage to arrange the classes the right way to make it work.
first i have tried to make a Productobject(which extenes ChangeNotifier) inside ProductCard class and use provider.of(context) and retrieve the quantity of the prodcut.
plus,at the main before the material I used ChangeNotifierProvider
I have a mess in my head and i would love to see someone arranging the code with explanation of how the things works
main
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sally_smart/utilities/product_notifier.dart';
import 'screens/checkout_screen.dart';
import 'screens/login_screen.dart';
import 'screens/registration_screen.dart';
import 'screens/welcome_screen.dart';
import 'package:provider/provider.dart';
//void main() => runApp(Sally());
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(new Sally());
});
}
class Sally extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
backgroundColor: Colors.teal,
cardColor: Color(0xFF068194),
),
initialRoute: LoginScreen.id,
routes: {
WelcomeScreen.id: (context) => WelcomeScreen(),
RegistrationScreen.id: (context) => RegistrationScreen(),
LoginScreen.id: (context) => LoginScreen(),
CheckoutScreen.id: (context) => CheckoutScreen()
},
);
}
}
ProductCard
import 'package:flutter/material.dart';
import 'package:sally_smart/utilities/constants.dart';
import 'package:sally_smart/utilities/product.dart';
import 'package:sally_smart/utilities/round_icon_button.dart';
class ProductCard extends StatefulWidget {
final Product prodcut;
ProductCard(Product product);
#override
_ProductCardState createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard> {
double finalPrice;
// static int quantity = 1;
#override
Widget build(BuildContext context) {
finalPrice = widget.prodcut.quantity * widget.prodcut.productPrice;
return Card(
elevation: 5.0,
child: ListTile(
leading: Padding(
padding: EdgeInsets.only(
left: 2.0,
),
child: Icon(
widget.prodcut.productIcon,
size: 35,
),
),
title: Text(
widget.prodcut.productName,
style: kProductNameTextStyle,
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RoundIconButton(
icon: Icons.add,
color: Colors.green,
function: () {
setState(() {
widget.prodcut.quantity++;
});
}),
Text(
'$widget.prodcut.quantity',
),
RoundIconButton(
icon: Icons.remove,
color: Colors.red,
function: () {
setState(() {
widget.prodcut.quantity--;
if ( widget.prodcut.quantity == 0) {
widget.prodcut.quantity++;
}
});
}),
],
),
),
Text(
'${finalPrice.toStringAsFixed(2)} ₪',
style: TextStyle(fontSize: 15),
),
],
),
),
);
}
}
Prodcut
import 'package:flutter/cupertino.dart';
class Product extends ChangeNotifier{
String productName;
double productPrice;
IconData productIcon;
String id;
String barCode;
int quantity;
Product(this.productName, this.productPrice, this.productIcon, this.id,
this.barCode,this.quantity);
}
welcome screen
import 'package:audioplayers/audio_cache.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
import 'package:sally_smart/screens/login_screen.dart';
import 'package:sally_smart/screens/registration_screen.dart';
import 'package:sally_smart/utilities/constants.dart';
import 'package:sally_smart/utilities/product.dart';
import 'package:sally_smart/utilities/product_card.dart';
import 'package:sally_smart/utilities/scan_button_const.dart';
import 'package:sally_smart/utilities/scan_methods.dart';
//import 'package:sally_smart/utilities/scan_pageML.dart';
//import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart';
//import 'package:firebase_ml_vision/firebase_ml_vision.dart';
//working version
//List<ProductCard> shoppingList = [];
final sallyDatabase = Firestore.instance;
class WelcomeScreen extends StatefulWidget {
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
final _auth = FirebaseAuth.instance;
final textEditorController = TextEditingController();
String _scanBarcode = 'Unknown';
String productName = 'Product Test';
double productPrice;
String productBarCode;
IconData productIcon = Icons.add_shopping_cart;
final List<ProductCard> shoppingList = [];
int productId = 0;
static AudioCache barcodeSound = AudioCache();
// saves barcodes data
List<String> data = [];
Future<void> initPlatformState() async {
String barcodeScanRes;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
barcodeScanRes =
await FlutterBarcodeScanner.scanBarcode("#ff6666", "Cancel", true);
} on PlatformException {
barcodeScanRes = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_scanBarcode = barcodeScanRes;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF21bacf),
appBar: AppBar(
elevation: 3,
backgroundColor: Colors.black54,
leading: Icon(
Icons.shopping_basket,
size: 30,
),
title: Text(
'Sally',
textAlign: TextAlign.end,
style: kHeaderTextStyle,
),
actions: <Widget>[
IconButton(icon: Icon(Icons.settings), onPressed: () {}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
IconButton(
icon: Icon(Icons.power_settings_new),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
IconButton(icon: Icon(Icons.share), onPressed: () {}),
VerticalDivider(
color: Color(0x8CFFFFFF),
width: 3,
),
// PopupMenuButton(itemBuilder: ),
],
),
body: Container(
decoration: kBackgroundGradientScan,
child: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'ברוכה הבאה, סאלי',
textAlign: TextAlign.right,
style: kHeaderTextStyle,
),
Padding(
padding: EdgeInsets.only(top: 5, right: 15),
child: Hero(
tag: 'Sally',
child: CircleAvatar(
backgroundImage:
AssetImage('images/missing_avatar_F.png'),
maxRadius: 25,
),
),
)
],
),
Padding(
padding: EdgeInsets.symmetric(vertical: 3, horizontal: 15),
child: TextField(
textAlign: TextAlign.center,
onChanged: (value) async {
_scanBarcode = value;
productPrice = await getProductPrice(_scanBarcode);
productName = await getProductName(_scanBarcode);
},
decoration: kTextFieldDecoration.copyWith(
prefixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {
_scanBarcode = '';
textEditorController.clear();
try {
setState(() {
textEditorController.clear();
//checking if a product was already scanned
//adding a ProductCard to the shopping list with the ProductCard const. Works on scan
shoppingList.add(ProductCard( new Product(productName, productPrice, productIcon, shoppingList.length.toString(),
productBarCode, 1)));
});
} catch (e) {
print(e);
}
},
),
// prefix: IconButton(
// icon: Icon(Icons.search),
// onPressed: () {
//
// }),
hintText: '...הכנס ברקוד או שם מוצר ידנית'),
),
),
DividerSally(),
shoppingListBuilder(),
DividerSally(),
Container(
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: Column(
children: <Widget>[
ScanMainButton(
iconData: Icons.flip,
buttonText: 'סרוק מוצר',
onPressed: () async {
//Navigator.pushNamed(context, ScanScreen.id);
await initPlatformState();
barcodeSound.play('barcode_sound.mp3');
//Changes the product name by referencing to the database
productBarCode = _scanBarcode;
productPrice =
await getProductPrice(_scanBarcode);
productName =
await getProductName(_scanBarcode);
setState(() {
//checking if a product was already scanned
//adding a ProductCard to the shopping list with the ProductCard const. Works on scan
shoppingList.add(ProductCard( new Product(productName, productPrice, productIcon, shoppingList.length.toString(),
productBarCode, 1)));
});
},
color: Colors.teal,
),
ScanMainButton(
iconData: Icons.check,
buttonText: 'מעבר לתשלום',
color: Colors.green,
onPressed: () {
Navigator.pushNamed(
context, RegistrationScreen.id);
}),
],
),
),
),
)
],
),
),
),
));
}
Expanded shoppingListBuilder() {
return Expanded(
child: Container(
color: Colors.black38,
child: ListView.builder(
reverse: true,
itemCount: shoppingList.length,
itemBuilder: (context, index) {
ProductCard item = shoppingList[index];
return Dismissible(
key: Key(item.prodcut.id),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {
setState(() {
shoppingList.removeAt(index);
});
},
background: Container(
child: Icon(
Icons.restore_from_trash,
size: 40,
),
margin: EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
Color(0x8C650223),
Color(0x8CB9013E),
],
stops: [0.1, 0.9],
),
),
),
child: item //ListTile(title: Text('${item.productName}.')),
);
},
),
));
}
}