Hi I'm newbie at coding and Flutter is my first language.
I want to delete Firestore data(Chat List) which is in the ListView from the StreamBuilder when user long tab the 'OK' button in AlertDialog.
(Process Summary:
longPress one item of the ListViewBuilder
show check AlertDialog
tab 'OK'
OK button's Function execute)
But when i longPress the item, then the deleteFunction(OK button's function) is automatically executed before i see the dialog.
How can I make it?
It is really difficult!
Here is my code
StreamBuilder(
stream: chatRoomDB,
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.active &&
snapshot.data != null) {
return ListView(
children: snapshot.data!.docs
.map<Widget>((DocumentSnapshot ds) {
Map<String, dynamic> data =
ds.data()! as Map<String, dynamic>;
receiverProfileImageURL = data['ProfileImageURL'];
receiverUID = data['UserID'];
receiverNickName = data['NickName'];
msgContent = data['MsgContent'];
chatID = data['ChatID'];
return Container(
margin: EdgeInsets.all(3),
child: ListTile(
shape: Border(
bottom:
BorderSide(color: Colors.grey, width: 1)),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChattingRoom(
chatID: data['ChatID'],
receiverUID: data['UserID'],
receiverImageURL:
data['ProfileImageURL'],
receiverNickName: data['NickName'],
)));
},
onLongPress: () => checkDialog2(
context: context,
msg: 'Delete?',
okButtonString: 'OK',
okFunction: chatDBDeleteFunction(
data['UserID'], data['ChatID']),
noButtonString: 'No'),
leading: Container(
child: CircleAvatar(
foregroundImage: NetworkImage(
'$receiverProfileImageURL',
),
backgroundImage:
NetworkImage('$errorImageURL'),
)),
title: Text('$receiverNickName'),
),
);
}).toList());
}
return Container();
})
checkDialog2({
required context,
required String? msg,
required String? okButtonString,
required Future<dynamic> okFunction,
required String? noButtonString,
}) {
print(1);
okFunctions(okFunc) {
print(3);
okFunction;
Navigator.pop(context);
print(4);
}
print(5);
showDialog(
context: context,
builder: (context) {
print(2);
return AlertDialog(content: Text('$msg'), actions: <Widget>[
TextButton(
onPressed: () => okFunctions(okFunction),
child: Text(
'$okButtonString',
textAlign: TextAlign.end,
),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
'$noButtonString',
textAlign: TextAlign.end,
),
),
]);
});
}
Future chatDBDeleteFunction(receiverUID, chatID) async {
await FirebaseFirestore.instance
.collection('ChatMessage')
.doc('${FirebaseAuth.instance.currentUser?.uid}')
.collection(chatID)
.get()
.then((QuerySnapshot qs) => {
qs.docs.forEach((DocumentSnapshot snapshot) {
snapshot.reference.delete();
})
});
Log Order is,
print 1->5>2 and automatically deleted + showDialog.
At that time(list item already disappeared), if i tab the 'OK' button, then print '3' and error(because there is nothing to delete)
(ps. although i change the okfunction to the void Function, it starts automatically. same)
Thanks for your help
I would prefer passing the UserId and ChatId and then call the chatDBDeleteFunction(receiverUID, chatID) Function and pass the values from values
TextButton(
onPressed: () {
Class.chatDBDeleteFunction(receiverUID, chatID)
}
)
The chatDBDeleteFunction(receiverUID, chatID) function can be static
Related
I am currently developing an App. At my registration page, I want to check the password and password confirm text box for equality and check for duplicate email or phone registration. I have a function, which calls my api in order to check, whether the email/phone number is already registered. I call the function when I press the button, so I wrapped it in a FutureBuilder and assigned it to the future property of the builder. I know, it is better to load the future element in the initState method and assign it to a variable, which then you assign to the builder property, but I can't do that, as I only get the email/phone number after the widget is built the first time.
So, now to my problem:
I assign the desired error text to the textbox in the build method. I have wrapped the assignments in a setState.
So, normally the error text should be shown, if i press the register button.
However, this only happnes after I hot-reload the flutter app. I find this very confusing and I tried several things:
I tried to wrap it only with a setState, I tried it with a StatefulBuilder, I tried to outsource the assignment into a function, which then I call in the build method. Nothing worked, so I am asking here and hope to get an answer to my specific question :)
Here is the Code of the button in the build method:
StatefulBuilder(
builder: (context, setState) => FutureBuilder(
future: checkForDuplicates(
_emailBox.controller.text, _phoneBox.controller.text),
builder: (BuildContext context,
AsyncSnapshot<String> snapshot) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
),
child: Text(
"Registrieren",
style: TextStyle(
fontSize: 20,
color: Theme.of(context).dividerColor),
),
onPressed: () {
setState(
() {
_dateController.text = _backupDate;
_dateController.text.isEmpty
? _validate = true
: _validate = false;
},
);
if (_pBox.controller.text !=
_confirmPasswordBox.controller.text) {
setState(() {
_pBox.errorText =
"Passwörter stimmen nicht überein!";
_confirmPasswordBox.errorText =
"Passwörter stimmen nicht überein!";
});
} else {
if (_formKey.currentState!.validate()) {
if (snapshot.hasData) {
if (snapshot.data == "email-already-exists") {
setState(() {
_emailBox.errorText =
"Email existiert beretis!";
});
} else if (snapshot.data ==
"phone-already-exists") {
setState(() {
_emailBox.errorText =
"Telefonnummer existiert beretis!";
});
} else {
//no duplicates
if (_isChecked) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
AddPersonalDataScreen(
firstName: _fNameBox
.controller.text
.trim(),
lastName: _lNameBox
.controller.text
.trim(),
dateOfBirth:
DateTime
.parse(
_dateInput.text),
email: _emailBox
.controller.text
.trim(),
password:
_pBox.controller.text,
phoneNumber: _phoneBox
.controller.text
.trim()),
),
(route) => false,
);
}
}
} else {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"AGB's nicht akzeptiert!",
style: TextStyle(
fontSize: 20,
color:
Theme.of(context).dividerColor),
),
content: Text(
"Um sich zu Registrieren müssen Sie den AGB's zustimmen!",
style: TextStyle(
fontSize: 20,
color:
Theme.of(context).dividerColor),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Container(
decoration: BoxDecoration(
borderRadius:
const BorderRadius.all(
Radius.circular(50),
),
color: Theme.of(context)
.colorScheme
.primary,
),
padding: const EdgeInsets.all(25),
child: Text(
"Zurück",
style: TextStyle(
fontSize: 20,
color: Theme.of(context)
.dividerColor),
),
),
),
],
),
);
}
}
}
},
);
},
),
),
Here is the function, which calls the api (but i dont think it is important to the problem):
Future<String> checkForDuplicates(String email, String phoneNumber) async {
var phpScript = "XXX";
var response = await http.post(Uri.parse(phpScript), body: {
'email': email,
'phoneNumber': phoneNumber,
});
return response.body;
}
I want to import information retrieved from FirebaseAuth into a Text Widget and display it.
I'm new to Flutter and don't know much about it, so I'd like to know more.
By the way, I was able to get the information and display it in Print.
This is the code for the retrieving side.
void initState(){
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
String? name = user.displayName; // <-- User ID
String? email = user.email; // <-- Their email
String? image = user.photoURL;
String? uid = user.uid;
print(name);
print(email);
print(uid);
print(image);
}
});
}
This is the code for the side you want to display
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => account()),
);
},
child:
UserAccountsDrawerHeader(
accountName:Text('name'),//I want it to appear here
accountEmail: Text('email',style: TextStyle(color: Colors.white),),//I want it to appear here
currentAccountPicture: CircleAvatar(
child: ClipOval(
child: Image.network(
'https://pbs.twimg.com/profile_images/1494938183448281089/xXIv3xmE_400x400.jpg',
width: 90,
height: 90,
fit: BoxFit.cover,
),
),
),
decoration: BoxDecoration(
color: Colors.lightGreen,
image: DecorationImage(
image: NetworkImage(
'https://pbs.twimg.com/profile_banners/1394312681209749510/1634787753/1500x500',
),
fit: BoxFit.cover,
),
),
),
),
ListTile(
leading: Icon(Icons.event_available_outlined),
title: Text('行事予定'),
onTap: () {
launch('https://www.ous.ac.jp/common/files//285/20220311164731084854.pdf');
},
),
ListTile(
leading: Icon(Icons.public_outlined),
title: Text('マイログ'),
onTap: () {
launchUrl(Uri.https('mylog.pub.ous.ac.jp', '/uprx/up/pk/pky501/Pky50101.xhtml'),mode:LaunchMode.externalApplication );
},
),
ListTile(
leading: Icon(Icons.book_outlined),
title: Text('学生便覧'),
onTap: () {
launch('https://edu.career-tasu.jp/p/digital_pamph/frame.aspx?id=7540000-3-30&FL=0');
},
),
Divider(),
ListTile(
leading: Icon(Icons.link_outlined),
title: Text('各種リンク集'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Link()),
);
},
),
ListTile(
leading: Icon(Icons.call_outlined),
title: Text('各種連絡先'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Call()),
);
},
),
Divider(),
ListTile(
leading: Icon(Icons.settings_outlined),
title: Text('設定/その他'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Setting()),
);
},
),
],
),
);
}
}
You can declare the fields you want to display as members of your state class:
class YourWidgetState extends State<YourWidget> {
String? name;
String? email;
String? image;
String? uid;
// ...
Then in your initState() method, set those values rather than create new variables:
void initState(){
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
// here, don't declare new variables, set the members instead
setState(() {
name = user.displayName; // <-- User ID
email = user.email; // <-- Their email
image = user.photoURL;
uid = user.uid;
});
}
});
}
And then when you want to display the values, you can create Text widgets with them:
#override
Widget build(BuildContext context) {
// ...
Text(name ?? 'default text if name is null')
// similar for the other values you want to diplay
}
I wonder if i can use Navigator afther i get API data and I want to navigate to another page when i use ElevatedButton. But for some reason i cannot navigate to another page when i want to use it inside FutureBuilder.
This is the full code:
ElevatedButton(
style: ElevatedButton.styleFrom(
fixedSize: const Size.fromHeight(20),
maximumSize: const Size.fromWidth(250),
primary: clientSettings
.getColor("login_button_color"),
shape: const StadiumBorder(),
),
onPressed: () {
var credentials = {
"data[email]": _emailController.text,
"data[password]":
_passwordController.text
};
FutureBuilder(
future:
DataFeed().getDataFeed(credentials),
builder: (BuildContext context,
AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
var dataFeed = snapshot.data;
var _list = dataFeed["data"]
["views"]
.values
.toList();
Navigator.of(context)
.pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
AppView(
selectedMenuItems:
_list[0])),
(Route<dynamic> route) =>
false);
return dataFeed;
} else {
return const CircularProgressIndicator();
}
},
);
},
child: Text(
'Login',
style: TextStyle(
fontFamily:
clientSettings.getLogoAsset(
"login_font_family"),
fontSize: clientSettings
.getNumber("login_font_size"),
color: clientSettings
.getColor("login_text_color")),
)),
You can directly await an api call and navigate to the next page. You dont need a future builder
onPressed:() async{
var response = await DataFeed().getDataFeed(credentials);
Navigator.push();
}
Here reponse will have same data as snapshot.data.
I need to update the percentage var inside the AlertDialog, I know that you can't update anything inside the showDialog() which I am using here because it is built in another Widget tree, but worth asking, it would really be very helpful.
Thanks in advance. :)
Update
The uploadTask listener redo the function until sth like Navigator pushes to a different screen.
My Code
Future storageupload() async {
await checkInternet();
try {
if (controller == null) {
dialog('Error', 'Please Provide A Video Name', () => {});
} else {
StorageReference ref = FirebaseStorage.instance
.ref()
.child("Khatma 1")
.child("Videos")
.child(controller.text != null ? controller.text : "");
StorageUploadTask uploadTask = ref.putFile(
File(Variables.lastVideoPath),
StorageMetadata(contentType: 'video/mp4'));
uploadTask.events.listen((event) {
if (uploadTask.isComplete) {
AwesomeDialog(
context: context,
headerAnimationLoop: false,
dialogType: DialogType.SUCCES,
animType: AnimType.BOTTOMSLIDE,
title: 'Uploaded',
desc: 'Your Video Was Successfully Uploaded !',
btnOkOnPress: () => {print('success')},
)..show();
} else {
setState(() {
percentage = event.snapshot.bytesTransferred /
event.snapshot.totalByteCount *
100;
});
}
});
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Uploading'),
content: Column(
children: [
Center(
child: Text('Uploading .... Please Be Patient'),
),
SizedBox(
height: height * 0.02,
),
Text(percentage.toString()),
],
),
);
},
);
}
} catch (e) {
print(e);
}
}
code
return StatefulBuilder(
builder: (BuildContext context, void function) => AlertDialog(
title: Text('Uploading'),
content: Column(
children: [
Center(
child: Text('Uploading .... Please Be Patient'),
),
SizedBox(
height: height * 0.02,
),
Text(percentage.toString()),
],
),
),
);
all dialogs are StateLess widgets.... so u can not call setstate to update their data to show on the UI. If u want to do that then u can wrap the dialog inside a StatefullBuilder . which will allow you to call setState.
I'm the newbie Flutter Developer. I got any problem when I tap the custom drawer, body content viewed the widget after that I tap add button with api and success created new data. but when back to drawer can't reload automatically. below are some of my codecs.
I user drawerbehavior version 0.0.8
MyCustomDrawer code
DrawerScaffold(
percentage: 1,
cornerRadius: 0,
appBar: AppBarProps(
title: Text(
"ToDO",
style: TextStyle(fontFamily: 'Acme'),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => tambahAgenda(context, '4', true))
]),
menuView: new MenuView(
menu: menu,
headerView: headerView(context),
footerView: footerView(context),
animation: false,
textStyle: TextStyle(fontFamily: 'Acme', color: Colors.white),
color: Theme.of(context).primaryColor,
selectedItemId: selectedMenuItemId,
onMenuItemSelected: (String itemId) {
selectedMenuItemId = itemId;
if (itemId == 'beranda') {
setState(() => _widget = IsiBerandaUI());
} else if (itemId == 'agenda') {
setState(() => _widget = Container());
} else if (itemId == 'kalenderagenda') {
setState(() => _widget = AgendaCalendarUI());
}
},
),
contentView: Screen(
contentBuilder: (context) => Center(child: _widget),
color: Colors.white,
),
);
_navigateAndDisplaySelection(
BuildContext context, String idKategori, bool statusLogin) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => TambahAgendaUI()),
);
if (result != null) {
// bloc.fetchAllAgendaTGL(idKategori, statusLogin);
setState(() {
selectedMenuItemId = 'kalenderagenda';
_widget = AgendaCalendarUI();
});
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Beranda(
selectedMenuItemId: 'kalenderagenda',
)));
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(
content: Text(
"$result",
style: TextStyle(fontFamily: 'googleSans'),
)));
}
}
and myadd data navigator like this
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Beranda(
selectedMenuItemId: 'kalenderagenda',
)
)
);
But When I pushReplacement widget get any error.
any conclusion ???