I have to pass parameter to Future async function from floatingbutton
My Codes like
FloatingActionButton(
onPressed: getImageFromCam,
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
),
And
Future getImageFromCam() async { // for camera
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
});
}
It is multiple button so i have to pass index to async function.
Can anyone please help to solve this.
Thanks in advance
Sathish
You cannot explicitly specify any argument when using a tear-off. Instead, you should manually define a closure:
FloatingActionButton(
onPressed: () => getImageFromCam(index),
tooltip: 'Pick Image',
child: Icon(Icons.add_a_photo),
);
...
Future<void> getImageFromCam(int index) async {
// Do whatever you want with `index`.
final image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() => _image = image);
}
Related
How to disable onTap function when a single click has been clicked. Using Flutter.
This is my code below, kindly help me check it out...
class VoteCalonUmumPage extends StatelessWidget {
const VoteCalonUmumPage({Key? key, required this.title}) : super(key: key);
final String title;
Widget _buildListItem(BuildContext context, DocumentSnapshot document) {
return ListTile(
tileColor: Color(0xff99c2ec),
title: Row(
children: [
Expanded(
child: Text(document['name'],
style: TextStyle(
color: Colors.black87,
fontSize: 20,
)),
),
Container(
decoration: const BoxDecoration(
color: Color(0xffecc399),
),
padding: const EdgeInsets.all(10.0),
child: Text(
document['votes'].toString(),
style: Theme.of(context).textTheme.headline4,
),
),
],
),
onTap: () {
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'votes': freshSnap['votes'] + 1,
});
});
},
);
}
}
Checkout below code a simple logic it may help you ,
bool isLoading = false; //global variable
onTap: () {
if(!isLoading)
{
isLoading = true;
try{
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap = await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {'votes': freshSnap['votes'] + 1,});
isLoading = false;
});
}catch((e){
isLoading = false
});
}
},
In order to actually disable the onTap handler you have to pass null to onTap. I would create a variable inside this class to keep track of if the onTap has been pressed yet, and if it has, pass null to onTap rather than your callback function.
onTap: onTapPressed ? null : () {
setState(() {
// call set state here so that the UI will be updated.
onTapPressed = true;
});
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'votes': freshSnap['votes'] + 1,
});
});
},
And then in your widget add this member.
bool onTapPressed = false;
Also ListTile also has an optional parameter called enabled, which you could set to false instead of passing null to onTap. This approach will disable all handlers on the ListTile, not just the onTap (you might also have an onLongPress handler for example). And it will also update the styling to use the disabled colors from the current Theme.
disabled: !onTapPressed,
onTap: () {
setState(() {
// call set state here so that the UI will be updated.
onTapPressed = true;
});
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'votes': freshSnap['votes'] + 1,
});
});
},
Please refer to below code
IgnorePointer is a built-in widget in flutter which is similar to the AbsorbPointer widget, they both prevent their children’s widget from pointer-events which are taping, clicking, dragging, scrolling, and hover.IgnorePointer widget just ignores the pointer-events without terminating it, which means if there is any other element below the IgnorePointer widget tree then it will be able to experience that pointer-event.
bool disableOnClick = false;
IgnorePointer(
ignoring: disableOnClick ?? false,
child: ListTile(
tileColor: Color(0xff99c2ec),
title: Row(
children: [
Expanded(
child: Text(document['name'],
style: TextStyle(
color: Colors.black87,
fontSize: 20,
)),
),
Container(
decoration: const BoxDecoration(
color: Color(0xffecc399),
),
padding: const EdgeInsets.all(10.0),
child: Text(
document['votes'].toString(),
style: Theme.of(context).textTheme.headline4,
),
),
],
),
onTap: () {
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'votes': freshSnap['votes'] + 1,
});
});
disableOnClick = true;
setState(() {});
},
),
)
you can make condition like :-
set one bool variable and set it true and when user tap on button set it false if you want to permanently disable use prefrences
bool isClicked = true;
GestureDetector(
onTap: (){
if(isClicked){
isClicked = true;
enter code here
}
}
child: Container(),
)
I am trying to work out how a user can upload a eg a profile image and have this store in firebase. this is the code I have so far which shows the image picker but I cannot get the path nor have the image uploaded
dynamic _showSelectImageDialog() {
return Platform.isIOS ? _iosBottomSheet() : _androidDialog();
}
Future _iosBottomSheet() async => showCupertinoModalPopup(
context: context,
builder: (context) {
return CupertinoActionSheet(
// title: Text('Add Photo'),
actions: <Widget>[
CupertinoActionSheetAction(
onPressed: () => _upload(ImageSource.camera),
child: const Text('Take Photo'),
),
CupertinoActionSheetAction(
onPressed: () => _upload(ImageSource.gallery),
child: const Text('Choose Photo'),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
);
},
);
_androidDialog() {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text('Add Photo'),
children: <Widget>[
SimpleDialogOption(
onPressed: () => _upload(ImageSource.camera),
child: const Text('Take Photo'),
),
SimpleDialogOption(
onPressed: () => _upload(ImageSource.gallery),
child: const Text('Choose From Gallery'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context),
child: const Text(
'Cancel',
style: TextStyle(
color: Colors.redAccent,
),
),
),
],
);
},
);
}
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
_upload(ImageSource source) async {
var picker = ImagePicker();
PickedFile pickedImage;
try {
pickedImage = (await picker.pickImage(source: source, maxWidth: 1920))
as PickedFile;
File imageFile = File(pickedImage.path);
try {
// Uploading the selected image with some custom meta data
await storageRef
.child('uploads/user/avatar/${widget.user.id}/$imageFile.jpg')
.putFile(imageFile);
print(imageFile);
// Refresh the UI
setState(() {});
} on FirebaseException {
// print(error);
}
} catch (err) {
print(err);
}
Navigator.pop(context);
}
_displayProfileImage() {
// No new profile image
if (_profileImage == null) {
// No existing profile image
if (widget.user.profileImageUrl.isEmpty) {
// Display placeholder
return AssetImage('assets/images/user_placeholder.jpg');
} else {
// User profile image exists
return CachedNetworkImageProvider(widget.user.profileImageUrl);
}
} else {
// New profile image
return FileImage(File(_profileImage.path));
}
}
1) Pick image using image picker
Put this package in your pubspec.yaml
image_picker: ^0.8.4+4
2) Use this code to pick image
image = await _picker.pickImage(source: ImageSource.gallery);
3) save the image in firebase cloud and get the image URL
Put these packages in your pubspec.yaml
cloud_firestore: ^3.1.0
firebase_storage: ^10.1.0
firebase_core: ^1.10.0
Use this code to upload the image to cloud storage
var imageFile = File(image!.path);
String fileName = basename(imageFile.path);
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref =
storage.ref().child("Image-" + productname.text);
Use this code to get the URL
UploadTask uploadTask = ref.putFile(imageFile);
await uploadTask.whenComplete(() async {
var url = await ref.getDownloadURL();
image_url = url.toString();
}).catchError((onError) {
print(onError);
});
4) Finally add image url to firebase database
Code to add data to firebase database
Map<String, dynamic> demodata = {
"image_url": imageurl
};
CollectionReference collectionreference =
FirebaseFirestore.instance.collection(image);
collectionreference.add(demodata);
I'm trying to get the "Child_Name" and "Parent_Name" from firebase rtdb and create a list of the names using ListView.builder. I have done this before in another part of the app and it works perfectly. I am trying to apply the same logic again but I am getting an error.
Error is occurs inside the setState where the line childrenList = Map.from(value) is.
View of my firebase rtdb
is here (image)
Error:
- [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'forEach' was called on null.
- Tried calling: forEach(Closure: (dynamic, dynamic) => void)
Code(1):
Future<List> getListOfChildren() async {
print("Getting Children");
databaseReference
.child("users")
.child("Absent_Children")
.child(formattedDate)
.onValue
.listen(
(event) {
setState(
() {
var value = event.snapshot.value;
childrenList = Map.from(value)
.values
.map((e) => Children.fromJson(Map.from(e)))
.toList();
},
);
},
);
return childrenList;
}
Code(2): Class for the data
class Children {
final String childName;
final String parentName;
Children({
this.childName,
this.parentName,
});
static Children fromJson(Map<dynamic, dynamic> json) {
return Children(
childName: json["Child_Name"],
parentName: json["Parent_Name"],
);
}
}
Code(4): formattedDate
getTodaysDate() {
setState(
() {
DateTime now = DateTime.now();
var date = DateFormat("dd-mm-yyyy");
formattedDate = date.format(now).toString();
},
);
}
Code(3): My ListView.builder
body: childrenList.isEmpty
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: childrenList.length,
itemBuilder: (context, int index) {
final Children child = childrenList[index];
final String childName = child.childName;
final String parentName = child.parentName;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
child: ExpansionTile(
title: Text(
childName.toUpperCase(),
style: GoogleFonts.lexendMega(),
textAlign: TextAlign.center,
),
children: [
Column(
children: [
Text(
parentName,
textAlign: TextAlign.center,
style: GoogleFonts.lexendMega(fontSize: 13),
),
],
)
],
),
),
);
},
),
Thank you.
As I said here too, it looks like there's no data as databaseReference.child("users").child("Absent_Children").child(formattedDate) and your code doesn't handle that situation.
If the absence of data is a normal occurrence, you should check if the snapshot has a value before trying to access its value:
databaseReference
.child("users")
.child("Absent_Children")
.child(formattedDate)
.onValue
.listen(
(event && event.snapshot.exists) { // 👈 add exists check here
setState(
() {
var value = event.snapshot.value;
childrenList = Map.from(value)
.values
.map((e) => Children.fromJson(Map.from(e)))
.toList();
},
);
Hello Im very to the flutter framework, so please let me know if im going wrong anywhere and the appropriate way of doing the things.
this is a drawerPage.dar file
In this file im trying to call a function getData for retrieving the data from firebase,this fucntion is in Database.dart file.
Database.dart
In the Database.dart file i wrote the getData function inside which im retrieving a particular record from the firebase and storing in a global variable. And then im trying to print the global variable in the drawerPage.dart file.But here when ever i run the program, for the first time the variable is having a null value and upon hot reload the actual value is getting stored in the variable.Please let me know how can i get rid of this problem.
output
drawerPageOutput
drawerPage.dart
import 'package:attendee/constants.dart';
import 'package:attendee/models/userdeails.dart';
import 'package:attendee/pages/profile.dart';
import 'package:attendee/services/authentication_service.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:attendee/services/database.dart';
import 'package:provider/provider.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:attendee/pages/userdetails.dart';
class StudentDashboard extends StatefulWidget {
#override
_StudentDashboardState createState() => _StudentDashboardState();
}
class _StudentDashboardState extends State<StudentDashboard> {
userdetails userdetail;
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final AuthenticationService _auth = AuthenticationService();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
DatabaseService().getData('email');
final drawerHeader = UserAccountsDrawerHeader(
accountName: Text(userName),
accountEmail: Text('${result}'),
currentAccountPicture
: CircleAvatar(
child: FlutterLogo(size: 42.0),
backgroundColor: Colors.white,
);
final drawerItems = ListView(
children: <Widget>[
drawerHeader,
ListTile(
title: Row(
children: <Widget>[
Icon(Icons.perm_identity_outlined),
Text(' Profile'),
],
),
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (context)=>Profile())),
),
ListTile(
title: Text('To page 2'),
onTap: () => Navigator.of(context).push(_NewPage(2)),
),
ListTile(
title:Row(
children: <Widget>[
Icon(Icons.exit_to_app_rounded),
Text(' Logout'),
],
),
onTap: () async {
await _auth.signOut();
Navigator.of(context).pushNamed('/homepage');
},
),
],
);
return StreamProvider<List<userdetails>>.value(
value: DatabaseService().students,
initialData: [],
child: SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightGreen,
title: Text('Student Welcome'),
actions: <Widget>[
TextButton.icon(
onPressed: () async {
await _auth.signOut();
Navigator.of(context).pushNamed('/homepage');
},
icon: Icon(Icons.person),
label: Text('Logout'))
],
),
body:
UserDetails(),
drawer: GestureDetector(
onTap: display,
child: Drawer(
child: drawerItems,
),
),
),
),
);
}
display() async{
await DatabaseService().getData('email');
}
}
// <Null> means this route returns nothing.
class _NewPage extends MaterialPageRoute<Null> {
_NewPage(int id)
: super(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page $id'),
elevation: 1.0,
),
body: Center(
child: Text('Page $id'),
),
);
});
}
database.dart
import 'package:attendee/models/userdeails.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import '../constants.dart';
class DatabaseService{
final String uid;
DatabaseService({this.uid});
//collection reference
final CollectionReference user_details=FirebaseFirestore.instance.collection('users');`
final CollectionReference tutor_details` `=FirebaseFirestore.instance.collection("tutors");`
Future updateStudentData(String fullname,String mobilenumber,String `email,String rollno,String tutorid,String role) async {`
return await user_details.doc(uid).set({
'fullname' : fullname,
'mobilenumber': mobilenumber,
'email' : email,
'rollno': rollno,
'tutorid': tutorid,
'role' : role,//FMERT series
});
}
Future updateTutorData(String fullname,String mobilenumber,String `email,String rollno,String tutorid,String role) async {`
return await tutor_details.doc(uid).set({
'fullname' : fullname,
'mobilenumber': mobilenumber,
'email' : email,
'rollno': rollno,
'tutorid': tutorid,
'role' : role,//FMERT series
});
}
//studentDetails from snapshot
List<userdetails> _studentDetailsFromSnapshot(QuerySnapshot snapshot){
return snapshot.docs.map((doc){
return userdetails(
fullname: doc.data()['fullname'] ?? '',
mobilenumber: doc.data()['mobilenumber'] ?? '',
email: doc.data()['email'] ?? '',
rollno: doc.data()['rollno'] ?? '',
tutorid: doc.data()['tutorid'] ?? '',
//role: doc.data()['role'] ?? '',
);
}).toList();
}
//get students stream
Stream<List<userdetails>> get students {
return user_details.snapshots()
.map(_studentDetailsFromSnapshot);
}
//tutorsDetails from snapshot
List<userdetails> _tutorDetailsFromSnapshot(QuerySnapshot snapshot){
return snapshot.docs.map((doc){
return userdetails(
fullname: doc.data()['fullname'] ?? '',
mobilenumber: doc.data()['mobilenumber'] ?? '',
email: doc.data()['email'] ?? '',
rollno: doc.data()['rollno'] ?? '',
tutorid: doc.data()['tutorid'] ?? '',
);
}).toList();
}
//get tutors stream
Stream<List<userdetails>> get tutors {
return user_details.snapshots()
.map(_studentDetailsFromSnapshot);
}
void display() {
tutor_details.get().then((querySnapshot) {
querySnapshot.docs.forEach((result) {
print(result.data());
});
});
}
getData (String string) async{
String userId = await FirebaseAuth.instance.currentUser.uid;
final document = isTutor ? `FirebaseFirestore.instance.doc('tutors/$userId') :`
await FirebaseFirestore.instance.doc('users/$userId');
document.get().then((DocumentSnapshot) async {
if(string =='role') {
checkRole = DocumentSnapshot.data()[string].toString();
print('$checkRole inside getData Function');
//return checkRole;
print(checkRole);
}
else {
print(result);
result = await DocumentSnapshot.data()[string].toString();
print('${DocumentSnapshot.data()[string].toString()} in the `database else block');`
//return result;
}
//print(document("name"));
});
}
}
After changes
terminaloutput
draweroutput
""when ever i run the program, for the first time the variable is having a null value and upon hot reload the actual value is getting stored in the variable""
When we try to get data from http / https request, it takes some time. Meanwhile the page gets loaded and you get null values.
You can use Provider package to resolve this issue, or try the below code. Please add the below code in your drawerPage.dart.
What I have done below is made getData() return type. Only on receiving a value from this function, _loadOnce will change to false & final screen will be shown.
Database.dart
Future<bool> getData (String string) async{
String userId = await FirebaseAuth.instance.currentUser.uid;
final document = isTutor ? `FirebaseFirestore.instance.doc('tutors/$userId') :`
await FirebaseFirestore.instance.doc('users/$userId');
document.get().then((DocumentSnapshot) async {
if(string =='role') {
checkRole = DocumentSnapshot.data()[string].toString();
print('$checkRole inside getData Function');
//return checkRole;
print(checkRole);
return true;
}
else {
print(result);
result = await DocumentSnapshot.data()[string].toString();
print('${DocumentSnapshot.data()[string].toString()} in the `database else block');`
//return result;
return false;
}
//print(document("name"));
});
}
}
/// create a new variable.
bool _loadOnce = true;
/// shift your code `DatabaseService().getData('email');`
#override
void didChangeDependencies() {
if(_loadOnce == true) {
DatabaseService().getData('email').then((value) {
if(value == true){
setState(() {
_loadOnce = false;
});
} else {
/// you can write your code here
setState(() {
_loadOnce = false;
});
}
)}
}
super.didChangeDependencies();
}
Below code will show a spinner till the time all the code gets executed and values are retreived.
/// in your main page under Scaffold
body: _loadOnce == true
? Center(
child: CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor,
),
)
: UserDetails(),
The method in my code is supposed to grab the timeout needed for questions for our survey mobile app. The method, however, only returns null even though we establish a document snapshot that should hold a copy of the data. We have a fallback hard coded in so that when the timeout is null it will return a default widget.
WE have tried several asyncs and awaits in the widget and the method it self and none of them seem to be able to make the widget wait for the timeout from the firestore document.
const fiveSeconds = Duration(seconds: 5);
Future<int> getTimeOutData() async{
int toReturn;
Firestore.instance.collection("config").getDocuments().then((DocumentSnapshot) async=>{
Future.delayed(fiveSeconds, () async => toReturn = await DocumentSnapshot.documents[0]['timeout']),
print( toReturn)
});
return toReturn;
}
Widget _buildListItem(BuildContext context, DocumentSnapshot doc) {
return ListTile(
title: Text(
doc['question_text'].toString(),
style: Theme.of(context).textTheme.headline,
),
dense: true,
trailing: Icon(Icons.keyboard_arrow_right),
contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
onTap: () async{
timeout= await getTimeOutData();
envelope = new Envelope(doc['complete'], doc.documentID, doc['user'],
doc['question'], doc['answer_text'], doc['answer_type'], doc['time_stamp']);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ViewAnswerController(envelope, timeout);
},
),
);
},
selected: true,
);
}
I expect 1 millisecond but the actual value is null on print within the method and on a later check in a different widget.
const fiveSeconds = Duration(seconds: 5);
Future<int> getTimeOutData() async{
int toReturn;
await Firestore.instance.collection("config").getDocuments().then((DocumentSnapshot) async=>{
await Future.delayed(fiveSeconds, () async => toReturn = await DocumentSnapshot.documents[0]['timeout']),
print( toReturn)
});
return toReturn;
}
Nevermind I just needed some more awaits because .then() is also a Future object.