This was working initially and it just stopped and I cannot figure out where the problem lies.
I am working with streams on my flutter project in provider package. Streams are being emitted from services files and listening is happening on the widgets file. Firebase onAuthStateChanged stream is working but mine are not working.
I have alot of code in my files so am not going to post everything here.
I have a problem with AuthStatus stream
I tried subscribing to the stream on the widget class but it seems like no streams are getting emitted
MyApp(){
auth.authStateStream.listen((d){print("$d is data");});
}
This how firebase streams are getting emiited from services file
Stream<UserModel> get onAuthStateChanged{
return _firebaseAuth.onAuthStateChanged.map(_userFromFirebase);
}
I have a problem with AuthStatus stream. This was working initially
This is how AuthStatus stream is getting emmited from services file
//Services file
final StreamController<AuthStatus> _currentAuthStateController =
StreamController<AuthStatus>.broadcast();
Stream<AuthStatus> get authStateStream{
return _currentAuthStateController.stream;
}
void testStremas() {
//Stoast.setMessage("Test Message");
_currentAuthStateController.add(AuthStatus.ACTIVE);
}
This is how provider is litening to streams as a parent of the MaterialAPP widget
class MyApp extends StatelessWidget {
//I was trying if i my widget could subscribe to the stream
MyApp (){
auth.authStateStream.listen((d){print("$d is data");});
}
final ToastHelper toast = ToastHelper();
final ThemeHelper theme = ThemeHelper();
final AuthService auth = AuthService();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<UserModel>.value(value: auth.onAuthStateChanged),
StreamProvider<ToastMessage>.value(value: toast.onNewMessage),
StreamProvider<AuthStatus>.value(
value: auth.authStateStream, initialData: AuthStatus.NONE),
],
child: MaterialApp(
title: Strings.appName,
theme: theme.darkThemeData(),
home: Loader(),
routes: {
'home': (context) => Home(),
},
debugShowCheckedModeBanner: false,
),
);
}
}
This is how the above method is getting called on a the widget on a click of a button
//Widgets file
onTap: () => auth.testStremas(),
The expected result should be when the AuthStatus change from the services file, The widgets should be notified via the provider package. Thanks in advance
Widget _body(BuildContext context) {
final AuthStatus _authStatus = Provider.of<AuthStatus>(context);
return Center(
child: Container(
constraints: BoxConstraints(maxWidth: 300),
child: SingleChildScrollView(
child: Center(
child: _authStatus == AuthStatus.ACTIVE
? Padding(
padding: const EdgeInsets.all(8.0),
child:CircularProgressIndicator(strokeWidth: 2,)
)
: _buildScreen(context),
)),
),
);
}
I'm not sure - try to change
final StreamController<AuthStatus> _currentAuthStateController =
StreamController<AuthStatus>.broadcast();
to
final StreamController<AuthStatus> _currentAuthStateController =
BehaviorSubject<AuthStatus>();
This BehaviorSubject from rxdart library https://pub.dev/packages/rxdart, so, you should import it. BehaviorSubject is keep last state of stream. You can read more here https://pub.dev/documentation/rxdart/latest/rx/BehaviorSubject-class.html
import 'package:rxdart/rxdart.dart';
Related
So, i've setup up a project on Firebase and followed many tutorials on how to connect firebase to my flutter application. I started by reading FlutterFire docs, step by step, and i managed to install the FlutterFire CLI. After that, i went straight into reading the Realtime Database section and whenever i try to write into the db, nothing happens.
The database is in test mode, firebase is correctly initialised inside the project and i get no errors while trying to write inside it, so i think that even the URL is correct (but i might be wrong)
Here's the code i used:
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'firebase_options.dart'; //generated with FlutterFire CLI
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await Firebase.initializeApp(
options: Platform.isWindows ? null : DefaultFirebaseOptions.currentPlatform, //not working on windows
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final FirebaseDatabase database = FirebaseDatabase.instance;
final DatabaseReference ref = FirebaseDatabase.instance.ref("/");
void writeToFirebase() async {
print('wrote to database');
await ref.set({
'title': 'Hello World',
'body': 'This is my first post',
'userId': '123',
});
await ref.child('title').set('Hello World');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: writeToFirebase,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
I noticed that when the print() statement is above ref.set() , i see the output in the console. But, if i put it beneath the ref.set() statement, i see no output. So, this makes me think that the ref.set() does never end its execution or something like that.
I'm 2 weeks in learning flutter and i really can't make Firebase work
Since you're using await, did you consider using try-catch too so that you can catch and log any errors?
So:
void writeToFirebase() async {
print('Start writing to database');
try {
await ref.set({
'title': 'Hello World',
'body': 'This is my first post',
'userId': '123',
});
await ref.child('title').set('Hello World');
}
catch (error) {
print(error);
}
finally {
print('Done writing to database');
}
}
This question already has answers here:
Check whether there is an Internet connection available on Flutter app
(27 answers)
Closed 1 year ago.
how do you continously check internet access? I was able to show if wifi is connectected or mobile data. However, not all connection would have internet access.
import 'package:connectivity/connectivity.dart';
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
// I am connected to a mobile network.
} else if (connectivityResult == ConnectivityResult.wifi) {
// I am connected to a wifi network.
}
This is currently the code im using.
I was hoping how someone could check continously of internet access?
Here is the way you can build Network Aware applications
High level overview
Create a service that listen to Connectivity change events, for
example wifi, mobile and none (offline). This service will emit
NewtorkStatus (our custom class) into a stream every time the
Connectivity changes.
Create consumer for the above NetworkStatus stream that will be
notified everytime the NetworkStatus changes.
Based on the network status rebuild the HomeScreen to show either
online or offline contents.
Sounds tricky but its actually easy to implement, we will be using connectivity & provider package to our rescue.
Firstly configure our project to use above dependencies, edit pubspec.yaml to include the dependencies -
dependencies:
flutter:
sdk: flutter
connectivity: ^3.0.6
provider: ^6.0.1
Run $ pub get you synchronise all the dependencies.
Now we will create our own NewtorkStatusService this service will use NetworkStatus enumeration with two states Online & Offline to notify the Connectivity state.
network_status_service.dart
enum NetworkStatus {
Online,
Offline
}
Now our NetworkStatusService will use the Connectivity package to get status of current connection status (wifi, mobile, none) and based on that it will emit a new NetworkStatus to stream. Our final NetworkStatusService would look something like this -
network_status_service.dart
import 'dart:async';
import 'package:connectivity/connectivity.dart';
enum NetworkStatus { Online, Offline }
class NetworkStatusService {
StreamController<NetworkStatus> networkStatusController =
StreamController<NetworkStatus>();
NetworkStatusService() {
Connectivity().onConnectivityChanged.listen((status){
networkStatusController.add(_getNetworkStatus(status));
});
}
NetworkStatus _getNetworkStatus(ConnectivityResult status) {
return status == ConnectivityResult.mobile || status == ConnectivityResult.wifi ? NetworkStatus.Online : NetworkStatus.Offline;
}
}
Now we will create our won custom widget that will return either an onlineChild or offlineChild based on NetworkStatus value. Here we will use provider package to get NetworkStatus. I would look something like this -
network_aware_widget.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/services/network_status_service.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
class NetworkAwareWidget extends StatelessWidget {
final Widget onlineChild;
final Widget offlineChild;
const NetworkAwareWidget({Key? key, required this.onlineChild, required this.offlineChild})
: super(key: key);
#override
Widget build(BuildContext context) {
NetworkStatus networkStatus = Provider.of<NetworkStatus>(context);
if (networkStatus == NetworkStatus.Online) {
return onlineChild;
} else {
_showToastMessage("Offline");
return offlineChild;
}
}
void _showToastMessage(String message){
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1
);
}
}
Here I am also using the FlutterToast to show toast message (just to add some interactivity to app)
Now's the fun part we will bring all the pieces together to make our app respond to NetworkStatus value. We will use out custom made widget inside a StreamProvider widget. The StreamProvider will subscribe on the NewtorkStatusService networkStatusController stream and trigger a build on child components every time the NetworkStatus changes to Online or Offline. Here's how it will look -
home.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/services/network_status_service.dart';
import 'package:flutter_network_aware_app/ui/components/network_aware_widget.dart';
import 'package:provider/provider.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Network Aware App"),
),
body: StreamProvider<NetworkStatus>(
create: (context) =>
NetworkStatusService().networkStatusController.stream,
child: NetworkAwareWidget(
onlineChild: Container(
child: Center(
child: Text(
"I am online",
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w600),
),
),
),
offlineChild: Container(
child: Center(
child: Text(
"No internet connection!",
style: TextStyle(
color: Colors.grey[400],
fontWeight: FontWeight.w600,
fontSize: 20.0),
),
),
),
),
),
);
}
}
As you can see we are wrapping our NetworkAwareWidget inside a StreamProvider of NetworkStatus. StreamProvider also makes sure that on create it will subscribe to the NetworkStatusService controller stream.
Finally our app starting point main.dart will look something like this -
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_network_aware_app/ui/screens/home_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(primaryColor: Colors.blue),
home: Home());
}
}
The application would work as follows -
I hope this helps you to build you own network aware app and components!
You can use this alternative, without using any packages. Call this function whenever you need to check internet connectivity
Future<bool> internetConnectivity() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
} on SocketException catch (_) {
return false;
}
return false;
}
You can use this https://pub.dev/packages/connectivity_widget . By installing this package use this code in your build function.
ConnectivityWidget(
builder: (context, isOnline) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("${isOnline ? 'Online' : 'Offline'}", style: TextStyle(fontSize: 30, color: isOnline ? Colors.green : Colors.red),),
SizedBox(height: 20,),
Text(
'Number of times we connected to the internet:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
)
connectivity package is just for discovering network connectivity. if you want to be sure about internet access you can use data_connection_checker.
The last few days I spend a lot of time to read through several SO-questions and tutorials. What I'm trying to achieve is, that a user of my flutter app can choose a firebase project and log in with email/password. After the login, obviously, the correct data of the corresponding database should be shown. And that is where I fail.
After a while of reading some sites and questions from SO, I went with the following site to get the first part of the login.
https://firebase.googleblog.com/2016/12/working-with-multiple-firebase-projects-in-an-android-app.html
After working through this article, I was able to successfully log in to my defined firebase projects.
How did I know that the login was successful? I compared the user-uids from the projects with the print statement from my app in the console. That was the prove my configuration for the non-default project is correct.
But now the main problem which I can't solve.
After the login, the data is always of the default firebase project from the google-service.json.
For state management, I choose the provider package, as they mentioned in the I/O '19. So inside my main.dart, I wrap the whole application with MultipleProvider:
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<LoginModel>(
builder: (_) => LoginModel(),
),
ChangeNotifierProvider<Auth>(
builder: (_) => Auth(),
),
],
child: MaterialApp(
title: 'Breaking News Tool',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RootPage(),
),
);
}
The provided Auth class is a service that connects to firebase sdk and also configure non-default apps to create the needed firebase auth
abstract class BaseAuth {
getDefaultAuth();
getAbnAuth();
...
}
class Auth with ChangeNotifier implements BaseAuth {
...
Auth() {
_configureAbnApp();
_configureProdApp();
}
getDefaultAuth() {
_firebaseAuth = FirebaseAuth.instance;
}
getAbnAuth() {
_firebaseAuth = FirebaseAuth.fromApp(_abnApp);
}
_configureAbnApp() {
FirebaseOptions abnOptions = FirebaseOptions(
databaseURL: 'https://[project-id].firebaseio.com',
apiKey: 'AIzaSxxxxxxxxxxxxxxxx,
googleAppID: '1:10591xxxxxxxxxxxxxxxxxxx');
FirebaseApp.configure(name: 'abn_database', options: abnOptions)
.then((result) {
_abnApp = result;
});
}
...
}
After a log in the app redirects the user to the home_page (StatefulWidget). Here I use a snapshot of the database to show data.
_stream = Firestore.instance.collection(collection).snapshots();
...
Center(
child: Container(
padding: const EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: _stream,
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading...');
default:
return ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return CustomCard(
docID: document.documentID,
title: document[title],
message: document[message],
fromDate: document[fromDate],
endDate: document[endDate],
disableApp: document[disableApp],
);
}).toList(),
);
}
},
),
),
),
In the beginning, I only had one project to connect to and the data was correct. But now I successfully connect to another project with the correct user-uid, but the data is always from the default project which is defined by the google-service.json.
And at this point, I have no clue why this happens.
Did anyone have an advice or idea?
You create your _stream based on Firestore.instance, which will give you the default firebase app, as documented in the docs:
/// Gets the instance of Firestore for the default Firebase app.
static Firestore get instance => Firestore();
Therefore you always get the data from the default project.
To fix this you need to create your firestore using the app created by FirebaseApp.configure().
So replace:
_stream = Firestore.instance.collection(collection).snapshots();
with
_stream = Firestore(app: _abnApp).collection(collection).snapshots();
I am trying to set up a toggle switch button from flutter to firestore. I have already set up the dependencies in my flutter project, however, I do not know how to connect the switch with the firestore.
I am trying to make an on/off switch which can be used to control light; I have tried giving it some values but, even then, I am not sure how to connect with firestore.
class _HomeState extends State<Home> {
bool _value = false;
void _onChanged(bool value) {
setState(() {
_value = value;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home ${widget.user.email}'),
),
body: new Container(
padding: new EdgeInsets.all(32.0),
child: new Column(
children: <Widget>[
new SwitchListTile.adaptive(
title: new Text('Bedroom light'),
activeColor: Colors.red,
secondary: const Icon(Icons.lightbulb_outline),
value: _value,
onChanged: (bool value) {
_onChanged(value);
})
],
),
),
);
}
}
This is the code I have so far. I know that we have to use StreamBuilder but I would like to know how.
You have to create a database reference first in firestore say-
databaseReference = Firestore.instance.collection('Switches').where('switch','==',/*ANY NAME*/);
And then run a transition to update the value of value
Firestore.instance.runTransaction((transaction) async {
await transaction.update(
documentReference, _value);
};
Just make sure that in the firestore, the field which will take the value of _value isboolean
I am just getting into Flutter, Dart and Redux. Have followed a YouTube video to modify the default Flutter example to use Redux but its failing for me and I still have a hard time understanding exceptions and reacting to them effectively. Here is the code:
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
// following this youtube video: https://youtu.be/X8B-UzqEaWc
void main() => runApp(new MyApp());
#immutable
class AppState {
final int counter;
AppState(this.counter);
}
// actions
enum Actions { increment }
// pure function
AppState reducer(AppState prev, action) {
if(action == Actions.increment) {
return new AppState(prev.counter + 1);
}
return prev;
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData.dark(),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final store = new Store(reducer, initialState: new AppState(0));
//print(store.state.counter); <----- Undefined class 'counter'.
#override
Widget build(BuildContext context) {
return new StoreProvider(
store: store,
child: new Scaffold(
appBar: new AppBar(
title: new Text("Flutter Redux"),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new StoreConnector(
converter: (store) => store.state.counter,
builder: (context, counter) => new Text(
"$counter",
style: Theme.of(context).textTheme.display1,
)
)
],
),
),
floatingActionButton: new StoreConnector<int, VoidCallback>(
converter: (store) {
return () => store.dispatch(Actions.increment);
},
builder: (context, callback) => new FloatingActionButton(
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
)
),
);
}
}
So first of all, when I try to run this, I am getting an exception that states that "The following NoSuchMethodError was thrown building StoreConnector(dirty):
I/flutter (20662): The getter 'store' was called on null.". Secondary question is why the print method highlighted in the code is not recognizing counter getter? Thanks.
The problem was that I had "dart.previewDart2" set to true and I guess something might be screwed up in the latest preview build. Once I set the option to false, all worked good.
Details:
Got to File -> Preferences -> Settings.
Type 'dart" in the search box.
Once you find the setting dart.previewDart2, click on the pencil icon to the left of it and select "Copy to Settings".
On the right hand side in user settings, set the setting to true.