I have 3 screens, login, homepage and chat. In chat I want to use user, but for some reasons I am getting an error.
Error in HomePage class while trying to pass user to the Chat: 'Undefined name 'user''.
Here samples of code:
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
String email;
String password;
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Future<String> login(String _email, String _password) async {
FirebaseUser user = (await _firebaseAuth.signInWithEmailAndPassword(
email: _email, password: _password))
.user;
() =>
Navigator.push(context, MaterialPageRoute(builder: (context) => Bar(user: user)));
}
...
Why is it not defined? I want to pass user from Login(), through Homepage() to the Chat().
Thank you in advance
EDIT:
I noticed it is not defined only in List, but besides it works properly.
How can I pass it to the list?
class HomePage extends StatefulWidget {
final FirebaseUser user;
const HomePage({Key key, this.user}) : super(key:key);
#override
_BarState createState() => _BarState();
}
class _BarState extends State<HomePage> {
void test() {
() =>
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) =>
Chat(user: widget.user))); < ---- WORKING
}
int tabIndex = 0;
List<Widget> widgetOptions = [
Match(),
Chat(user: widget.user), < --- NOT WORKING
AddBook(),
Profile(),
];
Here you want to access user object in other screen, instead of passing it in cconstructor, create a singleton class, Like this
class AuthUser {
static var authUserId;
static var email;
static var userName;
static var role;
static var companyId;
}
During login Set values like this, please check here print(user); and set value respectively
Future<String> login(String _email, String _password) async {
FirebaseUser user = (await _firebaseAuth.signInWithEmailAndPassword(
email: _email, password: _password))
.user;
() =>
AuthUser.email = user.email,
AuthUser.email = user.userName,
..........
));
}
Access data in other screens like, AuthUser.email, AuthUser.userName.....
Use Chat(user: widget.user) instead.
when you are using a stateful widgets and what to get properties from constructor you need to do it like this:
widget.varNameInConstructor
most of the time it's not needed but if you want to assign that to you own new variable in state you can do it at initState.
Related
I am creating an App using riverpod, hooks and freezed. My aim is to remove the entire logic out of the widget tree. This article by #ttlg inspired me. In my app, I am trying to implement the following pattern. I am pretty new to riverpod so am i doing something wrong? You have my thanks.
what I am trying to achieve - image
my PasswordInputWidget
Widget build(BuildContext context, WidgetRef ref) {
final _authState = ref.watch(loginScreenStateProvider);
final _authController = ref.watch(authControllerProvider);
final _textController = useTextEditingController();
bool _isPasswordObscured = _authState.isPasswordObscured;
return TextField(
controller: _textController,
obscureText: _isPasswordObscured,
decoration: InputDecoration(
label: Text(AppLocalizations.of(context)!.password),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
suffixIcon: IconButton(
onPressed: () => _authController.toggleObscurePassword(),
icon: _isPasswordObscured
? const Icon(Icons.visibility_off_rounded)
: const Icon(Icons.visibility_rounded))),
onChanged: (value) =>
_authController.inputPassword(textController: _textController));
}
the logic is kept inside a file named auth_controller.dart as shown below
the controller updates the auth_state using user inputs.
The controller also handles the data coming from the repository which in turn updates the state.
abstract class AuthController {
void inputUserName({required TextEditingController textController});
void inputPassword({required TextEditingController textController});
void toggleObscurePassword();
bool checkUserNameisValid(String userName);
void login();
}
class AuthControllerImpl implements AuthController {
final Reader _read;
AuthControllerImpl(this._read);
#override
void inputUserName({required TextEditingController textController}) {
final state = _read(loginScreenStateProvider);
bool isValidUserName = checkUserNameisValid(textController.text);
_read(loginScreenStateProvider.notifier).setLoginScreenState(state.copyWith(
userName: textController.text, isValidUserName: isValidUserName));
}
#override
void toggleObscurePassword() {
final state = _read(loginScreenStateProvider);
_read(loginScreenStateProvider.notifier).setLoginScreenState(
state.copyWith(isPasswordObscured: !state.isPasswordObscured));
}
#override
void inputPassword({required TextEditingController textController}) {
final state = _read(loginScreenStateProvider);
_read(loginScreenStateProvider.notifier)
.setLoginScreenState(state.copyWith(password: textController.text));
}
#override
bool checkUserNameisValid(String userName) {
return TextUtils.isValidInput(
text: userName, exp: AppConstants.EMAIL_VALIDATOR);
}
#override
void login() {
final state = _read(loginScreenStateProvider);
final repository = _read(authRepositoryProvider);
if (state.userName.isNotEmpty &&
state.isValidUserName &&
state.password.isNotEmpty) {
repository.login(userName: state.userName, password: state.password);
}
}
}
final authControllerProvider = StateProvider.autoDispose<AuthControllerImpl>(
(ref) => AuthControllerImpl(ref.read));
The state is kept in a separate file auth_state.dart and is exposed using a getter and setter.
class LoginScreenState extends StateNotifier<LoginScreenModel> {
LoginScreenState() : super(const LoginScreenModel());
LoginScreenModel getLoginScreenState() {
return state;
}
void setLoginScreenState(LoginScreenModel newloginScreenState) {
state = newloginScreenState;
}
}
final loginScreenStateProvider =
StateNotifierProvider.autoDispose<LoginScreenState, LoginScreenModel>(
(ref) => LoginScreenState());
The model of the state is created using freezed as shown below
import 'package:freezed_annotation/freezed_annotation.dart';
part 'auth_model.freezed.dart';
#freezed
class LoginScreenModel with _$LoginScreenModel {
const factory LoginScreenModel(
{#Default('') String userName,
#Default('') String password,
#Default(true) bool isValidUserName,
#Default(true) bool isPasswordObscured,
#Default(false) bool showInvalidUserNameError}) = _LoginScreenModel;
}
API calls are handled in the repository as shown below.
//auth repository should be used to write data or fetch data from an api or local storage;
import 'package:dio/dio.dart';
import 'package:glowing/utils/api_utils.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
abstract class AuthRepository {
Future<void> login({required String userName, required String password});
Future<void> forgotPassword();
}
class AuthRepositoryImpl implements AuthRepository {
#override
Future<void> forgotPassword() {
// TODO: implement forgotPassword
throw UnimplementedError();
}
#override
Future<void> login(
{required String userName, required String password}) async {
const String endpoint = "https://example.com/v1/login";
Map<dynamic, dynamic> params = {'email': userName, 'password': password};
Response response = await APIUtils.post(endpoint, params);
print(response);
if (response.statusCode == 200) {
//just printing response now
print(response.data);
}
}
}
final authRepositoryProvider =
StateProvider.autoDispose<AuthRepository>((ref) => AuthRepositoryImpl());
I am trying to develop login checker. The following code should redirect to HomeScreen when user is loggedin and to LoginPage in User is not loggedin. But it only gets redirect to LoginScreen() not to HomeScreen() even though it's already logged in.
User Model:
class User {
User({
required this.id,
required this.name,
required this.email,
required this.cart,
});
String id;
String name;
String email;
List cart;
}
UserController:
class UserController extends GetxController {
RxString id = ''.obs;
RxBool isLoggedIn = false.obs;
RxString name = ''.obs;
RxString email = ''.obs;
RxString image = ''.obs;
RxList cart = [].obs;
final NetworkHandler _handler = NetworkHandler();
#override
void onInit() {
super.onInit();
getUserDetails();
}
getUserDetails() {
User _user = _handler.userDetails();
id.value = _user.id;
if (id.value != '') {
isLoggedIn.value = true;
}
name.value = _user.name;
}
}
Checker Screen
class StateCheck extends StatelessWidget {
var controller = Get.put(UserController());
StateCheck({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Obx(
() => controller.isLoggedIn.value
? const HomeScreen()
: const LoginScreen(),
);
}
}
First you have to set login value in SharedPreferences.
when login success
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("isLogin", true);
log out
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("isLogin", false);
You can Check login state || check this in splash screen for best practice (inside init method)
if(prefs.getBool('isLogin')==null||prefs.getBool('isLogin')==false){
// login screen
}else{
// home screen
}
I have the below class like.dart that need to send some data to home.dart, the start page is the home dart and after click on button on post navigate to other page like.dart with parameters, after user click on like I want to update the view on home.dart to show that user liked this post
class imageModal extends StatefulWidget {
//imageModal({Key key}) : super(key: key);
final title;
final comments;
final links;
final urlImages;
final userid;
final postid;
final userlikes;
int totallikes;
final like;
imageModal(this.title,this.comments,this.links,
this.urlImages,this.postid,this.userid,this.userlikes,this.totallikes,this.like);
#override
imageModalState createState() => imageModalState();
}
...
new IconButton(
icon: new Icon(Icons.favorite_border, color: Colors.black) ,
onPressed: (){
_like(widget.postid,state);
}
),
...
_like(postid,StateSetter updateState) async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var userid = jsonDecode(localStorage.getString('userid'));
var user = jsonDecode(localStorage.getString('user'));
var data = {
'userid' : userid,
'postid': postid,
};
var res = await Network().like(data, 'post/like/');
var body = json.decode(res.body);
print(body['data']['users']);
updateState(() {
widget.like.add(body['data']);
//print( posts[i]['like']);
widget.userlikes.add(body['data']);
var totallikes = widget.totallikes;
var finallikes = totallikes+1;
widget.totallikes = finallikes;
});
}
I want to send to the home.dart the below values new values
widget.like
widget.userlikes
widget.totallikes
and when I send them to setstate them so can update the view
If you want to return from the other screen to home with the updated values, you can use Navigator.pop(context, result);
In FirstScreen
_navigateToAnotherScreen(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
// print(result);
}
In SecondScreen
Navigator.pop(context, [value1, value2, value3]);
Use state management technique like Provider
https://pub.dev/packages/provider
i am calling this method(sendOtp) from another class but getting error: the method "sendOtp" isn't defined for class 'LoginPage'
it is a phone authentication loginpage method to sendOtp
class LoginPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return LoginPageState();
}
}
class LoginPageState extends State<LoginPage> {
Future<void> sendOtp() async {
final PhoneVerificationCompleted phoneVerificationCompleted =
(AuthCredential credential) {};
final PhoneVerificationFailed phoneVerificationFailed =
(AuthException exception) {
print("Login Faild due to $exception");
};
final PhoneCodeSent phoneCodeSent =
(String verificationId, [int forceResendingToken]) {
this.verificationId = verificationId;
};
final PhoneCodeAutoRetrievalTimeout phoneCodeAutoRetrievalTimeout =
(String verificationId) {
this.verificationId = verificationId;
print("time out");
};
await _auth.verifyPhoneNumber(
phoneNumber: _numberController.text,
timeout: Duration(seconds: 120),
verificationCompleted: phoneVerificationCompleted,
verificationFailed: phoneVerificationFailed,
codeSent: phoneCodeSent,
codeAutoRetrievalTimeout: phoneCodeAutoRetrievalTimeout);
}
----------------ANOTHER CLASS-------------------
class OtpScreen extends StatefulWidget {
final String _name,_number, _id;
OtpScreen(this._name, this._number, this._id);
#override
OtpScreenState createState() {
return OtpScreenState();
}
}
class OtpScreenState extends State<OtpScreen> {
final TextEditingController _otpController = TextEditingController();
var _auth = FirebaseAuth.instance;
LoginPage loginPage = LoginPage();
Widget resend() {
return FlatButton(
child: Text("Send Otp again"),
onPressed: () => loginPage.sendOtp(), //ERROR IS HERE: sendOtp isn't defined for class LoginPage
);
}
}
You can't just call a method of another class without any reference. If the method is in the parent widget, you can pass it down when calling the child widget. If the method is in the child, you can pass a GlobalKey from the parent to the child, add that key to the child, and then through the key call the methods of the child.
If the two widgets have no relation what-so-ever, then you would benefit from using an InheritedWidget or a State Management solution that allows you to pass methods around in your app.
I'm following a tutorial building my first login system with Flutter. I stumbled upon a getter error I can't resolve.
Before I refactored the code to move the auth parts into their own file, everything was working fine.
Here's the problematic code:
abstract class BaseAuth {
Future<String> signInWithEmailAndPassword(String email, String password);
}
class Auth implements BaseAuth {
Future<String> signInWithEmailAndPassword(String email, String password) async {
FirebaseUser user = (await
FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password
)).user;
return user.uid;
}
}
Here's how I try to use it:
class LoginPage extends StatefulWidget {
LoginPage({this.auth});
final BaseAuth auth;
#override
State<StatefulWidget> createState() => _LoginPageState();
}
enum FormType {
login,
register
}
...
class _LoginPageState extends State<StatefulWidget> {
final formKey = GlobalKey<FormState>();
String _email;
String _password;
FormType _formType = FormType.login;
void validateAndSubmit() async {
if (validateAndSave()) {
try {
if (_formType == FormType.login) {
String userID = await widget.auth.singInWithEmailAndPassword(_email,_password);
print('Signed in as $userID');
} ...
} catch(e) {
print('Error: $e');
}
}
}
...
}
This is the error message I receive:
"The getter 'auth' isn't defined for the class StatefulWidget".
The code works just fine in the tutorial.
I keep looking for differences between our codebases but there's nothing that seems out of place to me. Maybe someone can help an improver out?
class _LoginPageState extends State<StatefulWidget> {
should be
class _LoginPageState extends State<LoginPage> {