In my app I am taking picture and storing it in the device also storing the path using sqlite . Now if I delete the data using the code given below it delete from the local database(sqlite) but do not delete the picture from the file . for example I create 3 transaction and delete 2 of them but in file I still have 3 images(in file) . So how to delete them . please help .
Saving :
Future _takeImage() async {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.camera,
maxWidth: 600,
);
_saveImg(imageFile);
}
Future _saveImg(PickedFile imageFile) async {
if (imageFile == null) {
return;
}
setState(() {
_storedImage = File(imageFile.path);
});
final appDirectory = await sysPath.getApplicationDocumentsDirectory();
final fileName =
path.basename(_storedImage.path); //name of the photo created by camera.
final savedImage = await _storedImage
.copy('${appDirectory.path}/$fileName'); // storing image.
widget.onSelectImage(savedImage.path);
}
Deleting :
Future<void> deleteExpanse(int id) async {
try {
final MyDatabase dbManager = MyDatabase();
await dbManager.deleteTransaction(id, "Expense");
DataSample temp = _expenseItems.firstWhere((element) => id == element.id);
await _deleteImage(temp);
_expenseItems.removeWhere((element) => element.id == id);
} catch (error) {
throw error;
}
notifyListeners();
}
_deleteImage(DataSample data )async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, data.image );
bool isExist = await File(path).exists();
if (isExist) {
await File(path).delete();
}
}
for detail code :
taking or choosing picture from here and passing it to a method =>
class ImageInput extends StatefulWidget {
final Function onSelectImage;
final String imageFile;
ImageInput(this.onSelectImage, this.imageFile);
#override
_ImageInputState createState() => _ImageInputState();
}
class _ImageInputState extends State<ImageInput> {
File _storedImage;
Future _choseImage() async {
try {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.gallery,
maxWidth: 600,
);
_saveImg(imageFile);
} catch (error) {
throw error;
}
}
Future _takeImage() async {
try {
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.camera,
maxWidth: 600,
);
_saveImg(imageFile);
} catch (error) {
throw error;
}
}
Future _saveImg(PickedFile imageFile) async {
try {
if (imageFile == null) {
return;
}
bool a = await File(imageFile.path).exists();
setState(() {
if(a){
_storedImage = File(imageFile.path);
}
});
final appDirectory = await sysPath.getApplicationDocumentsDirectory();
final fileName = path
.basename(_storedImage.path); //name of the photo created by camera.
final savedImage = await _storedImage
.copy('${appDirectory.path}/$fileName'); // storing image.
widget.onSelectImage(savedImage.path);
} catch (error) {
throw error;
}
}
#override
void initState() {
// TODO: implement initState
_storedImage = widget.imageFile.isEmpty ? null : File(widget.imageFile);
super.initState();
}
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.24,
width: MediaQuery.of(context).size.width * 0.5,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 1, color: Color(0xFF495464)),
),
child: _storedImage != null
? Image.file(
_storedImage,
fit: BoxFit.cover,
width: double.infinity,
)
: Text(
"No Image Chosen",
style: GoogleFonts.courgette(
fontSize: MediaQuery.of(context).size.width * 0.05),
),
alignment: Alignment.center,
),
SizedBox(width: 10),
Expanded(
child: FittedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlatButton.icon(
icon: Icon(
Icons.camera,
color: Color(0xFF495464),
),
label: Text(
'Take Picture',
style: TextStyle(color: Color(0xFF495464), fontSize: 20),
),
onPressed: _takeImage,
),
FlatButton.icon(
icon: Icon(
Icons.photo_library,
color: Color(0xFF495464),
),
label: Text(
'Choose Picture',
style: TextStyle(color: Color(0xFF495464), fontSize: 20),
),
onPressed: _choseImage,
),
],
),
),
),
],
);
}
}
it comes here and then I pass it to the provider delete method given above(I only give the expense delete method above) =>
var _initState = true;
var trData;
String initialPrice = '';
var _newTransaction = DataSample(
id: null,
datetime: null,
title: '',
image: '',
price: 0.0,
description: '',
);
#override
void didChangeDependencies() {
if (_initState) {
trData = ModalRoute.of(context).settings.arguments as Map;
if (trData['id'] != 0) {
if (trData['type'] == "Expense") {
_newTransaction = Provider.of<ExpanseProvider>(context, listen: false)
.findId(trData['id']);
} else {
_newTransaction = Provider.of<IncomeProvider>(context, listen: false)
.findId(trData['id']);
}
_selectedDate = _newTransaction.datetime;
initialPrice = _newTransaction.price.toString();
}
}
_initState = false;
super.didChangeDependencies();
}
final _gKey = GlobalKey<FormState>();
DateTime _selectedDate = DateTime.now();
String _pickedImage = '';
void _selectImage(String pickedImage) {
_pickedImage = pickedImage;
}
void _saveInput(String page) {
final _isValid = _gKey.currentState.validate();
if (!_isValid) {
return;
}
_gKey.currentState.save();
_newTransaction = DataSample(
title: _newTransaction.title,
datetime: _selectedDate,
image: _pickedImage.isEmpty ? _newTransaction.image : _pickedImage,
id: _newTransaction.id,
price: _newTransaction.price,
description: _newTransaction.description,
);
deleteOrUpdate(page);
}
Future<void> deleteOrUpdate(String page) async {
if (_newTransaction.id == null) {
if (page == 'Expense') {
await Provider.of<ExpanseProvider>(context, listen: false)
.addExpanseTransaction(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
} else {
await Provider.of<IncomeProvider>(context, listen: false)
.addIncomeTransaction(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
}
} else {
if (page == 'Expense') {
await Provider.of<ExpanseProvider>(context, listen: false)
.updateExpense(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
} else {
await Provider.of<IncomeProvider>(context, listen: false)
.updateIncome(_newTransaction)
.then((value) => Navigator.of(context).pop())
.catchError((error) {
return _onError();
});
}
}
}
I once faced a similar issue using the async file deletion, I then switched to the deleteSync method. I guess in your case it should have no side effect since you already await for deletion.
Documentation: https://api.flutter.dev/flutter/dart-io/FileSystemEntity/deleteSync.html
Related
I'm using the code from the example of this dependencie image_downloader: ^0.31.0, the problem is that it doesn't show any error but the image doesn't go to the galery.
This screen is to show the images from firestore and create listtyle that when the user clicks the image is suposed to download it.
import 'dart:io';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:image_downloader/image_downloader.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:pap_test/upload/upload_resumos_screen.dart';
class DownloadScreen extends StatefulWidget {
const DownloadScreen({Key? key}) : super(key: key);
static const routeName = '/downlaod-resumos';
#override
State<DownloadScreen> createState() => _DownloadScreenState();
}
class _DownloadScreenState extends State<DownloadScreen> {
String _message = "";
String _path = "";
String _size = "";
String _mimeType = "";
File? _imageFile;
int _progress = 0;
String query = '1';
CollectionReference _firebaseFirestore =
FirebaseFirestore.instance.collection('images');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Resumos'),
),
body: StreamBuilder<QuerySnapshot>(
stream: _firebaseFirestore.snapshots().asBroadcastStream(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else {
if (snapshot.data!.docs
.where((QueryDocumentSnapshot<Object?>
element) =>
element['disciplina']
.toString()
.toLowerCase()
.contains(query.toLowerCase()))
.isEmpty) {
return Center(
child: Text(
'Por aqui está muito lento, carrega no botão e publica um resumo.',
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
);
} else {
return ListView(
children: [
...snapshot.data!.docs
.where((QueryDocumentSnapshot<Object?>
element) =>
element['disciplina']
.toString()
.toLowerCase()
.contains(query.toLowerCase()))
.map(
(QueryDocumentSnapshot<Object?> data) {
final String descricao = data.get('descricao');
final _image = data['url'];
return ListTile(
onTap: () {
_downloadImage(_image);
},
leading: CircleAvatar(
backgroundImage: NetworkImage(_image),
),
title: Text(
descricao.toString(),
style: Theme.of(context).textTheme.headline5,
),
);
},
)
],
);
}
}
},
),
);
}
Future<void> _downloadImage(
String url, {
AndroidDestinationType? destination,
bool whenError = false,
String? outputMimeType,
}) async {
String? fileName;
String? path;
int? size;
String? mimeType;
try {
String? imageId;
if (whenError) {
imageId = await ImageDownloader.downloadImage(url,
outputMimeType: outputMimeType)
.catchError((error) {
if (error is PlatformException) {
String? path = "";
if (error.code == "404") {
print("Not Found Error.");
} else if (error.code == "unsupported_file") {
print("UnSupported FIle Error.");
path = error.details["unsupported_file_path"];
}
setState(() {
_message = error.toString();
_path = path ?? '';
});
}
print(error);
}).timeout(Duration(seconds: 10), onTimeout: () {
print("timeout");
return;
});
} else {
if (destination == null) {
imageId = await ImageDownloader.downloadImage(
url,
outputMimeType: outputMimeType,
);
} else {
imageId = await ImageDownloader.downloadImage(
url,
destination: destination,
outputMimeType: outputMimeType,
);
}
}
if (imageId == null) {
return;
}
fileName = await ImageDownloader.findName(imageId);
path = await ImageDownloader.findPath(imageId);
size = await ImageDownloader.findByteSize(imageId);
mimeType = await ImageDownloader.findMimeType(imageId);
} on PlatformException catch (error) {
setState(() {
_message = error.message ?? '';
});
return;
}
if (!mounted) return;
setState(
() {
var location = Platform.isAndroid ? "Directory" : "Photo Library";
_message = 'Saved as "$fileName" in $location.\n';
_size = 'size: $size';
_mimeType = 'mimeType: $mimeType';
_path = path ?? '';
if (!_mimeType.contains("video")) {
_imageFile = File(path!);
}
return;
},
);
}
}
This is what shows in the console after i click on the image
And this is the galery after i clicked
by runtime everything works fine but when I press on the button to send the data to the database firebase Firestore I get this error
`
this is my error
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: LateInitializationError: Field 'TaakBeschrijving' has not been initialized.
#0 _TaakState.TaakBeschrijving (package:cameratest2/Taak.dart)
#1 _TaakState.uploadText (package:cameratest2/Taak.dart:72:50)
#2 _TaakState.afrondenbutton. (package:cameratest2/Taak.dart:333:13)
#3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:198:24)
#5 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:608:11)
#6 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:296:5)
#7 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:267:7)
`
2. this is my code
import 'dart:ui';
import 'package:cameratest2/Homedashboard.dart';
import 'package:cameratest2/model/user_model.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:image_picker/image_picker.dart';
import 'package:multi_image_picker2/multi_image_picker2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart' as firebase_core;
// import 'package:path_provider/path_provider.dart';
class Taak extends StatefulWidget{
_TaakState createState() => _TaakState();
}
class _TaakState extends State<Taak> {
firebase_storage.FirebaseStorage ref =
firebase_storage.FirebaseStorage.instance;
// // late String filePath = uploadFile(filePath) as String;
// // String filePath = "IMG_7337.HEIC";
// String? downloadURL;
//
// Future uploadfoto() async {
// try {
// Reference ref = FirebaseStorage.instance.ref("gs://cameratest2-41782.appspot.com");
// await ref.putFile(image!);
// downloadURL = await ref.getDownloadURL();
// print(downloadURL);
// //then((value) => print({('het is je gelukt')}));
// } on firebase_core.FirebaseException catch (e) {
// e.code == 'wat miss gegaan';
// }
// await firebase_storage.FirebaseStorage.instance.ref().child("fotos")".putFile(fileToUpload)";
// // .then((value) => print({('het is je gelukt')}));
// } on firebase_core.FirebaseException catch (e) {
// e.code == 'wat miss gegaan';
// }
// // File file = File(filePath);
// // assert(file.absolute.existsSync());
//
// firebase_storage.FirebaseStorage.instance.ref().child("fotos").putFile(image!);
// // .then((value) => print({('het is je gelukt')}));
//
// // uploadFile(filePath).then((value) => print({('het is je gelukt')}));
String? downloadURL;
// methode for sending Pictures to to the data base
Future<void> uploadPhoto() async {
firebase_storage.Reference ref = FirebaseStorage.instance.ref().child("images");
await ref.putFile(image!);
downloadURL = await ref.getDownloadURL();
print(downloadURL);
}
late final String TaakBeschrijving;
late final String TaakOplossing;
// text string mothde to send text data to the database
Future<void> uploadText() async {
String dataUrl = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==';
try {
await firebase_storage.FirebaseStorage.instance
.ref('uploads/hello-world.text').child(TaakBeschrijving!).child(TaakOplossing!)
.putString(dataUrl, format: firebase_storage.PutStringFormat.dataUrl);
} on firebase_core.FirebaseException catch (e) {
// e.g, e.code == 'canceled'
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Taak'),),
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: GestureDetector(
child: Stack(
children: <Widget>[Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0x66012e67),
Color(0x99012e67),
Color(0xcc012e67),
Color(0xff012e67),
]
)),
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(
horizontal: 25,
vertical: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(height: 1,),
afrondenbutton(),
SizedBox(height: 20,),
taakbeschrijving(),
SizedBox(height: 30,),
taakoplossing(),
SizedBox(height: 20,),
bewijsmatriaal(),
SizedBox(height: 20,),
uploadbutton(context),
SizedBox(height: 50, width: 100,),
screen(context),
SizedBox(height: 200, width: 100,),
Column(
children: [
Row(
),
Container(
child: buildGridViewimages(
),
),
],
),
],
// Text('',
// style: TextStyle(
// color: Colors.white,
// fontSize: 40,
// fontWeight: FontWeight.bold,
// ),),
// ],
),
// ),
// );
),
),
])))
);
}
// Future<void> loadAssets() async {
// List<Asset> resultList = <Asset>[];
// String error = 'No Error Detected';
// resultList = await MultiImagePicker.pickImages(
// maxImages: 10,
// materialOptions: MaterialOptions(
// actionBarColor: "#abcdef",
// actionBarTitle: "Example App",
// allViewTitle: "All Photos",
// useDetailsView: false,
// selectCircleStrokeColor: "#000000",
// ),
// );
//
// setState(() =>
// {
// this.images = resultList as File?;
// error = error;
// });z
// }
//
// File? image, images;
//
// Future<void> pickImage() async {
// final image = await ImagePicker().pickImage(source: ImageSource.gallery);
// if (image == null) return;
// if (image.path == null) return;
//
// final imageFile = File(image.path);
// setState(() => this.image = imageFile);
//
// }
//
// Future getCamera() async {
// final pickedFile = await ImagePicker().pickImage(
// source: ImageSource.camera);
//
// setState(() {
// if (pickedFile != null) {
// image = File(pickedFile.path);
// }
// });
// }
// Future<void> loadAssets() async {
// List<Asset> resultList = <Asset>[];
// String error = 'No Error Detected';
//
// resultList = await MultiImagePicker.pickImages(
// maxImages: 10,
// materialOptions: MaterialOptions(
// actionBarColor: "#abcdef",
// actionBarTitle: "Example App",
// allViewTitle: "All Photos",
// useDetailsView: false,
// selectCircleStrokeColor: "#000000",
// ),
// );
//
// setState(() => {
//
// this.images = resultList
// }
//
// );
// }
File? image;
List<Asset> images = <Asset>[];
final imagePicker = ImagePicker();
// late List<File> images;
// <vooi>
Future pickImage() async {
final pick = await imagePicker.pickImage(source: ImageSource.gallery);
setState(() {
if (pick != null) {
image = File(pick.path);
}
else {
print(Error);
}
});
// final image = await ImagePicker().pickImage(source: ImageSource.gallery);
// if (image == null) return;
// if (image.path == null) return;
// final imageFile = File(image.path);
// this.image = imageFile;
// setState(() => this.image = imageFile);
}
Future getCamera() async {
final pickedFile = await ImagePicker().pickImage(
source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
image = File(pickedFile.path);
}
});
}
Future<void> loadAssets() async {
List<Asset> resultList = <Asset>[];
resultList = await MultiImagePicker.pickImages(
maxImages: 20,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
setState(() {
// uploadFile(filePath);
images = resultList;
});
}
Widget buildGridViewimages() {
return Column(
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
}
Widget screen(BuildContext context) {
if (image != null) {
return
Image.file(image!);
} else {
loadAssets();
return FlutterLogo();
}
}
// final Winkel store = Winkel();
Widget afrondenbutton() {
final ButtonStyle raisedButtonStyle = ElevatedButton.styleFrom(
onPrimary: Colors.white,
primary: Colors.green[300],
minimumSize: Size(260, 36),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15)),
),
);
return Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.all(20),
child: ElevatedButton(
child: const Text('Afronden'),
style: raisedButtonStyle,
onPressed: () {
// if(image != null) {
uploadText();
}
// .store.uploadFile(filePath).then((value) => print('het is je gelukt'));
),
);
}
Widget uploadbutton(BuildContext context) {
final ButtonStyle raisedButtonStyle = ElevatedButton.styleFrom(
onPrimary: Colors.white,
primary: Colors.green[300],
minimumSize: Size(180, 36),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15)),
),
);
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: ElevatedButton(
child: const Text('Uploaden'),
style: raisedButtonStyle,
// FlutterLogo();
onPressed: () {
showImageSourceActionSheet(context);
// Image.network(
// 'https://i0.wp.com/www.joyfromjoyce.nl/wp-content/uploads/2017/07/shutterstock_642124366.jpg?fit=1000%2C667&ssl=1',
// width: 100, height: 50,);
// // // Image.file(File(imagePath)
}
),
);
}
im trying to send data String and pictures to firebase database storage but im getting error with late initialization and null check what is going on so with both ways im getting error is there any other way to solve this please can any one help?
The problem comes from the late in this variable declaration:
late final String TaakBeschrijving;
By using late here you're saying: "I don't know the value of this variable now, but I promise to give it a value before I ever read from it". Then your code goes ahead and reads TaakBeschrijving before it has gotten a value, so Flutter tells you that you broke your promise.
There are a few possible solutions:
Initialize TaakBeschrijving before using it, as you promised by using late
Make TaakBeschrijving nullable (as Yeasin also commented):
String? TaakBeschrijving;
So now you're telling Flutter that TaakBeschrijving may either be a string or it may be null, and Flutter will help you deal with the possible null in all of your code.
Give TaakBeschrijving an initial value:
var TaakBeschrijving = "default value";
Now if you read TaakBeschrijving before changing its value, it'll have its default value.
Which of these solutions is best depends on your situation.
I'm trying to build an app with Flutter and Firebase password-less authentication. I'm able to receive the email from Firebase but when I like on the link
auth.isSignInWithEmailLink(link) says false.
My pubspec.yaml firebase dependencies
firebase_core: ^1.0.3
firebase_auth: ^1.0.2
firebase_dynamic_links: ^2.0.2
Here is the full Login code
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
class LoginPage extends StatefulWidget {
static String tag = "login page";
#override
LoginPageState createState() => new LoginPageState();
}
class LoginPageState extends State<LoginPage> with WidgetsBindingObserver {
String _email;
final _formKey = GlobalKey<FormState>();
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
this.initDynamicLinks();
WidgetsBinding.instance.addObserver(this);
}
void initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
print('DeepLink: ' + deepLink.path);
await _signInWithEmailAndLink(deepLink.toString());
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
}
#override
Widget build(BuildContext context) {
final snackBarEmailSent = SnackBar(content: Text('Email Sent!'));
final snackBarEmailNotSent = SnackBar(
content: Text('Email Not Sent. Error.'),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
validator: (value) {
if (value.isEmpty) return "Email cannot be empty";
return null;
},
onSaved: (value) => _email = value,
decoration: InputDecoration(
hintText: 'Email',
prefixIcon: Icon(Icons.mail),
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
child: Text("Send Verification Email"),
onPressed: (() async => await validateAndSave()
? ScaffoldMessenger.of(context).showSnackBar(snackBarEmailSent)
: ScaffoldMessenger.of(context)
.showSnackBar(snackBarEmailNotSent))),
);
final loginForm = Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24, right: 24),
children: <Widget>[
SizedBox(height: 50),
email,
SizedBox(height: 40),
loginButton
],
),
);
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
body: Center(child: loginForm));
}
Future<bool> validateAndSave() async {
final FormState form = _formKey.currentState;
if (form.validate()) {
form.save();
bool sent = await _sendSignInWithEmailLink();
return sent;
}
return false;
}
Future<bool> _sendSignInWithEmailLink() async {
final FirebaseAuth auth = FirebaseAuth.instance;
try {
auth.sendSignInLinkToEmail(
email: _email,
actionCodeSettings: ActionCodeSettings(
url: 'https://<MyApp>.page.link/<key>',
handleCodeInApp: true,
androidInstallApp: true,
androidMinimumVersion: "12"));
} catch (e) {
_showDialog(e.toString());
return false;
}
print(_email + "<< sent");
return true;
}
Future<void> _signInWithEmailAndLink(link) async {
final FirebaseAuth auth = FirebaseAuth.instance;
// final PendingDynamicLinkData data =
// await FirebaseDynamicLinks.instance.getInitialLink();
// final Uri deepLink = data?.link;
print('Link: ' + link);
bool validLink = auth.isSignInWithEmailLink(link);
print('Is Valid Link: ' + validLink.toString());
if (validLink) {
try {
print('email:' + _email);
print('link:' + link);
await auth.signInWithEmailLink(email: _email, emailLink: link);
} catch (e) {
print('Error' + e);
_showDialog(e.toString());
}
}
}
void _showDialog(String error) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Error"),
content: new Text("Please Try Again.Error code: " + error),
actions: <Widget>[
new TextButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
Let me know what I'm missing here.
Thank you!
Try the plugin app_links along with firebase_dynamic_links.
Sample Code
Future<bool> retrieveDynamicLinkAndSignIn() async {
try {
await Future.delayed(const Duration(seconds: 2));
final _appLinks = AppLinks(
onAppLink: (Uri uri, String url) {
appLogs('onAppLink[$url][$uri]');
},
);
final deepLink = await _appLinks.getInitialAppLink();
appLogs('appLinks.uri[$deepLink]');
if (deepLink != null) {
bool validLink =
_firebaseAuth.isSignInWithEmailLink(deepLink.toString());
if (validLink) {
String email = SPService.instance.getString('email') ?? '';
appLogs('retrieveDynamicLinkAndSignIn[$email]');
if (email.isEmpty) {
return false;
}
SPService.instance.setString('email', '');
final firebase_auth.UserCredential userCredential =
await _firebaseAuth.signInWithEmailLink(
email: email,
emailLink: deepLink.toString(),
);
if (userCredential.user != null) {
await _setUserFromFirebaseUser();
logLogin(SignUp.email, true);
return true;
} else {
logLogin(SignUp.email, false);
AppToast.info(strings.noCredentialsWereFound);
}
} else {
appLogs('Link is not valid');
AppToast.info(strings.noCredentialsWereFound);
}
} else {
appLogs('retrieveDynamicLinkAndSignIn.deepLink[$deepLink]');
}
} catch (e, s) {
AppToast.error(null, e, s);
}
return false;
}
I am trying to upload image in firebase storage getting the image from image picker plugin by accessing camera. Image is not uploading. I also add I change the firebase rules so only authenticated users can upload the image. Git hub Repo. I used the image uploading logic defined at the auth_screen.dart Line No 48 to 59[I commented out for time being]. I also add as i add these line my other firebase fuctions which are running prefectly before. getting the errors.
auth_screen.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
// import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/services.dart';
import '../widgets/auth/auth_form.dart';
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final _auth = FirebaseAuth.instance;
var _isLoading = false;
void _submitAuthForm(
String email,
String password,
String userName,
File userImage,
bool isLogin,
BuildContext ctx,
) async {
dynamic authResult;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
authResult = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
} else {
print(email);
print(userName);
print(userImage.path);
authResult = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// final FirebaseStorage storage = FirebaseStorage(
// app: FirebaseStorage.instance.app,
// storageBucket: 'gs://chatapp-1b780.appspot.com',
// );
// final StorageReference ref2 =
// storage.ref().child('userimage').child('${authResult.user.id}.jpg');
// final StorageUploadTask uploadTask = ref2.putFile(userImage);
// uploadTask.onComplete
// .then((value) => print(value))
// .catchError((error) => print(error));
// print(uploadTask.lastSnapshot.error.toString());
// ///...
// final ref = FirebaseStorage.instance
// .ref()
// .child('user_image')
// .child(authResult.user.id + '.jpg');
// await ref.putFile(userImage).onComplete;
///
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user.uid)
.set({
'username': userName,
'email': email,
});
}
} on PlatformException catch (error) {
var message = 'An error occured,Please check your credentials';
if (error.message != null) {
setState(() {
_isLoading = false;
});
message = error.message;
}
print(message);
} catch (error) {
setState(() {
_isLoading = false;
});
Scaffold.of(ctx).showSnackBar(
SnackBar(
content: Text(error.toString()),
backgroundColor: Theme.of(ctx).errorColor,
),
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: AuthForm(_submitAuthForm, _isLoading),
);
}
}
image being picked using image picker from auth/auth_form.dart to user_image_picker.dart where i added the argument so the image is passed down.
auth/authform.dart
import 'package:flutter/material.dart';
import 'dart:io';
import '../pickers/user_image_picker.dart';
class AuthForm extends StatefulWidget {
final bool isLoading;
final void Function(String email, String password, String userName,
File userImage, bool isLogin, BuildContext ctx) submitFn;
AuthForm(this.submitFn, this.isLoading);
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
String _userEmail = '';
String _userName = '';
String _userPassword = '';
File _userImageFile;
void _pickedImage(File image) {
_userImageFile = image;
}
void _trysubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (_userImageFile == null && !_isLogin) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Please Pick an Image'),
backgroundColor: Theme.of(context).errorColor,
),
);
return;
}
if (isValid) {
_formKey.currentState.save();
print(_userEmail);
print(_userPassword);
widget.submitFn(_userEmail.trim(), _userPassword.trim(), _userName.trim(),
_userImageFile, _isLogin, context);
print(_userEmail);
print(_userPassword);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (!_isLogin)
UserImagePicker(
imagePickFn: _pickedImage,
),
TextFormField(
key: ValueKey('emailAdress'),
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email address',
),
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please return a valid email address';
}
return null;
},
onSaved: (newValue) {
_userEmail = newValue;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('userName'),
decoration: InputDecoration(labelText: 'Username'),
validator: (value) {
if (value.isEmpty || value.length < 4) {
return 'Please Enter at least 4 characters';
}
return null;
},
onSaved: (newValue) {
_userName = newValue;
},
),
TextFormField(
key: ValueKey('password'),
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Please Enter at least 7 characters';
}
return null;
},
onSaved: (newValue) {
_userPassword = newValue;
},
),
SizedBox(
height: 12,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
RaisedButton(
onPressed: _trysubmit,
child: Text((_isLogin) ? 'Login' : 'SignUp'),
),
if (!widget.isLoading)
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(_isLogin
? 'Create new account'
: 'I already have an account'),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
],
),
),
),
),
),
),
);
}
}
user_image_picker.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class UserImagePicker extends StatefulWidget {
UserImagePicker({this.imagePickFn});
final void Function(File pickedImage) imagePickFn;
#override
_UserImagePickerState createState() => _UserImagePickerState();
}
class _UserImagePickerState extends State<UserImagePicker> {
File _image;
final picker = ImagePicker();
Future<void> getImage() async {
final pickedFile = await ImagePicker().getImage(source: ImageSource.camera);
setState(() {
_image = File(pickedFile.path);
});
widget.imagePickFn(_image);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 40,
backgroundColor: Colors.grey,
backgroundImage: _image != null ? FileImage(_image) : null,
),
FlatButton.icon(
onPressed: getImage,
icon: Icon(Icons.image),
label: Text('Add Image'),
textColor: Theme.of(context).primaryColor,
),
],
);
}
}
Since you asked me to show you how to upload images to Firebase Storage, I will show you the whole procedure including using the Image Picker plugin. This is how you should use Image Picker:
class PickMyImage{
static Future<File> getImage() async {
final image = await ImagePicker().getImage(
source: ImageSource.gallery,
maxHeight: 1500,
maxWidth: 1500,
);
if (image != null) {
return File(image.path);
}
return null;
}
}
This is how you can get and upload that image to firebase storage:
final File _myImage=await PickMyImage.getImage();
if(_myImage!=null){
final StorageReference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("user/${_auth.currentUser().uid}/i"); //i is the name of the image
StorageUploadTask uploadTask =
firebaseStorageRef.putFile(_myImage);
StorageTaskSnapshot storageSnapshot = await uploadTask.onComplete;
var downloadUrl = await storageSnapshot.ref.getDownloadURL();
if (uploadTask.isComplete) {
final String url = downloadUrl.toString();
print(url);
//You might want to set this as the _auth.currentUser().photourl
} else {
//error uploading
}
}
The issue i got because i am returning the ImagePicker() function of the file then gettting the image from camera then passing the file to the Fire Storage bucket.
In user_image_picker.dart
I written this
final pickedFile = await ImagePicker().getImage(source: ImageSource.camera);
Instead of i have to write this
final pickedFile = await picker.getImage(source: ImageSource.camera);
I started learning Flutter. I am developing a simple application using it. Now, I am developing a feature where my application will display the records from the SQLite database and where the user adds the new records into the SQLite database. But my ListView is displaying the blank screen.
I have a class called DatabaseHelper with the following code.
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
Database _database;
String noteTable = 'note_table';
String colId = 'id';
String colTitle = 'title';
String colDescription = 'description';
String colPriority = 'priority';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'notes.db';
var notesDatabase = await openDatabase(path, version: 1, onCreate: _createDB);
return notesDatabase;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $noteTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, $colDescription TEXT, $colPriority INTEGER, $colDate TEXT)');
}
Future<List<Map<String, dynamic>>> getNoteMapList() async {
Database db = await this.database;
return await db.query(noteTable, orderBy: '$colPriority ASC');
}
Future<int> insertNote(Note note) async {
Database db = await this.database;
return await db.insert(noteTable, note.toMap());
}
Future<int> updateNote(Note note) async {
var db = await this.database;
return await db.update(noteTable, note.toMap(), where: '$colId = ?', whereArgs: [note.id]);
}
Future<int> deleteNote(int id) async {
var db = await this.database;
return await db.rawDelete('DELETE FROM $noteTable WHERE $colId = $id');
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT(*) FROM $noteTable');
return Sqflite.firstIntValue(x);
}
}
Then I have a widget called NoteList with the following code where the list of items are displayed.
class NoteList extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _NoteListState();
}
}
class _NoteListState extends State<NoteList> {
List<Note> _notes = [];
int _count = 0;
DatabaseHelper _databaseHelper = DatabaseHelper();
_NoteListState() {
this._notes = getNotes();
this._count = _notes.length;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Notes"),),
body: Container(
child: getListView(context),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
navigateToNoteForm("Add Note");
},
),
);
}
Widget getListView(BuildContext context) {
return ListView.builder(
itemCount: _count,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: _notes[index].priority == 1? Colors.yellow: Colors.red,
child: Icon(_notes[index].priority == 1 ? Icons.arrow_right : Icons.add),
),
title: Text(_notes[index].title),
subtitle: Text(_notes[index].date),
trailing: Icon(Icons.delete),
onTap: () {
navigateToNoteForm("Edit Note", _notes[index]);
},
);
});
}
void navigateToNoteForm(String pageTitle, [Note note]) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return NoteForm(pageTitle, note);
}));
if (result) {
setState(() {
debugPrint("Updating list");
_notes = getNotes();
_count = _notes.length;
});
}
}
List<Note> getNotes() {
List<Note> notes = List<Note>();
Future<List<Map<String, dynamic>>> notesFuture = _databaseHelper.getNoteMapList();
notesFuture.then((notesMap) {
debugPrint("Total notes found in the database ${notesMap.length}");
notesMap.forEach((map) {
notes.add(Note.fromMapObject(map));
});
});
return notes;
}
}
Then I also have another widget class called NoteForm with the following code.
class NoteForm extends StatefulWidget {
String _title = "";
Note _note = null;
NoteForm(String title, [Note note]) {
this._title = title;
this._note = note;
}
#override
State<StatefulWidget> createState() {
return _NoteFormState();
}
}
class _NoteFormState extends State<NoteForm> {
double _minimumPadding = 15.0;
var _priorities = [ 1, 2 ];
var _titleController = TextEditingController();
var _descriptionController = TextEditingController();
var _dateController = TextEditingController();
DatabaseHelper _databaseHelper = DatabaseHelper();
var _selectedPriority = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget._title),),
body: Builder(
builder: (scaffoldContext) => Form(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _titleController,
decoration: InputDecoration(
labelText: "Title",
hintText: "Enter title"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _descriptionController,
decoration: InputDecoration(
labelText: "Description",
hintText: "Enter description"
),
),
)
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _dateController,
decoration: InputDecoration(
labelText: "Date",
hintText: "Enter date"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: DropdownButton<int>(
value: _selectedPriority,
items: _priorities.map((dropdownItem) {
return DropdownMenuItem<int>(
value: dropdownItem,
child: Text(dropdownItem == 1? "Low": "High"),
);
}).toList(),
onChanged: (int newSelectedValue) {
setState(() {
_selectedPriority = newSelectedValue;
});
},
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: RaisedButton(
child: Text(
"Save"
),
onPressed: () {
_save(scaffoldContext);
},
),
),
)
],
),
),
)
);
}
void _save(BuildContext context) async {
Note note = Note();
note.title = _titleController.text;
note.description = _descriptionController.text;
note.date = _dateController.text;
note.priority = _selectedPriority;
if (widget._note != null && widget._note.id!=null) {
//update
_databaseHelper.updateNote(note);
this.showSnackBar(context, "Note has been updated.");
} else {
//create
_databaseHelper.insertNote(note);
this.showSnackBar(context, "Note has been added.");
}
closeForm(context);
}
void showSnackBar(BuildContext context, String message) {
var snackBar = SnackBar(
content: Text(message),
action: SnackBarAction(
label: "UNDO",
onPressed: () {
},
),
);
Scaffold.of(context).showSnackBar(snackBar);
}
void closeForm(BuildContext context) {
Navigator.pop(context, true);
}
}
When I run my application, it is just displaying the blank screen as follows.
As you can see I am logging out the number of records returned from the database using debugPrint method. It is saying that there are 6 records within the database. It is just not displaying the records. What is wrong with my code and how can I fix it?
As i mention in comment that was happening because of async task take some time to perform and if you do not keep it async then setState function execute before actual data load or set.
So Following changes solve your issue.
make getNotes async method And
getNotes().then((noteresponce){ setState((){ _notes=noteresponce; _count = _notes.length;} });