Flutter Listview - Subtitle and DateDiff problem - flutter

i need your help :)
I think this is not working... but i mean i can do it with an extra page like a "detailpage" and show the data. Well here is my issue
i have the main screen with a listview.Builder for all my entries.
it just shows an icon, the title(name) and a Date (the Date is in the future that i can define in the add screen)
ok now my problem. i need a Datediff. i dont want to show the future Date (endTime), i want the differnce days between today and the future Date
child: ListTile(
leading: CircleAvatar(
backgroundImage:
AssetImage('asset/veggi.png'), ),
title: Text(vegetableEntry.items[index].title),
onTap: () => Navigator.of(context).pushNamed(vegetableDetailScreen.routeName,
arguments: vegetableEntry.items[index].id),
subtitle: Text(vegetableEntry.items[index].endTime.difference(dateNow2).inDays),
somtehing like:
that i get on my subtitle smth like: Icon/ Title(name) /DaysLeft: 29 (checks everytime on open?)
i'm getting the error:
The method 'difference' isn't defined for the type 'String'.
Try correcting the name to the name of an existing method, or defining a method named 'difference'.
i know i can fix it in the DetailScreen with
DateTime startDate = _pickedStartDate;
DateTime endDate = _pickedEndDate;
final daysLeft = endDate.difference(startDate).inDays;
print(daysLeft);
but i dont think this is possible in the Listview.builder ?
i hope this is understandable and someone can help me
best regards,
and a happy day :)

