Okay so my profile posts are working as intended right here, I am showing the users posts that only they have made to their very own profile
Now here is the code doing that
static Future<List<Post>> getUserPosts(String currentUserId) async {
QuerySnapshot userPostsSnap = await postsRef
.doc(currentUserId)
.collection('userPosts')
.orderBy('timestamp', descending: true)
.get();
List<Post> userPosts =
userPostsSnap.docs.map((doc) => Post.fromDoc(doc)).toList();
return userPosts;
}
and also to show them to the profile page as you see in the image:
showProfilePosts(UserModel author) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: AlwaysScrollableScrollPhysics(),
itemCount: _allPosts.length,
itemBuilder: (context, index) {
return PostContainer(
post: _allPosts[index],
author: author,
currentUserId: widget.currentUserId,
);
}),
);
}
getAllPosts() async {
List<Post> userPosts =
await DatabaseMethods.getUserPosts(widget.visitedUserId);
if (mounted) {
setState(() {
_allPosts = userPosts;
});
}
}
#override
void initState() {
super.initState();
getAllPosts();
}
now my goal is to show every single post made by every user (I'm creating one big forum) so how can I show every single post made by everyone in the database to my home screen? My database also looks like this for some visuals, would I have to loop through?
here is my Home screen's code, where I wish to display every users posts
class HomeScreen extends StatefulWidget {
final String currentUserId;
const HomeScreen({Key? key, required this.currentUserId}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List _homeScreenPosts = [];
bool _loading = false;
buildHomeScreenPosts(Post post, UserModel author) {
return PostContainer(
post: post,
author: author,
currentUserId: widget.currentUserId,
);
}
showHomeScreenPosts(String currentUserId) {
List<Widget> homePostsList = [];
for (Post post in _homeScreenPosts) {
homePostsList.add(
FutureBuilder(
future: usersRef.doc(post.authorId).get(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
UserModel author = UserModel.fromSnap(snapshot.data);
return buildHomeScreenPosts(post, author);
} else {
return SizedBox.shrink();
}
},
),
);
}
return homePostsList;
}
setupHomeScreenPosts() async {
setState(() {
_loading = true;
});
List homeScreenPosts =
await DatabaseMethods.getHomeScreenPosts(widget.currentUserId);
if (mounted) {
setState(() {
_homeScreenPosts = homeScreenPosts;
_loading = false;
});
}
}
#override
void initState() {
super.initState();
setupHomeScreenPosts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchScreen(
currentUserId: widget.currentUserId,
),
),
);
},
icon: Icon(Icons.search),
),
],
automaticallyImplyLeading: false,
title: Text('Home'),
centerTitle: true,
),
body: RefreshIndicator(
onRefresh: () => setupHomeScreenPosts(),
child: ListView(
physics: BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
children: [
_loading ? LinearProgressIndicator() : SizedBox.shrink(),
SizedBox(height: 5),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 5),
Column(
children: _homeScreenPosts.isEmpty && _loading == false
? [
SizedBox(height: 5),
Padding(
padding: EdgeInsets.symmetric(horizontal: 25),
child: Text(
'There is No New posts',
style: TextStyle(
fontSize: 20,
),
),
),
]
: showHomeScreenPosts(widget.currentUserId),
),
],
)
],
),
),
);
}
}
Firebase does not have the a concept of "tables" the way relational/sql databases do. I.e. there is not a built-in method to access all documents labelled as a "post".
Because of this, you'll need to access each post through each of the user documents.
Assuming you have a List of all of your user Id's called allUserIds, then you can do something like the following:
List<Post> allPostsForAllUsers = [];
allUserIds.forEach((id) {
allPostsForAllUsers.addAll(await getUserPosts(id));
}
Okay so I figured it out myself, all I had to do was call the collectionGroup 'userPosts' like so
static Future<List<Post>> getHomeScreenPosts(String currentUserId) async {
QuerySnapshot homePostsSnap = await FirebaseFirestore.instance
.collectionGroup('userPosts')
.orderBy('timestamp', descending: true)
.get();
List<Post> homeScreenPosts =
homePostsSnap.docs.map((doc) => Post.fromDoc(doc)).toList();
return homeScreenPosts;
}
Related
I'am using flutter in making my mobile app. I wanted to display specific data from my database in firebase into my app. The problem is that when I run hasData the output says it has no data but I already have some data inputted in my collection in firestore.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('customers')
.snapshots(),
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
if (snapshot.hasData) {
var data = 'No Data';
return Text(data);
}
if (snapshot.connectionState == ConnectionState.waiting) {
var data = 'Loading';
return Text(data);
}
final data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return Container(
child: Column(
children: [
detailsWidget(
icon: Icons.person,
field: 'Name',
value: '${data.docs[index]['name']}',
),
detailsWidget(
icon: Icons.order,
field: 'Order',
value: '${data.docs[index]['order']}',
),
],
),
);
});
}),
I initialized the variable in a separate class
import 'package:cloud_firestore/cloud_firestore.dart';
class DatabaseManagement {
final CollectionReference customerList =
FirebaseFirestore.instance.collection('customers');
Future<void> createUserData(
String name,
String order,
String uid,
) async {
return await customerList.doc(uid).set({
'name': name,
'order': order
});
}
}
Now I don't know how to improve my code to make the output shows up
Try This code.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('customers')
.snapshots(),
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
var data = 'Loading';
return Text(data);
case ConnectionState.active:
case ConnectionState.done:
if (snapshot.hasData) {
var data = 'No Data';
return Text(data);
} else {
final data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return Container(
child: Column(
children: [
detailsWidget(
icon: Icons.person,
field: 'Name',
value: '${data.docs[index]['name']}',
),
detailsWidget(
icon: Icons.oder,
field: 'Order',
value: '${data.docs[index]['order']}',
),
],
),
);
});
}
default:
return const Center(
child: Text("Somethign went wrong"),
);
}
}),
I have little problem and I don't know how I can solve this. I am fetching datas from database and when I click on the list it is navigating to new screen. I mean I want to fetch datas which are on first screen to second screen. it is not giving me error but the simulator gives me this and codes below here:
class ServisIhaleEkran extends StatelessWidget {
final url = 'https://escar.com/cek.php';
Future<List<dynamic>> getIhaleData() async {
var response = await http.get(url);
return json.decode(response.body);
}
String _brand(dynamic user) {
return user['marka'];
}
String _model(dynamic user) {
return user['model'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder<List<dynamic>>(
future: getIhaleData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: <Widget>[
ListTile(
title: Text(
_brand(
snapshot.data[index],
).toString(),
),
onTap: () => _sendDataToSecondScreen(context),
),
],
),
);
},
);
} else {
return Center(child: Text('Error'));
}
},
),
);
}
void _sendDataToSecondScreen(BuildContext context) {
String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
}
class Details extends StatelessWidget {
final String brand;
Details({this.brand});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(brand),
));
}
}
The First Screen: ServisIhaleEkran
The Second Screen: Details
I think, the problem is here:
void _sendDataToSecondScreen(BuildContext context) {
String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
}
probably String brandSend = _brand.toString(); is giving me error but I don't know what is this, please help me, thanks.
and my first screen:
Rasat change your code as below:
void _sendDataToSecondScreen(BuildContext context, String brandSend) {
//String brandSend = _brand.toString();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Details(brand: brandSend),
));
}
And use it in your widget as:
ListTile(
title: Text(
_brand(
snapshot.data[index],
).toString(),
),
onTap: () => _sendDataToSecondScreen(context, _brand(snapshot.data[index])),
),
I am working on a flutter project and I want to fetch datas which I post to database. I can post successfully (I can see them in my database) but I cannot fetch data. I want your help... please help me... the codes, explanation and the problem below here.
the code:
class GetId {
String id;
GetId({this.id});
factory GetId.fromJson(Map<String, dynamic> json) {
return GetId(
id: json["id"],
);
}
}
Future<GetId> sendData() async {
_DenemeState controls = new _DenemeState();
final response = await http.post(
"https://www.ekrts.com.tr/bloom/get.php",
body: {
"id": "${controls.idController.text.toString()}"
},
);
if (response.statusCode == 200) {
return GetId.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load album');
}
}
class _DenemeState extends State<Deneme> {
TextEditingController nameController = TextEditingController();
TextEditingController surnameController = TextEditingController();
TextEditingController idController = TextEditingController();
Future<GetId> futureGetId;
Container _getValues() {
return Container(
child: Column(
children: <Widget>[
Text(
nameController.text.toString(),
),
Text(
'textfield değeri ' + idController.text.toString(),
),
Text(
"Response: ",
)
],
),
);
}
#override
void initState() {
super.initState();
futureGetId = sendData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Scaffold(
appBar: AppBar(
title: Text("Register"),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Text(
"ad",
style: TextStyle(fontSize: 18.0),
),
TextField(
controller: nameController,
decoration: InputDecoration(hintText: 'ad'),
),
Text(
"soyad",
style: TextStyle(fontSize: 18.0),
),
TextField(
controller: surnameController,
decoration: InputDecoration(hintText: 'soyad'),
),
Text(
"id",
style: TextStyle(fontSize: 18.0),
),
TextField(
controller: idController,
decoration: InputDecoration(hintText: 'id'),
),
RaisedButton(
child: Text("Register"),
onPressed: () {
setState(() {
_getValues();
sendData();
});
},
),
_getValues(),
FutureBuilder<GetId>(
future: futureGetId,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.id);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
],
),
),
),
),
);
}
}
Explanation:
GetId class: This class contains the data from network request
Future sendData(): This class connects my database and post the data to database, I can see them.
Container _getValues(): I created to see my data from the database on screen.
And my problem, I cannot see the data on emulator screen but I can post and see on database. I hope, I could explain my problem... please help me...
FirebaseAuth.instance.currentUser().then((user) {
id= user.uid;
});
i hope you are asking for something like this. you can load the user id to id variable from this.
I use sqflite for flutter database management. In particular, I would like the user to enter the data only once and therefore I would need to hide and disable the button only once the data has been entered. How can I do?
Home Page, where is the button
class Casa extends StatefulWidget {
static const routeName = '/';
#override
_CasaState createState() => _CasaState();
}
class _CasaState extends State<Casa> {
DataRepository _repository;
#override
void initState() {
super.initState();
_repository = SqlRepository();
}
#override
void dispose() async {
await _repository.closeDB();
super.dispose();
}
void getNewItem(BuildContext context) async {
Attivita newItem =
await Navigator.pushNamed<Attivita>(context, AddItemScreen.routeName);
if (newItem != null) {
await _repository.add(newItem);
setState(() {});
}
}
void switchAndUpdate(Attivita item) async {
await _repository.put(item.id, item);
setState(() {});
}
void delete(Attivita item) async {
await _repository.delete(item.id);
setState(() {});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.lightBlue[900],
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add, color: Colors.lightBlue[900],),
backgroundColor: Colors.white,
onPressed: () {
getNewItem(context);
},
),
body:
FutureBuilder<List<Attivita>>(
future: _repository.getAll(),
builder:
(BuildContext context, AsyncSnapshot<List<Attivita>> snapshot) {
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: snapshot.data == null ? 0 : snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Dismissible(
key: UniqueKey(),
background: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Align(
alignment: Alignment(-0.9, 00),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {
Attivita item = snapshot.data[index];
snapshot.data.removeAt(index);
delete(item);
},
child: Card(
child: ListTile(
title: Text(snapshot.data[index].nome, style: TextStyle(color: Colors.lightBlue[900]),),
onTap: () {
Navigator.pushNamed(context, DettaglioScreen.routeName, arguments: snapshot.data[index]);
},
onLongPress: () {
switchAndUpdate(snapshot.data[index]);
},
),
),
);
},
);
},
)
),
);
}
}
so i have to add some details, because it is written that "it looks like your post is mostly code; please add some more details"
To check if user put so data you can use:
Use sharedPreferences and store bool value if user entered data.
On initState check if database contains data if yes it means user put some data and you can hide button.
I don't use Sqlite in flutter but I think you can use
List<Map<String, dynamic>> result;
result = await db.query(tableName);
isNotData = result.isEmpty;
Or something similar :) You can do it
Choose one way and store bool value eg. in bool isNotData
When you will have bool value about data you can write:
In _CasaState above initState: bool isNotData;
and in Scaffold in floatingActionButton property:
Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
floatingActionButton: isNotData
? FloatingActionButton(
onPressed: () {},
)
: null,
body: Center(
),
),
),
Hi I am currently trying to access a child of my database in Flutter so that I can link it to another child. I am able to pull the data from one child, but unable to link this data with my other child. I want to be able to access a field of the 'Record' child and link to the 'Volunteer' child using the "volunteer" field but am unable to get them to link together. Any help would be appreciated!
The database structure is as follows:
This is the code for My Volunteer class:
class Volunteer {
String volunteerID;
String name;
String role;
Volunteer(this.volunteerID, this.name, this.role);
Volunteer.fromSnapshot(DataSnapshot snapshot)
: volunteerID = snapshot.key,
name = snapshot.value["name"],
role = snapshot.value["role"];
toJson() {
return {
"key": volunteerID,
"name": name,
"role": role
};
}
}
And this is the code for my UI:
class SignInPageState extends State<SignInPage> {
List<Volunteer> volunteers;
Volunteer volunteer;
DatabaseReference dbRef;
DatabaseReference volunteerRef;
DatabaseReference recordRef;
#override
void initState() {
super.initState();
volunteers = new List();
volunteer = Volunteer("","", "");
final FirebaseDatabase database = FirebaseDatabase.instance;
dbRef = database.reference();
volunteerRef = database.reference().child('volunteer');
recordRef = database.reference().child('record');
dbRef.onChildAdded.listen(_onEntryAdded);
dbRef.onChildChanged.listen(_onEntryChanged);
volunteerRef.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> getMap = snapshot.value;
getMap.forEach((key, values) {
String volunteerRecord = recordRef.child('volunteer').toString();
if (volunteerRecord == volunteer.volunteerID){
volunteer.role = volunteerRecord;
}
volunteers.add(volunteer);
});
});
}
_onEntryAdded(Event event) {
setState(() {
volunteers.add(Volunteer.fromSnapshot(event.snapshot));
});
}
_onEntryChanged(Event event) {
var old = volunteers.singleWhere((entry) {
return entry.volunteerID == event.snapshot.key;
});
setState(() {
volunteers[volunteers.indexOf(old)] = Volunteer.fromSnapshot(event.snapshot);
});
}
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.all(10.0),
color: Colors.white,
child: Column(
children: <Widget>[
Expanded(
flex: 8,
child: Container(
child: FirebaseAnimatedList(
query: volunteerRef,
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
return new ListTile(
title: Text(
(volunteers[index].name + " " + volunteers[index].role),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.bold ,color: Color.fromRGBO(139, 195, 68, 1)),
),
onTap: () {
SuccessSignInPage(volunteers[index].name);
},
);
},
),
)
),
],
)),
),
);
}
void Back() async {
await Navigator.of(context).pop();
}
void SuccessSignInPage(String name) async {
var route = new MaterialPageRoute(
builder: (BuildContext context) => new SignInSuccessPage(value: name));
await Navigator.of(context).push(route);
}
}