Flutter ChangeNotifierProxyProvider Firebase rest API auth error - firebase

void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
ChangeNotifierProxyProvider<Auth, Products>(
create: (_) => Products(
Provider.of(context, listen: false).token,
Provider.of(context, listen: false).items,
),
update: (ctx, auth, previousProducts) => Products(
auth.token,
previousProducts == null ? [] : previousProducts.items,
),
),
ChangeNotifierProvider.value(
value: Cart(),
),
ChangeNotifierProvider.value(
value: Orders(),
),
],
child: Consumer(
builder: (ctx, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
fontFamily: 'Lato',
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.purple)
.copyWith(secondary: Colors.deepOrange),
),
home: auth.isAuth ? const ProductsOverviewScreen() : AuthScreen(),
routes: {
ProductDetailScreen.routeName: (ctx) => const ProductDetailScreen(),
CartScreen.routeName: (ctx) => const CartScreen(),
OrdersScreen.routeName: (context) => const OrdersScreen(),
UserProductsScreen.routeName: (context) =>
const UserProductsScreen(),
EditProductScreen.routeName: (context) => const EditProductScreen(),
},
),
),
);
}
}

Related

Flutter streamprovider issue with userdata from Firebase

I've been stuck in this issue for sometime now and after lots of tries, now i don't know where the issue is.
The problem is i'm using StreamProvider to get userData from firebase and then use that userData through provider throughout my project, Now everything works fine but the issue arises when i try to log out. Actually even logout works perfectly, untill i close the app using the backbutton of my phone and then reopen the app from open apps list, then when i try to logout it doesn't work correctly. When i refresh the app the user is logged out but initially it doesn't navigate to the login screen.
here is the logout code.
InkWell(
onTap: () async {
await showDialog(
context: context,
useRootNavigator: false,
builder: (ctx) => AlertDialog(
title: const Text("Are you Sure?"),
content: const Text("Do You want to logout?"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text(
"No",
style: TextStyle(
color: ColorConstant.appColor,
),
),
),
TextButton(
onPressed: () async {
Navigator.of(context).pop(true);
await AuthService().signOut();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: ((context) =>
const LoginScreen())),
(route) => false);
},
child: const Text(
"Yes",
style: TextStyle(
color: ColorConstant.appColor,
),
),
),
],
),
);
},
And here is the main.dart i've defined StreamProvider.
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
final _auth = AuthService();
final String? _userId = _auth.user?.uid;
return MultiProvider(
providers: [
StreamProvider<List<Packages>>(
create: (_) => DatabaseService().packages, initialData: const []),
StreamProvider<UserModel?>(
create: (_) => DatabaseService().userData(_userId),
initialData: null,
),
],
builder: (context, child) {
return MaterialApp(
title: 'DreamaX',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: ColorConstant.appColor,
errorColor: Colors.red,
),
home: const Wrapper(),
);
},
);
}
}
Also one another thing that when i'm logging in, i navigate to MyApp so that the StreamProvider can get the userId and initialize the streamprovider.
here is the login code
try {
await _authService.signIn(
emailCont: _emailCont.text.trim(),
passCont: _passCont.text.trim());
Navigator.of(context)
.pushAndRemoveUntil(
MaterialPageRoute(
builder: ((context) =>
const MyApp())),
(route) => false);
} on FirebaseAuthException catch (e) {
So i'm really confused now what could be the cause here?

How to use StreamBuilder to listen for a document change in Firestore

My goal is to refactor the code below to use a StreamBuilder. It has been suggested that I could improve my code even further by using a StreamBuilder but after a few days of trying I honestly can't figure out what to do or where to begin.
I want the user interface and the Firestore database to react to user taps on a switch tile. The boolean value in Firestore should toggle when the user clicks the switch and the switch tile user interface should update accordingly.
The code below works just fine but it doesn't use a StreamBuilder.
Thanks in advance for any help.
class InterestsFitnessTile extends StatefulWidget {
const InterestsFitnessTile({
Key? key,
}) : super(key: key);
#override
State<InterestsFitnessTile> createState() => _InterestsFitnessTileState();
}
class _InterestsFitnessTileState extends State<InterestsFitnessTile> {
bool isFitnessActive = true;
final String? currentSignedInUserID = Auth().currentUser?.uid;
Future<void> _updateFitnessSetting() async {
await Auth()
.userInterestsSettingsReference
.doc(currentSignedInUserID)
.update({
AuthString.fitness: isFitnessActive,
});
setState(() {
isFitnessActive = !isFitnessActive;
});
}
#override
Widget build(BuildContext context) {
return SwitchListTileSliver(
icon: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? Icons.thumb_down
: Icons.thumb_up,
onChanged: (value) {
final provider = Provider.of<InterestsPageProvider>(
context,
listen: false,
);
provider.updateFitnessSettings(isOn: value);
_updateFitnessSetting();
},
subTitle: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff
? const Text(
SettingsPageString.fitnessOff,
)
: const Text(
SettingsPageString.fitnessOn,
),
title: SettingsPageString.fitness,
value: Provider.of<InterestsPageProvider>(context).isFitnessTurnedOff,
);
}
}
class InterestsPageProvider extends ChangeNotifier {
bool _currentFitness = false;
bool get isFitnessTurnedOff => _currentFitness == true;
void updateFitnessSettings({required bool isOn}) {
_currentFitness = !_currentFitness;
notifyListeners();
}
}
Here are two examples in which I have used Streambuilder:
Example 1:
class Messages extends StatelessWidget {
const Messages({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final currentUser = FirebaseAuth.instance.currentUser!.uid;
return StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection("chat")
.orderBy("createdAt", descending: true)
.snapshots(),
builder: (ctx, snapShot) {
if (snapShot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
final chatDocs = snapShot.data!.docs;
return ListView.builder(
reverse: true,
itemBuilder: (ctx, i) => MessageBubble(
chatDocs[i]['text'],
chatDocs[i]['userName'],
chatDocs[i]['userId'] == currentUser,
chatDocs[i]['userImg'],
),
itemCount: chatDocs.length,
);
}
},
);}}
Example 2:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CarsProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (ctx, snapShot) =>
snapShot.hasData ? const HomePage() : const UserAuth(),
),
routes: {
HomePage.routeName: (_) => const HomePage(),
SearchPage.routeName: (_) => const SearchPage(),
SearchedItemDetail.routeName: (_) => const SearchedItemDetail(),
ForgotPassword.routeName: (_) => const ForgotPassword(),
AddItem.routeName: (_) => const AddItem(),
},
),
);
}
}