This actually is possible in ListView.builder. Just do the work in the builder function before you return the ListTile. You can't use (context, index) =>. You'll have to use (context, index) {}.
You can also convert the Timestamp String into a DateTime inline like so
subtitle: Text(DateTime.parse(vegetableEntry.items[index].endTime).difference(dateNow2).inDays.toString(),

Related

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

How to access model data of type List having multiple item in each class in ListView.builder

I am making a simple app which has a model with 2 items in it. I want to access the list in listView builder but it gives an error:
The operator '[]' isn't defined for the class 'FirstSem'.
lib/main.dart:72 - 'FirstSem' is from
'package:project/model/model.dart' ('lib/model/model.dart').
package:project/model/model.dart:1 Try correcting the operator to an
existing operator, or defining a '[]' operator. trailing:
Text(student[index].code)
Suggest me a good way to access it. Thanks in advance.
Here is my code:
model.dart
import 'package:flutter/material.dart';
class FirstSem {
String? title;
String? code;
FirstSem({this.title,this.code});
}
List <FirstSem> subject=[
FirstSem(title: "MatheMatics",code: "MTH162"),
FirstSem(title:"Physice",code:"Phy162"),
FirstSem(title:"Digital Logic",code:"csc 162"),
FirstSem(title:"C Programming",code:"csc 159"),
FirstSem(title:"Introduction of Information Technology",code:"csc 160"),
];
main.dart
ListView.builder(itemCount: 5, itemBuilder: (context, index) {
return ListTile(
title: Text(FirstSem[index].title),
trailing: Text(FirstSem[index].code),
);
})
This is very simple to solve ✔️
You're trying to access item at index index of a dart Class. This is only possible on Lists
Changing your Text(FirstSem[index].title) to Text(subject[index].title) and
Setting your itemCount to subject.length will definitely solve your problem
Happy coding 🎉🎉🎉
FirstSem is class, not object. Change the FirstSem to subject list like this
ListView.builder(
itemCount:subject.length,
itemBuilder: (context,index){
final _subject = subject[index];
return ListTile(
title: Text(_subject.title),
trailing: Text(_subject.code),
);
})

How to initialize DateTime value on TextFormField like initialValue property in Dart?

I'm trying to use a template for making a task manager in flutter for an upcoming project, my main problem resides in the method to create a new task, which gets an error when I try to use the floating button.
When I try to create a new task, the app throws the following:
Image link: https://imgur.com/a/eMoTd54
Here's the terminal message when the error happens:
Image Link: https://imgur.com/a/l9r18bI
The error occurs in line 135 of my file "add_new_task.dart" in which the template adds a new task to the main homepage of the application, where I can edit or delete the task whenever I want. From what I understand the template and the flutter version are quite old, so I assume back then you didn't new to initialize the value.
Image Link: https://imgur.com/a/v9XsY7R
Around this line of code:
Text('Due date', style: Theme.of(context).textTheme.subtitle2),
TextFormField(
onTap: () {
_pickUserDueDate();
},
readOnly: true,
decoration: InputDecoration(
hintText: _selectedDate == DateTime.utc(2020,1,1)
? 'Provide your due date'
: DateFormat.yMMMd().format(_selectedDate).toString(),
),
),
const SizedBox(
height: 20,
),
First I thought that initializing the value with the property "initialValue" would do the trick, like this:
initialValue: _selectedDate = DateTime.now(),
and that would've been it, however, it seems I can't do that since "initialValue" only accepts Strings as values, then I thought casting or converting the value would also work using the formatted, creating a final variable with the date of today, a final DateFormat for converting the DateTime and a call to the variable where I needed the string for the "initialValue":
final DateTime now = DateTime.now()
final DateFormat formatter = DateFormat("yyyy-MM-dd")
//...a lot of code...//
String formatted = formatter.format(now);
//...
initialValue: _selectedDate=formatted,
Sadly that didn't work also, so I'm stuck here not knowing how to initialize the variable, and I'm suspecting the same problem will arise with _selectedTime when _selectedDate is solved, so my question for this conundrum is, how can I initialize the variable _selectedDate in the TextFormField widget? would the same problem happen in the variable _selectedTime?
Thank you for your time.
You should set _selectedDate = formatted before you put in the initialValue, or else you will get that error.
So something like this:
_selectedDate = formatted;
//...
initialValue: _selectedDate,

The method 'jumpToDay' was called on null. [Flutter]

In this application, the user will be able to add tasks and display it in a PageView.builder. The user will also be able to scroll through the PageView.builder by swiping left or right. The pageview is mapped to dates (ex: current page maps to today's date, next page maps to tomorrow's date, etc.). I also wanted to implement a jump feature which lets the user move to a new page by specifying a date on a showDatepicker widget.
The PageView.builder was implemented by using this project. this project also has the jump to page feature : https://github.com/ZedTheLed/calendar_views
the showDatepicker is implemented in the method below. it is called by clicking on a Raisedbutton:
_selectDate() async {
final DateTime picker =await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2040)
);
if (picker != null) {
print(picker);
return _daysPageController.jumpToDay(picker); // this method jumps the user to a selected date
// Navigator.pop(context);
// print(selectedDate);
// await runJump(selectedDate);
// return selectedDate;
}
}
when the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when i pass this value to the jumptopage method, it gives his error : The method 'jumpToDay' was called on null.
The PageView.builder is implemented in the code below :
final List<DateTime> days;
Scaffold(
floatingActionButton: new RaisedButton(
child: new Text("Jump To Today"),
onPressed: () {
_selectDate();
},
),
body: new Column(
children: widget.days.map(((day) => Container(
constraints: new BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 1.00,
maxWidth: MediaQuery.of(context).size.width * 1.00
),
child: Starting_screen(_makeTextString(day)), //this screen displays the tasks added by the user
)
),
).toList()
),
);
the method _makeTextString just modifies a DateTime value and returns it in a desirable format.
Could i get a suggestion on how to handle this error?
full project is available here : https://bitbucket.org/NotAnurag/todolist_restarted/src/master/
When the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when I pass this value to the jumptopage method, it gives his error: "The method jumpToDay was called on null"
The problem that I see in the code is that _daysPageController is not initialized. IDE helpfully suggests various methods that you can call on DaysPageController, but the fact remains that it is declared, but no value is assigned to it (meaning that it is null):
DaysPageController _daysPageController; // remains null unless assigned a value
Therefore, what the error is attempting to tell is that jumpToDay(DateTime) is called on null (which obviously does not have such a method). If you look at the stack trace a bit more explicit hint is buried in there:
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'jumpToDay' was called on null.
Try to initialize the controller and see if it helps to resolve the issue.

Difference between flutter onTap() and javascript/jquery $(this) in click listener

