Changing a boolean value in a flutter widget - flutter

I have a Job class which has a list of Tasks assigned to it. Everything is working fine, but I am trying to add a boolean field to mark a Job as complete. For now I am not checking all sub tasks. Just a simple check box that the Job is complete or not.
I have a data file that has predefined Jobs and Tasks in it. If I assign true or false to the complete variable in the data file, it all loads, the check boxes are populated, etc... but I can't change the value as it is hardcoded.
If I leave the value undefined I get a boolean expression must not be null error.
So in my Widget were I generate the list of Jobs (which can be pressed to show list of Tasks), I assume I need to initialize the complete variable before it renders the list. This Widget was a Stateless Widget before I added the boolean variable, I have changed it to Stateful as I am thinking I need to setState() to change the boolean variable. But since the Job is in data file this is where I am getting a bit stuck trying to assign or change the boolean variable.
Any pointers in what I am missing would be much appreciated.
class Job {
int jobID;
List<Task> task_list;
String imageURL;
String jobName;
bool complete;
Job({
this.jobId,
this.task_list,
this.imageURL,
this.jobName,
this.complete,
});
}
class Task{
int taskID;
String imageURL;
String name;
String type;
int taskTime;
Task({
this.taskID,
this.imageURL,
this.name,
this.type,
this.taskTime,
})
}

For your Job class constructor, could you change:
Job({
this.jobId,
this.task_list,
this.imageURL,
this.jobName,
this.complete,
});
to this:
Job({
this.jobId,
this.task_list,
this.imageURL,
this.jobName,
this.complete = false,
});
Giving complete a default value of false should avoid the must not be null error. I assume this is OK since a job shouldn't be done by default, correct?

by any chance is the data file generated with sqflite? if yes, the bool type field must be changed to an int field using 0 and 1 for representing the bool

If you want to see changes on the widget, you have to surround the declaration with the setState(() {complete = true});

Related

Making non-nullable class fields not required if they have a default value

I have the following class:
class MarkdownRenderingContextData {
MarkdownRenderingContextData({
required this.textSize,
required this.textStyle
});
MarkdownTextSize textSize = MarkdownTextSize.text;
MarkdownTextStyle textStyle = MarkdownTextStyle.normal;
}
What I want is:
If you don't pass textStize and textStyle, they have the default value.
If you pass them, they must not be null.
I'm not being able to do it. Dart is forcing me to add the required in the construtor, which is making them mandatory during instanciation and I don't want it. If I make them NOT required (e.g MarkdownTextSize?) now I have to check for null during use.
Is there any way around it?
You can specify a default value in the constructor, and make the members final:
class MarkdownRenderingContextData {
MarkdownRenderingContextData({
this.textSize = MarkdownTextSize.text,
this.textStyle = MarkdownTextStyle.normal
});
final MarkdownTextSize textSize;
final MarkdownTextStyle textStyle;
}

Dart/Flutter : Why should we AVOID public late final fields without initializers?

https://dart.dev/guides/language/effective-dart/design#avoid-public-late-final-fields-without-initializers
AVOID public late final fields without initializers.
Unlike other final fields, a late final field without an initializer
does define a setter. If that field is public, then the setter is
public. This is rarely what you want. Fields are usually marked late
so that they can be initialized internally at some point in the
instance’s lifetime, often inside the constructor body.
Unless you do want users to call the setter, it’s better to pick one
of the following solutions:
Don’t use late. Use late, but initialize the late field at its
declaration. Use late, but make the late field private and define a
public getter for it.
The above explanation is abstract and I have no concrete image of what kind of risk this rule envisions.
I would be grateful if you could give me a hint as to how to think.
The risk is that you accidental try to assign a value twice, which will result in an error.
late final String a;
void someMethod() {
a = "a";
a = "b";
}
The above code compiles perfectly fine and is valid code because of the late but leads to a crash.
As for the suggested solutions
Don’t use late.
Use late, but initialize the late field at its declaration.
final String a = "b";
// or
late final String a = "b";
void someMethod() {
a = "a";
a = "b";
}
This makes it that the above code doesn't even compile, making it sure that the crash doesn't happen.
Late modifier means a variable's value is not known during declaration but will definitely get initialized and not null when it's accessed.
When we declare a variable as final, it means that it will only assigned once. Therefore, all the final fields has to be initialized either at declaration or inside the class constructor.
Given above facts, for one to declare a late final variable as public would probably a mistake. One should either pass the value to final field as class constructor parameter, or declare the late final field as private and initialize it internally.
Let see the example why late final field should not be made public
class Coffee {
late final String temperature; // public field as there's no prefix underscore, e.g. _temperature
// based on description from the guide, a setter will be created automatically for public late final
set temperature(String val) => temperature = val;
// again, do you think you would want above?
// as it's final field, it means it should only be initialized once!
// The creation of the setter for late final (public field) does not make too much sense
// Therefore usage late final as public field is rarely what you will want
}
Not sure if it's true, but I think this advice is to enforce better architecture. If field is final then you can set it value only once and almost always you need to initialize it from within the class it belongs to.
But if setter for final field is public then people might attempt to set it value from elsewhere AFTER it is already initialized, and this will lead to an error.
UPD: two sections above there is this advice, that basically summarizes my point:
Objects shouldn’t generally expose more state than they need to.
...and setter is not needed after final field has been initialized.

