not getting error while changing value of final in flutter..it should generate error - flutter

I have noticed one thing in a tutorial that it changes the value of final object and working well, but so far I know , final can't be changed...
Than why it is working well with this code..
here is the code
check my commented lines
class CompleteProfile extends StatefulWidget {
final UserModel userModel;
final User firebaseUser;
const CompleteProfile({Key? key, required this.userModel, required this.firebaseUser}) : super(key: key);
#override
_CompleteProfileState createState() => _CompleteProfileState();
}
class _CompleteProfileState extends State<CompleteProfile> {
File? imageFile;
TextEditingController fullNameController = TextEditingController();
void uploadData() async {
UIHelper.showLoadingDialog(context, "Uploading image..");
UploadTask uploadTask = FirebaseStorage.instance.ref("profilepictures").child(widget.userModel.uid.toString()).putFile(imageFile!);
TaskSnapshot snapshot = await uploadTask;
String? imageUrl = await snapshot.ref.getDownloadURL();
String? fullname = fullNameController.text.trim();
// here are the statement of changing value of final object....
widget.userModel.fullname = fullname;
widget.userModel.profilepic = imageUrl;
await FirebaseFirestore.instance.collection("users").doc(widget.userModel.uid).set(widget.userModel.toMap()).then((value) {
log("Data uploaded!");
Navigator.popUntil(context, (route) => route.isFirst);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) {
return HomePage(userModel: widget.userModel, firebaseUser: widget.firebaseUser);
}),
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
```

Are you sure your UserModel class's fields: fullname and profilepic is final? Currently, you're changing these fields, not the UserModel object (which is final). If they're not marked as final, it's only logical for them to be changed.
final keyword does not apply to complex objects' fields. They ought to be final too if you want them to never change their values.
If you want to see an error try:
widget.userModel = UserModel();
or make fields fullname and profilepic final:
class UserModel{
final String? fullName;
final String? profilepic;
}
then try:
widget.userModel.fullName = 'Anything' // this will raise an error

Related

The instance member 'value' can't be accessed in an initializer. Try replacing the reference to the instance member with a different expression

I am hoping to use value passed on from another widget in one of the references for a collection within a document. However, this error pops up:
The instance member 'value' can't be accessed in an initializer. Try replacing the reference to the instance member with a different expression
How should I go about this?
class FriendProfileScreen extends StatefulWidget {
String value;
FriendProfileScreen({Key? key, required this.value}) : super(key: key);
#override
_FriendProfileScreenState createState() => _FriendProfileScreenState(value);
}
class _FriendProfileScreenState extends State<FriendProfileScreen> {
String value;
_FriendProfileScreenState(this.value);
var uid = value;
final CollectionReference _todoref = FirebaseFirestore.instance
.collection("users")
.doc(value)
.collection("todos");
#override
I'd suggest to mark it late, so like
late final CollectionReference _todoref = FirebaseFirestore.instance
.collection("users")
.doc(value)
.collection("todos");
Put your initializing code into a future type function and call the function in init method. It will work.
var uid;
Future loadData()async{
uid = value;
final CollectionReference _todoref = FirebaseFirestore.instance
.collection("users")
.doc(value)
.collection("todos");
}
#override
void initState() {
loadData();
super.initState();
}

Problems with shared preference-flutter

I wanna ask how to save state from textfield? cause i can't saving this state, after hot restart my value always reset, i just want to save state after hot restart, can i know my problem where it's wrong?
it's my code:
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController nameController = TextEditingController();
var nama = 'nama';
void setPref() async {
var prefs = await SharedPreferences.getInstance();
prefs.setString(nama, nameController.text);
}
void load() async {
var prefs = await SharedPreferences.getInstance();
setState(() {
nama = prefs.getString(nameController.text) ?? '';
nameController.text = nama;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
load();
}
#override
Widget build(BuildContext context) {
.....
}
}
There is a problem in your code:
In shared Prefrences you have to use key to store and get value.
But you are using it in wrong way:
Here is correct code:
void load() async {
var prefs = await SharedPreferences.getInstance();
String value = '';
setState(() {
value= prefs.getString(nama) ?? '';
nameController.text = value;
});
}
The nama is a key name and you are also using it to receive value. And the key you are using is nameController.text is also wrong.
Bonus
The convection of writing keys in Flutter is Following:
String nameKey = 'NAMEKEY';

setting state with if else using flutter

long time listener, first time caller. I am not a developer, but trying to make a useful program for myself and some colleagues. The app is used to display pdf's that I have saved on firebase, but I want the UI to vary based on if the file has been downloaded or not. The pdf would be displayed on a card with options to view online or download, while a second car would have options to view, share, and delete. To do this I am trying to use an if else after a check if the file exists. But I don't really know how to manipulate the set state to change my isDownloaded variable to alter the state. Here is the code snippet that I'm working with, I don't get an error, just the isDownloaded state never changes unless hardcoded. localPath is a variable for the local documents directory.
Thanks for the help with this!
class RefCardType extends StatefulWidget {
const RefCardType(
{Key? key,
required this.urlPath,
required this.fileName,
required this.page,
required this.title,
required this.cardTitle,
required this.cardSubTitle})
: super(key: key);
final String urlPath;
final String fileName;
final int page;
final String title;
final String cardTitle;
final String cardSubTitle;
#override
_RefCardTypeState createState() => _RefCardTypeState();}
class _RefCardTypeState extends State<RefCardType> {
void checkFile() async {
File file = File('$localPath/${widget.fileName}');
if (await file.exists() == true) {
setState(() {
isDownloaded = true;
});
{
setState(() {
isDownloaded = false;
});
}
}
}
bool isDownloaded = true;
#override
Widget build(BuildContext context) {
if (isDownloaded == true) {
return refFileCard(context,
urlPath: widget.urlPath,
fileName: widget.fileName,
page: widget.page,
title: widget.title,
cardTitle: widget.cardTitle,
cardSubTitle: widget.cardSubTitle);
} else {
return refUrlCard(context,
urlPath: widget.urlPath,
fileName: widget.fileName,
page: widget.page,
title: widget.title,
cardTitle: widget.cardTitle,
cardSubTitle: widget.cardSubTitle);
}
}
}

Future Provider Stuck In loading state

I am using a future provider to display a login page on load and then a loading indicator on loading. Here is my future provider
final loginProvider = FutureProvider.family((ref, UserInput input) =>
ref.read(authRepositoryProvider).doLogin(input.email, input.password));
In my UI I have this....
class LoginScreen extends HookWidget {
final TextEditingController emailEditingController = TextEditingController();
final TextEditingController passwordEditingController =
TextEditingController();
#override
Widget build(BuildContext context) {
var userInput =
UserInput(emailEditingController.text, passwordEditingController.text);
final login = useProvider(loginProvider(userInput));
return login.when(
data: (user) => Login(emailEditingController, passwordEditingController),
loading: () => const ProgressIndication(),
error: (error, stack) {
if (error is DioError) {
return Login(emailEditingController, passwordEditingController);
} else {
return Login(emailEditingController, passwordEditingController);
}
},
);
}
}
here is my doLogin function.
#override
Future<dynamic> doLogin(String email, String password) async {
try {
final response = await _read(dioProvider)
.post('$baseUrl/login', data: {'email': email, 'password': password});
final data = Map<String, dynamic>.from(response.data);
return data;
} on DioError catch (e) {
return BadRequestException(e.error);
} on SocketException {
return 'No Internet Connection';
}
}
I would like to know why it's stuck in the loading state. Any help will be appreciated.
First off, family creates a new instance of the provider when given input. So in your implementation, any time your text fields change, you're generating a new provider and watching that new provider. This is bad.
In your case, keeping the UserInput around for the sake of accessing the login state doesn't make a lot of sense. That is to say, in this instance, a FamilyProvider isn't ideal.
The following is an example of how you could choose to write it. This is not the only way you could write it. It is probably easier to grasp than streaming without an API like Firebase that handles most of that for you.
First, a StateNotifierProvider:
enum LoginState { loggedOut, loading, loggedIn, error }
class LoginStateNotifier extends StateNotifier<LoginState> {
LoginStateNotifier(this._read) : super(LoginState.loggedOut);
final Reader _read;
late final Map<String, dynamic> _user;
static final provider =
StateNotifierProvider<LoginStateNotifier, LoginState>((ref) => LoginStateNotifier(ref.read));
Future<void> login(String email, String password) async {
state = LoginState.loading;
try {
_user = await _read(authRepositoryProvider).doLogin(email, password);
state = LoginState.loggedIn;
} catch (e) {
state = LoginState.error;
}
}
Map<String, dynamic> get user => _user;
}
This allows us to have manual control over the state of the login process. It's not the most elegant, but practically, it works.
Next, a login screen. This is as barebones as they get. Ignore the error parameter for now - it will be cleared up in a moment.
class LoginScreen extends HookWidget {
const LoginScreen({Key? key, this.error = false}) : super(key: key);
final bool error;
#override
Widget build(BuildContext context) {
final emailController = useTextEditingController();
final passwordController = useTextEditingController();
return Column(
children: [
TextField(
controller: emailController,
),
TextField(
controller: passwordController,
),
ElevatedButton(
onPressed: () async {
await context.read(LoginStateNotifier.provider.notifier).login(
emailController.text,
passwordController.text,
);
},
child: Text('Login'),
),
if (error) Text('Error signing in'),
],
);
}
}
You'll notice we can use the useTextEditingController hook which will handle disposing of those, as well. You can also see the call to login through the StateNotifier.
Last but not least, we need to do something with our fancy new state.
class AuthPage extends HookWidget {
const AuthPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final loginState = useProvider(LoginStateNotifier.provider);
switch (loginState) {
case LoginState.loggedOut:
return LoginScreen();
case LoginState.loading:
return LoadingPage();
case LoginState.loggedIn:
return HomePage();
case LoginState.error:
return LoginScreen(error: true);
}
}
}
In practice, you're going to want to wrap this in another widget with a Scaffold.
I know this isn't exactly what you asked, but thought it might be helpful to see another approach to the problem.

how to access to variable from StatefulWidget to State class flutter

I try to pass data from page one to page two data is pass OK but I have one problem now.
this is my code:
class SecondScreen extends StatefulWidget {
final int itemHolder ;
SecondScreen({Key key, #required this.itemHolder}) : super(key: key);
#override
State<StatefulWidget> createState() {
return new mainState();
}
}
class mainState extends State <SecondScreen> {
bool value = false ;
MyPreferences _myPreferences = MyPreferences();
#override
void initState() {
// TODO: implement initState
super.initState();
initial();
}
void initial() async {
setState(() {
});
}
final String apiURL = 'http://xxxxxxxxx/getFlowersList.php';
Future<List<Flowerdata>> fetchFlowers() async {
var response = await http.get(apiURL);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Flowerdata> listOfFruits = items.map<Flowerdata>((json) {
return Flowerdata.fromJson(json);
}).toList();
return listOfFruits;
}
else {
throw Exception('Failed to load data from Server.');
}
}
I try to use var (itemHolder ) in the link like that:
final String apiURL = 'http://xxxxxxx/getFlowersList.php?id=' +itemHolder;
but I get error:
Undefined name 'itemHolder'. Try correcting the name to one that is defined, or defining the name.
I can access to itemHolder. So how can I access to it?
try this:
...
String apiURL;
#override
void initState() {
super.initState();
apiURL = 'http://xxxxxxx/getFlowersList.php?id=' +widget.itemHolder.toString();
}
...
To use the variables declared in the SecondScreen you have to access it with the prefix 'widget' and the dot operator, not directly. Here is the code:
final String apiURL = 'http://xxxxxxx/getFlowersList.php?id=' + widget.itemHolder;
And when you make the variable final, you have to initialize it while declaration or through constructor else delete keyword final: