Countdown timer with Cloud Firebase - firebase

I am working on a project where images in Firebase database disappear after 10 seconds. I can achieve this to some extent with this code on the front end, however, it doe snot link directly to the post, so every time the page is refreshed, the duration also starts over. Is there a way to make my timer start from the post date in the database?
Code:
SizedBox(
height: MediaQuery.of(context).size.height * 0.35,
width: double.infinity,
child: Image.network(
widget.snap['postUrl'].toString(),
fit: BoxFit.cover,
),
),
TweenAnimationBuilder<Duration>(
duration: Duration(seconds: 10),
tween: Tween(begin: Duration(seconds: 10), end: Duration.zero),
onEnd: () {
deletePost(
widget.snap['postId'].toString(),
);
},
builder: (BuildContext context, Duration value, Widget? child) {
final minutes = value.inMinutes;
final seconds = value.inSeconds % 60;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Text('$minutes:$seconds',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.green,
backgroundColor: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 130)
)
);
}
),
Future<String> uploadPost(Uint8List file, String uid, String profImage) async {
String res = "Some error occurred";
try {
String photoUrl =
await StorageMethods().uploadImageToStorage('posts', file, true);
String postId = const Uuid().v1();
Post post = Post(
uid: uid,
postId: postId,
datePublished: DateTime.now(),
postUrl: photoUrl,
profImage: profImage,
);
_firestore.collection('posts').doc(postId).set(post.toJson());
res = "success";
} catch (err) {
res = err.toString();
}
return res;
}

Related

Flutter: How can I get my stream to show updated value without having to reload the page?

I have user time spent on app from firebase in seconds, I then convert it into hours, min and sec, and want to display to the user, I'm using streams but it will not update when there is a new value. I have to reload the page or go to a different page then come back to see the updated value. What am I doing wrong?
late Stream<String> testStream;
#override
void initState() {
super.initState();
setState(() {
testStream = printDuration();
});
});
}
Stream<String>printDuration() async*{
FirebaseFirestore.instance
.collection("users")
.doc(user!.uid)
.snapshots()
.listen(
(event) => print("current data: ${event.data()!['timeActive']}"),
onError: (error) => print("Listen failed: $error"),
);
Duration duration = Duration(seconds: loggedInUser.timeActive!);
String? data = loggedInUser.timeActive.toString();
print('###');
print(data);
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
String _getData = "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
print(_getData);
yield _getData;
}
StreamBuilder<String>(
stream: testStream,
builder: ((context, snapshot) {
if (snapshot.data != null) {
//userDocument['timeActive'];
return Center(
child: Text(snapshot.data,
style: TextStyle(
color: Color(0xff516395),
fontSize: 26.0,
letterSpacing: 2.0,
fontWeight: FontWeight.bold,
),
),
);
} else {
return Text('0',
style: TextStyle(
color: Color(0xff516395),
fontSize: 30.0,
letterSpacing: 2.0,
fontWeight: FontWeight.bold,
));
}
}),
)

Getting specific data values from Realtime Database in Flutter

I'm working on a project with Firebase (Realtime database). In this project I will have a main screen with will have several buttons according to the user. The Buttons info are going to be stored inside the realtime database. This is basically a Home Automation project.
This is how my db looks:
The quantity, means how many buttons does that user have. button1 and button2 have the button characteristics. So what I'm attempting to do is.
When the user logs in. I have a Streambuilder that will check if the quantity has data. If I has if will run inside a For loop which will create the buttons in the user screen.
I having problem getting the specific values from the database, for example, getting the quantity and storing into a variable in the main screen.
This is how I'm attempting to get the quantity (I will use this code for getting other values too, later on) but it isn't working:
Future<int> receive_quantity() async{
final FirebaseUser user = await _auth.currentUser();
var snapshot = databaseReference.child(user.uid+"/buttons"+"/quantity").once();
var result;
await snapshot.then((value) => result = value);
print(result);
return result;
}
Error that I get:
_TypeError (type 'DataSnapshot' is not a subtype of type 'FutureOr<int>')
My StreamBuilder:
body: StreamBuilder(
stream: _auth.getButtonQuantity(),
initialData: 0,
builder: (context, snapshot) {
if (snapshot.hasError || snapshot.hasError){
return Container(color: Colors.red);
}
if (!snapshot.hasData || !snapshot.hasData){
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasData || snapshot.hasData){
return GridView.count(
padding: EdgeInsets.all(15),
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
crossAxisCount: 3,
children: [
for (int i = 0; i < buttonquant; i++){
Button(),
},
GestureDetector(
onTap: () async{
_auth.receive_quantity();
},
child: Container(
color: Colors.black,
width: 150,
height: 150,
child: Icon(Icons.add, color: Colors.white,),
),
),
],
);
}
}
),
My Button:
class Button extends StatelessWidget {
const Button({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
},
child: Container(
width: 150,
height: 150,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(15)
),
child: Stack(
children: [
Positioned(
top: 10,
left: 10,
child: Icon(
Icons.lightbulb,
size: 35,
color: Colors.white,
),
),
Positioned(
top: 95,
left: 15,
child: Text("Televisao", style: TextStyle(color: Colors.white),),
),
],
),
),
);
}
}```
What you need to do is you need to get the value of the snapshot not using it directly:
Future<int> receive_quantity() async{
final FirebaseUser user = await _auth.currentUser();
var snapshot = await databaseReference.child(user.uid+"/buttons"+"/quantity").once();
var result = snapshot.value; //get the value here
print(result);
return result;
}
This is how you get the value in general:
databaseReference.once().then((DataSnapshot snapshot) {
print('Data : ${snapshot.value}');
});

Retrieving Data From Firestore in time (outside of Widget build(BuildContext context) )

If you would like some context I asked a similar question here. In my flutter app you are able to send emails
static getEmailCredentials(String email1, String password1) {
email = email1;
passw = password1;
}
sendMail() async {
String username = email;//gets email from db
String password = passw;//gets password for email from db
final SmtpServer = gmail(username, password); //fix one day
final message = Message()
..from = Address(username)
..recipients.add("xxx#gmail.com")
..subject = "From "+name //need name here from db
..html = "<h3>" + emailContent.text + "</h3>";
try {
final SendReport = await send(message, SmtpServer);
Fluttertoast.showToast(
msg: "Message sent! Hang in there!",
gravity: ToastGravity.CENTER,
);
} on MailerException catch (e) {
e.toString();
Fluttertoast.showToast(
msg: "Message failed to send! Try again?",
gravity: ToastGravity.CENTER,
);
}
}
}
As seen above. I know it's probably not the best to store the email and password but it works (well it would work if the data came in time). So my problem is I'll run this function at the beginning of the app but sometimes it won't load in on time.
UI Code:
class EmergencyReport extends StatelessWidget {
EmergencyReport();
static String email;
static String passw;
final TextEditingController emailContent = TextEditingController();
#override
Widget build(BuildContext context) {
getEmailCredentialsF();//function that calls to db
DateTime now = DateTime.now();
DateTime weekAgo = now.subtract(new Duration(days: 7));
DateFormat formadate = DateFormat('dd-MM');
String formatedDate = formadate.format(now); // current date formatted
String weekAgoForm =
formadate.format(weekAgo); // date from week ago formatted
countDocuments();
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Container(
width: 54,
margin: EdgeInsets.only(top: 44),
child: FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Column(
children: <Widget>[Icon(Icons.arrow_back_ios)],
),
),
),
),
Text(
"Emergency Report",
style: new TextStyle(
color: Colors.white,
fontSize: MediaQuery.of(context).size.width / 10,
),
),
Card(
margin: EdgeInsets.only(top: 30),
color: Colors.white,
child: Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
controller: emailContent,
maxLines: 8,
decoration: InputDecoration.collapsed(
hintText: "Enter what happened here..."),
),
)),
Container(
width: 260,
height: 70,
padding: EdgeInsets.only(top: 20),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Text(
"Send",
style: new TextStyle(
color: Colors.white,
fontSize: 38.0,
),
),
color: Colors.grey[850],
onPressed: () {
if (emailContent.text != "") {
sendMail();
Navigator.of(context).pop();
} else {
Fluttertoast.showToast(
msg: "You need to put a message!",
gravity: ToastGravity.CENTER,
);
}
},
),
),
],
),
),
),
),
);
}
void getEmailCredentialsF() {
print("Attemping to get email!");
final firestoreInstance = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
firestoreInstance.collection("SendMailCredentials").doc("w1HsHFRgq7Oc3X9xUEnH").get().then((value) {
EmergencyReport.getEmailCredentials((value.data()["email"]),(value.data()["password"]));
});
}
Is there a way to make the code wait for that information to be gathered from the db before running the rest? I've tried await and async and future builders (could have used them wrong I am fairly new to flutter)
Thank you for all the help you give
Pic of UI if it helps UI
yesterday I've answered you this
FutureBuilder<DocumentSnapshot>(
future: firestoreInstance.collection("Users").doc(uid).get(),
builder: (_,snap){
return snap.hasData ? Text(snap.data.data()["firstName"]):CircularProgressIndicator();
},)
now implement the same like
Lets say you have a Object which you keep saperate from UI
class MyDB{
//...
}
and you need to get document in users collection
class MyDB{
MyDB();
Map<String,dynamic> userData;
Future<void> getUser() async {
userData = //...set
}
}
and you want to get something else
class MyDB{
MyDB();
Map<String,dynamic> userData;
Map<String,dynamic> someThingElse;
Future<void> getUser() async {
userData = //...set
}
Future<void> getSomeThingElse() async {
someThingElse = //...set
}
}
and you want to wait for all these data to be available before you show anything
class MyDB{
MyDB();
Map<String,dynamic> userData;
Map<String,dynamic> someThingElse;
Future<void> getUser() async {
userData = //...set
}
Future<void> getSomeThingElse() async {
someThingElse = //...set
}
Future getEveryThing() async {
await getUser();
await getSomeThingElse();
}
}
now use that getEverything future in UI
final myDB = MyDB();
build(){
return FutureBuilder<bool>(
future: myDB.getEveryThing(),
builder: (_,snap){
if(snap.hasData){
//myDB.userData and myDB.someThingElse will not be null
}
//if we are still waiting for the data
return CircularProgressIndicator();
},);
}

Flutter Sending data to Firebase.(problem with cupertinopicker)

First Sorry about my bad English and I just started to learn Flutter.
So I want to get all the informations in Firestore and I cant solve these problems.
Question 1:
If i click the select button, Cupertinopicker will show up and the result will show right next to the button. So If I pick b, i want the result sended to the Firestore. and I have no idea how i can...with the CupertinoPicker...
I would also like to know how i can use the validator and show the error sign too
enter image description here
This is the code below with the Cupertinopicker. I want the
Text(_countryType[_selectedIndex] sendend to Firebase.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton(
borderRadius: BorderRadius.circular(29.0),
color: kPrimaryColor,
padding: const EdgeInsets.all(12.0),
child: Text(
"select",
style: TextStyle(fontSize: 16.0),
),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 170.0,
child: CupertinoPicker(
scrollController:
new FixedExtentScrollController(
initialItem: _selectedIndex,
),
itemExtent: 32.0,
onSelectedItemChanged: (int index) {
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
children: new List<Widget>.generate(
_countryType.length, (int index) {
return new Center(
child: new Text(_countryType[index]),
);
})),
);
});
},
),
Container(
margin: EdgeInsets.symmetric(vertical: 17),
width: 70,
child: Center(
child: Text(
_countryType[_selectedIndex],
style: TextStyle(fontSize: 16.0),
),
),
),
SizedBox(
height: 20.0,
),
],
),
Question2: I want all email, password, name, alphabet(the one with the cupertinopicker) sended to the firestore User. So i want to put it in [User- uid- fields ]I'm also stucked here too.
This is the Signup button below.
Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: size.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(29),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
color: kPrimaryColor,
onPressed: () async {
try {
FirebaseUser user = (await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
))
.user;
if (user != null) {
UserUpdateInfo updateUser = UserUpdateInfo();
updateUser.displayName = _usernameController.text;
user.updateProfile(updateUser);
Navigator.of(context).pushNamed(AppRoutes.authLogin);
}
} catch (e) {
print(e);
_usernameController.text = "";
_passwordController.text = "";
_repasswordController.text = "";
_emailController.text = "";
}
setState(() {
saveAttempted = true;
});
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
}
},
child: Text(
"Sign Up",
style: TextStyle(color: Colors.white),
),
),
),
),
Which code do I need to use....
It would be super helpful if someone help me..Im so stressed out.
Thank you very much
I am assuming that you are aware of the basics of how to use Firebase with Flutter.
For the first question, all you need to do is call a function inside
onSelectedItemChanged: (int index) {
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
What happens here is, whenever you select an item. onSelectedItemChanged is called. So all you need to do is call a function here
Example -
onSelectedItemChanged: (int index) {
addToFirebase(_countryType[_selectedIndex]);
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
For your second question, Firebase authentication doesn't work like that. User details are stored in the Authentication area of Firebase. You cannot see the password as well. To store the country type attached with the user, you can use the User's Id as the key as it will be unique.
FirebaseUser user = (await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
))
.user;
String uid = user.uid;

Flutter: CRUD clarifications over Firebase

I've been working on a little project on flutter since I just started learning it a week ago and I'm just wondering how I could retrieve a specific snippet of data from Firebase's Firestore database.
Here is the code on the relevant files:
database.dart
import 'package:plannus/models/user.dart';
class DatabaseMethods {
final String uid;
DatabaseMethods({this.uid});
final CollectionReference users = Firestore.instance.collection("users");
Future<void> updateUserData(String name, String handle) async {
print(uid);
return await users.document(uid).updateData({
'name' : name,
'handle' : handle,
});
}
Future<void> updateSpecificUserData(String uid, String name, String handle) async {
print(uid);
return await users.document(uid).updateData({
'name' : name,
'handle' : handle,
});
}
Future<Set<Set<String>>> getUserData() {
return users.document(uid).get().then((value) => {
if (value.exists) {
value.data['handle']
}
});
}
void getSpecificUserData(String uid, String capture) async {
DocumentSnapshot snapshot = await users.document(uid).get();
capture = snapshot.data['handle'];
print(capture);
}
Future<String> retrieveData(String uid) async {
DocumentSnapshot snap = await users.document(uid).get();
Map<String, String> map = snap.data;
String handle = map['name'];
return handle;
}
//
uploadUserInfo(userMap) {
Firestore.instance.collection("users").add(userMap);
}
// user data from snapshot
Stream<QuerySnapshot> get userInfo {
return users.snapshots();
}
}
profile.dart
import 'package:flutter/material.dart';
import 'package:plannus/messages/database.dart';
import 'package:plannus/models/user.dart';
import 'package:plannus/services/auth.dart';
import 'package:provider/provider.dart';
class Profile extends StatefulWidget {
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
final AuthService auth = AuthService();
final formKey = GlobalKey<FormState>(); // 'id' of form
bool loading = false;
// text field state
String name = '';
String password = '';
String handle = '';
String error = '';
DatabaseMethods databaseMethods = new DatabaseMethods();
QuerySnapshot currentUser;
#override
Widget build(BuildContext context) {
User user = Provider.of<User>(context);
String handle = '';
print(user.uid);
Future<String> str = databaseMethods.retrieveData(user.uid);
str.then((value) => {
handle = value
});
print(handle);
return new Scaffold(
// appBar: AppBar(
// title:
// ),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 50),
child: Form(
key: formKey, // keep track of form and its state
child : Column (
children: <Widget>[
Image.asset('assets/profilepicture.png', height: 300, width: 300),
SizedBox(height: 20),
TextFormField(
decoration: InputDecoration(
hintText: 'Name',
icon: Icon(Icons.person_outline, color: Colors.blue),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[300], width: 2),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
)
),
validator: (val) => val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
SizedBox(height: 20),
TextFormField(
decoration: InputDecoration(
hintText: 'Handle',
icon: Icon(Icons.alternate_email, color: Colors.blue),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[300], width: 2),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
)
),
obscureText: false,
validator: (val) => val[0] != '#' ? 'Handle starts with #!' : null,
onChanged: (val) {
setState(() => handle = val);
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget> [
RaisedButton(
color: Colors.blueAccent,
child: Text(
'Update',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if(formKey.currentState.validate()) {
print(user.uid);
await databaseMethods.updateSpecificUserData(user.uid, name, handle);
setState(() {
error = 'Update successful!';
});
}
},
),
],
),
SizedBox(height: 12),
Text(
error,
style: TextStyle(color: Colors.black, fontSize: 16),
)
],
),
),
),
);
}
}
My code can be real messy (for which I apologise because I have been stuck on this for a quite long time and have been rigorously attempting various methods to extract the data out).
Ultimately, my main objective is to get the value(handle) from my data stored in firebase and then to dynamically display it on my appbar.
My firebase database collection is named 'users' and carries only data { name: "...", handle: "..."}.
Thanks for bearing with my long post.
Profile page
Here is how you can get data from firebase's firestore. I think its best to rename your "name" as "n" to make the size of your data stored in the database smaller.
await Firestore.instance
.collection('users')
.document(uid)
.get()
.then((DocumentSnapshot ds) {
username = ds["name"];
});

Resources