Dart null safety with if check [duplicate] - flutter

This question already has answers here:
"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety
(3 answers)
Closed 1 year ago.
I am use Dart Null Safety version
Have a widget:
itemBuilder expects a Widget type.
footer is Widget? type and will be null
Why Dart ignoring my null check? Also I only found one solution:
if (footer != null && index == data.length) {
return footer ?? const SizedBox();
}

Why Dart ignoring my null check?
Because when the following code executed:
Widget? footer;
...
if (footer != null && index == data.length) {
return footer;
}
There is a probability that your footer is set to null from the other part of your code hence the error is shown.
You can add ! if you're completely sure that the footer won't be nulled for the rest of its life. So, you can use this:
if (footer != null && index == data.length) {
return footer!;
}
but your solution much safer because it always check if footer not null:
if (footer != null && index == data.length) {
// whenever footer is nulled, return SizedBox
return footer ?? const SizedBox();
}

Correct code:
final footer = this.footer;
if (footer != null && index == data.length) {
return footer;
}
Why? Because subclass of this class can override footer getter.
i.e.:
Widget get footer {
if (Random().nextBool()) return null;
else return super.footer;
}
So every call to footer could return null.
Personally, I always do '!'(if (footer != null) footer!) after check. Because providing getter with side effects is a large code smell.

You can use this code snippet to check that a variable is null or not
a != null && [do something]

Related

How to check in if condition whether a File is not empty

I am trying to work with a code where I want it to check if my file is not empty. When I try to do this:
void uploadProduct() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
if (image != null) {
setState(() {
image = null;
});
_formKey.currentState!.reset();
} else {
snackBar('Please Pick Image', context);
}
} else {
snackBar('Fields must not be empty', context);
}
}
What I am trying is to check whether or not if I have the file(image) selected or not, when I don't have any image selected, it should show the snackBar (please pick image) as stated in the else, but it doesn't work.
How can i fix it?
Check for value is null or not
if(_image != null)
If you have the path of the file, you can use dart:io
var file = File('the_path_to_the_image');
print(file.lengthSync());
now check if length > 0 then file is not empty otherwise file is empty
File not being empty isn't very clear. There might be two conditions:
File is null
You can check it by:
if(_image != null)
If the file exists but it's empty
You can check that by:
final _imageContent = await _image.readAsString();
if(_imagContent.length > 0)

textfield validation fails in flutter

