Flutter: ChangeNotifierProxyProvider: not providing updated correct state - flutter

I am trying to get state from one ChangeNotifier Auth.dart into another ChangeNotifier ProductsProvider.dart. But ChangeNotifierProxyProvider is providing incorrect state data for Auth.
main.dart
void main() => runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Auth>(create: (ctx) => Auth()),
ChangeNotifierProxyProvider<Auth, ProductsProvider>(
create: (context) => ProductsProvider(
Provider.of<Auth>(context, listen: false),
productList: [],
),
update: (ctx, auth, preProducts) {
print("ChangeNotifierProxyProvider Token ${auth.isAuth}");
print("ChangeNotifierProxyProvider Token ${auth.token}");
print("ChangeNotifierProxyProvider Test ${auth.test}");
return ProductsProvider(
auth,
productList:
preProducts == null ? [] : preProducts.getProductList,
);
},
),
ChangeNotifierProvider(create: (ctx) => Cart()),
ChangeNotifierProvider(create: (ctx) => Order()),
ChangeNotifierProvider(create: (ctx) => Auth()),
],
child: MyApp(),
),
);
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<Auth>(
builder: (ctx, auth, _) {
print("Builder Token ${auth.isAuth}");
print("Builder Token ${auth.token}");
print("Builder Test ${auth.test}");
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.orange,
fontFamily: "Lato",
),
routes: {
"/": (ctx) => auth.isAuth ? ProductOverviewScreen() : AuthScreen(),
ProductDetailScreen.PRODUCT_DETAIL_ROUTE: (ctx) =>
ProductDetailScreen(),
CartScreen.CART_SCREEN_ROUTE: (ctx) => CartScreen(),
OrderScreen.ORDER_SCREEN_ROUTE: (ctx) => OrderScreen(),
UserProductScreen.USER_PRODUCT_ROUTE: (ctx) => UserProductScreen(),
EditProductScreen.EDIT_PRODUCT_ROUTE: (ctx) => EditProductScreen(),
},
);
},
// ),
);
}
}
Auth.dart
import 'dart:convert';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'package:shop_app/models/HttpException.dart';
class Auth with ChangeNotifier {
String _token;
String _userId;
DateTime _expiryDate;
String test;
bool get isAuth => token != null;
String get token {
if (_token == null
// && _expiryDate != null &&
// _expiryDate.isAfter(DateTime.now())
) {
return null;
}
return _token;
}
Future<void> _authenticate(String email, String password, String url) async {
final uri = Uri.parse(url);
final response = await http.post(
uri,
body: jsonEncode({
"email": email,
"password": password,
"returnSecureToken": true,
}),
);
Map<String, dynamic> responseData = jsonDecode(response.body);
if (responseData["error"] != null) {
throw HttpException(responseData["error"]["message"]);
}
_token = responseData["idToken"];
_userId = responseData["localId"];
test = "_token";
// _expiryDate = DateTime.now()
// .add(Duration(seconds: int.parse(responseData["expiresIn"])));
notifyListeners();
}
Future<void> signUp(String email, String password) async {
const url =
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[KEY]";
return await _authenticate(email, password, url);
}
Future<void> login(String email, String password) async {
const url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[KEY]";
return await _authenticate(email, password, url);
}
}
ProductsProvider.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:shop_app/models/HttpException.dart';
import 'package:shop_app/models/Product.dart';
import 'package:shop_app/providers/Auth.dart';
class ProductsProvider with ChangeNotifier {
List<Product> _productList = [];
Auth _auth;
ProductsProvider(this._auth, {List<Product> productList = const []})
: _productList = productList;
Future<void> fetchAndSetProducts() async {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products.json?auth=${_auth.token}");
try {
final response = await http.get(uri);
if (response.body != "null") {
final Map<String, dynamic> decodedJSON = jsonDecode(response.body);
final List<Product> loadedProductList = [];
decodedJSON.forEach((prodId, prodData) {
loadedProductList.add(Product(
id: prodId,
title: prodData["title"],
description: prodData["description"],
price: prodData["price"],
imageUrl: prodData["imageUrl"],
isFavourite: prodData["isFavourite"],
));
});
_productList = loadedProductList;
} else {
_productList = [];
}
notifyListeners();
} catch (error) {
throw error;
}
}
List<Product> get getProductList {
return _productList;
}
Product findById(String id) =>
_productList.firstWhere((element) => element.id == id);
Future<void> addProduct(Product product) async {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products.json");
try {
final responseProduct =
await http.post(uri, body: jsonEncode(product.toJSon()));
final finalProduct = Product(
id: jsonDecode(responseProduct.body)["name"],
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl);
_productList.add(finalProduct);
notifyListeners();
return Future.value();
} catch (error) {
throw error;
}
}
Future<void> updateProduct(String id, Product product) async {
var productIndex = _productList.indexWhere((element) => element.id == id);
if (productIndex >= 0) {
var uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products/$id.json");
try {
await http.patch(uri,
body: jsonEncode({
"title": product.title,
"description": product.description,
"price": product.price,
"imageUrl": product.imageUrl,
"isFavourite": product.isFavourite,
}));
_productList[productIndex] = product;
notifyListeners();
} catch (error) {
throw error;
}
}
}
Future<void> deleteProduct(String id) async {
final uri = Uri.parse(
"https://flutter-shop-app-3035a-default-rtdb.europe-west1.firebasedatabase.app/products/$id.json");
final existingProductIndex =
_productList.indexWhere((element) => element.id == id);
var existingProduct = _productList[existingProductIndex];
_productList.removeAt(existingProductIndex);
final response = await http.delete(uri);
if (response.statusCode >= 400) {
_productList.insert(existingProductIndex, existingProduct);
notifyListeners();
throw HttpException("Could not delete product");
}
existingProduct = null;
notifyListeners();
}
}
After I click the login button the login method from the Auth.dart is trigged. After fetching the token the from firebase the screen is updated to ProductOverviewScreen. But the ProductsProvider.dart is not able to fetch the items because the ChangeNotifierProxyProvider update is returning an incorrect state for Auth.
Output:
Builder Token true
Builder Token eyJhbGciOiJSUzI1NiIsImtpZCI6IjNkOWNmYWE4OGVmMDViNDI0YmU2MjA1ZjQ2YjE4OGQ3MzI1N2JjNDIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vZmx1dHRlci1zaG9wLWFwcC0zMDM1YSIsImF1ZCI6ImZsdXR0ZXItc2hvcC1hcHAtMzAzNWEiLCJhdXRoX3RpbWUiOjE2MjE3NzUxMDYsInVzZXJfaWQiOiJ5Y0dVVWhwYTFvY2EwMThlYUx4VGZkQnRNbmsyIiwic3ViIjoieWNHVVVocGExb2NhMDE4ZWFMeFRmZEJ0TW5rMiIsImlhdCI6MTYyMTc3NTEwNiwiZXhwIjoxNjIxNzc4NzA2LCJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsidGVzdEB0ZXN0LmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.t1xosbzllt79NV6FQ79mTQ2J3VCR5fILKMxE5-ObOxMI2DtD_kMg2AP9NXm_f1IsLF9AT5xeXeVU36goVDLQuKSWmbejOANDn7hsF6VzZMyBV1P9qehXpWgSmCscjXT8FRlKViZzxOZwCWSHS1M94n92YYhwaZltiDcQ87hhv7ZdKyLrlDsUPfr7IjNBeSVDmzws_9uBoZwYKRYCW1veWPc7HPWtdP8QT7K_vkCEvGLHfxbmVHOgUkDMzLqhgusZl34GCPVKr_PSpQ9SgC7Mg95QeZyzYzPmhasGUptq5pQsjEoqTxgYHnmEuMRRjksZT5lbfsQQFOJMsXBTIC7RDQ
Builder Test _token
ChangeNotifierProxyProvider Token false
ChangeNotifierProxyProvider Token null
ChangeNotifierProxyProvider Test null
Error: Expected a value of type 'int', but got one of type 'String'
at Object.throw_ [as throw] (http://localhost:1344/dart_sdk.js:5333:11)
at ProductProvider.ProductsProvider.new.fetchAndSetProducts (http://localhost:1344/packages/shop_app/providers/ProductProvider.dart.lib.js:84:21)
at fetchAndSetProducts.next (<anonymous>)
at http://localhost:1344/dart_sdk.js:39031:33
at _RootZone.runUnary (http://localhost:1344/dart_sdk.js:38888:58)
at _FutureListener.thenAwait.handleValue (http://localhost:1344/dart_sdk.js:33874:29)
at handleValueCallback (http://localhost:1344/dart_sdk.js:34434:49)
at Function._propagateToListeners (http://localhost:1344/dart_sdk.js:34472:17)
at _Future.new.[_completeWithValue] (http://localhost:1344/dart_sdk.js:34314:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:1344/dart_sdk.js:34337:35)
at Object._microtaskLoop (http://localhost:1344/dart_sdk.js:39175:13)
at _startMicrotaskLoop (http://localhost:1344/dart_sdk.js:39181:13)
at http://localhost:1344/dart_sdk.js:34688:9
I am learning dart and flutter. I am not sure what I am missing. Can someone could help me fix this issue.

I was able to find what was causing this issue.
It appears I was reinitializing the Auth ChangeNotifierProvider. If you see the last line in the MultiProvider constructor providers argument.
If anyone else comes across such an issue ensure that you have specified the providers in the correct order.

Product Id defined int/Integer, but the parser from firebase is String. You need change in Product Id to String or use int.parse(prodId)

Related

Flutter GoRouter with Firebase Auth

This bounty has ended. Answers to this question are eligible for a +100 reputation bounty. Bounty grace period ends in 21 hours.
Chris wants to draw more attention to this question.
I am using the go_router and Firebase Auth for my web application but can not properly set it up. I tried this:
class AuthService {
static final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
static User? get currentUser => FirebaseAuth.instance.currentUser;
static bool isLoggedIn() {
return _firebaseAuth.currentUser != null;
}
...
With my router:
redirect: (context, state) {
final String destination = state.location;
final bool isOnStartView = destination == '/start';
final bool isOnEmailFlow = state.subloc.contains('/email');
if (!isOnStartView && !isOnEmailFlow && !AuthService.isLoggedIn()) {
return '/start';
}
return null;
},
However this is not working properly as isLoggedIn is always return false even if there a is a user logged in. I searched for this topic and found that I probably use some sort of Stream or Notifier with onAuthStateChange but I didn't find anything on how to implement a proper FirebaseAuthentication Flow in combination with GoRouter.
How would I do that?
Let me know if you need any more info.
You can use riverpod or provider to listen changes
here is code sample
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:testproject/Home%20Screen/home_screen.dart';
import 'package:testproject/Model/user_model.dart';
import 'package:testproject/Providers/UserProvider/user_data_provider.dart';
import 'package:testproject/Screens/login_screen.dart';
import 'package:testproject/Screens/sign_up.dart';
import 'package:testproject/Service/auth_service.dart';
import '../Providers/Satates/user_states.dart';
import '../Providers/UserProvider/user_state_provider.dart';
class MyRoutes extends ChangeNotifier {
final Ref ref;
MyRoutes(this.ref) {
ref.listen<LoginState>(
userStateprovider, (previous, next) => notifyListeners());
}
List<GoRoute> get _routes => [
GoRoute(
name: "Login",
path: "/login",
builder: (context, state) => SigninPage(),
),
GoRoute(
name: "Home",
path: "/home",
builder: (context, state) => const HomeScreen(),
),
GoRoute(
name: "Signup",
path: "/signup",
builder: (context, state) => const SignUpScreen(),
),
];
String? _redirectLogic(GoRouterState state) {
final loginState = ref.read(userStateprovider);
final user = ref.read(userProvider.state);
if (loginState is LoginStateInitial && auth.currentUser != null) {
log("message");
Future.delayed(const Duration(seconds: 0), () {
user.state = UserModel(
email: auth.currentUser!.email!, userid: auth.currentUser!.uid);
ref.read(userStateprovider.notifier).newstate = LoginStateSuccess(
UserModel(
email: auth.currentUser!.email!,
userid: auth.currentUser!.uid));
});
}
log(state.location);
log(auth.currentUser.toString());
final areWeLoggingIn = state.location == '/home';
log(areWeLoggingIn.toString());
if (areWeLoggingIn) {
return loginState is LoginStateSuccess ? null : "/login";
}
return null;
}
}
final routeProvider = Provider<GoRouter>((ref) {
final routeRef = MyRoutes(ref);
return GoRouter(
urlPathStrategy: UrlPathStrategy.path,
initialLocation: "/login",
refreshListenable: routeRef,
redirect: routeRef._redirectLogic,
routes: routeRef._routes);
});
You can do this
class AuthService {
static final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
static User? get currentUser => FirebaseAuth.instance.currentUser;
static bool? _isLoggedIn = null;
static bool isLoggedIn() {
if(_isLoggedIn == null) {
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
_isLoggedIn = user?.uid != null;
});
_isLoggedIn = _firebaseAuth.currentUser?.uid != null;
return _isLoggedIn ?? false;
}
else {
return _isLoggedIn ?? false;
}
...

Repository testing with mocktail and flutter test - I'm trying to write a test for my repository but I keep getting an error 'No such mrthod'

error message Repository testing with mocktail and flutter test - I'm trying to write a test for my repository but I keep getting an error 'No such method'
I've tried with ThenAnswer as well but it still won't go through. I'll appreciate any help :)
That's what my code looks like :
Test file:
`import 'package:curlzzz_new/data_source/remote_watch_data_source.dart';
import 'package:curlzzz_new/models/watch_model.dart';
import 'package:curlzzz_new/repositories/watch_repository.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
class MockWatchDataSource extends Mock implements RemoteWatchDataSource {}
void main() {
//sut to System under testing
late WatchRepository sut;
late MockWatchDataSource dataSource;
setUp(() {
dataSource = MockWatchDataSource();
sut = WatchRepository(dataSource);
});
group('getWatchStream', () {
test('should return a stream of WatchModels', () {
//1
when(() => dataSource.getRemoteWatchStream()).thenThrow(
(_) => Stream.value([
WatchModel(title: 'titanic', id: '555'),
WatchModel(title: 'top gun', id: '555'),
WatchModel(title: 'matrix', id: '111')
]),
);
//2
final results = sut.getWatchStream();
//3
expect(results, [
WatchModel(title: 'titanic', id: '555'),
WatchModel(title: 'top gun', id: '555'),
WatchModel(title: 'matrix', id: '111')
]);
});
});
}
`
Repository:
import 'package:curlzzz_new/data_source/remote_watch_data_source.dart';
import 'package:curlzzz_new/models/watch_model.dart';
class WatchRepository {
WatchRepository(this.remoteDataSource);
final RemoteWatchDataSource remoteDataSource;
Stream<List<WatchModel>> getWatchStream() {
return remoteDataSource.getRemoteWatchStream().map((querySnapshot) {
return querySnapshot.docs.map((doc) {
return WatchModel(title: doc['title'], id: doc.id);
}).toList();
});
}
Future<void> addMovies({
required String title,
}) {
return remoteDataSource.addRemoteWatchData(title: title);
}
Future<void> dismiss({required String id}) {
return remoteDataSource.dismissRemoteData(id: id);
}
}
Data Source:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class RemoteWatchDataSource {
Stream<QuerySnapshot<Map<String, dynamic>>> getRemoteWatchStream() {
final userID = FirebaseAuth.instance.currentUser?.uid;
if (userID == null) {
throw Exception('User is not logged in');
}
return FirebaseFirestore.instance
.collection('users')
.doc(userID)
.collection('movies')
.snapshots();
}
Future<DocumentReference<Map<String, dynamic>>?> addRemoteWatchData({
required String title,
}) async {
final userID = FirebaseAuth.instance.currentUser?.uid;
if (userID == null) {
throw Exception('User is not logged in');
}
return FirebaseFirestore.instance
.collection('users')
.doc(userID)
.collection('movies')
.add(
{'title': title},
);
}
Future<void> dismissRemoteData({required String id}) async {
final userID = FirebaseAuth.instance.currentUser?.uid;
if (userID == null) {
throw Exception('User is not logged in');
}
return FirebaseFirestore.instance
.collection('users')
.doc(userID)
.collection(
'movies',
)
.doc(id)
.delete();
}
}
It seems like a a problem with the closure type.
try this. don't combine 2 functions in a single test.
group('getWatchStream', () {
test('should return a stream of WatchModels', () async {
final List<WatchModel> models = [
WatchModel(title: 'titanic', id: '555'),
WatchModel(title: 'top gun', id: '555'),
WatchModel(title: 'matrix', id: '111')
];
//1
when(() => dataSource.getRemoteWatchStream()).thenAnswer(
(_) => Stream.value(models),
);
//2
await dataSource.getRemoteWatchStream();
//3
expect(dataSource.getRemoteWatchStream, emits(models) );
});
});

type 'Null' is not a subtype of type 'Future<bool>'

I'm getting the below error while I'm trying to implement bloc testing in my flutter project
type 'Null' is not a subtype of type 'Future<bool>'
package:mynovatium/features/signup/repositories/signup_repository.dart 10:16 MockRepository.createAccountsignup
Following are the corresponding files that might help identify the cause of the error
signup_bloc_test.dart
class MockRepository extends Mock implements SignUpRepository {}
void main() async {
await configureInjection(inj.Environment.test);
group('SignupBloc', () {
late SignUpBloc signUpBloc;
late SignUpRepository signupRepositoryMock;
setUp(() {
signupRepositoryMock = MockRepository();
signUpBloc = SignUpBloc(signUpRepository: signupRepositoryMock);
});
test('initial state of the bloc is [AuthenticationInitial]', () {
expect(SignUpBloc(signUpRepository: signupRepositoryMock).state,
SignupInitial(),);
});
group('SignUpCreateAccount', () {
blocTest<SignUpBloc, SignUpState>(
'emits [SignUpCreateAccountLoading, SignupInitial] '
'state when successfully Signed up',
setUp: () {
when(signupRepositoryMock.createAccount(
'Nevil',
'abcd',
'nikunj#gmail.com',
'english',
),).thenAnswer((_) async => Future<bool>.value(true));
},
build: () => SignUpBloc(signUpRepository: signupRepositoryMock),
act: (SignUpBloc bloc) => bloc.add(
const SignUpCreateAccount(
'Nevil',
'abcd',
'nikunj#gmail.com',
'english',
),
),
expect: () => [
SignUpCreateAccountLoading(),
SignupInitial(),
],
);
});
});
}
signup_repository.dart
This is the code for the signup repository.
class SignUpRepository {
Future<bool> createAccount(String _firstName, String _lastName, String _eMailAddress, String _language) async {
final Response _response;
try {
_response = await CEApiRequest().post(
Endpoints.createCustomerAPI,
jsonData: <String, dynamic>{
'firstName': _firstName,
'lastName': _lastName,
'email': _eMailAddress,
'language': _language,
'responseUrl': Endpoints.flutterAddress,
},
);
final Map<String, dynamic> _customerMap = jsonDecode(_response.body);
final CustomerModel _clients = CustomerModel.fromJson(_customerMap['data']);
if (_clients.id != null) {
return true;
} else {
return false;
}
} on KBMException catch (e) {
final KBMException _exception = e;
throw _exception;
}
}
}
If anyone has any ideas on what might be the issue here, please help!!
Okay so in the above code you need to stub the methods within the mock repository as well and override it to have it return something incase null is being returned.
class MockRepository extends Mock implements SignUpRepository {
#override
Future<bool> createAccount(String? _firstName, String? _lastName, String? _eMailAddress, String? _language) =>
super.noSuchMethod(Invocation.method(#createAccount, [_firstName, _lastName, _eMailAddress, _language]),
returnValue: Future<bool>.value(false),);
}
Doing something like that done in the above code works well.

How to use Sessions with Flutter and Nestjs?

I'm trying to keep users logged in with nestjs backend, when I use Postman the process works very smoothly, but with Flutter I don't know how to do it. I don't think that I actually understand how sessions work for mobiles, I tried looking for some proper explaining but I couldn't find anything so far.
Nestjs Code
#Controller('users')
#Serialize(UserDto)
export class UsersController {
constructor(
private usersService: UsersService,
private authService: AuthService,
) {}
#Get('/whoami')
#UseGuards(AuthGuard)
whoAmI(#currentUser() user: User) {
return user;
}
#Get()
getUsers(#Query('email') email: string) {
return this.usersService.find(email);
}
#Post('/signup')
async sendUser(#Body() body: UserDto, #Session() session: any) {
console.log(body);
const user = await this.authService.signup(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
#Post('/signin')
async signin(#Body() body: UserDto, #Session() session: any) {
const user = await this.authService.signin(body.email, body.password);
session.userId = user.id;
console.log(session.userId);
return user;
}
#Post('/signout')
async signout(#Session() session: any) {
console.log(session.userId);
if (!session.userId) {
throw new NotFoundException('user not found');
}
session.userId = null;
}
}
Flutter Code
Future<void> signin(
String username, String password, BuildContext context) async {
try {
var url = 'https://example-app.herokuapp.com/users/signin';
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password}, options: Options(headers: {'Accept': 'application/json'}));
print(response.headers);
// response;
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout() async {
try {
var url = 'https://example-app.herokuapp.com/users/signout';
var dio = Dio();
var response = await dio.post(url,
options: Options(headers: {
'cookie':
'key'
}
)
);
print(response.headers);
response;
// return response;
} catch (err) {
print(err);
throw err;
}
}
Thanks to #RichardHeap 's comment I managed to solve my issue.
Check out session management with cookies:
Flutter http Maintain PHP session
I used FlutterSecureStorage package to store the incoming cookie and then decide which screen to show as a home screen using FutureBuilder as seen below:
I used these functions to write cookies and delete them from the device:
Future<void> signin(
String username, String password, BuildContext context) async {
try {
// String cookie = '';
var url = 'https://daleel-app.herokuapp.com/users/signin';
var storage = FlutterSecureStorage();
var dio = Dio();
var response =
await dio.post(url, data: {'email': username, 'password': password});
List<String>? cookies = response.headers['set-cookie'];
for (int i = 0; i <= cookies!.length - 1; i++) {
var cokIndex = cookies[i].indexOf(';');
var subCookies = cookies[i].substring(0, cokIndex + 1);
cookie += subCookies + ' ';
}
var subbedCookie = cookie.substring(0, cookie.length - 2);
print(subbedCookie);
storage.write(key: 'cookie', value: subbedCookie);
loggedIn = true;
// print(response.headers['set-cookie']);
// [express:sess=eyJ1c2VySWQiOjU1fQ==; path=/; httponly, express:sess.sig=Zy_Lc7kXM1BqZKIZRRt7ygpCTrM; path=/; httponly]
Navigator.of(context).pushNamed(CategoryDetailScreen.routeName);
} catch (err) {
print(err);
throw err;
}
}
Future<void> signout(BuildContext context) async {
try {
var url = 'https://daleel-app.herokuapp.com/users/signout';
var dio = Dio();
var fStorage = FlutterSecureStorage();
var header = await fStorage.read(key: 'cookie');
await dio.post(url, options: Options(headers: {'cookie': header}));
fStorage.delete(key: 'cookie');
Navigator.of(context).pushReplacementNamed(LoginScreen.routeName);
print('you reached here');
} catch (err) {
print(err);
throw err;
}
}
And here I used the FutureBuilder to decide which screen to show:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var cookie = FlutterSecureStorage().read(key: 'cookie');
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => Places(),
),
ChangeNotifierProvider(
create: (ctx) => Offers(),
),
],
child: FutureBuilder(
future: cookie,
builder: (BuildContext context, AsyncSnapshot snapshot) => MaterialApp(
debugShowCheckedModeBanner: true,
title: 'Daleel',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: snapshot.hasData ? HomeScreen() : LoginScreen(),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
TestScreen3.routeName: (ctx) => TestScreen3(),
TestScreen2.routeName: (ctx) => TestScreen2(),
HomeScreen.routeName: (ctx) => HomeScreen(),
DetailsScreen.routeName: (ctx) => DetailsScreen(),
ExploreScreen.routeName: (ctx) => ExploreScreen(),
CategoryDetailScreen.routeName: (ctx) => CategoryDetailScreen(),
SearchDetailsScreen.routeName: (ctx) => SearchDetailsScreen(),
}),
),
);
}
}

Could not find the correct Provider<AuthProvider> above this SignUpIdols Widget

I know there is many answer on flutter provider but I cannot find my answer after hours of debugging please help me
I have a widget which is SignUpIdols
Widget signupidolsUI(BuildContext context) {
final auth = Provider.of<AuthProvider>(context);
This is the issues final auth = Provider.of(context);
My AuthProvider Class
class AuthProvider with ChangeNotifier {
Status _loggedInStatus = Status.NotLoggedIn;
Status _registeredInStatus = Status.NotRegistered;
Status get loggedInStatus => _loggedInStatus;
Status get registeredInStatus => _registeredInStatus;
Future<Map<String, dynamic>> register(
String name, String email, String password) async {
_registeredInStatus = Status.Registering;
CollectionReference users = FirebaseFirestore.instance.collection('users');
var result;
users
.add({'name': name, 'email': email, 'password': password})
.then((value) => () {
result = {
'status': true,
'message': 'Successful',
'user': 'Register Successful'
};
_registeredInStatus = Status.Registered;
})
.catchError((error) => () {
result = {'status': true, 'message': 'Error', 'user': '$error'};
});
return result;
}
}
Error I face
Thanks.
I fix it after I inject multiprovider on my main app its works
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<AuthProvider>(create: (BuildContext context) {
return AuthProvider();
}),
],
child: MaterialApp(