I am currently trying to get the current user state from FirebaseAuth and switch between home screen if user didn't logged out or splash screen if user is logged out. User registration and login are both successful and registered in firestore database. But everytime i closes the application from my phone and re opens, the MediaQuery.of(context) width has a null value and shows an error.
But the bottom navigation bar is still showing. It works when i rebuild the app and login again, it brings me to the home screen. It only occurs when i close and re open the app.
import 'package:country_code_picker/country_localizations.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'routes.dart';
import 'package:screens/home/home_screen.dart';
import 'package:screens/splash/splash_screen.dart';
import 'constants.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
supportedLocales: [Locale('en', 'US')],
localizationsDelegates: [CountryLocalizations.delegate],
title: 'App',
theme: theme(),
routes: routes,
home: LandingPage(),
);
}
}
class LandingPage extends StatelessWidget {
const LandingPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final Future<FirebaseApp> _init = Firebase.initializeApp();
return FutureBuilder(
future: _init,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
if (snapshot.connectionState == ConnectionState.done) {
return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, streamSnapshot) {
if (streamSnapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${streamSnapshot.error}"),
),
);
}
if (streamSnapshot.connectionState == ConnectionState.active) {
print(streamSnapshot.data.toString());
if (streamSnapshot.data == null) {
return SplashScreen();
} else {
return HomeScreen();
}
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
color: kPrimaryColor,
strokeWidth: 3,
),
),
);
},
);
}
return Scaffold(
body: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
color: kPrimaryColor,
strokeWidth: 3,
),
),
);
},
);
}
}
Maybe i thought its a problem with the future builder or stream builder? Any of you have a solution for this problem or another way to implement it.
Launching lib/main.dart on STK L21 in debug mode...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:33019/yIPGCqY2gwY=/ws
I/flutter ( 4249): locale.languageCode: en
D/AwareBitmapCacher( 4249): handleInit switch not opened pid=4249
I/flutter ( 4249): User(displayName: , email: rohanbhautoo#gmail.com, emailVerified: false, isAnonymous: false, metadata: UserMetadata(creationTime: 2021-06-10 08:20:44.583, lastSignInTime: 2021-06-10 15:50:23.573), phoneNumber: , photoURL: null, providerData, [UserInfo(displayName: , email: rohanbhautoo#gmail.com, phoneNumber: , photoURL: null, providerId: password, uid: rohanbhautoo#gmail.com)], refreshToken: , tenantId: null, uid: yviaYOJ5ziayFQhvhvemB3MjkPr1)
════════ Exception caught by widgets library ═══════════════════════════════════
The following _CastError was thrown building Body(dirty):
Null check operator used on a null value
The relevant error-causing widget was
Body
When the exception was thrown, this was the stack
#0 getProportionateScreenWidth
#1 Body.build
#2 StatelessElement.build
#3 ComponentElement.performRebuild
#4 Element.rebuild
...
════════════════════════════════════════════════════════════════════════════════
Size_config.dart
import 'package:flutter/material.dart';
class SizeConfig {
static MediaQueryData? _mediaQueryData;
static double? screenWidth;
static double? screenHeight;
static double? defaultSize;
static Orientation? orientation;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData!.size.width;
screenHeight = _mediaQueryData!.size.height;
orientation = _mediaQueryData!.orientation;
}
}
// Proportionate height per screen size
double getProportionateScreenHeight(double inputHeight) {
double? screenHeight = SizeConfig.screenHeight;
return (inputHeight / 812.0) * screenHeight!;
}
// Proportionate width per screen size
double getProportionateScreenWidth(double inputWidth) {
double? screenWidth = SizeConfig.screenWidth;
return (inputWidth / 375.0) * screenWidth!;
}
The stacktrace line for #0 is return (inputWidth / 375.0) * screenWidth!; It is showing that im using a null check on screenWidth!.
I don't see where you actually call SizeConfig().init(context) ?
Nothing gets defined for you until that happens at the top of your project.
I guess the culprit is this line:
print(streamSnapshot.data.toString());
You are actually checking that streamSnapshot.data is null on the next line:
print(streamSnapshot.data.toString());
if (streamSnapshot.data == null) {
return SplashScreen();
} else {
return HomeScreen();
}
Related
I'm trying to create a chart on a Flutter web app by accessing data from Cloud Firestore.
However, it can't seem to extract and map the details from Firestore.
Firebase console
main.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
home.dart
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:inglesy/items.dart';
import 'package:charts_flutter/flutter.dart' as charts;
class Home extends StatefulWidget {
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<charts.Series<Item, String>>? _seriesBarData; //Try (dynamic,String)
List<Item>? myData;
_generateData(myData) {
print("_generateData worked");
_seriesBarData?.add(
charts.Series(
domainFn: (Item item, _) => item.itemstring.toString(),
measureFn: (Item item, _) => item.itemvotes,
id: 'Items',
data: myData,
),
);
}
#override
Widget build(BuildContext context) {
print("returning AppBar/scaffold now");
return Scaffold(
appBar: AppBar(
title: const Text("This is a title."),
foregroundColor: Colors.pink,
),
body: _buildBody(context),
);
}
Widget _buildBody(context) {
print("Doing _buildBody now");
final Stream<QuerySnapshot> _userStream =
FirebaseFirestore.instance.collection("poll").snapshots();
return StreamBuilder<QuerySnapshot>(
stream: _userStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
} else {
List<Item> item = snapshot.data!.docs
.map((DocumentSnapshot document) =>
Item.fromMap(document.data() as Map<String, dynamic>))
.toList();
return _buildChart(context, item);
}
},
);
}
Widget _buildChart(BuildContext context, List<Item> item) {
myData = item;
_generateData(myData);
return Padding(
padding: EdgeInsets.all(8.0),
child: Container(
child: Center(
child: Column(
children: [
Text("This is a text"),
SizedBox(height: 10.0),
Expanded(
child: charts.BarChart(
_seriesBarData!,
animate: true,
animationDuration: const Duration(seconds: 2),
),
)
],
),
),
),
);
}
}
items.dart
class Item {
final String? itemstring;
final int? itemvotes;
Item({this.itemstring, this.itemvotes});
Item.fromMap(Map<String, dynamic> map)
: assert(map['itemstring'] != null),
assert(map['itemvotes'] != null),
itemstring = map['itemstring'],
itemvotes = map['itemvotes'];
#override
String toString() {
return "Item string: $itemstring | Item votes: $itemvotes";
}
}
It shows this error
PS, I've already done the necessary set-up i.e. I've already installed Firebase CLI and have it generated firbase_options.dart
PPS, I have also already set up Firebase (anonymous) authentication and it works with no errors. But for now, I'm not using it and I'm automatically running home.dart to focus on the Firebase database aspect.
Why don’t you try making the Item.fromMap method a regular factory method like:
factory Item.fromMap(Map<String, dynamic> map) {
return Item(
itemstring = map['itemstring'] ?? '',
itemvotes = map['itemvotes'] ?? ''
);
}
What I am trying to do isto pick images from gallery/camera and then store it in firebase storage.
After clicking on camera/gallery, I can choose the image, but when i try to upload it, then the error below is shown. its shown also in the screen of the emulator.
The error and the code are below.
The error :
The following assertion was thrown building Uploader(dirty, state: _UploaderState#8962b):
A build function returned null.
The offending widget is: Uploader
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The relevant error-causing widget was:
Uploader file:///Users/yassinezagliz/AndroidStudioProjects/dekra/lib/screens/auth/widgets/box.dart:94:13
When the exception was thrown, this was the stack:
#0 debugWidgetBuilderValue.<anonymous closure> (package:flutter/src/widgets/debug.dart:302:7)
#1 debugWidgetBuilderValue (package:flutter/src/widgets/debug.dart:323:4)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4632:7)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
My code is:
import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:flutter/foundation.dart';
class Box extends StatefulWidget {
#override
_BoxState createState() => _BoxState();
}
class _BoxState extends State<Box>{
File _imageFile;
//Select an image via gallery or camera
Future<void> _pickImage(ImageSource source) async {
// ignore: deprecated_member_use
File selected = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = selected;
});
}
//Remove image
void _clear() {
setState(() => _imageFile = null);
}
//Crop Image
Future<void> _cropImage() async {
File cropped = await ImageCropper.cropImage(
sourcePath: _imageFile.path,
//toolbarColor: Colors.purple,
//toolbarWidgetColor: Colors.white,
//toolbarTitle: 'Crop It'
);
setState(() {
_imageFile = cropped ?? _imageFile;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink.shade100,
appBar: new AppBar(
title: new Text("Box Photos"),
backgroundColor: Colors.pink.shade100,
),
bottomNavigationBar: BottomAppBar(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.photo_camera),
onPressed: () => _pickImage(ImageSource.camera),
),
IconButton(
icon: Icon(Icons.photo_library),
onPressed: () => _pickImage(ImageSource.gallery),
),
],
),
),
body: ListView(
children: <Widget>[
if (_imageFile != null) ...[
Image.file(_imageFile),
Row(
children: <Widget>[
FlatButton(
onPressed: _cropImage,
child: Icon(Icons.crop)
),
FlatButton(
onPressed: _clear,
child: Icon(Icons.refresh)
),
],
),
The line which is picked by the exception: Uploader(file: _imageFile) => box.dart:94:13
Uploader(file: _imageFile)
]
],
),
);
}
}
class Uploader extends StatefulWidget {
final File file;
Uploader({Key key, this.file}) : super(key: key);
createState() => _UploaderState();
}
class _UploaderState extends State<Uploader> {
final FirebaseStorage _storage =
// ignore: deprecated_member_use
FirebaseStorage(storageBucket: 'gs://dekra-c50a1.appspot.com');
UploadTask _uploadTask;
void _startUpload() {
String filePath = 'images/${DateTime.now()}.png';
setState(() {
_uploadTask = _storage.ref().child(filePath).putFile(widget.file);
});
}
#override
Widget build(BuildContext context) {
}
}
Per the error message seems to me that the problem is that your build method of _UploaderState is not returning a widget. You should at least return an empty Container:
#override
Widget build(BuildContext context) {
return Container();
}
I've seen similar questions that were asked in regards to this but my problem is a little different in that I'm keeping my application modular so I have defined the following method in a different dart file(Simply a class, not a widget):
Future getProfile() async {
return await usersCollection.doc(uid).get().then<dynamic>((DocumentSnapshot snapshot) async {
print(snapshot.data()['name']);
if(snapshot.data()['name'] == null){
print("No name exists");
}
else {
return snapshot.data()['name'];
}
});
And I'm trying to use it's value on my home widget:
import 'package:flutter/material.dart';
import 'package:carpoolapp/services/auth.dart';
import 'package:carpoolapp/services/database.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
User user = FirebaseAuth.instance.currentUser;
DatabaseService db = DatabaseService(uid: FirebaseAuth.instance.currentUser.uid);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.redAccent,
appBar: AppBar(
title: Text('Signed in'),
backgroundColor: Colors.blueAccent,
elevation: 0.0, //no drop shadow
actions: <Widget>[
FlatButton.icon(
onPressed: () async {
await _auth.signOutUser();
},
icon: Icon(Icons.person),
label: Text('logout')),
],
),
body: Text(db.getProfile()), // Error is here
//body: UserTile(user: FirebaseAuth.instance().getCurrentUser()),
);
}
}
How do I go about making this work without sacrificing the modularity?
By seeing
The argument type 'Future<dynamic>' can't be assigned to the parameter type 'String'
this and
Text(db.getProfile())
the issue is db.getProfile() is an async method. That's why its telling Future can't be assigned to String since Text widget data key is of type String not Future<String>.
You can use FutureBuilder in the body and use the snapshot in the Text which will have the String value.
I would like to add to #Pradyot Prakash's answer with some actual code:
Use the following code snippet as an example to achieve the modularity
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: getProfile() // 👈 Your future function here
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data = snapshot.data!.data()!;
return Text(data['name']); //👈 Your valid data here
},
)),
);
}
I'm trying to play a video from a URL of a Firestore Document. To play a video in Flutter, I have to instantiate its Url in the init() method. I set a default URL to a butterfly video, and the value was supposed to be replaced by the URL obtained from Firestore. (So that it is easy for me to see if the code works). However, the code does not work properly. I got an error that says "NoSuchMethodError: The getter 'value' was called on null".
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// Create the initialization Future outside of build
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
// Check for error
if (snapshot.hasError) {
print(snapshot.error);
return Center(
child: Container(
child: Text(
"Something went wrong",
textDirection: TextDirection.ltr,
),
),
);
}
//Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
title: 'Flutter Demo',
home: VideoPlayerScreen(),
);
}
return CircularProgressIndicator();
});
}
}
class VideoPlayerScreen extends StatefulWidget {
#override
_VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
FirebaseFirestore firestore = FirebaseFirestore.instance;
String videoUrl =
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4';
#override
void initState() {
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
// _controller.dispose();
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize();
print(videoUrl);
})
});
// _controller = VideoPlayerController.network(videoUrl);
// _initializeVideoPlayerFuture = _controller.initialize();
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Video Player"),
),
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
children: [
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
),
],
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
Try the following:
#override
void initState() {
super.initState();
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
});
});
}
Since initialize() is asynchronous, then you can use the method then which will get called when the future completes. Inside the callback, you can call setState() which will trigger a rebuild and notify the framework that the internal state of the widgets has changed .
https://pub.dev/packages/video_player
When I Run getting following error. These are basic code for flutter into firebase.
The following assertion was thrown building MyHomePage(dirty, state: MyHomePageState#b163a):
'package:flutter/src/widgets/text.dart': Failed assertion: line 235 pos 15: 'data != null': is not
Please, Can Anyone Help me How to Resolve This?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
Future<void> main() async {
final FirebaseApp app = await FirebaseApp.configure(
name: 'vscodefirebase',
options: const FirebaseOptions(
googleAppID: 'xxx',
gcmSenderID: 'xxx',
apiKey: 'xxxx',
projectID: 'vscodefirebase',
),
);
final Firestore firestore = Firestore(app: app);
await firestore.settings(timestampsInSnapshotsEnabled: true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
}).toList(),
);
},
),
);
}
}
You have a Text widget with null text.
Here, you did not enter title property for MyHomePage
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase',
home: MyHomePage(),
);
}
}
So this Text widget has null text value.
appBar: AppBar(
title: Text(widget.title),
),
To solve this, declare MyHomePage like this:
MyHomePage(title: "My Home Page")