this is my first question here. I am not sure if I am writing it in a correct form.
I would like to validate TextField widget but it fails and throw an error.
here is how the code look like.
void surfaceCalc() {
if(_length == '' && _length == null && _width == '' && _width == null){
print('one of the field is empty');
} else{
final surfaceArea = double.parse(_length.text) *
double.parse(_width.text);
}
but the problem with this, that when i click on calculate button, it goes to this file double_patch.dart and highlight invalid double. as far as i understand, it throws and error because the text field is empty and has not been validated, it skips the validation and goes to calculation and throws an error. but if i type values in the textfield, it works fine.
any help is highly appreciated

Assigning different color to a widget elements based on a selected category in Flutter

I am new to flutter and to programming and I need guidance.
I am building an app where users can create tasks and based on the selected category the corresponding color should be displayed withing the widget.
Currently, I get the error: The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The function (I get the error on _selectedCatColor):
Color _selectedCatColor(String catTitile) {
switch (catTitile) {
case 'Work':
return Colors.deepPurple;
case 'Personal':
return Colors.green;
case 'Kids':
return Colors.red;
case 'Parents':
return Colors.indigo;
case 'Friends':
return Colors.yellow;
case 'Misc':
return Colors.teal.shade800;
}
}
How I call it:
void submitData() {
final enteredTitle = titleController.text;
final enteredCategory = _selectedCategory;
final enteredColor = _selectedCatColor(_selectedCategory!);
My gut feeling is that this is something simple, but I can't figure it out.
The return type from your function is Color, which is non-nullable. Your function should never return null. (If you wanted to allow it to be nullable, it should be Color?.)
Your function body, on the other hand, has a switch statement looking for a few string comparisons. Now I imagine I call your function like this:
_selectedCatColor("Jack")
Your function will not return anything at all, because your switch statement doesn't handle "Jack". Dart can determine that this could happen, which is why it's giving you that message.
One way to avoid it is to have a default in your switch statement, for example:
case 'Misc':
return Colors.teal.shade800;
default:
return Colors.teal.shade800;
Now you will always return a Color.

Flutter - Replace a subsstring with a Widget

I am building an application with flutter, but I am having a bit of trouble with one of my widgets. I am getting a JSON response from an API endpoint in order to build the comments on posts, but I need to be able to take part of a string and wrap it in a GestureDetector, in order to handle "# mentions".
For example: I have the string hey there #MattChris how are you? I need to be able to wrap the #MattChris in a GestureDetector.
At the moment I parse the incoming string and provide a list with each space-separated word from the actual comment. Like so:
List<Widget> comment = new List();
outer: for (String word in json['content'].toString().split(" ")) {
if (word != null && word.isNotEmpty) {
if (word.startsWith('#')) {
comment.add(GestureDetector(
onTap: goToProfile,
child: Text(word + ' ')
);
} else {
comment.add(Text(word + ' '));
}
}
}
Only issue now is that's a lot of extra elements taking up memory, and a difficulty with ensuring that the text wraps in the way I expect. I've seen the answer here, but I'm not sure how to ensure that text wraps as if it were one string in a Text widget.
I was able to come to a working solution. Reading from the implementation I liked to again, and looking in the comments, I decided to use a recursive function:
List<TextSpan> _mentionParser(String message, Iterable<dynamic> mentions) {
if (message == null || message.isEmpty) // Don't return anything if there is no message.
return [];
for (Map<String, dynamic> mention in mentions) { // Loop through the list of names to replace
if (message.contains("#${mention['username']}")) { // If the message contains the name to replace
List<TextSpan> _children = [];
String preUsernameMessage = message.substring(0, message.indexOf("#${mention['username']}")).trimLeft(); // Get everything before the mention
if (preUsernameMessage != null && preUsernameMessage.isNotEmpty)
_children.add(TextSpan(children: _mentionParser(preUsernameMessage, mentions))); // if it isn't empty, recurse and add to the list
_children.add( // Always add the display name to the list
TextSpan(
text: "${mention['display_name']}".trim(),
style: TextStyle(color: Color(0xff2e6da4)),
recognizer: TapGestureRecognizer()
..onTap = () => {gotoProfile(json['username'])}
)
);
String postUsernameMessage = message.substring(message.indexOf("#${mention['username']}") + "#${mention['username']}".length, message.length).trimRight(); // Get everything after the mention
if (postUsernameMessage != null && postUsernameMessage.isNotEmpty) // If it isn't empty, recurse and add it to the list
_children.add(TextSpan(children: _mentionParser(postUsernameMessage, mentions)));
return _children; // return the constructed list
}
}
return [TextSpan(text: message)]; // If the string didn't contain any of the strings to replace, then just return the message as passed.
}
Then I just call this as the children variable on a TextSpan inside Text.rich. It took some time, but I was able to get the implementation working!
public String method(String str) {
if (str != null && str.length() > 0 && str.charAt(str.length() - 1) == 'x') {
str = str.substring(0, str.length() - 1);
}
return str; // to remove last character
}

Problems with MvxSpinner in ListView

I'm having a problem where I have a listview that contains a group of spinners. If I select an option for the first spinner and then scroll down I'll see a spinner that I haven't even touched has the same value as the first spinner I just set. I'm assuming this is an issue with the Spinner view being recycled and improperly used below. Has anyone else ran into this issue with spinners? I'm thinking we need to implement a solution similar to this in MvxAdapter?
I implemented my own MyMvxAdapter and MyMvxListView to handle this. The only thing I changed in the MyMvxListView was to have it use MyMvxAdapter as its adapter instead of the normal MvxAdapter. I then changed the GetBindableView in MyMvxAdapter to look like this:
protected virtual View GetBindableView(View convertView, object dataContext, int templateId)
{
if (templateId == 0)
{
// no template seen - so use a standard string view from Android and use ToString()
return GetSimpleView(convertView, dataContext);
}
// we have a templateid so lets use bind and inflate on it :)
var viewToUse = convertView as IMvxListItemView;
if (viewToUse != null)
{
if (viewToUse.TemplateId != templateId)
{
viewToUse = null;
}
}
if (viewToUse == null)
{
viewToUse = CreateBindableView(dataContext, templateId);
}
else
{
var spinner = (MvxSpinner)convertView.FindViewById(Resource.Id.taskFieldSpinner);
if (spinner != null)
{
spinner.SetSelection(((WrappedEmployeeTaskField)dataContext).TheField.SpinnerSelection);
}
BindBindableView(dataContext, viewToUse);
}
return viewToUse as View;
}
You'll notice the only real difference is that I needed to directly access my spinner resource to properly set it if viewToUse is not null. Then the last of the "magic sauce" was to keep track of the spinner's selected value on my data model, in this case as the property "SpinnerSelection" on my model which gets filled in every time the value gets selected.