Save Bookmark Article in Firebase Flutter - firebase

In Flutter app I want to fetch data list
I want to save bookmark any article from article list in Fire store data base but when bookmark button tapped the same article save in the database every time. I want that article should save in database for the first time
Does anyone lead me to the correct way? Any help is highly appreciated!
My code
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() => runApp( MyHomePage());
class MyHomePage extends StatefulWidget {
#override
_MyHomePage createState() => _MyHomePage();
}
class _MyHomePage extends State<MyHomePage> {
String title;
String subtitle;
int id;
Firestore firestore = Firestore.instance;
DocumentSnapshot document;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('jdj'),
),
body: Container(
child: ListView(
children: <Widget>[
stremBuilder(),
Container(
height: 310,
color: Colors.amber,
)
],
),
));
}
Widget stremBuilder() {
return Container(
height: 200,
child: StreamBuilder(
stream: Firestore.instance.collection("User").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: Text("Loding"),
);
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return listItem(context, snapshot.data.documents[index]);
},
);
},
),
);
}
Widget listItem(BuildContext context, DocumentSnapshot document) {
return ListTile(
title: Text(document["title"]),
subtitle: Text(document["subtitle"]),
trailing: GestureDetector(
child: Icon(Icons.bookmark),
onTap: () {
setState(() {
saveData(id, document);
});
}),
);
}
Map<String, dynamic> savedata = {};
saveData(int id, DocumentSnapshot document) {
Map<String, dynamic> savedata = {
"id": id,
"saveTitle": document["title"],
'saveSubtitle': document["subtitle"]
};
Firestore.instance.collection("savedata").add(savedata);
}
}

It looks like on the right track. Checking the code, the tapped List item should be saved. If what you're looking for is to save the "bookmark" only once, and clicking on it again should remove the saved bookmark. Then you can delete the document upon pressing again.
await FirebaseFirestore.instance.collection('savedata').doc(docId).delete();
Make sure to keep track of the id of the document that you'd like to delete to be used as reference.

Related

How to retrieve Firestore Document Data based on the currently logged in user

I have a Firebase/Firestore project that stores data from a QR Code scanner and later displays all the previously scanned items in a history list manner. I used this line to detrmine the stream, stream:FirebaseFirestore.instance.collection('product').where('user_id', isEqualTo:FirebaseAuth.instance.currentUser.uid).orderBy('Created_On', descending: true).snapshots(),
Without the .where('user_id', isEqualTo:FirebaseAuth.instance.currentUser.uid) condition the list outputs all the previously scanned data without the filter of the specific items the user scanned.
With the .where('user_id', isEqualTo:FirebaseAuth.instance.currentUser.uid) condition, the list displays correctly for a Second then displays a CircularProgressIndicator forever.
I want to display the correct data that the user has scanned based on the user ID, Please help me.
The code to display the list of the transactions:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class Transactions extends StatefulWidget {
#override
_TransctionsState createState() => _TransctionsState();
}
class _TransctionsState extends State<Transactions> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Transactions"),
),
body: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('product')
.where('user_id', isEqualTo: FirebaseAuth.instance.currentUser.uid)
.orderBy('Created_On', descending: true)
.snapshots(),
builder: (context, snapshot) {
if(snapshot.hasError)
{
return CircularProgressIndicator();
}
final List<DocumentSnapshot> documents = snapshot.data.docs;
return ListView(
children: documents.map((docValue) =>
Card(
child: ListTile(
leading: Icon(Icons.history, color: Colors.grey,),
title: Text(docValue["ScannedProd"]),
subtitle: Text(
docValue["Created_On"].toDate().toString()),
),
)).toList());
}
));
}
}
Firestore Collection and document structure
Then you can use this to get the list without querying
final String uid = FirebaseAuth.instance.currentUser.uid;
stream:FirebaseFirestore.instance.collection('Users/$uid/Product').orderBy('Created_On', descending: true).snapshots(),
Re written code:
class Transactions extends StatefulWidget {
#override
_TransctionsState createState() => _TransctionsState();
}
class _TransctionsState extends State<Transactions> {
final String uid = FirebaseAuth.instance.currentUser.uid;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Transactions"),
),
body: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Users/$uid/Product')
.orderBy('Created_On', descending: true)
.snapshots(),
builder: (context, snapshot) {
if(snapshot.hasData)
{
final List<DocumentSnapshot> documents = snapshot.data.docs;
return ListView(
children: documents.map((docValue) =>
Card(
child: ListTile(
leading: Icon(Icons.history, color: Colors.grey,),
title: Text(docValue["ScannedProd"]),
subtitle: Text(
docValue["Created_On"].toDate().toString()),
),
)).toList());
}else if (snapshot.hasError){
return Container(); //error handel it
} else{
return CircularProgressIndicator();
}
}
));
}
}
The above will return all the QR stored by the user.