I'm still in the process of learning dart/flutter. I'm experimenting with ListView/ListTile and specifically onTap() from ListTile.
I'm somewhat familiar with JS/Jquery and am having trouble understanding the differences in approach between JS and flutter.
Please try to ignore any semantic or technical errors in the code below. I'm more concerned with theory/approach than if this is a perfectly formatted and syntactically correct example.
In JS, it's common to do something like make an AJAX call to an API to get a list of items for sale from a database. Assume the API returned 4 fields (primary key ID, isAvailable, item name, and item price). You then process the list and create/insert DOM elements for display.
<div id="234" data-isavailable="y" class=".itemsForSale">TV: $800</div>
<div id="345" data-isavailable="y" class=".itemsForSale">Microwave: $200</div>
<div id="456" data-isavailable="n" class=".itemsForSale">Book: $30</div>
<div id="567" data-isavailable="y" class=".itemsForSale">Sofa: $450</div>
You can then set listeners arbitrarily. For instance, you could do...
$( ".itemsForSale" ).click(function() {
// do something
});
The click handler gets applied in "real-time". The code executed is aware of what was clicked and can analyze/interact with that item in the list. So, you can do something like:
$( ".itemsForSale" ).click(function() {
var isAvailable = $(this).attr('data-isavailable');
if( isAvailable == 'n' )
alert('sorry but that item is out of stock!');
else
addItemToCart( $(this).attr('id') );
});
The point being, that the click handler doesn't necessarily know or care about the underlying data of each item. It becomes "context" aware during runtime and then pulls the relevant values out of the UI/etc.
With flutter, I'm looking to recreate similar functionality using a ListView and ListTile. Specifically, ListTile's onTap(). I'm getting confused because it seems like everything is coded "ahead of time".
Here is a basic example (ignore for now I'm not displaying price/etc)...
import 'package:flutter/material.dart';
class SecondScreen extends StatelessWidget {
var mapper = {
'234': 'TV',
'345': 'Microwave',
'456': 'Book',
'567': 'Sofa'
};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body:
ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: mapper.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
key: new Key(mapper.keys.elementAt(index).toString()),
title: Text('${mapper.values.elementAt(index)}'),
onTap: () {
print('you clicked: ' + mapper.keys.elementAt(index).toString() );
addToShoppingCart( mapper.keys.elementAt(index).toString() ); // this doesnt exist yet and is just an example
}
);
}
)
);
}
}
First of all, I'm not even sure I need to assign a custom key to each ListView item (based on the database's primary key), but that's irrelevant for now.
What I'm getting stuck on is that the onTap handler doesn't seem to have an equivalent of "$(this)". Does flutter give each ViewTile it's "own" copy of onTap() and that each relevant key info is "hardcoded" into each one (for each itemBuilder loop, the current value of mapper.keys.elementAt(index).toString() is substituted into onTap() )?
I'm probably not describing my confusion properly and I'm not even sure all of the issues I'm going to run into. I'm sure my way of doing this is very "old" and not aligned with react and other newer approaches/frameworks (combining data within the UI elements).
I'm just having trouble seeing how I'm going to be able to add more complex logic (like checking availability of what was clicked).
Does anyone have any references or explanations that help me bridge this gap? I don't even know how to describe the concept of $(this) and how I would search for it in comparison to flutter/etc. I just know that something feels very different.
Thanks!
I understand your confusion probably because I'd a similar question when I started with Flutter just a few months back. And here is what I think -
It doesn't really matter whether the ListTile item has it's own copy of onTap() or not. A. It does not have it's own copy. (Following code snippet will explain) and B. Every programming language / SDK / whatever has its own way of working. What you are trying to say, probably, is that you've a BMW. It has got certain type of breaks. And you are trying to make exact type of break in Audi. It may not be right to do it as the other systems related to the breaks may not work in the optimised way.
Now, look at the following code snippet :
#override
Widget build(BuildContext context) {
return ListView.separated(
separatorBuilder: (context, index) => ListViewDivider(),
itemCount: faceRecTransactions.length,
itemBuilder: (BuildContext context, int index) {
return FacerecTransactionListItem(facerecTransaction: faceRecTransactions[index], onTap:()=> _onTap(faceRecTransactions[index],context),);
},
);
}
void _onTap(FacerecTransaction facerecTransaction, BuildContext context) {
print('Status : ${facerecTransaction.userId}');
Navigator.push(context, MaterialPageRoute(builder: (context) => FacerecDetailPage(
facerecTransaction: facerecTransaction,
criminalList: this.criminalList,)));
}
There's no copy of onTap for every list item. It just 'feels' as it has because we write onTap inside ListView. If you look at the example above, when the user taps on certain item, then the onTap receives the information. We don't create array of onTap as such.
Since, there's no copy of onTaps, it's not really ahead of time code. It's pretty much works like in Ajax where the onTap doesn't really care about the payload. It just does the action(s) specified.
Now, in the above example, the Detailed Page can check the availability of the particular item. And if the item is not available then either appropriate message can be shown. Depending on the requirement, we can either write this code within onTap or on the next page. In short, the onTap can handle the complex logic as you need.