Can this class be reconfigured to accept named parameters in Flutter?

Background code
I have a class called Result that I'm using to pass on some error codes and error messages to an error screen.
class Result<T>{
Result._();
factory Result.loading(T msg) = LoadingState<T>;
factory Result.success(T value) = SuccessState<T>;
factory Result.error(T title, T msg, T errorcode) = ErrorState<T>;
}
class ErrorState<T> extends Result<T> {
final T title;
final T msg;
final T errorcode;
ErrorState(this.title, this.msg, this.errorcode) : super._();
//final T msg;
}
This class is called as follows:
return Result.error("Error","Status code not 200", 1);
My problem
Functionally it all works great.
The problem is I see myself in the future having to refer back to my class Result code to remember what each field represents which may become even more problematic if I want to add in more fields down the line
I'd rather convert this so that the fields are named
My question
Can this class be converted so that it is called like this (with a name describing the parameter):
return Result.error(title:"Error", msg:"Status code not 200", errorcode:1);
If you want to change Result.error to accept named parameters without breaking existing call sites, you can't do that. Parameters can be either positional or named, but not both.
If you're okay with breaking existing call sites, then you can just make them required named parameters. Since you're using redirecting constructors, you either will need to:
Change the signature of the redirectee constructor (in your case, ErrorState) to exactly match that of Result.error:
factory Result.error(
{required T title, required T msg, required T errorcode}) = ErrorState<T>;
...
ErrorState({required this.title, required this.msg, required this.errorcode})
: super._();
Or change Result.error to be a non-redirecting constructor:
factory Result.error(
{required T title, required T msg, required T errorcode}) {
return ErrorState<T>(title, msg, errorcode);
}
(If you do want to avoid breaking existing callers, you could add a separate named constructor (or static method) that uses named parameters, and you could optionally deprecate the old constructor.)
As an aside, it does not make sense that Result and ErrorState are generic classes. Do you really expect title and msg to not be Strings? Does it really make sense for the type of title, msg, and errorcode to be the same? (With the example you've shown, you'll end up with Result<Object>, which defeats the point of using a generic class.)

why does my indexOf output -1 in flutter?

class Task{
String name;
bool isDone;
Task({this.name, this.isDone = false});
}
class TaskData{
List<Task> tasks = [
Task(name: 'Buy milk'),
Task(name: 'Buy eggs'),
Task(name: 'Buy bread')
];
}
void main(){
print(TaskData().tasks.indexOf(Task(name: 'Buy milk')));
}
why does it print -1 ?
Flutter(Dart) can not compare objects directly as we compare variables like int, strings and other.
We have to do it manually by checking each and every variables are same or not then we can say that both object are same or not.
However, we can compare class object as other variable by using Equatable package.
Add Equatable package in pubspec.yaml file and then change your class as below. now you will get desire outputs.
class Task extends Equatable {
String name;
bool isDone;
Task({this.name, this.isDone = false});
#override
List<Object> get props => [name, isDone];
}
Your program prints -1 becuase the Task argument you sent to indexOf() does not exist in tasks. The following explanation is dart-related more than it is flutter-related.
By default, instance of an object in Dart is considered equal to another instance only if those are the same instance. Here, you created two different instances, perhaps with the same properties but they are actually independent of each other. In this case both tasks are logically equal but there is no way Dart could know that. Your options are:
Use a const constructor
Const constructors in Dart let you create instances that are compile-time constants. If you use such a constructor, Dart will know for sure that after you create a Task its properties can never change. Thus, it will be comfortable making the assumption that Task(name: 'Buy milk') will always have the same properties of another Task(name: 'Buy milk') no matter what (They are equal). Under the hood, Dart uses the same instance for both. To implement this you'll have to change your code as follows:
class Task {
final String name;
final bool isDone;
const Task({this.name, this.isDone = false});
}
Override the hashCode and the == operator
If you don't want Task to be immutable, you should override the current primitive equality check of Task. from Dart's documentation:
The default hash code implementation provides an identity hash—two
objects generally only have the same hash code if they are the exact
same object. Likewise, the default behavior for == is identity.
If you are overriding ==, it implies you may have different objects
that are considered “equal” by your class. Any two objects that are
equal must have the same hash code. Otherwise, maps and other
hash-based collections will fail to recognize that the two objects are
equivalent.
The default hashCode represents the identity of an instance, but we want it to represent its properties in this case. Note that hashCode should not end up being the same for instances with different properties. It generally does not matter how it's implemented as long as this principle is preserved. I'll use the example provided here to give a possible implementation:
#override
int get hashCode {
int result = 17;
result = 37 * result + name.hashCode;
result = 37 * result + isDone.hashCode;
return result;
}
Now override the == operator to reflect the changes:
#override
bool operator ==(dynamic other) {
if (other is! Task) return false;
Task task = other;
return (task.name == name &&
task.isDone == isDone);
}
}
Note that Dart genrally recommends to avoid defining custom equality for mutable classes, and, following this design rule, the first solution I've listed is the easiest to implement.

