In constructor of the following bloc, I subscribe to a stream of firebase auth changes. go_router handles redirection.
When a user signs in/out _onAppUserChanged is called. If successfully signed in, I await for user's firestore data to be fetched. If there is, among the data, a location entry, I need to emit AppState with status==AppStatus.hasLocation if and only if my CatalogBlog has emitted state with status==CatalogStatus.loaded. Neither await for (var catalogState in _catalogBloc.stream) nor adding a listener will work. AppState with status: AppStatus.hasLocation won't be emmited although CatalogBloc will definatelly emit with status==CatalogStatus.loaded at some point.
class AppBloc extends Bloc<AppEvent, AppState> {
final UserRepository _userRepository;
final AuthRepository _authRepository;
final CatalogBloc _catalogBloc;
AppBloc(
UserRepository userRepository,
AuthRepository authRepository,
PrefsRepository prefsRepository,
CatalogBloc catalogBloc,
) : _userRepository = userRepository,
_authRepository = authRepository,
_catalogBloc = catalogBloc,
super(const AppState()) {
on<AppUserChanged>(_onAppUserChanged);
on<AppSignOutRequested>(_onAppSignOutRequested);
on<AppSelectedLocationSet>(_onAppSelectedLocationSet);
_authRepository.getAuthStateChanges().listen((String uid) {
add(AppUserChanged(uid));
});
}
void _onAppUserChanged(AppUserChanged event, Emitter<AppState> emit) async {
if (event.uid.isEmpty) {
emit(const AppState(status: AppStatus.noUser));
} else {
await for (var user in _userRepository.getUserData(event.uid)) {
if (_catalogBloc.state.status == CatalogStatus.initial) {
_catalogBloc.add(CatalogStarted());
}
if (user.locations.isEmpty) {
// Go to '/location_search'
emit(AppState(status: AppStatus.noLocation, user: user));
} else {
// Wait for catalog data to be fetched, then go to '/catalog'
await for (var catalogState in _catalogBloc.stream) {
if (catalogState.status == CatalogStatus.loaded) {
emit(AppState(
status: AppStatus.hasLocation,
user: user,
selectedLocation: user.prefLocation,
));
}
}
}
}
}
}
}
App State:
enum AppStatus { initial, hasLocation, noLocation, noUser, error }
class AppState extends Equatable {
final AppStatus status;
final User user;
final Location? selectedLocation;
const AppState({
this.status = AppStatus.initial,
this.user = const User(),
this.selectedLocation = const Location(),
});
#override
List<Object?> get props => [status, user, selectedLocation];
AppState copyWith({
AppStatus? status,
User? user,
Location? selectedLocation,
}) {
return AppState(
status: status ?? this.status,
user: user ?? this.user,
selectedLocation: selectedLocation ?? this.selectedLocation);
}
}
AppEvents:
abstract class AppEvent extends Equatable {
const AppEvent();
#override
List<Object> get props => [];
}
class AppUserChanged extends AppEvent {
final String uid;
const AppUserChanged(this.uid);
#override
List<Object> get props => [uid];
}
User repo:
class UserRepository {
final FirebaseFirestore _db = FirebaseFirestore.instance;
late User? user;
Stream<User> getUserData(String uid) {
var documentStream = _db.collection('users').doc(uid).snapshots();
return documentStream.map((snapshot) {
var data = snapshot.data();
if (data != null) {
user = User.fromJson(data);
return user!;
}
throw Exception("Firestore entry was not created for the signed in user");
});
}
...
}
Related
Here is my attempt
In my Controller I have this
class UserController extends GetxController {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
var _proo;
get prooo => _proo;
Future<Member?> readProfile() async {
_proo = FireStoreHelper().fFetch("users", "user1");
}
}
In my FireStoreHelper I have this
class FireStoreHelper {
fFetch(collection, doc) {
final docMember =
FirebaseFirestore.instance.collection(collection).doc(doc);
var query = docMember.get();
return query;
}
This is my Model
class Member {
final String? username;
//...others
Member({
this.username,
//...others
});
static Member fromJson(Map<String, dynamic> json) => Member(
username: json['username'],
//...others
);
}
Then in my UI I have this
Get.lazyPut(() => UserController().readProfile());
return GetBuilder<UserController>(builder: (userController) {
//.......
Text(userController.prooo.username),
}
Actually what am trying get a username of user1 as seen in the Image below
Please help me, I am new to this.
try this one...
fFetch(collection, doc) async {
final docMember = await
FirebaseFirestore.instance.collection(collection).doc(doc).get();
return docMember;
}
static Future<Member?> readProfile() async {
_proo = await FireStoreHelper().fFetch("users", "user1");
Member member = Member.fromJson(_proo);
return member;
}
So right now I'm building a shopping cart using GetX and firebase. I'm trying to write the data to firebase if the user taps add to cart but not allow duplicate entries just increase the quantity #. Right now I'm getting duplicate entries.
class CartController extends GetxController {
static CartController instance = Get.find();
//cart controller for the shopping cart
Rx<double> totalCartPrice = 0.0.obs;
RxList<CartItemModel> products = RxList<CartItemModel>([]);
#override
void onReady() {
super.onReady();
ever(logController.userModel, editTotalPrice);
}
void addToCart(ProductModel product) {
try {
if (_isItemAlreadyAdded(product)) {
Get.snackbar("Check your cart", "${product.name} is already added");
} else {
String itemID = Uuid().v1();
logController.updateUserData({
"cart": FieldValue.arrayUnion([
{
"id": itemID,
"productId": product.id,
// "name": product.name,
"quantity": 1,
"price": product.price,
"image": product.image,
"cost": product.price,
}
])
});
Get.snackbar("Item added", "${product.name} was added to your cart");
}
} catch (e) {
Get.snackbar("Whoops...Cannot add this right now!",
"There was an error adding to cart",
duration: Duration(seconds: 3), backgroundColor: Colors.pinkAccent);
debugPrint(e.toString());
}
}
void deductCartItem(CartItemModel cartItem) {
try {
logController.updateUserData({
"cart": FieldValue.arrayRemove([cartItem.toJson()])
});
} catch (e) {
Get.snackbar("Error", "Cannot remove this item");
debugPrint(e.toString());
}
}
editTotalPrice(LoginUserModel usrModel) {
if (usrModel.cart!.isEmpty) {
print("Cart empty!");
} else if (usrModel.cart!.isNotEmpty) {
totalCartPrice.value = 50;
print("hi");
usrModel.cart!.forEach((cartItem) {
totalCartPrice.value += cartItem.cost!;
});
}
}
bool _isItemAlreadyAdded(ProductModel product) =>
logController.userModel.value.cart!
.where((item) => item.name == product.name)
.isNotEmpty;
void decreaseQuantity(CartItemModel item) {
if (item.quantity == 1) {
deductCartItem(item);
} else {
deductCartItem(item);
item.quantity! - 1;
logController.updateUserData({
"cart": FieldValue.arrayUnion([item.toJson()])
});
}
}
void increaseQuantity(CartItemModel item) {
deductCartItem(item);
item.quantity! + 1;
logger.i({"quantity": item.quantity});
logController.updateUserData({
"cart": FieldValue.arrayUnion([item.toJson()])
});
}
}
and here is my class:
class CartItemModel {
CartItemModel(
{this.productId,
this.id,
this.image,
this.name,
this.quantity,
required this.price,
this.cost});
CartItemModel.fromMap(Map<String, dynamic> data) {
id = data[ID];
image = data[IMAGE];
name = data[NAME];
quantity = data[QUANTITY];
cost = data[COST].toDouble();
productId = data[PRODUCT_ID];
price = data[PRICE];
}
static const COST = "cost";
static const ID = "id";
static const IMAGE = "image";
static const NAME = "name";
static const PRICE = "price";
static const PRODUCT_ID = "productId";
static const QUANTITY = "quantity";
double? cost;
String? id;
String? image;
String? name;
double? price;
String? productId;
int? quantity;
Map toJson() => {
ID: id,
PRODUCT_ID: productId,
IMAGE: image,
NAME: name,
QUANTITY: quantity,
COST: price! * quantity!,
PRICE: price
};
}
and because this is tied into the login session here is my login class:
class LoginUserModel {
String? displayName;
String? email;
String? photoUrl;
String? uid;
List<CartItemModel>? cart;
LoginUserModel(
{this.displayName, this.email, this.photoUrl, this.uid, this.cart});
LoginUserModel.fromSnapshot(DocumentSnapshot<Map<String, dynamic>> snapshot) {
displayName = snapshot.data()!["DISPLAYNAME"];
photoUrl = snapshot.data()!["PHOTOURL"];
email = snapshot.data()!["EMAIL"];
uid = snapshot.data()!["UID"];
cart = _convertCartItems(snapshot.data()!["CART"] ?? []);
}
List<CartItemModel> _convertCartItems(List cartFomDb) {
List<CartItemModel> _result = [];
if (cartFomDb.length > 0) {
cartFomDb.forEach((element) {
_result.add(CartItemModel.fromMap(element));
});
}
return _result;
}
List cartItemsToJson() => cart!.map((item) => item.toJson()).toList();
}
And my login controller:
class LoginController extends GetxController {
static LoginController instance = Get.find();
Rxn<User> fbUser = Rxn<User>();
final googleSignIn = GoogleSignIn();
RxBool isLoggedIn = false.obs;
Rx<LoginUserModel> userModel = LoginUserModel().obs;
String usersCollection = "users";
// Rx<UserModel> usrModel = UserModel().obs;
GoogleSignInAccount? _googleAcc;
LoginUserModel? _userModel;
#override
void onReady() {
super.onReady();
fbUser = Rxn<User>(auth.currentUser);
fbUser.bindStream(auth.userChanges());
ever(fbUser, setInitialScreen);
}
LoginUserModel? get loggedInUserModel => _userModel;
setInitialScreen(User? user) {
if (user == null) {
print("going to login page...");
Get.offAll(() => LoginPage());
} else {
print("The user is ${user.displayName}");
userModel.bindStream(listenToUser());
Get.offAll(() => AppSetup());
}
}
void googleLogin() async {
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_googleAcc = googleUser;
final googleAuth = await googleUser.authentication;
final cred = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
await auth.signInWithCredential(cred).then((res) async {
print('Signed in successfully as ' + res.user!.displayName.toString());
print('email: ' + res.user!.email.toString());
LoginUserModel _newUser = LoginUserModel(
uid: res.user!.uid,
email: res.user!.email!,
displayName: res.user!.displayName,
photoUrl: res.user!.photoURL,
cart: [],
);
_addUserToFB(_newUser, res.user!);
});
} catch (e) {
debugPrint(e.toString());
Get.snackbar("Sign In Failed", "Try again");
}
}
// void signUp() async {
// try {
// await auth
// .createUserWithEmailAndPassword(
// email: email.text.trim(), password: password.text.trim())
// .then((result) {
// String _userId = result.user.uid;
// _addUserToFirestore(_userId);
// _clearControllers();
// });
// } catch (e) {
// debugPrint(e.toString());
// Get.snackbar("Sign In Failed", "Try again");
// }
// }
void signOut() async {
googleSignIn.signOut();
auth.signOut();
}
//maybe add clear controllers method?
updateUserData(Map<String, dynamic> data) {
logger.i("UPDATED");
firebaseFirestore
.collection(usersCollection)
.doc(fbUser.value?.uid)
.update(data);
}
Stream<LoginUserModel> listenToUser() => firebaseFirestore
.collection(usersCollection)
.doc(fbUser.value!.uid)
.snapshots()
.map((snapshot) => LoginUserModel.fromSnapshot(snapshot));
_addUserToFB(LoginUserModel usr, User firebaseUser) {
firebaseFirestore.collection(usersCollection).doc(usr.uid).set({
"displayName": usr.displayName,
"id": usr.uid,
"photoURL": usr.photoUrl,
"email": usr.email,
"cart": usr.cart
});
}
}
My firebase database is pictured below. The cart is in a subcategory (array) as I have it tied to the user who is logged in:
It looks like the issue is in your arrayUnion call because you are adding a new entry to the shopping cart array. There is perhaps an expectation that the method will find and update the provided object in the array.
What you would need to do is to find and replace/update the cart item in your local user object array and make a document update back to Firestore.
But instead of doing that, I'd like to suggest something you could consider: you might want to consider making the shopping cart a subcollection instead.
For two reasons
You have an unbound growing data-set (shopping cart items). That is making a good candidate for being a collection of its own.
You want to be able to update field values in individual documents (shopping cart items) without causing too much other "noise" in your app. When you store the shopping cart in your user object and update items in the array, you are also causing any listener that is subscribing to your user object to trigger a new read from the database.
Implementing your shopping cart as a sub collection allows for you to do this instead
Future<void> increaseQuantity(CartItemModel item) {
return FirebaseFirestore.instance
.collection("users")
.doc(userId)
.collection("cart")
.doc(item.id)
.update({"quantity": FieldValue.increment(1)});
}
You would do the same for decreaseQuantity and update quantity with FieldValue.increment(-1) instead.
Model class:
#JsonSerializable()
class EmpVerifyEntity extends Equatable {
#JsonKey(name: "access_token")
final String accessToken;
final EmpVerifyEmployee employee;
const EmpVerifyEntity(this.accessToken, this.employee);
factory EmpVerifyEntity.fromJson(Map<String, dynamic> json) =>
_$EmpVerifyEntityFromJson(json);
Map<String, dynamic> toJson() => _$EmpVerifyEntityToJson(this);
static const empty = EmpVerifyEntity(
'123',
EmpVerifyEmployee(
'1', 'avatar', 'sId', 'empName', 'empId', 'designation', 1));
#override
String toString() {
return jsonEncode(this);
}
#override
// TODO: implement props
List<Object?> get props => [accessToken, employee];
}
#JsonSerializable()
class EmpVerifyEmployee extends Equatable {
#JsonKey(name: "password")
final String password;
final String avatar;
#JsonKey(name: "_id")
final String sId;
#JsonKey(name: "emp_name")
final String empName;
#JsonKey(name: "emp_id")
final String empId;
final String designation;
#JsonKey(name: "__v")
final int iV;
const EmpVerifyEmployee(this.password, this.avatar, this.sId, this.empName,
this.empId, this.designation, this.iV);
factory EmpVerifyEmployee.fromJson(Map<String, dynamic> json) =>
_$EmpVerifyEmployeeFromJson(json);
Map<String, dynamic> toJson() => _$EmpVerifyEmployeeToJson(this);
static const empty = const EmpVerifyEmployee(
'password', 'avatar', 'sId', 'empName', 'empId', 'designation', 1);
#override
String toString() {
return jsonEncode(this);
}
#override
// TODO: implement props
List<Object?> get props =>
[password, avatar, sId, empName, empId, designation, iV];
}
auth repo:
class AuthenticationRepository {
Future<void> logIn({ //login process
required String username,
required String password,
}) async {
print("------------------");
print(username);
var res = await http.post(
Uri.parse("https://cots.com/api/v1/employee/login"),
headers: {
'Content-type': 'application/json',
'Accept': 'application/json'
},
body: jsonEncode({"emp_id": username, "password": password}));
dynamic data = json.decode(res.body);
print(data);
if (data['employee']["is_active"] == true) {
_controller.add(AuthenticationStatus.authenticated);///here it shows authenticated
}
}
User Repo:
class UserRepository {
EmpVerifyEntity? _empVerifyEntity;
UserRepository(this._empVerifyEntity);
Future<EmpVerifyEntity?> getUser() async {
if (_empVerifyEntity != null) {
return _empVerifyEntity;
}
}
}
Auth Bloc:
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
AuthenticationBloc({
required AuthenticationRepository authenticationRepository,
required UserRepository userRepository,
}) : _authenticationRepository = authenticationRepository,
_userRepository = userRepository,
super(const AuthenticationState.unknown()) {
on<AuthenticationStatusChanged>(_onAuthenticationStatusChanged);
on<AuthenticationLogoutRequested>(_onAuthenticationLogoutRequested);
_authenticationStatusSubscription = _authenticationRepository.status.listen(
(status) => add(AuthenticationStatusChanged(status)),
);
}
final AuthenticationRepository _authenticationRepository;
final UserRepository _userRepository;
late StreamSubscription<AuthenticationStatus>
_authenticationStatusSubscription;
#override
Future<void> close() {
_authenticationStatusSubscription.cancel();
_authenticationRepository.dispose();
return super.close();
}
void _onAuthenticationStatusChanged(
AuthenticationStatusChanged event,
Emitter<AuthenticationState> emit,
) async {
switch (event.status) {
case AuthenticationStatus.unauthenticated:
return emit(const AuthenticationState.unauthenticated());
case AuthenticationStatus.authenticated:
final user = await _tryGetUser();
return emit(user != null
? AuthenticationState.authenticated(user)
: AuthenticationState.unauthenticated());
default:
return emit(const AuthenticationState.unknown());
}
}
void _onAuthenticationLogoutRequested(
AuthenticationLogoutRequested event,
Emitter<AuthenticationState> emit,
) {
_authenticationRepository.logOut();
}
Future<EmpVerifyEntity?> _tryGetUser() async {
try {
final user = await _userRepository.getUser();
return user; /////----------------Here I'm getting null as a user
} catch (e) {
print(e);
}
}
}
I can able to do login but can't able to fetch data because it shows null, In login method I should return data so that I can able to fetch. It is authenticated but user data is null, how to pass the return data to userRepo so that I can fetch in authBloc.
-------------------------------------THank you--------------------------
New to testing blocs in flutter. I can't get this simple test to work:
Here is the bloc class:
#injectable
class MyBloc extends Bloc<MyEvent, MyState> {
final MyUseCase _myUseCase;
MyBloc(this._myUseCase): super(const MyState()) {
on<LoadingEvent>(_onLoadingEvent);
}
FutureOr<void> _onLoadingEvent(
LoadingEvent event, Emitter<MyState> emit) async {
String email = await _myUseCase.fetchEmailAddress();
emit(state.copyWith(email: email, status: MyStatus.initial));
}
}
And the state class:
class MyState extends Equatable {
const MyState(
{this.email = "",
this.status = MyStatus.initial,
});
final String email;
final MyStatus status;
MyState copyWith(
{String? email,
MyStatus? status
}) {
return MyState(
email: email ?? this.email,
status: status ?? this.status,
);
}
}
And this is the test that is failing:
#GenerateMocks([MyUseCase])
void main() {
late MockMyUseCase mockMyUseCase;
late MyBloc bloc;
setUp(() {
mockMyCase = MockMyUseCase();
bloc = MyBloc(mockMyUseCase);
});
test('initial state', () async {
when(mockMyUseCase.fetchEmailAddress()).thenAnswer((_) async => "email");
bloc.add(const LoadingEvent());
await expectLater(
bloc.state,
emitsInOrder([
const MyState(email: "email", status: MyStatus.initial)
]));
});
}
What I am really trying to test for is the status that comes back. But here is the error:
Expected: should emit an event that MyState:<MyState(email, MyStatus.initial)>
Actual: MyState:<MyState(, MyStatus.initial)>
Which: was not a Stream or a StreamQueue
I'm really close, but I can't figure out what this error message is telling me.
I am trying to make a post request in flutter using chopper. I have made an ApiService.dart file as
a generator file.
import 'package:bindle/Chopper/Models/LoginResponse.dart';
import 'package:chopper/chopper.dart';
part 'ApiService.chopper.dart';
#ChopperApi(baseUrl: 'http://192.168.1.20/bindal/api/v1/user/')
abstract class ApiService extends ChopperService {
#Post(path: "login")
Future<Response<LoginResponse>> doLogin([
#Header('auth_key') String authType,
#Query('email') String email,
#Query('password') String password,
#Query('userType') String userType,
]);
static ApiService create() {
final client = ChopperClient(
// The first part of the URL is now here
baseUrl: 'http://192.168.1.20/bindal/api/v1/user/',
services: [
// The generated implementation
_$ApiService(),
],
interceptors: [
HttpLoggingInterceptor()
],
// Converts data to & from JSON and adds the application/json header.
converter: JsonConverter(),
);
// The generated class with the ChopperClient passed in
return _$ApiService(client);
}
}
And this is my generated file.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'ApiService.dart';
// **************************************************************************
// ChopperGenerator
// **************************************************************************
class _$ApiService extends ApiService {
_$ApiService([ChopperClient client]) {
if (client == null) return;
this.client = client;
}
final definitionType = ApiService;
Future<Response<LoginResponse>> doLogin(
[String authType, String email, String password, String userType]) {
final $url = 'http://192.168.1.20/bindal/api/v1/user/login';
final Map<String, dynamic> $params = {
'email': email,
'password': password,
'userType': userType
};
final $headers = {'auth_key': authType};
final $request = Request('POST', $url, client.baseUrl,
parameters: $params, headers: $headers);
return client.send<LoginResponse, LoginResponse>($request);
}
}
Next what i Did is i generated a model class called as LoginResponse where I have to fetch the data.
abstract class LoginResponse implements Built<LoginResponse, LoginResponseBuilder> {
int get status;
String get message;
LoginResponse._();
factory LoginResponse([void Function(LoginResponseBuilder) updates]) = _$LoginResponse;
static LoginResponse fromJson(String jsonString){
return serializers.deserializeWith(LoginResponse.serializer, json.decode(jsonString));
}
static Serializer<LoginResponse> get serializer => _$loginResponseSerializer;
}
this is the generated file for the above LoginResponse.dart file using built_value generator
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'LoginResponse.dart';
// **************************************************************************
// BuiltValueGenerator
// **************************************************************************
Serializer<LoginResponse> _$loginResponseSerializer =
new _$LoginResponseSerializer();
class _$LoginResponseSerializer implements StructuredSerializer<LoginResponse> {
#override
final Iterable<Type> types = const [LoginResponse, _$LoginResponse];
#override
final String wireName = 'LoginResponse';
#override
Iterable<Object> serialize(Serializers serializers, LoginResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'status',
serializers.serialize(object.status, specifiedType: const FullType(int)),
'message',
serializers.serialize(object.message,
specifiedType: const FullType(String)),
];
return result;
}
#override
LoginResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new LoginResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'status':
result.status = serializers.deserialize(value,
specifiedType: const FullType(int)) as int;
break;
case 'message':
result.message = serializers.deserialize(value,
specifiedType: const FullType(String)) as String;
break;
}
}
return result.build();
}
}
class _$LoginResponse extends LoginResponse {
#override
final int status;
#override
final String message;
factory _$LoginResponse([void Function(LoginResponseBuilder) updates]) =>
(new LoginResponseBuilder()..update(updates)).build();
_$LoginResponse._({this.status, this.message}) : super._() {
if (status == null) {
throw new BuiltValueNullFieldError('LoginResponse', 'status');
}
if (message == null) {
throw new BuiltValueNullFieldError('LoginResponse', 'message');
}
}
#override
LoginResponse rebuild(void Function(LoginResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
#override
LoginResponseBuilder toBuilder() => new LoginResponseBuilder()..replace(this);
#override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is LoginResponse &&
status == other.status &&
message == other.message;
}
#override
int get hashCode {
return $jf($jc($jc(0, status.hashCode), message.hashCode));
}
#override
String toString() {
return (newBuiltValueToStringHelper('LoginResponse')
..add('status', status)
..add('message', message))
.toString();
}
}
class LoginResponseBuilder
implements Builder<LoginResponse, LoginResponseBuilder> {
_$LoginResponse _$v;
int _status;
int get status => _$this._status;
set status(int status) => _$this._status = status;
String _message;
String get message => _$this._message;
set message(String message) => _$this._message = message;
LoginResponseBuilder();
LoginResponseBuilder get _$this {
if (_$v != null) {
_status = _$v.status;
_message = _$v.message;
_$v = null;
}
return this;
}
#override
void replace(LoginResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$LoginResponse;
}
#override
void update(void Function(LoginResponseBuilder) updates) {
if (updates != null) updates(this);
}
#override
_$LoginResponse build() {
final _$result =
_$v ?? new _$LoginResponse._(status: status, message: message);
replace(_$result);
return _$result;
}
}
finally i called my api in the login page as
void doLogin(String email, String pass, BuildContext context) async {
try {
final response = await Provider.of<ApiService>(context)
.doLogin("d1d2fe0514f7d5c748c0e7e085b36f74","arpit1692#gmail.com",
"e10adc3949ba59abbe56e057f20f883e","App");
print(response.body);
} catch (e) {
print(e);
}
}
Which ultimately gives me Exception as => Instance of 'Response dynamic'
Please help me for what I am doing wrong.
The reason why the Response returns dyanmic is because the response wasn't serialized to the model you've defined. If LoginResponse is the model that should be used for the response, the LoginResponse class should have fromJson() that should serialize the json response. You can follow this guide to help you manage json serialization.