how to pass data between two pages in flutter using bottom navigation bar

i'm new in flutter world. i'm using bottom navigation bar but i don't have idea how to pass data from bottom navigation bar page to homepage since homepage is expecting 1 parameter. i'm passing data between other pages but i couldn't find a way to pass data between bottomnavigation bar and home page. any help would be apprecaited
thanks in advance
this is my navigation page code
import 'package:chat_app/models/user_model.dart';
import 'package:chat_app/screens/call_log_screen.dart';
import 'package:chat_app/screens/chat_screen.dart';
import 'package:chat_app/screens/home_screen.dart';
import 'package:chat_app/screens/search_screen.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class CustomBottomNavigationBar extends StatefulWidget {
UserModel user;
CustomBottomNavigationBar(this.user);
#override
_CustomBottomNavigationBarState createState() =>
_CustomBottomNavigationBarState();
}
class _CustomBottomNavigationBarState extends State<CustomBottomNavigationBar> {
int _selectedIndex = 0;
late final screens = [
HomeScreen(widget.user),
CallLog(),
CallLog(),
CallLog(),
];
void onTapped(int index) {
print(widget.user.name);
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: screens[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.black,
selectedIconTheme: IconThemeData(color: Colors.blue),
currentIndex: 2,
items: [
BottomNavigationBarItem(
icon: Icon(
CupertinoIcons.settings,
color: Colors.grey,
),
label: 'hi',
),
BottomNavigationBarItem(
icon: Icon(
CupertinoIcons.home,
color: Colors.grey,
),
label: 'hi',
),
BottomNavigationBarItem(
icon: Icon(
CupertinoIcons.phone,
color: Colors.grey,
),
label: 'hi',
),
BottomNavigationBarItem(
icon: Icon(
CupertinoIcons.chat_bubble_text,
color: Colors.grey,
),
label: 'hi',
),
],
onTap: onTapped,
),
);
}
}
and this is my homepage code
import 'package:cached_network_image/cached_network_image.dart';
import 'package:chat_app/models/user_model.dart';
import 'package:chat_app/screens/chat_screen.dart';
import 'package:chat_app/screens/search_screen.dart';
import 'package:chat_app/widgets/bottom_navigation_bar.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:intl/intl.dart';
import 'auth_screen.dart';
class HomeScreen extends StatefulWidget {
UserModel user;
HomeScreen(this.user);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance!.addObserver(this);
setStatus('online');
}
void setStatus(String status) async {
await FirebaseFirestore.instance
.collection('users')
.doc(widget.user.uid)
.update({"userStatus": status});
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
// TODO: implement didChangeAppLifecycleState
if (state == AppLifecycleState.resumed) {
//online
setStatus("online");
} else {
//offline
setStatus('offline');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
centerTitle: true,
backgroundColor: Colors.deepPurple,
actions: [
IconButton(
onPressed: () async {
await GoogleSignIn().signOut();
await FirebaseAuth.instance.signOut();
setStatus('offline');
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => AuthScreen(),
),
(route) => false);
},
icon: Icon(Icons.logout),
),
],
),
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(widget.user.uid)
.collection('messages')
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if (snapshot.data.docs.length < 1) {
return Center(
child: Text('No Chat Available!!!'),
);
}
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
var friendId = snapshot.data.docs[index].id;
var lastMsg = snapshot.data.docs[index]['last_message'];
var lastMsgTime =
snapshot.data.docs[index]['last_message_time'];
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.doc(friendId)
.get(),
builder: (context, AsyncSnapshot asyncSnapShot) {
if (asyncSnapShot.hasData) {
var friend = asyncSnapShot.data;
return ListTile(
leading: ClipRRect(
borderRadius: BorderRadius.circular(80.0),
child: CachedNetworkImage(
imageUrl: friend['image'],
placeholder: (context, url) =>
CircularProgressIndicator(),
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
// child: Image.network(
// friend['image'],
// ),
),
trailing: Text(
DateFormat.jm().format(
lastMsgTime.toDate(),
),
),
title: Text(
friend['name'],
),
subtitle: Text(
"$lastMsg",
style: TextStyle(color: Colors.grey),
overflow: TextOverflow.ellipsis,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatScreen(
currentUser: widget.user,
receiverId: friend['uid'],
receiverImage: friend['image'],
receiverName: friend['name'],
),
),
);
},
);
}
return LinearProgressIndicator();
},
);
},
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchScreen(widget.user),
),
);
// Navigator.pushAndRemoveUntil(
// context,
// MaterialPageRoute(
// builder: (context) => SearchScreen(widget.user),
// ),
// (route) => false);
},
child: Icon(CupertinoIcons.search),
),
bottomNavigationBar: CustomBottomNavigationBar(widget.user),
);
}
}
You can't access instance member widget in an initializer.
Try this
class _CustomBottomNavigationBarState extends State<CustomBottomNavigationBar> {
int _selectedIndex = 0;
late final List screens;
#override
void initState() {
super.initState();
screens = [
HomeScreen(widget.user),
CallLog(),
CallLog(),
CallLog(),
];
}
...
// the rest of your code

Issue in Flutter while using ChangeNotifierProxyProvider in my project. [Link for my project attached]

I can't get my app working when using ChangeNotifierProxyProvider.
Link to my project is : https://github.com/BH4R47k/Practice-Shopping-App.git
I hope someone download the project and run it to get my issue resolved.
Have a look in the main.dart file where I am using ChangeNotifierProxyProvider. I want to know if I did anything wrong(not only in main.dart but in the complete project [link is given above]), and would also appreciate if someone solve my issue.
And I am also putting my code here of the main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './screens/splash_screen.dart';
import './screens/cart_screen.dart';
import './screens/products_overview_screen.dart';
import './screens/product_detail_screen.dart';
import './providers/products.dart';
import './providers/cart.dart';
import './providers/orders.dart';
import './providers/auth.dart';
import './screens/orders_screen.dart';
import './screens/user_products_screen.dart';
import './screens/edit_product_screen.dart';
import './screens/auth_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
ChangeNotifierProxyProvider<Auth, Products>(
create: (context) => Products(
Provider.of<Products>(context).authToken,
Provider.of<Products>(context).userId,
Provider.of<Products>(context).items,
),
update: (context, auth, previousProducts) => Products(
auth.token,
auth.userId,
previousProducts == null ? [] : previousProducts.items,
),
),
ChangeNotifierProvider.value(
value: Cart(),
),
ChangeNotifierProxyProvider<Auth, Orders>(
create: (context) => Orders(
Provider.of<Orders>(context).authToken,
Provider.of<Orders>(context).userId,
Provider.of<Orders>(context).orders,
),
update: (context, auth, previousOrders) => Orders(
auth.token,
auth.userId,
previousOrders == null ? [] : previousOrders.orders,
),
),
],
child: Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: auth.isAuth
? ProductsOverviewScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: AuthScreen(),
),
routes: {
ProductDetailScreen.routeName: (ctx) => ProductDetailScreen(),
CartScreen.routeName: (ctx) => CartScreen(),
OrdersScreen.routeName: (ctx) => OrdersScreen(),
UserProductsScreen.routeName: (ctx) => UserProductsScreen(),
EditProductScreen.routeName: (ctx) => EditProductScreen(),
},
),
),
);
}
}
Thanks in advance.
I used the Optional Parameters in the constructor so that I don't have to pass anything in the main.dart file.
Block of code for products.dart(with optional parameters) looks like:
List<Product> _items;
String authToken = '';
String userId = '';
Products(this._items, [this.authToken, this.userId]);
Similarly block of code for orders.dart was changed.
Block of code for main.dart file looks like:
ChangeNotifierProxyProvider<Auth, Products>(
create: (_) => Products([]),
update: (ctx, auth, previousProducts) => Products(
previousProducts == null ? [] : previousProducts.items,
auth.token,
auth.userId,
),
),
ChangeNotifierProvider.value(
value: Cart(),
),
ChangeNotifierProxyProvider<Auth, Orders>(
create: (_) => Orders([]),
update: (ctx, auth, previousOrders) => Orders(
previousOrders == null ? [] : previousOrders.orders,
auth.token,
auth.userId,
),
),