Flutter required keyword

I don't really understand how required works. For example I've seen this code:
class Test{
final String x;
Test({
required this.x
});
factory Test.initial(){
return Test(x: "");
}
}
But what should required do here? Seems like it makes an optional parameter a non optional parameter.
Update
As of Dart 2.12, the required keyword replaces the #required meta annotation. For detailed info look into the official FAQ. The following answer has been updated to reflect both this and null safety.
Parameters required by default
The parameters of a class constructor or function are required by default.
class Test {
final String x;
Test(this.x);
}
You're not allowed to do this:
final value = Test();
// 1 positional argument(s) expected, but 0 found.
You must do this:
final value = Test('hello');
Optional named parameters
If you surround a parameter with curly braces, though, in addition to becoming a named parameter, it also becomes optional.
Since it's optional, the property must either be nullable like this:
class Test {
final String? x;
Test({this.x});
}
Or it has to have a default value like this:
class Test {
final String? x;
Test({this.x = ''});
}
So now this is ok:
final value = Test();
And so is this:
final value = Test(x: 'hello');
Required named parameters
Sometimes you don't want to allow a parameter to be null and there is no natural default variable. In that case you can add the required keyword in front of the parameter name:
class Test {
final String x;
Test({required this.x});
}
This is not ok anymore:
final value = Test();
// The named parameter 'x' is required, but there's no corresponding argument.
But this is still fine:
final value = Test(x: 'hello');
Dart 2.12 (null safety):
Beginning with Dart 2.12, the #required annotation is now replaced by the required keyword. You should mark your field required if it is mandatory for others to pass some value to it.
For example:
class Foo {
final int a; // Mandatory? Use 'required'
final int b; // Not mandatory? Don't use 'required'
Foo({
required this.a, // Marked 'required'
this.b = 1,
});
}
Usage:
Foo(); // Error: 'a' is required
Foo(a: 0); // Good
Foo(a: 0, b: 1); // Good
#required is an annotation that will create a warning for you to remember that the named parameter is necessary for the class to work as expected.
It will not create compile errors, at least for what I know.
#required bounds you to pass #required marked arguments while creating object of Class. For example, while showing a dialog, you'd mark context as required since, you cannot show dialog without having a valid context. But, you should not overuse it.
Short answer: Named parameters are optional by default in Dart. We prefer them to positional params for ease of use. In this case, the named parameters also might be expected to hold some value all the time (non-nullable) - from initialization itself. Hence, the double effort.
He could use default value initialization of the parameters instead of 'required', if the values were compile-time constants, and that doesn't seem to be the case here.
Positional parameters can be required or optional, which we pass in order when calling. The following is an example of required positional parameters' usage:
class Object{
String name;
int value;
Object(this.name, this.value=100); //auto type inference
}
final one = Object("Name here", 50); // All parameters are needed to call.
Named parameters are another type of optional parameters. Flutter APIs use named parameters and in our UI code, it is preferred to use named parameters instead of positional parameters. Reason being readability and clarity when reading code or calling the constructors later on at several parts of the code. You would have seen this as the case with all Widgets, Styles. For if it were to be positional it would be difficult to keep track of them upon calling with the sheer amount of methods that would be in use, and dynamic type inference could also be at work.
void display({required String name, int value1, int value2=100}) {...;} //named params
display(value1: 50, name: "Calculated name");
NOTE:
If exists, required positional parameters have to come first. Either named or optional positional params can follow(NOT BOTH).
String say(String from, String msg, [String? device]) { //req. pos params and opt pos params.
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
Remove
required
in constructor.
Instead write
final String? x;
So, it becomes as:
class Test{
final String? x;
Test({
this.x
});
factory Test.initial(){
return Test(x: "");
}
}