How do I get a query from another file to return a bool? - flutter

I am integrating the following system into my to-do app:
Every time the user opens the app, it should check whether the date stored in Cloud Firestore has been exceeded.
If this is the case, all To-Dos of the user should be reset to false.
This is the date in Cloud Firestore Iā€™m looking for:
This function should check if the date has been exceeded:
Future<bool> checkTime() async{
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
And this function should reset all To-Dos to false:
Future allFalse() async{
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level' : updateMap});
});
}
I created both functions in a separate file (database), as you can see here:
class DatabaseService {
String userID;
DatabaseService(this.userID);
final CollectionReference users =
FirebaseFirestore.instance.collection('users');
Future allFalse() async {
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level': updateMap});
});
}
Future<bool> checkTime() async {
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
}
I create an if condition in in inite State that includes checkTime. If checkTime returns true, the Future returns allFalse, which sets all To-Dos to false.
class _UebersichtState extends State<Uebersicht> {
User? user;
late DatabaseService database;
Future<void> connect() async{
final FirebaseAuth auth = FirebaseAuth.instance;
UserCredential result = await auth.signInAnonymously();
user = result.user;
database = DatabaseService(user!.uid);
}
#override
void initState() {
// TODO: implement initState
super.initState();
connect();
Future.delayed(Duration(seconds: 3), () async{
if(await database.checkTime()) {
return await database.allFalse();}
else print('Still time left');
});
}
I used a delay because the connect () function has to be executed first, it initializes database.
When I start the app, no error appears, but the To-Dos are not reset either.
Today we have the 21. 12. 2021 and in Cloud Firestore is 14. 12. 21 deposited.
The function allFalse works, it resets the To-Dos all.
It must be the function checkTime, which does not return a bool in the if condition. I just replaced it with if (0 == 0) and that triggers allFalse.
Can someone help me?

This is just a guess, but I believe this is the problem:
query = query.where('userID', isEqualTo: userID);
The above line would only work if your document had a field userID and said field was equal to your UID, but from what I could gather, you identify the UID by the name of the documents, if that is the case, this should work?
Future<bool> checkTime() async {
CollectionReference users = FirebaseFirestore.instance.collection('users');
final now = DateTime.now();
final doc = await users.doc(userID).get();
final stufenzeit = (doc.data() as Map<String, dynamic>)['Stufenzeit'] as Map<String, dynamic>;
final storedDate = (stufenSetit['Startdatum'] as TimeStamp).toDate();
return now.compareTo(storedDate) > 0;
}
There's probably also a way to do it with queries, but I am not so well versed on those to be completely honest.

Related

Instance of 'Future<String?>' flutter

Why is returning Instance of 'Future<String?>' instead String value?
Future<String?> getUser() async {
User user = await FirebaseAuth.instance.currentUser!;
FirebaseFirestore firestore = await FirebaseFirestore.instance;
String uid = user.uid;
String? userName;
// to get username from firebase
return firestore
.collection("users")
.doc(uid)
.get()
.then((value) {
if (value.exists) {
var data = value.data();
userName = data?["name"];
print("There is data :$userName");
} else {
print("There no Data!");
}
return Future.value(userName);
});
}
I am trying to get String value?
The place you like to get data from this method use await & the method is needed to be async. like
_myFunction() async{
final value = await getUser();
Also I will suggest to not mixing await and .then.
Future<String?> getUser() async {
User user = FirebaseAuth.instance.currentUser!;
FirebaseFirestore firestore = FirebaseFirestore.instance;
String uid = user.uid;
String? userName;
// to get username from firebase
final value = await firestore.collection("users").doc(uid).get();
if (value.exists) {
var data = value.data();
userName = data?["name"];
print("There is data :$userName");
} else {
print("There no Data!");
}
return userName;
}

Future not waiting to resolve before next then Flutter Dart

I'm trying to return a list of values.
Assessing by using Late
late List userLikes = userListLikes.getUsersLikes();
My Code:
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
List getUsersLikes() {
try {
print('start');
final docRef = _firestore.collection("user_details").doc(user.uid);
docRef.get().then((DocumentSnapshot doc) async {
final data = doc.data() as Map<String, dynamic>;
print("data[user_likes]");
print(data['user_likes']);
print('end');
return await data['user_likes']; // ā†’ not awaiting
},
onError: (e) => print("Error getting document: $e"),
);
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
}
The function is not completing and returns before the await has finished which is not the array I need.
start
[Nothing Returned] (Returns without completing)
data[user_likes]
[967, 769, 887, 820, 860, 833, 857, 1017] ā†’ The Array I want returned
end
As someone downvoted this answer here is the full working code:
This get an Array field from a Firestone database and then returns a list dynamic.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
Future<List> getUsersLikes() async {
// Get the list of user likes from the Firestone Database and then
// return the list so it will only show the users likes on the profile page.
try {
final docRef = _firestore.collection("user_details").doc(user.uid);
DocumentSnapshot doc = await docRef.get(); // Await
final data = doc.data() as Map<String, dynamic>;
return data['user_likes'];
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
Future<List> getLikes() async {
// Takes the Future<List> and turns it into a List<dynamic>
Future<List> userLikes = getUsersLikes();
List list = await userLikes;
return list; // Returns List<dynamic>
}
}
Then on the receiving Future builder it will have to be awaited.
GetUserLikes userLikesList = GetUserLikes();
List userLikes = await userLikesList.getLikes();

async function not completing when querying FirebaseFirestore

See the print statement down below. It never executes.
Future<void> populate() async {
final userId = FirebaseAuth.instance.currentUser!.uid;
final db = FirebaseFirestore.instance;
// Get list of ids of parties use swiped on.
var snapshot1 = await db
.collection("partiers_swipes")
.where('userId', isEqualTo: userId)
.get();
var partyIdsUserSwipesOn = [];
if (snapshot1.size > 0) {
snapshot1.docs.forEach((element) {
partyIdsUserSwipesOn.add(element.data()['partyId']);
});
}
var snapshot2 = await db
.collection("parties")
.where(FieldPath.documentId, whereNotIn: partyIdsUserSwipesOn)
.get();
print('This never executes');
}
The whereNotIn argument is not supported by the where clause. This crashes the function.

for-loop should wait for future

I have a list of userIDs and I want to get a value from the database for each user and write it to a new list. But the for loop doesn't wait for the future and throws the error "Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0"
List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
Future <dynamic> getList() async {
List items=[];
for (var i = 0; i < userIDs.length; i++) {
items[i] = await getUserItems(userIDs[i]);
}
return items;
}
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
database.ref().child('users').child(_userID!).once().then((pdata) {
userItem = pdata.snapshot.child('item').value as String?;
});
return userItem;
}
This is not problem with future. List items is empty so when you call items[0] = 3; there is no items[0] and you get RangeError. Proper way to add element to list is call items.add(3)
So your code should look like this:
List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
Future <dynamic> getList() async {
List items=[];
for (var i = 0; i < userIDs.length; i++) {
final item = await getUserItems(userIDs[i]);
items.add(item);
}
return items;
}
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
database.ref().child('users').child(_userID!).once().then((pdata) {
userItem = pdata.snapshot.child('item').value as String?;
});
return userItem;
}
By using .then you are telling dart to continue running and come back when the Future completes.
Instead you should use await inside getUserItems.
You have to fiddle around a bit but here's a suggestion to start with:
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
userItem = (await database.ref().child('users').child(_userID!).once()).snapshot.child('item').value as String?
return userItem;
}
Also using String? for userItem and setting it to " " is a bit of an anti pattern. Since you allow it to be nullable i'd suggest having it as null writing your logic around that.
Try to use it like this
Future <dynamic> getList() async {
List items=[];
userIDs.forEach((item) async {
items.add(await getUserItems(item));
});
return items;
}

How convert FirebaseUser to string in flutter?

Here is my code of a stateful class:
String id = FirebaseAuth.instance.currentUser().toString();
my function :
readLocal() async {
prefs = await SharedPreferences.getInstance();
id = prefs.getString('id') ?? '';
if (id.hashCode <= peerId.hashCode) {
groupChatId = '$id-$peerId';
} else {
groupChatId = '$peerId-$id';
}
setState(() {});
}
It works fine in String id.
I want the ID to be the same as the current user UID.
Calling FirebaseAuth.instance.currentUser() return a FirebaseUser, which is an object with all user data. If you only want the UID of the user:
FirebaseUser user = await FirebaseAuth.instance.currentUser();
String uid = user.uid;
Update: I just ran this and it prints the UID for me:
void _getUser() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
print(user.uid);
}
Which printed:
flutter: P07IXLCrwEahYlDhzO1Iv0SKDat2
Things to notice:
In order to be able to use await in the code, the method must be marked as async.