Flutter Firebase RealTime Databasee not ordering properly with OrderByChild() [duplicate]

This question already has an answer here:
Flutter: Firebase Real-Time database orderByChild has no impact on query result
(1 answer)
Closed 2 years ago.
I'm creating a simple application with Firebase Realtime database where a user inputs a text and it gets added to a list of chats.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _firebaseRef = FirebaseDatabase().reference().child('chats');
TextEditingController _txtCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
var comments = _firebaseRef.orderByChild('time').limitToLast(10);
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Row(children: <Widget>[
Expanded(child: TextField(controller: _txtCtrl)),
SizedBox(
width: 80,
child: OutlineButton(
child: Text("Add"),
onPressed: () {
sendMessage();
}))
])),
StreamBuilder(
stream: comments.onValue,
builder: (context, snap) {
if (snap.hasData &&
!snap.hasError &&
snap.data.snapshot.value != null) {
Map data = snap.data.snapshot.value;
List item = [];
data.forEach(
(index, data) => item.add({"key": index, ...data}));
return Expanded(
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(item[index]['message']),
);
},
),
);
} else
return Center(child: Text("No data"));
},
),
],
),
),
),
);
}
sendMessage() {
_firebaseRef.push().set({
"message": _txtCtrl.text,
'time': DateTime.now().millisecondsSinceEpoch
});
}
}
It stores and retrieves data perfectly. But when I try adding data, the new items are placed at random points in the list.
For example, in the image below, the last item I placed into the list was 'Nine'. But it was put in the center of the list:
I've tried sorting the list by timestamps, but it did nothing.
What could be causing this issue? And how can I fix it?
When you call snap.data.snapshot.value; the data in the snapshot (which is ordered) is converted to a Map<String, Object> which isn't ordered. To maintain the order, you'll want to listen to onChild... instead.
Note that FlutterFire has a convenient firebase_list library that handles most of the heavy lifting of onChild... for you.
Also see:
Flutter Firebase Database wrong timestamp order
Flutter sort Firebase snapshot by timestamp
Flutter: Firebase Real-Time database orderByChild has no impact on query result
This might work:
use a Query
Query comments = _firebaseRef.orderByChild('time').limitToLast(10);

Flutter: Items in StreamBuilder(Using firebase realtime database) are sorted randomly [duplicate]

This question already has an answer here:
Flutter: Firebase Real-Time database orderByChild has no impact on query result
(1 answer)
Closed 2 years ago.
I'm creating a simple application with Firebase Realtime database where a user inputs a text and it gets added to a list of chats.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _firebaseRef = FirebaseDatabase().reference().child('chats');
TextEditingController _txtCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
var comments = _firebaseRef.orderByChild('time').limitToLast(10);
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Row(children: <Widget>[
Expanded(child: TextField(controller: _txtCtrl)),
SizedBox(
width: 80,
child: OutlineButton(
child: Text("Add"),
onPressed: () {
sendMessage();
}))
])),
StreamBuilder(
stream: comments.onValue,
builder: (context, snap) {
if (snap.hasData &&
!snap.hasError &&
snap.data.snapshot.value != null) {
Map data = snap.data.snapshot.value;
List item = [];
data.forEach(
(index, data) => item.add({"key": index, ...data}));
return Expanded(
child: ListView.builder(
itemCount: item.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(item[index]['message']),
);
},
),
);
} else
return Center(child: Text("No data"));
},
),
],
),
),
),
);
}
sendMessage() {
_firebaseRef.push().set({
"message": _txtCtrl.text,
'time': DateTime.now().millisecondsSinceEpoch
});
}
}
It stores and retrieves data perfectly. But when I try adding data, the new items are placed at random points in the list.
For example, in the image below, the last item I placed into the list was 'Nine'. But it was put in the center of the list:
I've tried sorting the list by timestamps, but it did nothing.
What could be causing this issue? And how can I fix it?
When you call snap.data.snapshot.value; the data in the snapshot (which is ordered) is converted to a Map<String, Object> which isn't ordered. To maintain the order, you'll want to listen to onChild... instead.
Note that FlutterFire has a convenient firebase_list library that handles most of the heavy lifting of onChild... for you.
Also see:
Flutter Firebase Database wrong timestamp order
Flutter sort Firebase snapshot by timestamp
Flutter: Firebase Real-Time database orderByChild has no impact on query result
This might work:
use a Query
Query comments = _firebaseRef.orderByChild('time').limitToLast(10);

