I implemented a search list with consultation to firebase. Initially, all registered users appear on the screen and when I click on one of the users, the app shows another screen with all the data for that user. When you start typing in the search field, only users with respect to the text entered appear.
However, a problem arose: when filtering a customer, only it appears on the screen and when I click to open the customer's information, the app shows the information of the first user in the general list (without taking into account the filter).
I believe that this happens due to the index, which looks at the position of the document in the firebase.
How to fix this? Thank you!
body: Column(
children: <Widget>[
SizedBox(
height: 5,
),
TextField(
controller: _procurarpaciente,
decoration: InputDecoration(
border: OutlineInputBorder(), labelText: "Pesquisar paciente",prefixIcon: Icon(Icons.search)
),
onChanged: (val) {
setState(() {
nome = val;
});
},
),
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: (nome != "" && nome != null)
? Firestore.instance
.collection('pacientes')
.where("indexList", arrayContains: nome)
.snapshots()
: Firestore.instance.collection("pacientes").snapshots(),
builder: (context, snapshot) {
switch(snapshot.connectionState){
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.error_outline),
Text("Usuário não encontrado")
],
),
);
default:
// List<DocumentSnapshot> documentos =
// snapshot.data.documents;
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot data = snapshot.data.documents[index];
return ListTile(
title: Text(
data['nome'],
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16,
),),
subtitle:Text(
"Quarto: ${data['quarto']}",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 14,
),),
leading:CircleAvatar(
backgroundImage: NetworkImage(data['foto']),
),
onTap: ()=> {
//print(data.documentID),
_navegarParaPerfil(context, items[index]),
}
);
},
);
}
}
),
)
],
),
void _navegarParaPerfil(BuildContext context, Paciente paciente) async{
await Navigator.push(context,
MaterialPageRoute(builder: (context) => TelaPaciente(paciente)),
);
}
dsdsd
Step 1:
class Employee {
Employee(this.employeeID, this.employeeName, this.branch, this.designation, this.location,
this.salary,
{this.reference});
double employeeID;
String employeeName;
String designation;
String branch;
String location;
double salary;
DocumentReference reference;
factory Employee.fromSnapshot(DocumentSnapshot snapshot) {
Employee newEmployee = Employee.fromJson(snapshot.data());
newEmployee.reference = snapshot.reference;
return newEmployee;
}
factory Employee.fromJson(Map<String, dynamic> json) =>
_employeeFromJson(json);
Map<String, dynamic> toJson() => _employeeToJson(this);
#override
String toString() => 'employeeName ${employeeName}';
}
Step 2:
class EmployeeRepository {
List<Employee> employees = [];
final CollectionReference collection =
FirebaseFirestore.instance.collection('employees');
Stream<QuerySnapshot> getStream() {
return collection.snapshots();
}
Future<DocumentReference> add(Employee employee) {
var documentReference = collection.add(employee.toJson());
return documentReference;
}
update(Employee employee) async {
collection.doc(employee.reference.id).update(employee.toJson());
}
delete(Employee employee) async {
collection.doc(employee.reference.id).delete();
}
fromSnapShot(DocumentSnapshot snapshot) => Employee.fromSnapshot(snapshot);
Future<List<Employee>> buildData(
AsyncSnapshot snapshot, String filterKey) async {
List<Employee> list = [];
List<Employee> filteredList = [];
/// Based on the user snapShot, you can convert into the List and return to
/// the futurebuilder
await Future.forEach(snapshot.data.docs, (element) async {
list.add(Employee.fromSnapshot(element));
}).then((value) {
if (filterKey != null) {
filteredList = list
.where((element) =>
element.employeeID.toString() == filterKey ||
element.employeeName == filterKey ||
element.designation == filterKey ||
element.branch == filterKey ||
element.location == filterKey ||
element.salary.toString() == filterKey)
.toList();
}
});
if (filteredList.isEmpty) {
return Future<List<Employee>>.value(list);
} else {
return Future<List<Employee>>.value(filteredList);
}
}
}
Step 3:
EmployeeRepository employeeRepository = EmployeeRepository();
TextEditingController textEditingController = TextEditingController();
String filteredText = '';
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('ListView'),
),
body: StreamBuilder(
stream: employeeRepository.getStream(),
builder: (context, snapShot) {
if (snapShot.data == null ||
snapShot.connectionState == ConnectionState.waiting ||
snapShot.hasError ||
snapShot.data.docs.length == 0) {
return Container(
child: Center(child: CircularProgressIndicator()),
);
} else {
return StatefulBuilder(builder: (context, innerSetState) {
return FutureBuilder(
future: employeeRepository.buildData(
snapShot, filteredText),
builder: (context, futureSnapShot) {
if (!futureSnapShot.hasData) {
return Container(
child: Center(child: CircularProgressIndicator()),
);
} else {
return Column(
children: [
TextField(
controller: textEditingController,
decoration: InputDecoration(
icon: Icon(Icons.search),
hintText: 'Search here!'),
onSubmitted: (value) {
innerSetState(() {
filteredText = value;
});
},
onChanged: (value) {
innerSetState(() {
filteredText = value;
});
},
),
Container(
height: 400,
child: ListView.builder(
itemCount: futureSnapShot.data.length,
itemBuilder: (context, index) {
final Employee employee =
futureSnapShot.data[index];
return ListTile(
title: Text(employee.employeeName),
trailing:
Text('Salary${employee.salary}'),
subtitle: Text(employee.designation),
onTap: () {
print(employee.salary);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
EmployeeDetailsPage(
employee)));
},
);
},
),
),
],
);
}
});
});
}
},
)));
}
Step 4:
class EmployeeDetailsPage extends StatelessWidget {
final Employee employeeData;
const EmployeeDetailsPage(this.employeeData);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Employee Details'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(employeeData.employeeName, style: TextStyle(fontSize: 30))),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(employeeData.designation, style: TextStyle(fontSize: 20))),
),
Text('Salary ${employeeData.salary.toString()}'),
],
),
);
}
}
<blockquote class="imgur-embed-pub" lang="en" data-id="a/aqBaJ7N" data-context="false" ></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
Hey! Unfortunately it didn't work, look what keeps happening.
I think this is because of the index I send as a parameter, which does not understand that the values have been filtered:
onTap: ()=> {
//print(data.documentID),
_navegarParaPerfil(context, items[index]),
}
void _navegarParaPerfil(BuildContext context, Paciente paciente) async{
await Navigator.push(context,
MaterialPageRoute(builder: (context) => TelaPaciente(paciente)),
);
}
Ideally, it would be validated by documentID instead of this index, but I was unable to change it
Related
this is what happening
when i try to get list without filtering it's working good. but when i try to filter list using where condition is not working
this is what happening
when i try to get list without filtering it's working good. but when i try to filter list using where condition is not working
this is what happening
when i try to get list without filtering it's working good. but when i try to filter list using where condition is not working
late String _email = '';
var _users = [];
String api =
'https://raw.githubusercontent.com/ilkacase1234/Amore/main/Users.json';
login() async {
try {
final response = await http.get(Uri.parse(api));
var data = json.decode(response.body) as List;
setState(() {
_users = data;
});
} catch (e) {
EasyLoading.showError(e.toString());
}
}
#override
void initState() {
login();
super.initState();
}
check() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final String? login = prefs.getString('login');
if (login != null) {
Navigator.pushReplacementNamed(context, HomePage.id);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
elevation: 0,
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Column(
children: [
TextField(
onChanged: (val) {
setState(() {
_email = val;
});
},
keyboardType: TextInputType.url,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5)),
fillColor: Colors.white,
contentPadding: EdgeInsets.zero,
hintText: 'Halkan ku qor magalada gurigu ku yaalo',
prefixIcon: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
filled: true,
),
),
],
),
),
preferredSize: Size.fromHeight(56),
),
),
body: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final currentUser = _users[index];
if (_users.isEmpty) {
return Center(child: Text('No data'));
} else {
return Card(
child: ListTile(
leading: CircleAvatar(
radius: 28,
backgroundImage:
NetworkImage(currentUser['image'].toString()),
),
title: Text(currentUser['email'].toString()),
subtitle: Column(
children: [
Text(currentUser['password'].toString()),
Text(currentUser['name'].toString()),
],
),
),
);
}
}),
);
}
}
late String _email = '';
var _users = [];
String api =
'https://raw.githubusercontent.com/ilkacase1234/Amore/main/Users.json';
login() async {
try {
final response = await http.get(Uri.parse(api));
var data = json.decode(response.body) as List;
var data1 = data
.where((el) => el['email']
.toLowerCase()
.contains(_email.toLowerCase()))
.toList();
setState(() {
_users = data1;
});
} catch (e) {
EasyLoading.showError(e.toString());
}
}
#override
void initState() {
login();
super.initState();
}
check() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final String? login = prefs.getString('login');
if (login != null) {
Navigator.pushReplacementNamed(context, HomePage.id);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
elevation: 0,
bottom: PreferredSize(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Column(
children: [
TextField(
onChanged: (val) {
setState(() {
_email = val;
});
},
keyboardType: TextInputType.url,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5)),
fillColor: Colors.white,
contentPadding: EdgeInsets.zero,
hintText: 'Halkan ku qor magalada gurigu ku yaalo',
prefixIcon: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
filled: true,
),
),
],
),
),
preferredSize: Size.fromHeight(56),
),
),
body: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
final currentUser = _users[index];
if (_users.isEmpty) {
return Center(child: Text('No data'));
} else {
return Card(
child: ListTile(
leading: CircleAvatar(
radius: 28,
backgroundImage:
NetworkImage(currentUser['image'].toString()),
),
title: Text(currentUser['email'].toString()),
subtitle: Column(
children: [
Text(currentUser['password'].toString()),
Text(currentUser['name'].toString()),
],
),
),
);
}
}),
);
}
}
Try this:
login() async {
try {
final response = await http.get(Uri.parse(api));
response.body.forEach(e){
if(e["email"].toLowerCase() == _email.toLowerCase()){
_user = json.decode(e)
}
}
} catch (e) {
EasyLoading.showError(e.toString());
}}
Whenever I add an item to my least it adds to the list at the current state but when I reopen after pop context the item is no more there
*How can I have the items in list permanently *enter image description hereenter image description hereenter image description hereenter image description hereenter image description here
class Prabesh extends StatefulWidget {
#override
_PrabeshState createState() => _PrabeshState();
}
class _PrabeshState extends State<Prabesh> {
final List users = [
'Ram',
'Shyam',
'Hari',
'Paudel',
'Pandey',
'Sashwat',
'Kismat',
];
// ondlt(Key key) {
// for (int i = 0; i <= users.length; i++) {
// var a = users.elementAt(i);
// if (key == a.key) {
// users.removeAt(i);
// }
// }
// }
void onClk() {
myDialog(BuildContext, context);
}
final myUser = TextEditingController();
myDialog(BuildContext, context) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add a user'),
content: TextFormField(
controller: myUser,
maxLength: 20,
decoration: InputDecoration(
hintText: 'Enter Username',
),
),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
ElevatedButton(
onPressed: () {
setState(() {
if (myUser.text.isEmpty) {
return Navigator.pop(context);
} else {
users.add(myUser.text);
return Navigator.pop(context);
}
});
},
child: Text('Add'),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Prabesh'),
leading: BackButton(
onPressed: () => Navigator.pop(context),
),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Card(
elevation: 10,
child: ListTile(
// key: Key(users[index]),
//onLongPress: () => ondlt(key),
onTap: () {},
title: Text(users[index]),
trailing: Icon(Icons.menu),
leading: CircleAvatar(
child: Text(users[index].substring(0, 1)),
),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => onClk(),
child: Icon(Icons.add),
),
),
);
}
}
You must save your data locally or on an online database.
For saving data on mobile storage you can use this package.
But for saving data on an online database you can use Firebase or you must develop a web server.
)
I tried to program a Calendar App, where every user has his own events. I want to stream the events from Firestore but there is always the Error message "type 'QuerySnapshot' is not a subtype of type 'List'". Error message
I think the problem is in the StreamBuilder in the main file.
I would be incredibly happy if someone could show me how to solve this mistake.
Thanks to everyone in advance who tries to help me.
This is my main file:
class KalenderTable extends StatefulWidget {
#override
_KalenderTableState createState() => _KalenderTableState();
}
class _KalenderTableState extends State<KalenderTable> {
CalendarController _controller;
Map<DateTime, List<dynamic>> _events;
List<dynamic> _selectedEvents;
Stream events;
#override
void initState() {
getUserInfogetEvents();
super.initState();
_controller = CalendarController();
_events = {};
_selectedEvents = [];
}
Map<DateTime, List<dynamic>> _groupEvents(List<EventModel> allEvents) {
Map<DateTime, List<dynamic>> data = {};
allEvents.forEach((event) {
DateTime date = DateTime(
event.eventDate.year, event.eventDate.month, event.eventDate.day, 12);
if (data[date] == null) data[date] = [];
data[date].add(event);
});
return data;
}
getUserInfogetEvents() async {
Constants.myName = await HelperFunctions.getUserEmailSharedPreference();
DatabaseKalenderMethods().getUserEvents(Constants.myName).then((snapshots) {
setState(() {
events = snapshots;
print(
"we got the data + ${events.toString()} this is name ${Constants.myName}");
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: events,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<EventModel> allEvents = snapshot.data;
if (allEvents.isNotEmpty) {
_events = _groupEvents(allEvents);
} else {
_events = {};
_selectedEvents = [];
}
}
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TableCalendar(
events: _events,
initialCalendarFormat: CalendarFormat.twoWeeks,
calendarStyle: CalendarStyle(
canEventMarkersOverflow: true,
todayColor: Colors.orange,
selectedColor: Colors.cyan,
todayStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white)),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonDecoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(20.0),
),
formatButtonTextStyle: TextStyle(color: Colors.white),
formatButtonShowsNext: false,
),
startingDayOfWeek: StartingDayOfWeek.monday,
onDaySelected: (date, events) {
setState(() {
_selectedEvents = events;
});
},
builders: CalendarBuilders(
selectedDayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(10.0)),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)),
todayDayBuilder: (context, date, events) =>
Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(10.0)),
child: Text(
date.day.toString(),
style: TextStyle(color: Colors.white),
)),
),
calendarController: _controller,
),
..._selectedEvents.map((event) => ContainerKalender(
event.title,
() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => EventDetailsPage(
event: event,
)));
},
() {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => EventDetailsPage(
event: event,
)));
},
)),
],
),
);
}),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
backgroundColor: Colors.cyan,
onPressed: () => Navigator.pushNamed(context, 'add_event'),
),
);
}
}
class EventModel extends DatabaseItem{
final String id;
final String title;
final String description;
final DateTime eventDate;
EventModel({this.id,this.title, this.description, this.eventDate}):super(id);
factory EventModel.fromMap(Map data) {
return EventModel(
title: data['title'],
description: data['description'],
eventDate: data['event_date'],
);
}
factory EventModel.fromDS(String id, Map<String,dynamic> data) {
return EventModel(
id: id,
title: data['title'],
description: data['description'],
eventDate: data['event_date'].toDate(),
);
}
Map<String,dynamic> toMap() {
return {
"title":title,
"description": description,
"event_date":eventDate,
"id":id,
};
}
}
This is my Firebase connection:
class DatabaseKalenderMethods {
getUserEvents(String itIsMyName) async {
return await Firestore.instance
.collection("kalender")
.where('users', arrayContains: itIsMyName)
.snapshots();
}
}
I'm guessing the issue is here :
List<EventModel> allEvents = snapshot.data;
This is because (still guessing) in events = snapshots;, the snapshots is a Stream<QuerySnapshot>.
See this answer to map the stream.
I have uploaded the Excel file to Realtime Database. I'm new and I find it very convenient. Especially if there is a need to unload data back for processing in an Excel file. So, it is difficult to find lessons on how to customize the search bar in the application. Please, help. I will also be glad if you can tell me where I can learn to work with databases for applications created in the Dart language.
class UserDashboard extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<UserDashboard> implements AddUserCallback {
TextEditingController editingController = TextEditingController();
bool _anchorToBottom = false;
FirebaseDatabaseUtil databaseUtil;
#override
void initState() {
super.initState();
databaseUtil = FirebaseDatabaseUtil();
databaseUtil.initState();
}
#override
void dispose() {
super.dispose();
databaseUtil.dispose();
}
#override
Widget build(BuildContext context) {
Widget _buildTitle(BuildContext context) {
return InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'List of students',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
);
}
List<Widget> _buildActions() {
return <Widget>[
new IconButton(
icon: const Icon(
Icons.group_add,
color: Colors.white,
),
onPressed: () => showEditWidget(null, false),
),
];
}
return new Scaffold(
appBar: AppBar(
title: _buildTitle(context),
actions: _buildActions(),
backgroundColor: Colors.deepPurple,
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: FirebaseAnimatedList(
key: ValueKey<bool>(_anchorToBottom),
query: databaseUtil.getUser(),
reverse: _anchorToBottom,
sort: _anchorToBottom
? (DataSnapshot a, DataSnapshot b) => b.key.compareTo(a.key)
: null,
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return SizeTransition(
sizeFactor: animation,
child: showUser(snapshot),
);
},
),
),
]),
));
}
#override
void addUser(User user) {
setState(() {
databaseUtil.addUser(user);
});
}
#override
void update(User user) {
setState(() {
databaseUtil.updateUser(user);
});
}
Widget showUser(DataSnapshot res) {
User user = User.fromSnapshot(res);
var item = Card(
child: Container(
child: Center(
child: Row(
children: <Widget>[
CircleAvatar(
radius: 30.0,
child: Text(getShortName(user)),
backgroundColor: const Color(0xFF20283e),
),
Expanded(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
user.name,
// set some style to text
style: TextStyle(
fontSize: 20.0, color: Colors.deepPurple),
),
Text(
user.club,
// set some style to text
style: TextStyle(
fontSize: 20.0, color: Colors.lightBlueAccent),
),
],
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: const Icon(
Icons.edit,
color: Colors.deepPurple,
),
onPressed: () => showEditWidget(user, true),
),
IconButton(
icon: const Icon(Icons.delete_forever),
color: Colors.deepPurple,
onPressed: () => onDelete(user),
),
],
),
],
),
),
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0)),
);
return item;
}
String getShortName(User user) {
String shortName = "";
if (!user.name.isNotEmpty) {
shortName = user.name.substring(0, 1);
}
return shortName;
}
showEditWidget(User user, bool isEdit) {
showDialog(
context: context,
builder: (BuildContext context) =>
AddUserDialog().buildAboutDialog(context, this, isEdit, user),
);
}
void onDelete(User user) async {
if (await _showConfirmationDialog(context)) {
databaseUtil.deleteUser(user);
}
}
Future<bool> _showConfirmationDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: Text("Delete?"),
actions: <Widget>[
FlatButton(
textColor: Colors.red,
child: Text("Delete"),
onPressed: () => Navigator.pop(context, true),
),
FlatButton(
textColor: Colors.black,
child: Text("Cancel"),
onPressed: () => Navigator.pop(context, false),
),
],
));
}
}
Here's how I load and unload data into the application:
class FirebaseDatabaseUtil {
DatabaseReference _counterRef;
DatabaseReference _userRef;
StreamSubscription<Event> _counterSubscription;
StreamSubscription<Event> _messagesSubscription;
FirebaseDatabase database = FirebaseDatabase();
int _counter;
DatabaseError error;
static final FirebaseDatabaseUtil _instance =
new FirebaseDatabaseUtil.internal();
FirebaseDatabaseUtil.internal();
factory FirebaseDatabaseUtil() {
return _instance;
}
void initState() {
// Demonstrates configuring to the database using a file
_counterRef = FirebaseDatabase.instance.reference().child('counter');
// Demonstrates configuring the database directly
_userRef = database.reference().child('record');
database.reference().child('counter').once().then((DataSnapshot snapshot) {
print('Connected to second database and read ${snapshot.value}');
});
database.setPersistenceEnabled(true);
database.setPersistenceCacheSizeBytes(10000000);
_counterRef.keepSynced(true);
_counterSubscription = _counterRef.onValue.listen((Event event) {
error = null;
_counter = event.snapshot.value ?? 0;
}, onError: (Object o) {
error = o;
});
}
DatabaseError getError() {
return error;
}
int getCounter() {
return _counter;
}
DatabaseReference getUser() {
return _userRef;
}
addUser(User user) async {
final TransactionResult transactionResult =
await _counterRef.runTransaction((MutableData mutableData) async {
mutableData.value = (mutableData.value ?? 0) + 1;
return mutableData;
});
if (transactionResult.committed) {
_userRef.push().set(<String, String>{
"Name": "" + user.name,
"date": "" + user.date,
"email": "" + user.email,
"phone": "" + user.phone,
"Place": "" + user.place,
"Club": "" + user.club,
}).then((_) {
print('Transaction committed.');
});
} else {
print('Transaction not committed.');
if (transactionResult.error != null) {
print(transactionResult.error.message);
}
}
}
void deleteUser(User user) async {
await _userRef.child(user.id).remove().then((_) async{
await _counterRef.runTransaction((MutableData mutableData) async {
mutableData.value = (mutableData.value ?? 0) - 1;
return mutableData;
});
print('Transaction committed.');
});
}
void updateUser(User user) async {
await _userRef.child(user.id).update({
"Name": "" + user.name,
"date": "" + user.date,
"email": "" + user.email,
"phone": "" + user.phone,
"Place": "" + user.place,
"Club": "" + user.club,
}).then((_) {
print('Transaction committed.');
});
}
void dispose() {
_messagesSubscription.cancel();
_counterSubscription.cancel();
}
}
Here is info from RTDB:
Datafetchfrom
counter: 2
record
0
Club:"Club1"
Name:"Name1"
Place:"City1"
date: "31737"
email:"sss#gmail.com"
phone:"98988"
2
Club:"Club2"
Name:"Name2"
Place:"City2"
date: "34334"
email:"ddd#gmail.com"
phone:"12333"
In my flutter application i am using mvp with clean architecture and my server return 5 items when it hit api, and when i scroll more it again hit api and get next 5 items. And i am saving these items in a list so that i can not call api again and again for already fetched items and this list was used in listview.builder. I had used bottom navigation bar and when i move from product items tab to any other tab and from there came to products items it again fetch products from api and thats not what i want. I want to show that list which was already fetched by that list in products list tab whenever i return back.
Video of my problem.
import 'dart:async';
import 'package:bakery_application/Bloc/TECartBloc.dart';
import 'package:bakery_application/Singleton/CartManager.dart';
import 'package:bakery_application/data/dataSource/product/remote/ProductRemoteDataSource.dart';
import 'package:bakery_application/data/model/responseDTO/ProductResponseDTO.dart';
import 'package:bakery_application/data/model/responseDTO/models/products.dart';
import 'package:bakery_application/data/model/responseDTO/models/productsList.dart';
import 'package:bakery_application/domain/repository/product/ProductRepo.dart';
import 'package:bakery_application/ui/productdetailscreeen/ProductDetailScreen.dart';
import 'package:bakery_application/ui/productscreen/IProductPresenter.dart';
import 'package:bakery_application/ui/productscreen/IProductView.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bakery_application/localmodels/ProductModel.dart';
import 'package:bakery_application/widgets/TEProductIncrementor.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:provider/provider.dart';
import 'ProductPresenter.dart';
class ProductScreen extends StatefulWidget {
Key key;
List<Products> myList = new List<Products>();
int _pageNumber = 1;
ProductScreen({
this.key,
}) : super(key: key);
#override
_ProductScreenState createState() => _ProductScreenState();
}
class _ProductScreenState extends State<ProductScreen> implements IProductView {
_ProductScreenState() {
productPresenter = ProductPresenter(
this,
ProductRepo(
ProductRemoteDataSource(),
),
);
}
bool circularindicator = false;
Color circularColor;
double circularOpacity;
IProductPresenter productPresenter;
AsyncSnapshot snapshotList;
var _connectionStatus = 'Unknown';
Connectivity connectivity;
StreamSubscription<ConnectivityResult> subscription;
ScrollController _scrollController = ScrollController();
bool cupertinoProgress;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.orange,
automaticallyImplyLeading: false,
title: Text(
'Product',
style: TextStyle(color: Colors.white),
),
),
body:
StreamBuilder(
stream: productPresenter.getProducts,
builder: (context, AsyncSnapshot<ProductsList> snapshot) {
if (snapshot.hasData) {
return productListView(widget.myList);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(
child: Container(
child: CircularProgressIndicator(),
),
);
},
),
);
}
Future<Null> refreshList() async {
await Future.delayed(Duration(seconds: 2));
setState(() {});
return null;
}
Widget productListView(List snapshot) {
return RefreshIndicator(
onRefresh: refreshList,
child:
ListView.builder(
key: widget.key,
controller: _scrollController,
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
if(index+1 == widget.myList.length) {
CupertinoActivityIndicator();
}
var plist = widget.myList[index];
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(
product: plist,
),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 120,
height: 130,
child: Image(
image: NetworkImage(plist.image),
),
),
Container(
child: Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
plist.name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Text(
plist.description,
softWrap: true,
textAlign: TextAlign.left,
),
SizedBox(
height: 7,
),
Row(
children: <Widget>[
Text(plist.price.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
)),
Spacer(),
Text(plist.brand),
],
),
TEProductIncrementor(
product: plist,
),
//TODO reverse it alse
],
),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Divider(
color: Colors.grey.shade300,
),
),
],
)
],
),
),
);
},
itemCount: widget.myList.length,
),
);
}
productlist(BuildContext context, int index
}
#override
hideProgress(ProductsList response) {
setState(() {
// Here you can write your code for open new view
cupertinoProgress=false;
});
for (var c in response.products) {
widget.myList.add(c);
}
}
#override
showError(String error) {
// TODO: implement showError
return null;
}
#override
showProgress() {
print('Successful');
setState(() {
cupertinoProgress=true;
});
}
#override
void initState() {
super.initState();
connectivity = new Connectivity();
print('Init state called');
print('Init state called');
print('Init state called');
subscription =
connectivity.onConnectivityChanged.listen((ConnectivityResult result) {
_connectionStatus = result.toString();
print(_connectionStatus);
if (result == ConnectivityResult.wifi ||
result == ConnectivityResult.mobile) {
widget.myList.isEmpty
? productPresenter.fetchProducts(widget._pageNumber.toString())
:
widget._pageNumber = widget._pageNumber + 1;
productPresenter.fetchProducts(widget._pageNumber.toString(),);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
widget._pageNumber = widget._pageNumber + 1;
print(widget._pageNumber);
productPresenter.fetchProducts(widget._pageNumber.toString(),);
}
});
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Center(
child: Container(
child: Icon(
Icons.add_alert,
color: Colors.orange,
size: 20,
),
),
),
content: Text('Check your internet'),
actions: <Widget>[
new FlatButton(
child: new Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
});
}
#override
void dispose() {
subscription.cancel();
super.dispose();
}
getMoreData() async {
}
}
The main problem you're facing is that each time the user scrolls of the tab you're in and returns to it, the app re-fetches the data again.
You can use IndexedStack to make the data only loads once, for that you can edit your code to be this way.
class BaseScreenState extends State<BaseScreen> {
List<Widget> _pages = [Page1(), Page2(), Page3()];
#override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: currentIndex,
children: _pages,
),
);
}
}