I'm getting a weird error, can anyone explain why this is and what would be the solution?
I need to compare different collection fields in firestore. I was thinking it might be because I'm using both streambuilder and provider? so one of the context gets 'confused'. If this is so, is there any alternative to what I'm trying to do?
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:carpoolapp/shared/loading.dart';
import 'package:provider/provider.dart';
import 'package:carpoolapp/models/chatdata.dart';
import 'package:carpoolapp/screens/home/chat_tile.dart';
final _firestore = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
class preMessageTab extends StatefulWidget {
#override
_preMessageTabState createState() => _preMessageTabState();
}
class _preMessageTabState extends State<preMessageTab> {
int count = 0;
var chats;
void prov(){
chats = Provider.of<List<ChatData>>(context);
}
#override
Widget build(BuildContext context) {
prov();
return StreamBuilder(
stream: _firestore.collection('users').doc(user.uid).collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: Loading(),
);
}
else{
return ListView.builder(
itemCount: chats.length,
itemBuilder: (context, index) {
snapshot.data.docs.forEach((doc) {
if(doc.data()['sender'] == chats[index].uid){
++count;
}
});
if(count>=1){
return ChatTile(chat: chats[index],);
}
else{
return SizedBox(height: 20.0,);
}
}
);
}
}
);
}
}
The error indicates that your widget can't access the provider. This could be due to the multiple reasons mentioned in the red screen and debug console.
Mainly, always check that your provider is above your widget.
If you are using more than one provider, use multiProvider.
If the problem still persists, it would mean that the widget you are calling provider from, and your multiprovider, are in two separate material route.
Fixing this issue would solve the problem usually, as you suggested also, using a middleMan widget.
Created another dart file and used that as a 'middleman' to get to the original tab. The route was the issue.
#Huthaifa Thank you for your help.
class prepreMessageTab extends StatefulWidget {
#override
_prepreMessageTabState createState() => _prepreMessageTabState();
}
class _prepreMessageTabState extends State<prepreMessageTab> {
#override
Widget build(BuildContext context) {
return StreamProvider<List<ChatData>>.value(
value: DatabaseService().chatData,
child: Scaffold(
body: preMessageTab(),
),
);
}
}
Related
I am trying to fetch data from various collections in Firebase for a flutter app. However, I've noticed that as the number of documents in my collections increase, the longer it takes for it to display in my app on an emulator using Android Studio. Specifically, for the collection with 1 doc, it loads instantly, for the collection with 2 docs, it takes a little longer, and for my collection with 5 docs, it doesn't load at all. How can I solve this problem? All docs have the same number of fields and I am mapping the same function on all collections to access and display their data.
This is the code I use to fetch the data, and I call this class in my main.dart file. This current code does have a rangeError currently since I'm not checking whether the currentIndex is within the bounds, but I believe the issues are unrelated since I cannot get the first question to display in case the subject is 'biology', which is the collection with 5 docs.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import './questions.dart';
class QuizPage extends StatefulWidget {
final String subjectHolder;
const QuizPage(this.subjectHolder, {Key? key}) : super(key: key);
#override
State<QuizPage> createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
String subject = 'biology';
#override
void initState(){
subject = widget.subjectHolder;
super.initState();
}
Stream<List<Question>> readQuestions() =>
FirebaseFirestore.instance.collection(subject).snapshots()
.map((snapshot) => snapshot.docs.map((doc) => Question.fromJson(doc.data())).toList());
var currentIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<List<Question>>(
stream: readQuestions(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final questions = snapshot.data!;
return Center(
child: Column(children: [
Text("${questions[currentIndex].question}"),
ElevatedButton(onPressed: () {
setState(() {
currentIndex +=1;
});
},
child: Text("${questions[currentIndex].option_a}")),
ElevatedButton(onPressed: () {
setState(() {
currentIndex +=1;
});
},
child: Text("${questions[currentIndex].option_b}")),
ElevatedButton(onPressed: () {
setState(() {
currentIndex +=1;
});
},
child: Text("${questions[currentIndex].option_c}")),
]
),
);
}
else {
return Center(child: CircularProgressIndicator());
}
}),
);
}
}
i am trying to call data from firestore but i have hit a problem. it keeps giving me this error even though every source of a solution i have seen use 'documents' to locate the particular data that is needed. help is needed very much
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class BoardApp extends StatefulWidget {
const BoardApp({Key? key}) : super(key: key);
#override
State<BoardApp> createState() => _BoardAppState();
}
class _BoardAppState extends State<BoardApp> {
var firestoreDb = FirebaseFirestore.instance.collection('board').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('community board'),
),
body: StreamBuilder(
stream: firestoreDb,
builder: (BuildContext context, snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data?.documents.length,
itemBuilder: (context, int index){
return Text(snapshot.data?.documents[index]);
}
);
}else{
return CircularProgressIndicator();
}
}
),
);
i have done everything that is needed but i still get the error
You can use StreamBuilder<QuerySnapshot> to access the data from firestore by replacing StreamBuilder().
A QuerySnapshot is returned from a collection query, and allows you to inspect the collection, such as how many documents exist within it, and gives access to the documents within the collection.
You can refer the document & Cloud Firestore
import 'package:flutter/material.dart';
import 'package:flutter_user_profile/home/parking_tile.dart';
import 'package:provider/provider.dart';
import 'parking_tile.dart';
import '../model/parking.dart';
class ParkingList extends StatefulWidget {
#override
State<ParkingList> createState() => _ParkingListState();
}
class _ParkingListState extends State<ParkingList> {
#override
Widget build(BuildContext context) {
final parkings = Provider.of<List<Parking>>(context);
return ListView.builder(
itemCount: parkings.length,
itemBuilder: (context,index){
return ParkingTile(parking: parkings[index]);
},
);
return Container();
}
}
And heres my coding for main.dart file
import 'package:flutter_user_profile/services/auth.dart';
import 'package:provider/provider.dart';
import 'package:flutter_user_profile/model/user.dart';
Future <void> main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: FirebaseOptions(apiKey: "AIzaSyD59Nz0y4Z8S-rVpeu5E5lslsW_8WYrEiE",
appId: "XXX", messagingSenderId: "XXX", projectId: "parkingtech-f1449") );
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
return StreamProvider<Client?>.value(
initialData: null,
value: AuthService().user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
)
);
}
}
when I run the app it could not find the correct provider and I'm not sure how to solve this,I've tried most of the solution but it seems that I still cant find the right way to do it. I'm still new to flutter please help
Have you registered this Parking in your main.dart ?
If didn't, look at the mine answer.. Thanks
Error: Could not find the correct Provider<AppStateNotifier> above this Consumer<AppStateNotifier> Widget
You have to wrap you main app (parent class) with a provider (depending on the use case)!
Please check out the official documentation of Provider package to understand how to add a provider in the main app.
Link to the original package on pub: https://pub.dev/packages/provider
Example: https://pub.dev/packages/provider/example
So i want to implement role based authentication to my app in flutter. Only users with the permissions should get to this site. Im getting the error:
The method 'then' isn't defined for the type 'User'.
Try correcting the name to the name of an existing method, or defining a method named 'then'.
I've tried to solve it for 2 hours now, but every tutorial is outdated or not for my usecase.
Full code of Authentication Handler:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:learnon/screens/lehrerstartpage.dart';
import '../screens/startscreen.dart';
import '../screens/auth_screen.dart';
class AutoLoginHandler extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
//Streambuilder looks if data is avaliable
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data != null) {
return MainPage(); //when data here goto Startscreen
}
return LoginScreen(); //when no data is here goto Login
},
);
}
final FirebaseAuth auth = FirebaseAuth.instance;
authorizeAccess(BuildContext context) {
FirebaseAuth.instance.currentUser!.then((user) {
FirebaseFirestore.instance
.collection('/users')
.where('uid', isEqualTo: user.uid)
.get()
.then((results) {
if (results.size > 0) {
if (results.docs[0].data()['role'] == 'admin')
{
Navigator.of(context).push(new
MaterialPageRoute(
builder: (BuildContext context) => new
LehrerMainPage()));
}
}
});
});
}
}
I am trying to make a Telegram client for android using the tdlib flutter port. I am currently attempting to make a contact list of sorts, by requesting it from telegram and making a listview of textbuttons.
The only issue is that since the library is async, I get the contact list after the layout has been initialized. Is it possible to somehow rebuild the layout or update it to make the list load properly.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fima/services/telegram_service.dart';
import 'package:tdlib/td_api.dart' show TdError;
import 'package:provider/provider.dart';
import 'package:tdlib/td_api.dart' as TdApi;
class ContactListScreen extends StatefulWidget {
#override
_ContactListScreenState createState() => _ContactListScreenState();
}
class _ContactListScreenState extends State<ContactListScreen> {
final String title = 'Contact list';
bool _loadingStep = false;
String _Error;
String route = "initRoute";
List<TextButton> contacts = [];
#override
void initState() {
super.initState();
_getContacts(onError: _handelError,);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
backgroundColor: Color(0xD3232323),
),
body: Container(
child:
ListView (
children: contacts,
),
),
);
}
Future _getContacts(
{
void Function(TdError) onError,
}) async {
final result = await context.read<TelegramService>().send(
TdApi.GetContacts(
),
);
if (result is TdError && onError != null) {
onError(result);
}
TdApi.Users users = result;
for (var i = 0; i < users.totalCount; i++) {
final result = await context.read<TelegramService>().send(
TdApi.GetUser(userId: users.userIds[i]),
);
TdApi.User user = result;
print(user.firstName + " " + user.lastName);
final contact = TextButton(
onPressed: () {
print("Test");
},
child: Text(user.firstName + " " + user.lastName),
);
setState(() {
contacts.add(contact);
});
}
}
void _handelError(TdError error) async {
setState(() {
_loadingStep = false;
_Error = error.message;
});
}
}
I have attempted to use setState, but without much success, could anyone be so kind as to provide me with the solution to this problem?
Using the FutureBuilder might help. It is a widget that builds itself based on the latest snapshot of interaction with a Future.
You can modify your build to return a FutureBuilder something like this:
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getContacts,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
//Use snapshot data to build by returning your Container with List
}
else{
//Return a CircularProgressIndicator
}
}
}
Refer the documentation on the FutureBuilder class here.