How to restrict the user from creating more than one doc in firestore database? - flutter

I have a form on my flutter app where the userr can submit his personal info:
try {
await FirebaseFirestore.instance
.collection('users')
.doc(userID).collection('personalInfo')
.add(_insertProfInfoToDBToDB.toJson());
This function is triggered by a sunmit button, now the problem is that if the user doesnt have an internet connection for example and he submit this form, then he will get an error that there is no internet connection which is coming from another function
Future<void> _tryConnection() async {
try {
final response = await InternetAddress.lookup('Example.com');
setState(() {
_isConnectionSuccessful = response.isNotEmpty;
});
} on SocketException catch (e) {
print(e);
setState(() {
_isConnectionSuccessful = false;
});
}
if (_isConnectionSuccessful != true){
Utils.showSnackBar("Please check your internet connection");
}
}
but this doesnt restric him from pressing the submit button again and again and again...
So what is happening is that once the user gets an internet connection, there will be multiple docs created at the same time inside the 'personalInfo' collection.
My question is how to restrict the user from creating more than one doc inside a collection?

Use setData
Firestore.instance.
collection('users').
document('userID').collection('collection name').document('docId')
set(data, merge: true)
Now this will create a new entry if it doesnt exist and update it if its existing
From the docs
setData(Map<String, dynamic> data, {bool merge: false}) → Future
Writes to the document referred to by this DocumentReference. If the document does not yet exist, it will be created.
.If merge is true, the provided data will be merged into an existing document instead of overwriting.>

Related

Execute a code after await function finishes

I have this scenario where I have a list of books that is populated with a listview builder via an API. And each list has an add button where a user can add the books into the local db (sqlite). I am trying to check on the tap the add button if the book already exists, the user will be alerted with a pop and won't be able to add.
This is the code where I check if the book exists in the DB or not. The function _checkBookExist gets called on the onPressed in button in the list.
My problem is, till the time SQL query gets executed, the rest of the statements finishes. Any elegant way to address the issue ? I tried using .then() and .whenComplete() but those didn't work either.
_checkBookExist(id, author, title, thumbnail) async {
final List<BookShelf> result = await bookshelfDb.bookExists(id);
// below statements where I check if the book exist
if (result.length == 0 || result[0].volumeid == id) {
final booksToAdd = BookShelf(
author: author,
volumeid: id,
thumbnail: thumbnail,
title: title,
dateAdded: date.toString());
// below statements adds the book into the DB
await bookshelfDb.addItem(booksToAdd).then((value) => {
SnackBarMessage.snackBar(context, "Added to Bookshelf", "Ok", 2000),
});
} else {
print("Book Exist");
}
}
await waits until asynchronous addItem is executed and only after the execution of the rest continues.
await bookshelfDb.addItem(booksToAdd);
SnackBarMessage.snackBar(context, "Added to Bookshelf", "Ok", 2000);

How to handle reading from database when API-request hasn't finished yet to save to database in Flutter?

For my App i'm loading the link for the background-image for each screen from my API.
Right after the query that downloads and saves the image-link, i'm querying the link from the database.
The problem now is, that the function isn't waiting for the download and saving to finish although i'm using await, therefor i get an empty result from the database and get an error from the imageloader.
Future<String> downloadAsset(String name) async {
final Map<String, String> _json = {
'mandant': Config.mandant,
'name': name
};
final query = MakePost('get_app_assets', false, _json, saveAsset);
await query.queryAPI(); // Function won't wait for this to finish
String ret = await dbAppAssets.getText(name); // Get link from database
return ret;
}
I've already tried to use .then(), but the same thing happens.
This only happens initially on the first call of each screen, but how is this normally beeing handled?
I'm using riverpod with futureProviders if that matters.
I do not know where you are using the downloadAsset function, but when you use Future on a function you should also await the function where you are using it, for example:
Future<void> _reverseScrollToTopAnimation() async {
await controller!.reverse();
_showBackToTopButton = false; // hide the back-to-top button
}
then, wherever you call it you should also await that function:
await _reverseScrollToTopAnimation();
If not the function will act as a synchronous operation even though you are using await inside the function.

Flutter - How to save a file requesting permission with Permission Handler if my code is deprecated?

I'm new to Flutter and I've been following this tutorial but it's from 2020 and I know a lot of things have changed.
I want to save a file on my local phone and apparently I need to ask permission to do so. I'm not sure if checking the platform is still needed or not.
I don't want to run the --no-sound-null-safety command.
This is the only part that I wasn't able to update by myself.
_save() async {
if (Platform.isAndroid) {
await _askPermission();
}
var response = await Dio().get(widget.imgUrl!,
options: Options(responseType: ResponseType.bytes));
final result =
await ImageGallerySaver.saveImage(Uint8List.fromList(response.data));
print(result);
Navigator.pop(context);
}
_askPermission() async {
if (Platform.isIOS) {
await PermissionHandler().requestPermissions([PermissionGroup.photos]);
} else {
await PermissionHandler().checkPermissionStatus(PermissionGroup.storage);
}
}
The _save method seems alright but I wonder if there's something to update there as well.
The _askPermission method is the one that I need help with.

How to use StreamBuilder in FirebaseStorage to inform my App from changes in my Firebase Storage? In Flutter

Here is my challenge:
I'm using the following example from https://firebase.flutter.dev/docs/storage/usage/
to upload images to my FireBaseStorage from my phone gallery (which delivers me the String filepath-variable).
Future<void> handleTaskExample2(String filePath) async {
File largeFile = File(filePath);
firebase_storage.UploadTask task = firebase_storage.FirebaseStorage.instance
.ref('uploads/picture-to-upload.jpeg')
.putFile(largeFile);
task.snapshotEvents.listen((firebase_storage.TaskSnapshot snapshot) {
print('Task state: ${snapshot.state}');
print(
'Progress: ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100} %');
}, onError: (e) {
print(task.snapshot);
if (e.code == 'permission-denied') {
print('User does not have permission to upload to this reference.');
}
});
try {
await task;
print('Upload complete.');
} on firebase_core.FirebaseException catch (e) {
if (e.code == 'permission-denied') {
print('User does not have permission to upload to this reference.');
}
// ...
}
}
Actually, everything works fine. My uploaded Image to my Storage gets shown in my GridView inside the App...
But if I upload an Image to my Storage manually over the FireBase Website, my gridView (where the pictures from my storage are shown) is not auto-updating.
But if I change my screen and come back, the manually uploaded picture is shown.
It looks like I need something like a StreamBuilder that my App gets informed whenever changes happen in my Storage.
Does anyone have an Idea how to implement this or any other ideas to solve my problem?
Thanks
The listAll and list only get the data once so you unfortunately can't have a stream on them. You have 2 options here.
Call the listAll in a periodic interval like every 2-3 min
Create a cloud functions that get's triggered when files get uploaded to that specific directory and change a value in RTDB or Firestore. In the App you can listen to that data. Idealy it should be just a timestamp. You can store in your app the last timestamp you got from the database and if that changes just call listAll.
It depends on your usecase what would fit for you the best.

Open an app in flutter based on the url provided in the email sent for verification

So I have been working on a flutter app and once the user registers through my app they are sent an email for the verification of their account. Once the url in the link is tapped they are verified. Now after their verification,the users must be redirected to the app. I looked into firebase dynamic links but in all of the articles,they were trying to share their app by generating a link. Is there a way I can implement this? Thanks in advance!
Use this package
https://pub.dev/packages/uni_links
For getting the link when the app is started.
This is the case in which your app was in the closed state.
Future<Null> initUniLinks() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
String initialLink = await getInitialLink();
// Parse the link and warn the user, if it is not correct,
// but keep in mind it could be `null`.
} on PlatformException {
// Handle exception by warning the user their action did not succeed
// return?
}
}
For listening to link clicks. This is for the case when your app is already open and you click the link.
_sub = getLinksStream().listen((String link) {
// Parse the link and warn the user, if it is not correct
}, onError: (err) {
// Handle exception by warning the user their action did not succeed
});
// NOTE: Don't forget to call _sub.cancel() in dispose()
}
Usually, you need to implement both of them together since your app may be in the closed state or open state while you click the link.
Future<Null> initUniLinks() async {
try {
String initialLink = await getInitialLink();
} on PlatformException {
}
_sub = getLinksStream().listen((String link) {}, onError: (err) {});
}}