Why is data not showing on first click?
this is a problem i ran into later. Previously, the data was coming when I first clicked or when the program was first opened, but then I guess I broke a code without realizing it and I can't fix it back please help me
widget's code
import 'package:flutter/material.dart';
import 'package:todo/data/todo_service.dart';
import 'package:todo/models/todo.dart';
class TodoListWidget extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return TodoListWidgetState();
}
}
class TodoListWidgetState extends State<TodoListWidget>{
TodoService todoService = TodoService.instance;
List<Todo> todoList = [];
#override
Widget build(BuildContext context) {
return getTodoList(todoList);
}
#override
void initState() {
setState(() {
loadData();
});
super.initState();
}
getTodoList(List<Todo> todos) {
return todoList.isEmpty ? Center(child: Text("Nothing to do yet...", style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),)) :
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return Card(
color: const Color(0xffFE7E6D),
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
todos[index].title!,
style: TextStyle(
fontSize: 20, color: Colors.white),
),
Row(
children: [
Checkbox( value: todos[index].isDone,onChanged:(value){
setState(() {
todos[index].isDone = value;
});
},
),
IconButton(onPressed: (){
setState(() {
if(todos[index].isFavourite!){
todos[index].isFavourite = false;
}
else{
todos[index].isFavourite = true;
}
});
},
icon: todos[index].isFavourite! ? Icon(Icons.favorite) : Icon(Icons.favorite_border)),
IconButton(onPressed: (){
setState(() {
todoService.deleteTodo(todos[index]);
loadData();
});
},
icon: Icon(Icons.delete_outline)),
],
)
],
),
const SizedBox(
height: 10,
),
Container(
child: Text(
todos[index].description!,
style: TextStyle(
letterSpacing: 1, color: Colors.white),
),
color: Colors.transparent,
width: MediaQuery.of(context).size.width,
),
],
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),);
},
);
}
void loadData() {
setState(() {
todoService.getTodos(false).then((value) {
todoList = value;
});
});
}
}
Main screen
import 'package:flutter/material.dart';
import 'package:flutter_advanced_drawer/flutter_advanced_drawer.dart';
import 'package:todo/screens/add_todo_screen.dart';
import 'package:todo/widgets/favourites_widget.dart';
import 'package:todo/widgets/todo_list_widget.dart';
import 'package:todo/widgets/todo_widget.dart';
class MainScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MainScreenState();
}
}
class MainScreenState extends State {
final _advancedDrawerController = AdvancedDrawerController();
Widget? widgetForBody;
bool? _floatButton = true;
#override
void initState() {
setState(() {
widgetForBody = TodoListWidget();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return AdvancedDrawer(
backdropColor: Colors.grey.shade900,
controller: _advancedDrawerController,
animationCurve: Curves.easeInOut,
animationDuration: const Duration(milliseconds: 300),
animateChildDecoration: true,
rtlOpening: false,
disabledGestures: false,
childDecoration: const BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)),
),
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey.shade900,
shadowColor: Colors.transparent,
title: const Text('My To Do',
style: TextStyle(
color: Colors.white54,
fontSize: 25,
fontWeight: FontWeight.bold)),
centerTitle: true,
leading: IconButton(
color: Colors.white54,
onPressed: _handleMenuButtonPressed,
icon: ValueListenableBuilder<AdvancedDrawerValue>(
valueListenable: _advancedDrawerController,
builder: (_, value, __) {
return AnimatedSwitcher(
duration: Duration(milliseconds: 250),
child: Icon(
value.visible ? Icons.clear : Icons.apps,
key: ValueKey<bool>(value.visible),
),
);
},
),
),
),
body: widgetForBody,
floatingActionButton: _floatButton!
? FloatingActionButton(
onPressed: () {
setState(() {
widgetForBody = null;
});
goToTodoAdd();
},
child: Icon(
Icons.add,
color: Colors.white54,
),
backgroundColor: Colors.grey.shade900,
)
: null,
),
drawer: SafeArea(
child: Container(
child: ListTileTheme(
textColor: Colors.white,
iconColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
height: 150,
),
Text(
"WELCOME BACK",
style: TextStyle(color: Colors.white54, fontSize: 20),
),
SizedBox(
height: 50,
),
ListTile(
onTap: () {
setState(() {
widgetForBody = TodoListWidget();
_advancedDrawerController.value =
AdvancedDrawerValue.hidden();
_floatButton = true;
});
},
leading: Icon(Icons.check_box_outline_blank_sharp),
title: Text('To Do List',
style: TextStyle(color: Colors.white54)),
),
ListTile(
onTap: () {
setState(() {
widgetForBody = TodoWidget();
_advancedDrawerController.value =
AdvancedDrawerValue.hidden();
_floatButton = false;
});
},
leading: Icon(Icons.check_box_outlined),
title:
Text('History', style: TextStyle(color: Colors.white54)),
),
ListTile(
onTap: () {
setState(() {
widgetForBody = FavouritesWidget();
_advancedDrawerController.value =
AdvancedDrawerValue.hidden();
_floatButton = false;
});
},
leading: Icon(Icons.favorite),
title: Text('Favourites',
style: TextStyle(color: Colors.white54)),
),
Divider(indent: 20, height: 20, color: Colors.grey.shade800),
ListTile(
onTap: () {
setState(() {});
},
leading: Icon(Icons.info_outline),
title: Text('Info', style: TextStyle(color: Colors.white54)),
),
Spacer(),
DefaultTextStyle(
style: TextStyle(
fontSize: 12,
color: Colors.white54,
),
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0,
),
child: Text('To Do App Demo'),
),
),
],
),
),
),
),
);
}
void _handleMenuButtonPressed() {
// NOTICE: Manage Advanced Drawer state through the Controller.
_advancedDrawerController.showDrawer();
}
void goToTodoAdd() async {
bool result = await Navigator.push(
context, MaterialPageRoute(builder: (context) => AddTodoScreen()));
if (result != null) {
if (result) {
setState(() {
getTodoWidget();
});
}
}
}
getTodoWidget() {
setState(() {
widgetForBody = TodoListWidget();
});
}
}
and service
import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo/models/todo.dart';
class TodoService{
static TodoService instance = TodoService._internal();
TodoService._internal();
Database? _db;
factory TodoService(){
return instance;
}
Future<Database?> get db async{
if(_db == null){
_db = await _initDb();
}
return _db;
}
Future<Database> _initDb() async{
String dbPath = join(await getDatabasesPath(), "todo.db");
final todoDb = openDatabase(dbPath, version: 1, onCreate: createDb);
return todoDb;
}
void createDb(Database db, int version) async {
await db.execute("CREATE TABLE todos(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, description TEXT, isDone INT, isFavourite INT)");
}
Future<int> addTodo(Todo todo) async{
Database? db = await this.db;
var result = await db!.insert("todos", todo.toMap());
print(result);
return result;
}
Future<int> updateTodo(Todo todo) async{
Database? db = await this.db;
var result = await db!.update("todos", todo.toMap(), where: "id=?", whereArgs: [todo.id]);
return result;
}
Future<int> deleteTodo(Todo todo) async{
Database? db = await this.db;
var result = await db!.delete("todos",where: "id=?", whereArgs: [todo.id]);
return result;
}
Future<List<Map<String,dynamic>>?> getTodoMaps()async{
Database? db = await this.db;
return await db!.query("todos");
}
Future<List<Todo>> getTodos(bool isDone)async{
final mapList = await getTodoMaps();
List<Todo> todoList = [];
mapList?.forEach((element) {
todoList.add(Todo.fromMap(element));
});
if(isDone){
return todoList.where((element) => element.isDone == true).toList();
}
return todoList.where((element) => element.isDone == false).toList();
}
Future<List<Todo>> getFavouritesTodos()async{
final mapList = await getTodoMaps();
List<Todo> todoList = [];
mapList?.forEach((element) {
todoList.add(Todo.fromMap(element));
});
return todoList.where((element) => element.isFavourite == true).toList();
}
}
thank you
put the setstate inside the then
after you have received the result the screen will be updated
void loadData() {
todoService.getTodos(false).then((value) {
setState(() {
todoList = value;
});
});
}
Related
I was trying to get the single doc data from firebase and wanted to update
'''
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:wallet_app/utils/custom_textfield.dart';
import '../module/firebase_data.dart';
import '../utils/utilts.dart';
class EditPage extends StatefulWidget {
const EditPage({
Key? key,
required this.docId,
}) : super(key: key);
final String docId;
#override
State<EditPage> createState() => _EditPageState();
}
class _EditPageState extends State<EditPage> {
late DocumentSnapshot data;
Future getData() async {
User? user = FirebaseAuth.instance.currentUser;
await FirebaseFirestore.instance
.collection('users')
.doc(user?.uid)
.collection('transactions')
.doc(widget.docId)
.get()
.then((value) => data = value);
}
#override
Widget build(BuildContext context) {
TextEditingController titleController =
TextEditingController(text: data['title']);
TextEditingController amountController =
TextEditingController(text: data['amount'].toString());
TextEditingController descriptionController =
TextEditingController(text: data['description']);
bool income = data['type'];
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.grey.shade800,
elevation: 0,
centerTitle: true,
title: const Text(
'Edit Transaction',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomTextfield(
hintText: 'Title', controller: titleController),
CustomTextfield(
hintText: 'Amount',
controller: amountController,
keyBoradType: TextInputType.number,
),
CustomTextfield(
hintText: 'Description',
controller: descriptionController,
miniLines: 4,
maxLines: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Expense',
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18),
),
Switch(
activeColor: Colors.green.shade300,
inactiveTrackColor: Colors.red.shade300,
inactiveThumbColor: Colors.red.shade100,
value: income,
onChanged: (v) {
setState(() {
income = v;
});
}),
const Text(
'Income',
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18),
),
],
),
NeumorphicButton(
margin: const EdgeInsets.only(top: 15),
style: NeumorphicStyle(
shape: NeumorphicShape.flat,
color: Colors.grey.shade800,
depth: 6,
),
onPressed: () async {
if (titleController.text.isEmpty &&
amountController.text.isEmpty) {
Utils.showError(message: 'Please fill all the fields');
return;
} else {
FireData()
.updateTransaction(
title: titleController.text,
description: descriptionController.text,
amount: double.parse(amountController.text),
type: income,
docId: widget.docId)
.then((value) => {
if (income == true)
{
Utils.showError(
message: 'Income Edited Successfully')
}
else
{
Utils.showError(
message:
'Expense Edited Successfully')
},
titleController.clear(),
descriptionController.clear(),
amountController.clear(),
income = false,
});
Navigator.pop(context);
}
},
child: const Text(
'Edit Transaction',
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
TextButton(onPressed: () => data, child: const Text('data'))
],
),
);
}),
);
}
}
'''
I want to update the data note I am using setState function to update the state of the slider but its not updating. I want to show the available data and then allow to update it.
I also tried to get the data from the previous page but I even got stuck in that if.
I can get the Data from previous page if there's any solution for that also we will try that method.
So im trying to create a training app where i can type excercise, sets, reps and load and give it a specific time. I have done this with a calender widget. My page where i have createt the Editingpage looks like this
class EventEditingPage extends StatefulWidget {
final Event? event;
const EventEditingPage({Key? key, this.event}) : super(key: key);
#override
_EventEditingPageState createState() => _EventEditingPageState();
}
class _EventEditingPageState extends State<EventEditingPage> {
final _formKey = GlobalKey<FormState>();
final titleController = TextEditingController();
final List<TextEditingController> setsController = [];
final List<TextEditingController> repsController = [];
final List<TextEditingController> loadController = [];
List<String> exceriseItems = ['Squat', 'Deadlift', 'Bench'];
List<String> selectedExercise = [];
int numberOfTextFields = 1;
late DropdownButton Exercise;
late DateTime fromDate;
late DateTime toDate;
#override
void initState() {
super.initState();
createControllers();
if (widget.event == null) {
fromDate = DateTime.now();
toDate = DateTime.now().add(Duration(hours: 1, minutes: 30));
} else {
final event = widget.event!;
titleController.text = event.title;
createControllers();
selectedExercise[0] =
event.Exercise != "" ? event.Exercise : exceriseItems[0];
setsController[0].text = event.Sets;
repsController[0].text = event.Reps;
loadController[0].text = event.Load;
fromDate = event.from;
toDate = event.to;
}
}
#override
void dispose() {
titleController.dispose();
setsController.forEach((TextEditingController element) {
element.dispose();
});
repsController.forEach((TextEditingController element) {
element.dispose();
});
loadController.forEach((TextEditingController element) {
element.dispose();
});
super.dispose();
}
List<TextEditingController> _textEditingControllers = [
TextEditingController()
];
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
leading: CloseButton(),
actions: buildEditingActions(),
backgroundColor: Colors.red,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Trænings Information", style: TextStyle(fontSize: 24)),
buildTitle(),
SizedBox(height: 12),
buildDateTimePickers(),
Text("\nTræningen", style: TextStyle(fontSize: 24)),
for (int i = 0; i < numberOfTextFields; i++)
buildExerciseComplete(i),
buildAddMore(),
],
),
),
),
);
List<Widget> buildEditingActions() => [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.transparent, shadowColor: Colors.transparent),
onPressed: saveForm,
icon: Icon(Icons.done),
label: Text('Save'),
)
];
createControllers() {
for (var i = 0; i < numberOfTextFields; i++) {
setsController.add(TextEditingController());
repsController.add(TextEditingController());
loadController.add(TextEditingController());
}
selectedExercise.add(exceriseItems[0]);
}
Widget buildTitle() => TextFormField(
style: TextStyle(fontSize: 24),
decoration: InputDecoration(
border: UnderlineInputBorder(),
hintText: 'Add Title',
),
onFieldSubmitted: (_) => saveForm,
validator: (title) =>
title != null && title.isEmpty ? 'Title cannot be empty' : null,
controller: titleController,
);
Widget buildExerciseComplete(int idx) => Container(
padding: const EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 255, 200, 200),
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
width: 2.0,
),
),
height: 50,
child: Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(child: buildExercise(idx)),
Expanded(child: buildSets(idx)),
Expanded(child: buildReps(idx)),
Expanded(child: buildLoad(idx)),
],
),
),
],
),
);
Widget buildSets(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: setsController[idx],
);
Widget buildReps(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Reps',
),
onFieldSubmitted: (_) => saveForm,
validator: (reps) =>
reps != null && reps.isEmpty ? 'Reps cannot be empty' : null,
controller: repsController[idx],
);
Widget buildLoad(int idx) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: const TextStyle(fontSize: 15),
decoration: const InputDecoration(
labelText: 'Load',
border: const OutlineInputBorder(),
),
onFieldSubmitted: (_) => saveForm,
validator: (load) =>
load != null && load.isEmpty ? 'Load cannot be empty' : null,
controller: loadController[idx],
);
Widget buildExercise(int idx) => DropdownButton<String>(
value: selectedExercise[idx],
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.black),
onChanged: (String? newValue) {
setState(() {
selectedExercise[idx] = newValue!;
});
},
items: exceriseItems.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
Widget buildDateTimePickers() => Column(
children: [
buildFrom(),
buildTo(),
],
);
Widget buildFrom() => buildHeader(
header: 'FROM',
child: Row(
children: [
Expanded(
flex: 2,
child: buildDropdownField(
text: Utils.toDate(fromDate),
onClicked: () => pickFromDateTime(pickDate: true),
),
),
Expanded(
child: buildDropdownField(
text: Utils.toTime(fromDate),
onClicked: () => pickFromDateTime(pickDate: false),
),
),
],
),
);
Widget buildTo() => buildHeader(
header: 'TO',
child: Row(
children: [
Expanded(
flex: 2,
child: buildDropdownField(
text: Utils.toDate(toDate),
onClicked: () => pickToDateTime(pickDate: true),
),
),
Expanded(
child: buildDropdownField(
text: Utils.toTime(toDate),
onClicked: () => pickToDateTime(pickDate: false),
),
),
],
),
);
Widget buildDropdownField({
required String text,
required VoidCallback onClicked,
}) =>
ListTile(
title: Text(text),
trailing: Icon(Icons.arrow_drop_down),
onTap: onClicked,
);
Widget buildHeader({
required String header,
required Widget child,
}) =>
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
header,
style: TextStyle(fontWeight: FontWeight.bold),
),
child,
],
);
Widget buildAddMore() => ElevatedButton(
onPressed: () {
setState(() {
numberOfTextFields++;
createControllers();
});
},
child: const Text('Add new exercise'),
);
Future pickFromDateTime({required bool pickDate}) async {
final date = await pickDateTime(fromDate, pickDate: pickDate);
if (date == null) return;
if (date.isAfter(toDate)) {
toDate =
DateTime(date.year, date.month, date.day, toDate.hour, toDate.minute);
}
setState(() => fromDate = date);
}
Future pickToDateTime({required bool pickDate}) async {
final date = await pickDateTime(
toDate,
pickDate: pickDate,
firstDate: pickDate ? fromDate : null,
);
if (date == null) return;
setState(() => toDate = date);
}
Future<DateTime?> pickDateTime(
DateTime initialDate, {
required bool pickDate,
DateTime? firstDate,
}) async {
if (pickDate) {
final date = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: firstDate ?? DateTime(2020),
lastDate: DateTime(2100),
);
final time =
Duration(hours: initialDate.hour, minutes: initialDate.minute);
if (date == null) return null;
return date.add(time);
} else {
final timeOfDay = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(initialDate),
);
if (timeOfDay == null) return null;
final date =
DateTime(initialDate.year, initialDate.month, initialDate.day);
final time = Duration(hours: timeOfDay.hour, minutes: timeOfDay.minute);
return date.add(time);
}
}
Future saveForm() async {
final isValid = _formKey.currentState!.validate();
if (isValid) {
final event = Event(
title: titleController.text,
from: fromDate,
to: toDate,
Exercise: selectedExercise[0],
Sets: setsController[0],
Reps: repsController[0],
Load: loadController[0]);
final isEditing = widget.event != null;
final provider = Provider.of<EventProvider>(context, listen: false);
if (isEditing) {
provider.editEvent(event, widget.event!);
Navigator.of(context).pop();
} else {
provider.addEvent(event);
}
Navigator.of(context).pop();
}
}
}
class Event {
final String title;
final Exercise;
final Sets;
final Reps;
final Load;
final DateTime from;
final DateTime to;
final Color backgroundColor;
final bool isAllDay;
const Event({
required this.title,
required this.Exercise,
required this.Sets,
required this.Reps,
required this.Load,
required this.from,
required this.to,
this.backgroundColor = Colors.lightGreen,
this.isAllDay = false,
});
}
Im now trying to create a Viewing page where you can see you workout you have createt. I was thinking the basics to be like this
class EventViewingPage extends StatelessWidget {
final Event event;
#override
const EventViewingPage({
Key? key,
required this.event,
}) : super(key: key);
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(event.title),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.edit,
color: Colors.white,
),
onPressed: () => Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => EventEditingPage(
event: event,
),
),
),
),
IconButton(
icon: Icon(
Icons.delete,
color: Colors.white,
),
onPressed: () {},
)
],
),
body: ListView(
padding: EdgeInsets.all(32),
children: <Widget>[
SizedBox(height: 32),
Text(
"Show the data here",
style: TextStyle(
fontSize: 24,
),
),
],
),
);
}
But im not quite sure on how to display all the information when you add multiple exercises to the training
Hope someone can help, thanks in advance
I am putting up 3 .dart files which are required for the app.
StaffEvent.dart
import 'package:flutter/material.dart';
import 'package:flutter_new_app/addevent_screen.dart';
import 'package:flutter_new_app/services/crud.dart';
class StaffEvent extends StatefulWidget {
#override
_StaffEventState createState() => _StaffEventState();
}
class _StaffEventState extends State<StaffEvent> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot eventSnapshot;
Stream eventStream;
// ignore: non_constant_identifier_names
Widget EventList() {
return Container(
child: eventStream != null
? Column(
children: [
StreamBuilder(
stream: eventStream,
builder: (context, snapshot) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: eventSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return EventTile(
title: eventSnapshot.docs[index].data()['title'],
desc: eventSnapshot.docs[index].data()['desc'],
date: eventSnapshot.docs[index].data()['date'],
);
},
);
},
),
],
)
: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
#override
void initState() {
setState(() {
Stream result;
eventStream = result;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFffffff),
appBar: AppBar(
actions: [
FloatingActionButton(
backgroundColor: Colors.green,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddEvent()),
);
},
)
],
backgroundColor: Color(0xFFebd8b7),
title: Text(
'Events',
style: TextStyle(color: Colors.black),
),
),
);
}
}
// ignore: must_be_immutable
class EventTile extends StatelessWidget {
String title, desc, date;
EventTile({#required this.title, #required this.desc, #required this.date});
#override
Widget build(BuildContext context) {
return Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: SizedBox(
width: 500,
height: 80,
child: Container(
color: Color(0xFFeaffd0),
child: Column(
children: [
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
Text(
desc,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
Text(
date,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
)
],
),
),
),
),
],
);
}
}
Crud.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class CrudMethods {
Future<void> addData(eventData) async {
FirebaseFirestore.instance
.collection("events")
.add(eventData)
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance.collection("events").get();
}
}
Addevent.dart
import 'package:flutter_new_app/services/crud.dart';
class AddEvent extends StatefulWidget {
#override
_AddEventState createState() => _AddEventState();
}
class _AddEventState extends State<AddEvent> {
String title, desc, date;
CrudMethods crudMethods = new CrudMethods();
uploadEvent() async {
Map<String, String> eventMap = {"title": title, "desc": desc, "date": date};
crudMethods.addData(eventMap).then((result) {
Navigator.pop(context);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFffffff),
appBar: AppBar(
backgroundColor: Color(0xFFf38181),
title: Text(
'Add Event',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
GestureDetector(
onTap: () {
uploadEvent();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.file_upload)),
)
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Event Name"),
onChanged: (val) {
title = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Description"),
onChanged: (val) {
desc = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Date"),
onChanged: (val) {
date = val;
},
),
)
],
));
}
}
So here basically, the user has to enter some details for an event and when clicking the upload button it should be visible as a list in the Staffevent page . That is the problem. Nothung is showing in the Staffevent page. It is blank.
The data is being stored in the firebase database but when i am using snapshot and calling it back it is not showing in my flutter application.
Your stream is empty:
Stream result;
eventStream = result;
Firebase Firestore get() method returns a Future<DocumentSnapshot>:
Future<DocumentSnapshot> getData() async {
return await FirebaseFirestore.instance.collection("events").get();
}
If you need a stream you use snapshots() method which returns a Stream:
Stream collectionStream = FirebaseFirestore.instance.collection("events").snapshots();
Please refer to official documentation to get familiar with Firebase API.
Screenshot here
I would like to change the color of my arrow (Icon Button) after querying my firebase (likedby) array. Essentially my upvote / downvote system works by adding the user to a likedby/dislikedby array on the post and I want the arrow color to change if the users id is in the likedby or dislikedby arrays.
class HomeScreen extends StatefulWidget {
final String currentUserId;
const HomeScreen({Key key, this.currentUserId}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: Color(0xffff5722), title: Text("Feed")),
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('The Laryngoscope')
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.docs.map((document) {
return Center(
child: Padding(
padding: EdgeInsets.fromLTRB(15, 6, 15, 2),
child: Card(
elevation: 8.0,
child: Column(
children: [
ListTile(
title: Text(document['title'] + "\n"),
subtitle: Text(document['authors']),
),
Divider(),
ButtonBar(
children: [
Text(document['likes'].toString()),
IconButton(
icon: Icon(
FontAwesomeIcons.chevronUp,
color: Colors.grey,
size: 30,
),
onPressed: () async {
articleRef.doc(document['title']).update({
"dislikedby": FieldValue.arrayRemove(
[widget.currentUserId]),
"likedby": FieldValue.arrayUnion(
[widget.currentUserId])
});
var documents = (await articleRef
.doc(document['title'])
.get());
articleRef.doc(document['title']).update({
"likes":
(documents.data()['likedby'].length) -
(documents
.data()['dislikedby']
.length)
});
}),
IconButton(
icon: Icon(
FontAwesomeIcons.chevronDown,
color: Colors.grey,
size: 30,
),
onPressed: () async {
articleRef.doc(document['title']).update({
"likedby": FieldValue.arrayRemove(
[widget.currentUserId]),
"dislikedby": FieldValue.arrayUnion(
[widget.currentUserId])
});
var documents = (await articleRef
.doc(document['title'])
.get());
articleRef.doc(document['title']).update({
"likes": (documents
.data()['likedby']
.length) -
(documents.data()['dislikedby'].length)
});
},
),
OutlinedButton(
style: ElevatedButton.styleFrom(
primary: Colors.white, // background
onPrimary: Color(0xffff5722), // foreground
),
onPressed: () {},
child: Text('Comment'),
),
FloatingActionButton(
child: Icon(Icons.share),
backgroundColor: Color(0xFFFF5722),
onPressed: () {},
),
],
)
],
),
),
),
);
}).toList(),
);
}),
);
}
}
I am trying to add some city list to a dialog with checkbox so that i need to implement multiple click on items. what I am trying to do is given below.
onPressed from button calls Rest Service and on success result I just show a dialog
void showCityDialog(BuildContext context) {
SimpleDialog dialog = new SimpleDialog(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(
"CITIES",
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
new RaisedButton(
onPressed: () {print("clicked");},
color: Color(0xFFfab82b),
child: new Text(
"Done",
style: TextStyle(color: Colors.white),
),)],),
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
constraints: BoxConstraints(maxHeight: 500.0),
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: cityData.length,
itemBuilder: (context, position) {
return new CheckboxListTile(
value: checkboxValueCity,
onChanged: (bool value) {
setState(() {
checkboxValueCity = value;
});
},
activeColor: Color(0xFFfab82b),
dense: true,
title: Text(
cityData[position].city_name,
style: TextStyle(fontSize: 16.0, color: Colors.black),
),);},),),],)],);
showDialog(
context: context,
builder: (BuildContext context) {
return dialog;
});
}
checkboxValueCity is a boolean variable in class , on click of chekboxListItem i need to update checkbox value as checked and uncheced. At the same time need to add/remove that item to a list which is also inside that class.
But in my code checkbox is not refershing on every click but when i close that box and open it again checkbox is checked. then how can i get multiple click from tile and how can i return list from dialog?
Your dialog needs to be a StatefulWidget (Flutter Github issue). The member variable that tracks selection state needs to be in the dialog class. You can use a callback to update a member variable in your parent class with the List of selected cities. There also seem to be some issues using a ListView.builder inside of a SimpleDialog or AlertDialog (search the Flutter Github for issues) so I used a plain Dialog.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Checkbox Dialog Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Checkbox Dialog Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool checkboxValueCity = false;
List<String> allCities = ['Alpha', 'Beta', 'Gamma'];
List<String> selectedCities = [];
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return _MyDialog(
cities: allCities,
selectedCities: selectedCities,
onSelectedCitiesListChanged: (cities) {
selectedCities = cities;
print(selectedCities);
});
});
}),
);
}
}
class _MyDialog extends StatefulWidget {
_MyDialog({
this.cities,
this.selectedCities,
this.onSelectedCitiesListChanged,
});
final List<String> cities;
final List<String> selectedCities;
final ValueChanged<List<String>> onSelectedCitiesListChanged;
#override
_MyDialogState createState() => _MyDialogState();
}
class _MyDialogState extends State<_MyDialog> {
List<String> _tempSelectedCities = [];
#override
void initState() {
_tempSelectedCities = widget.selectedCities;
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'CITIES',
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
RaisedButton(
onPressed: () {
Navigator.pop(context);
},
color: Color(0xFFfab82b),
child: Text(
'Done',
style: TextStyle(color: Colors.white),
),
),
],
),
Expanded(
child: ListView.builder(
itemCount: widget.cities.length,
itemBuilder: (BuildContext context, int index) {
final cityName = widget.cities[index];
return Container(
child: CheckboxListTile(
title: Text(cityName),
value: _tempSelectedCities.contains(cityName),
onChanged: (bool value) {
if (value) {
if (!_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.add(cityName);
});
}
} else {
if (_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.removeWhere(
(String city) => city == cityName);
});
}
}
widget
.onSelectedCitiesListChanged(_tempSelectedCities);
}),
);
}),
),
],
),
);
}
}
Use StatefulBuilder to update Widgets only inside Dialog. StatefulBuilder is best for update sebsection of the widget tree where
state is needed.
simple code snippet
void _showDialog() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder( // StatefulBuilder
builder: (context, setState) {
return AlertDialog(
actions: <Widget>[
Container(
width: 400,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Student Attendence",
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 5,
),
Container(
height: 2,
color: Colors.black,
),
SizedBox(
height: 15,
),
CheckboxListTile(
value: user1,
title: Text("user1"),
onChanged: (value){
setState(() {
user1=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user2,
title: Text("user2"),
onChanged: (value){
setState(() {
user2=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user3,
title: Text("user3"),
onChanged: (value){
setState(() {
user3=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user4,
title: Text("user4"),
onChanged: (value){
setState(() {
user4=value;
});
},
),
Divider(
height: 10,
),
SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {},
child: Text("Save",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {
setState(() {
Navigator.of(context).pop();
});
},
child: Text("Cancel",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {},
child: Text("Select All",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
],
)
],
))
],
);
},
);
},
);
}
example
Although Albert's answer works, you need not go thru all that. Simply wrap the content: with a StatefulBuilder, voila!
https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html.
Note: It is important where you declare the variable(s) you want to change.
I modified your code a bit, I want when users check the list, the list won't be updated to the main view, but they will when users click the "Update" button.
But some how, it doesn't work. Can you please check ?
Thank you very much
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Checkbox Dialog Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Checkbox Dialog Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool checkboxValueCity = false;
List<String> allCities = ['Alpha', 'Beta', 'Gamma'];
List<String> selectedCities = [];
List<String> selectedCitiesTemp = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App Bar"),
),
body: Center(
child: Column(
children: <Widget>[
_list(),
RaisedButton(
child: Text("Update From TMP List"),
onPressed: () {
setState(() {
selectedCities = selectedCitiesTemp;
});
},
)
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return _MyDialog(
cities: allCities,
selectedCities: selectedCities,
onSelectedCitiesListChanged: (cities) {
setState(() {
selectedCitiesTemp = cities;
});
},
);
});
}),
);
}
Widget _list() {
List<Widget> list = [];
for(String item in selectedCities) {
list.add(ListTile(
title: Text(item),
));
}
return Column(
children: list
);
}
}
class _MyDialog extends StatefulWidget {
_MyDialog({
this.cities,
this.selectedCities,
this.onSelectedCitiesListChanged,
});
final List<String> cities;
final List<String> selectedCities;
final ValueChanged<List<String>> onSelectedCitiesListChanged;
#override
_MyDialogState createState() => _MyDialogState();
}
class _MyDialogState extends State<_MyDialog> {
List<String> _tempSelectedCities = [];
#override
void initState() {
_tempSelectedCities = widget.selectedCities;
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'CITIES',
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
],
),
Expanded(
child: ListView.builder(
itemCount: widget.cities.length,
itemBuilder: (BuildContext context, int index) {
final cityName = widget.cities[index];
return Container(
child: CheckboxListTile(
title: Text(cityName),
value: _tempSelectedCities.contains(cityName),
onChanged: (bool value) {
if (value) {
if (!_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.add(cityName);
});
}
} else {
if (_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.removeWhere(
(String city) => city == cityName);
});
}
}
widget.onSelectedCitiesListChanged(_tempSelectedCities);
}),
);
}),
),
],
),
);
}
}