Collection per Users FireStore Flutter App

Im trying to create a collection of users in my flutter application.
The application has a stock collection with items which are documents and those documents, like plates or bags, has 2 fields
I create a root users collection and that collection documents which identified the used with their user ID, one document for each user ID (the one you get from FirebaseAuth).
Ive been told that I have to set the access rules in Firebase to allow to each user to have their own stock collection.
Github https://github.com/juancarlosjr97/flutter_ims
Each user should have their own collection
My database the own it works looks like this:
and the other collection with a collection of users looks like this:
This is my code where I get access to the stock collection
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class StockWidget extends StatefulWidget {
#override
StockWidgetApp createState() => new StockWidgetApp();
}
class StockWidgetApp extends State<StockWidget> {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('stock').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 20.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.item),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.item),
trailing: Text(record.instock.toString()),
onTap: () =>
record.reference.updateData({'instock': record.instock + 1}),
onLongPress: () =>
record.reference.updateData({'instock': record.instock - 1}),
),
),
);
}
}
class Record {
final String item;
final int instock;
final DocumentReference reference;
#override
String toString() => "Record<$item:$instock>";
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['item'] != null),
assert(map['instock'] != null),
item = map['item'],
instock = map['instock'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
}
Use this collection for stock :
final userId = [get the user id from auth]
final col = Firestore.instance.collection("users").document(userId).collection("stock");
//add stock
col.add(yourstock);

Flutter - Fetch records from database and display in ListView Builder

I'm working on a Flutter project and using Sqflite database. I've managed to save data in db. Now I am trying to get list of all records from database based on table name and display them in "ListView.builder".
database_helper.dart
Future<List> getAllRecords(String dbTable) async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM $dbTable");
return result.toList();
}
employees_list.dart
import 'package:flutter/material.dart';
import 'package:flutter_with_db_single_helper/helpers/database_helper.dart';
var db = new DatabaseHelper();
Future<List> _users = db.getAllRecords("tabEmployee"); // CALLS FUTURE
class EmployeesListScreen extends StatefulWidget {
#override
_EmployeesListScreenState createState() => _EmployeesListScreenState();
}
class _EmployeesListScreenState extends State<EmployeesListScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Of Employees'),
),
body: ListView.builder(
// itemCount: _users.length,
itemBuilder: (_, int position) {
return Card(
child: ListTile(
title:
Text("Employee Name: "), // EMPLOYEE NAME TO BE DISPLAYED HERE
),
);
},
),
);
}
}
Where did I go wrong? What can I do to display all my db table records in list?
You could use a FutureBuilder to get and display your data :
class _EmployeesListScreenState extends State<EmployeesListScreen> {
var db = new DatabaseHelper(); // CALLS FUTURE
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Of Employees'),
),
body: FutureBuilder<List>(
future: db.getAllRecords("tabEmployee"),
initialData: List(),
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, int position) {
final item = snapshot.data[position];
//get your item data here ...
return Card(
child: ListTile(
title: Text(
"Employee Name: " + snapshot.data[position].row[1]),
),
);
},
)
: Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}
This might not be correct code, since I've not tested this, but this is how list view builder works and try using async await. Cleans up code quite a bit!
import 'package:flutter/material.dart';
import 'package:flutter_with_db_single_helper/helpers/database_helper.dart'
class EmployeesListScreen extends StatefulWidget {
#override
_EmployeesListScreenState createState() => _EmployeesListScreenState();
}
class _EmployeesListScreenState extends State<EmployeesListScreen> {
List<String> _records;
#override
initState(){
super.initState();
}
Future<void> _getRecords() async {
var res = await db.getAllRecords("tabEmployee");
setState((){
_records = res;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List Of Employees'),
),
body: _records==null ? Container():ListView.builder(
itemCount: _records.length,
itemBuilder: (_, int position) {
return Card(
child: ListTile(
title:
Text("Employee Name: ", _records[position]),
),
);
},
),
);
}
}
Or you can use a future builder, as the other answer shows. :)

Resources