Cannot get onMessage to show when App is in foreground

I am writing an app where you can press a button and it will send a 'Help' notification to every over app (this will be a closed group of around 100) I need the notifiction to pop up whatever state the app is in, I have the onResume and onLaunch sorted, but I cannot get it to display the notification when the app is in the foreground. There are many screens, I need the notification to show up on whatever screen the user is on.
I have tried many tutorials, but just cannot get it to work. I have the code in my initState on my Main page.
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
var initializationSettingsAndroid =
new AndroidInitializationSettings('#mipmap/ic_launcher');
var initializationSettingsIOS = IOSInitializationSettings();
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
showDialog(
context: context,
builder: (context) =>
AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
showDialog(
context: context,
builder: (context) =>
AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
showDialog(
context: context,
builder: (context) =>
AlertDialog(
content: ListTile(
title: Text(message['notification']['title']),
subtitle: Text(message['notification']['body']),
),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
},
);
Future onSelectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'your channel id', 'your channel name', 'your channel description',
importance: Importance.Max, priority: Priority.High,ticker:'ticker');
var iOSPlatformChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0, 'plain title', 'plain body', platformChannelSpecifics,
payload: 'item x');
}
}
// #override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Benidorm or Bust',
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21),
scaffoldBackgroundColor: Color(0xFF0A0E21),
),
initialRoute: '/',
routes: {
'/': (context) => MyHomePage(),
'/setup': (context) => Setup(),
'/dayinit': (context) => Dayinit(),
'/day1': (context) => Day1(),
'/day2': (context) => Day2(),
'/day3': (context) => Day3(),
'/day4': (context) => Day4(),
'/day5': (context) => Day5(),
'/CheckList': (context) => CheckList(),
'/eveinit': (context) => Eveinit(),
'eve1eve': (context) => Eve1Eve(),
// 'push':(context)=> Push(),
},
);
}
}
I am not getting any error, just nothing happens.
I faced the same issue, just move Firebase related code from "app" MyApp to MyHomePage widget. Inside MyHomePage it will have proper context.
I've used this as an example https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_messaging/example/lib/main.dart#L240

Resources