LateInitializationError: Field 'day0' has not been initialized - flutter

import 'package:intl/intl.dart';
late String day0;
late String dateMonth0;
late String day1;
late String dateMonth1;
late String day2;
late String dateMonth2;
late String day3;
late String dateMonth3;
late String day4;
late String dateMonth4;
late String day5;
late String dateMonth5;
void findDateTime(DateTime time) {
day0 = DateFormat('EEEEE', 'en_US').format(time);
dateMonth0 = DateFormat('d MMMM', 'en_US').format(time);
DateTime dateTime1 = DateTime(time.year, time.month, time.day + 1);
day1 = DateFormat('EEEEE', 'en_US').format(dateTime1);
dateMonth1 = DateFormat('d MMMM', 'en_US').format(dateTime1);
DateTime dateTime2 = DateTime(time.year, time.month, time.day + 2);
day2 = DateFormat('EEEEE', 'en_US').format(dateTime2);
dateMonth2 = DateFormat('d MMMM', 'en_US').format(dateTime2);
DateTime dateTime3 = DateTime(time.year, time.month, time.day + 3);
day3 = DateFormat('EEEEE', 'en_US').format(dateTime3);
dateMonth3 = DateFormat('d MMMM', 'en_US').format(dateTime3);
DateTime dateTime4 = DateTime(time.year, time.month, time.day + 4);
day4 = DateFormat('EEEEE', 'en_US').format(dateTime4);
dateMonth4 = DateFormat('d MMMM', 'en_US').format(dateTime4);
DateTime dateTime5 = DateTime(time.year, time.month, time.day + 5);
day5 = DateFormat('EEEEE', 'en_US').format(dateTime5);
dateMonth5 = DateFormat('d MMMM', 'en_US').format(dateTime5);
}
above code is to fetch day date and month of upcoming 6 days using current date
i have created pickup and delivery page in which i want to show these dates.I have called the above function find date time in the init state of PickupScreen and the code is attached below but i am still getting late initialisation error on all the variables declared late any way i could solve this?
class PickupScreen extends ConsumerStatefulWidget {
const PickupScreen({Key? key}) : super(key: key);
#override
ConsumerState<ConsumerStatefulWidget> createState() => _PickupScreenState();
}
class _PickupScreenState extends ConsumerState<PickupScreen> {
#override
void initState() {
super.initState();
time();
}
void time() async {
DateTime time = await Time().getTime();
findDateTime(time);
}

Check this
Your concept added to a loop and it will help to get the values with the help of index. you can call the static function from your code and await for it to add the results to the list

void time() async {
This function is asyncronous. That means it will run and return a Future of some kind to notify you when it is done. Since yours does not return a future (why is your linter not flagging this? Did you turn it off?) you are unable to determine when it is done.
So when you call it:
void initState() {
super.initState();
time();
}
It will return immediately. The point is that the Future it returns can be used with the await keyword to make sure it is finished. But you skipped that by chosing to return void.
So it will return immediately, but unlike non-async function, it will not actually be done. So your initState completes and the build starts, but your variables declared as late aren't actually assigned yet. That is why you get the exception.
There is no easy fix here. You have to understand how Futures and async/await patterns work and then find the best solution to your problem.
A good start might be What is a Future and how do I use it?

Related

How can I get a value from an if statement and work out the difference

I have a function that checks if a user has the app open or closed. If opened take the current time and store it in a variable, if the app is closed, do the same. then it should work out the difference and print it back.
I'm trying to work out how long the user has spent on the app.
I just not sure how to get it to work, I've tried to assign it to a global and use it from there but that did not work, I've tried sending the values to another function but I keep getting null returned.
What can I do to fix this?
*.dart
activeTimer(value) {
print(value);
if (value == true) {
startTimer();
print("TRUE 1");
DateTime dateTimeStart = DateTime.now();
} else {
print("FALSE 1");
stopTimer();
DateTime dateTimeEnd = DateTime.now();
};
final differenceInDays = dateTimeEnd.difference(dateTimeStart).inMinutes;
print(differenceInDays);
}
You can check when your app is being closed (or placed in background), so just initialize a variable when the app starts and calculate the time when the app closes:
in your main.dart file
late DateTime app_start;
#override
initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
app_start = DateTime.now();
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
// check if app is closed -> substract current time from app_start
// save to local storage or send to cloud or smth
}
I highly recommend you to use a Stream for this purpose.
For example:
Stream<int> tick({required int ticks}) {
return Stream.periodic(Duration(seconds: 1), (x) => ticks + x + 1)
.take(ticks);
}
That's very similar to what you can find in this Bloc Tutorial - link

Flutter GetX state management can't update the variables state

I Can't Change the state of any variable with .obs, RxType and Rx();
And when i try to change it it will give errors that ican't assign a value type int to variable type RxInt.
Here is the code:
class StateController extends GetxController {
late String sunrise;
late String sunset;
late int temperatureDegree;
late int maxDegree;
late int minDegree;
late double windSpeed;
late int humidity;
void updateUI(dynamic weatherDataInput) {
sunrise = weatherDataInput["current"]["sunrise"];
sunset = weatherDataInput["current"]["sunset"];
temperatureDegree = weatherDataInput["current"]["temp"];
maxDegree = weatherDataInput["daily"][0]["temp"]["max"];
minDegree = weatherDataInput["daily"][0]["temp"]["min"];
windSpeed = weatherDataInput["current"]["wind_speed"];
humidity = weatherDataInput["current"]["humidity"];
}
}
try this way,
class NameController extends GetxController{
final sunrise = ''.obs;
void updateSomeText(){
sunrise('Text updated'); //or sunrise(weatherDataInput["current"]
//["sunrise"].toString());
}
}
then to update it try wrap it with Obx e.g.:
final controller = Get.put(NameController());
Obx(
()=> Text(controller.sunrise.value)
),
You can use the update() method in the end of the updateUI() like this:
void updateUI(dynamic weatherDataInput) {
sunrise = weatherDataInput["current"]["sunrise"];
sunset = weatherDataInput["current"]["sunset"];
temperatureDegree = weatherDataInput["current"]["temp"];
maxDegree = weatherDataInput["daily"][0]["temp"]["max"];
minDegree = weatherDataInput["daily"][0]["temp"]["min"];
windSpeed = weatherDataInput["current"]["wind_speed"];
humidity = weatherDataInput["current"]["humidity"];
update();
}
,
and then use GetBuilder in your UI, alternatively, you should declare your variables as Rx, for example:
RxString sunrise = "".obs;
RxString sunset = "".obs;
and use observer widget in your UI:
Obx(
()=> Text(controller.sunset.value)
)
This will update your UI automatically when observables (sunrise and sunset) change.
.

How to pass arguments to a function in flutter?

I am having the following function:
Future<List<expense>> getExpenseDateWise(DateTime FromDate, DateTime ToDate) async {
final db = await database;
var expenses = await db
.rawQuery('SELECT * FROM EXPENSES WHERE DATE(DATETIME) >= ? AND DATE(DATETIME) <= ?',
['$FromDate','$ToDate']);
List<expense> expensesList = List<expense>();
expenses.forEach((currentExpense) {
expense expenses = expense.fromMap(currentExpense);
expensesList.add(expenses);
});
return expensesList;
}
And the above function requires 2 arguments.
I am calling the above function in a following way:
class dateWiseList extends StatefulWidget {
final DateTime fromDate;
final DateTime toDate;
dateWiseList({this.fromDate, this.toDate});
#override
_dateWiseListState createState() => _dateWiseListState();
}
class _dateWiseListState extends State<dateWiseList> {
#override
void initState() {
super.initState();
DatabaseProvider.db.getExpenseDateWise(// <----------1----------> //).then(
(expenseList) {
BlocProvider.of<ExpenseBloc>(context).add(SetDates(expenseList));
},
);
}
In <----------1----------> I need to pass the two arguments. I don't know how to do it please help me.
The function getExpenseDateWise is used for fetching data records between two dates selected by the user in a different form. That's why I have called those values using dateWiseList({this.fromDate, this.toDate});.
Thanks for your replies
Try widget.fromDate and widget.toDate. Coz I'm seeing you're using a stateful widget.
If your function takes positional arguments, eg
Future doSomething(String name, Bool jerk) {
Lots of code
}
Then when calling it inside a stateful widget, while using some arguments you passed to that widget, do tgis
blah blah = doSomething(widget.argument1, widget.argument2)
If it's not positional arguments, eg
Future doSomething({String name, Bool jerk} ) {
Lots of code
}
, then it's gonna be
blah blah = doSomething(
name: widget.argument1, jerk: widget.argument2)
You just need to pass the starting date and the end date to filter your data
DateTime now = DateTime.now();
DtaeTime yesterday = DateTime.now().subtract(Duration(days:1));
DatabaseProvider.db.getExpenseDateWise(yesterday, now).then(.........)
you can treat flutter functions just like any other functions

How to pass data in a stateful widget with constructor?

I am new to flutter and I think I miss a little piece of information about constructor and stateful widget. I tried many ways but always have an error. I just want to pass data into my stateful widget to manipulate from there.
Here is my Error
The instance member 'widget' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
Here is my code
class CreateEducatorEventForm extends StatefulWidget {
final DateTime day = DateTime.now();
final String favoriteId = '';
CreateEducatorEventForm(DateTime day, String favoriteId);
#override
_CreateEducatorEventFormState createState() =>
_CreateEducatorEventFormState();
}
class _CreateEducatorEventFormState extends State<CreateEducatorEventForm> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
String _eventName = '';
String _eventDescription = '';
DateTime _eventDateStart = widget.day;
DateTime _eventDateFinish = widget.day;
You can just move it into initState
class _CreateEducatorEventFormState extends State<CreateEducatorEventForm> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
String _eventName = '';
String _eventDescription = '';
DateTime _eventDateStart;
DateTime _eventDateFinish;
#override
void initState() {
super.initState();
_eventDateStart = widget.day;
_eventDateFinish = widget.day;
}
}
To be fair, unless you really need to store this into your state (say, if it really participates in the lifecycle of your widget), you should just refer to it via widget.day whenever you need it.

How to test code that uses DateTime.now in Flutter?

I have this class:
import 'package:flutter/material.dart';
class AgeText extends StatelessWidget {
final String dateOfBirth;
const AgeText({Key key, #required this.dateOfBirth}) : super(key: key);
#override
Widget build(BuildContext context) {
final age = _calculateAge();
return Text(age.toString());
}
int _calculateAge() {
final dateOfBirthDate = DateTime.parse(dateOfBirth);
final difference = DateTime.now().difference(dateOfBirthDate);
final age = difference.inDays / 365;
return age.floor();
}
}
I'd like to test that it produces the correct age when a date of birth is passed into it. What is the best way to do this in Flutter?
SOLUTION: For those interested, here's the solution using #Günter Zöchbauer's suggestion of the clock package.
My widget class:
import 'package:flutter/material.dart';
import 'package:clock/clock.dart';
class AgeText extends StatelessWidget {
final String dateOfBirth;
final Clock clock;
const AgeText({Key key, #required this.dateOfBirth, this.clock = const Clock()}) : super(key: key);
#override
Widget build(BuildContext context) {
final age = _calculateAge();
return Text(age.toString());
}
int _calculateAge() {
final dateOfBirthDate = DateTime.parse(dateOfBirth);
final difference = clock.now().difference(dateOfBirthDate);
final age = difference.inDays / 365;
return age.floor();
}
}
and my test class:
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/age.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets("shows age 30 when date of birth is 30 years ago", (WidgetTester tester) async {
final mockClock = Clock.fixed(DateTime(2000, 01, 01));
final testableWidget = MaterialApp(
home: AgeText(
dateOfBirth: "1970-01-01T00:00:00",
clock: mockClock,
),
);
await tester.pumpWidget(testableWidget);
expect(find.text("30"), findsOneWidget);
});
}
As Günter said, the clock package, maintained by the Dart team, provides a very neat way to achieve this.
Normal usage:
import 'package:clock/clock.dart';
void main() {
// prints current date and time
print(clock.now());
}
Overriding the current time:
import 'package:clock/clock.dart';
void main() {
withClock(
Clock.fixed(DateTime(2000)),
() {
// always prints 2000-01-01 00:00:00.
print(clock.now());
},
);
}
I wrote about this in more detail on my blog.
For widget tests, you need to wrap pumpWidget, pump and expect in the withClock callback.
If you use the clock package for code depending on DateTime.now() you can easily mock it.
Other than creating a custom wrapper around DateTime.now(), I don't think there is a better way than what the clock package provides.
As mentioned here: https://stackoverflow.com/a/63073876/2235274 implement extension on DateTime.
extension CustomizableDateTime on DateTime {
static DateTime _customTime;
static DateTime get current {
return _customTime ?? DateTime.now();
}
static set customTime(DateTime customTime) {
_customTime = customTime;
}
}
Then just use CustomizableDateTime.current in the production code. You can modify the returned value in tests like that: CustomizableDateTime.customTime = DateTime.parse("1969-07-20 20:18:04");. There is no need to use third party libraries.