Flutter how to create a loop in else if - flutter

i got a chart that display months (in french) when i go below the month == 1, i would like to go back to my current month and not see my 'error'.
Is there a method to make it ?
String numericToStringMonth(int month) {
if (month < 1 || month > 12) {
return 'error';
} else if (month == 1) {
return 'Janvier';
} else if (month == 2) {
return 'Février';
} else if (month == 3) {
return 'Mars';
} else if (month == 4) {
return 'Avril';
} else if (month == 5) {
return 'Mai';
} else if (month == 6) {
return 'Juin';
} else if (month == 7) {
return 'Juillet';
} else if (month == 8) {
return 'Août';
} else if (month == 9) {
return 'Septembre';
} else if (month == 10) {
return 'Octobre';
} else if (month == 11) {
return 'Novembre';
} else if (month == 12) {
return 'Décembre';
} else {
return 'error';
}
}

String numericToStringMonth(int month) {
// make list of months for easier access
List<String> months = [
'Janvier',
'Février',
'Mars',
'Avril',
'Mai',
'Juin',
'Juillet',
'Août',
'Septembre',
'Octobre',
'Novembre',
'Décembre'
];
int currentMonth = month - 1;
try {
if (currentMonth > 11) {
throw Exception('Month must be between 1 and 12');
} else if (currentMonth < 0) {
// setting month to the first one when value goes below 0, add your logic here
currentMonth = 1;
}
return months[currentMonth];
} catch (e) {
print(e);
}
return '';
}

Related

Compare two time in flutter

I would like to compare last_uploaded_time with current time.
How to check whether the two time is more or less than one minute?
bool compareTime(String starts) {
print(starts);
var start = starts.split(":");
DateTime currentDateTime = DateTime.now();
String currentTime =
DateFormat(DateUtil.TIME_FORMAT).format(currentDateTime);
print(currentTime);
var end = currentTime.split(":");
DateTime initDateTime = DateTime(
currentDateTime.year, currentDateTime.month, currentDateTime.day);
var startDate = (initDateTime.add(Duration(hours: int.parse(start[0]))))
.add(Duration(minutes: int.parse(start[1])));
var endDate = (initDateTime.add(Duration(hours: int.parse(end[0]))))
.add(Duration(minutes: int.parse(end[1])));
if (currentDateTime.isBefore(endDate) &&
currentDateTime.isAfter(startDate)) {
print("CURRENT datetime is between START and END datetime");
return true;
} else {
print("NOT BETWEEN");
return false;
}
}
Output
I/flutter (12908): 01:16
I/flutter (12908): 01:40
I/flutter (12908): NOT BETWEEN
difference
not exactly working with minutes and seconds so you can use some custom algorithm like
import 'package:intl/intl.dart';
class IntelModel { static String timeSinceDate(DateTime date) {
final now = DateTime.now();
final difference = now.toLocal().difference(date.toLocal());
if ((now.day - date.day) >= 8) {
return 'A few weeks ago';
} else if ((now.day - date.day) >= 1) {
return '${(now.day - date.day)} days ago';
} else if (now.day == date.day) {
if (now.hour > date.hour) {
if ((now.hour - date.hour) >= 2) {
if (now.minute == date.minute) {
return '${(now.hour - date.hour)} hours ago';
} else {
var mins = now.minute - date.minute;
if (mins > 1) {
return '${(now.hour - date.hour)} h ${(now.minute - date.minute)} minutes ago';
} else {
return '${(now.hour - date.hour) - 1} h ${60 + mins} minutes ago';
}
}
} else if ((now.hour - date.hour) == 1) {
int timeMin = now.minute + (60 - date.minute);
if (timeMin == 60) {
return '1 hours ago';
} else if (timeMin >= 60) {
return '1 h ${timeMin - 60} mins ago';
} else {
return '$timeMin minutes ago';
}
}
} else if (now.hour == date.hour) {
if (now.minute > date.minute) {
return '${(now.minute - date.minute)} minutes ago';
} else if (date.minute == now.minute) {
return '${(now.second - date.second)} seconds ago';
}
}
} else {
return 'Error in time';
} } }
void main() {
String getDifference(DateTime date){
Duration duration = DateTime.now().difference(date);
String differenceInMinutes = (duration.inMinutes).toString();
return differenceInMinutes;
}
String str = getDifference(DateTime.parse('2021-09-24'));
print (str);
}
i tried above code on dartpad, you can use this to compare tow dateTime variables. As per above example, you can get more options to compare for eg duration.inDays,duration.inHours,duration.inSeconds etc.

Dart function no returning the expected value

I have created a function that receives a String date and returns a string that shows the time between the given date and the current DateTime in the format: x days ago, x months ago, just now, x years ago, yesterday, etc:
This is the code for that function:
String tiempoDesdeFecha(String dateString, {bool numericDates = true}) {
DateTime date = DateTime.parse(dateString);
final date2 = DateTime.now();
final difference = date2.difference(date);
if ((difference.inDays / 365).floor() >= 2) {
return "hace".tr()+'${(difference.inDays / 365).floor()}'+"yearsago".tr();
} else if ((difference.inDays / 365).floor() >= 1 ) {
return (numericDates) ? '1yearago'.tr() : 'lastyear'.tr()+" "+(numericDates).toString();
} else if ((difference.inDays / 30).floor() >= 2) {
return "hace".tr()+'${(difference.inDays / 365).floor()}'+"monthsago".tr();
} else if ((difference.inDays / 30).floor() >= 1) {
return (numericDates) ? '1monthago'.tr() : 'lastmonth'.tr();
} else if ((difference.inDays / 7).floor() >= 2) {
return "hace".tr()+'${(difference.inDays / 7).floor()}'+ 'weeksago'.tr();
} else if ((difference.inDays / 7).floor() >= 1) {
return (numericDates) ? "1weekago".tr() : 'lastweek'.tr();
} else if (difference.inDays >= 2) {
return "hace".tr()+'${difference.inDays}'+ 'daysago'.tr();
} else if (difference.inDays >= 1) {
return (numericDates) ? '1dayago'.tr() : 'yesterday'.tr();
} else if (difference.inHours >= 2) {
return "hace".tr()+'${difference.inHours}'+ 'hoursago'.tr();
} else if (difference.inHours >= 1) {
return (numericDates) ? '1hourago'.tr() : 'anhourago'.tr();
} else if (difference.inMinutes >= 2) {
return "hace".tr()+'${difference.inMinutes} ' +'minutesago'.tr();
} else if (difference.inMinutes >= 1) {
return (numericDates) ? '1minuteago'.tr() : 'aminuteago'.tr();
} else if (difference.inSeconds >= 3) {
return "hace".tr()+'${difference.inSeconds}'+ 'secondsago'.tr();
} else {
return 'justnow'.tr();
}
}
I have included the code to show the returned string in one of the four Locale I am using.
Everything is working fine, but the condition:
else if ((difference.inDays / 30).floor() >= 2) {
return "hace".tr()+'${(difference.inDays / 365).floor()}'+"monthsago".tr();
which is always returning 0 months ago.
I am calling the function from:
fecha_recibida = DateFormat('yyyy-MM-dd HH:mm',"en").format(date);
fecha_recibida = tiempoDesdeFecha(fecha_recibida);
I am testing that issue with following String date:
"2021-5-5 19:34"
What am I doing wrong?
I believe the error is in the returned string,
difference.inDays / 365 must be difference.inDays / 30.
So the condition should look like..
else if ((difference.inDays / 30).floor() >= 2) {
return "hace".tr()+'${(difference.inDays / 30).floor()}'+"monthsago".tr();
A plus, as #aman mentioned, you could use timeago package

Customized Picker of Flutter Datetime Picker

I'm trying to use customized datepicker with creating CustomPicker class as is on Readme.
The problem is the callback of onChanged and onConfirm does not return the updated date. However when I change DatePicker.showPicker to DatePicker.showDatePicker, the callback returns the correct date.
I'm using the following code. I spent hours to investigate this but no luck.
class CustomPicker extends CommonPickerModel {
CustomPicker({DateTime currentTime, LocaleType locale})
: super(locale: locale) {
this.currentTime = currentTime ?? DateTime.now();
}
String yearDigits(int value) {
return '$value';
}
String monthDigits(int value) {
return '$value';
}
#override
String leftStringAtIndex(int index) {
return index >= DateTime.now().year - 100 &&
index <= DateTime.now().year - 18
? '$index'
: null;
}
#override
String middleStringAtIndex(int index) {
return index <= 12 && index >= 1 ? monthDigits(index) : null;
}
#override
String rightStringAtIndex(int index) {
return null;
}
#override
String leftDivider() {
return '';
}
#override
String rightDivider() {
return '';
}
#override
List<int> layoutProportions() {
return [1, 1, 0];
}
#override
DateTime finalTime() {
return currentTime.isUtc
? DateTime.utc(currentTime.year, currentTime.month, 1, 0, 0, 0)
: DateTime(currentTime.month, currentTime.month, 1, 0, 0, 0);
}
}
DatePicker.showPicker(
// ↑ When I change this to DatePicker.showDatePicker
// and comment out pickerModel, the value of print(dateTime) gets selected value.
context,
showTitleActions: true,
onConfirm: (dateTime) {
print(dateTime); // output same value and not updated one
},
pickerModel: CustomPicker(
currentTime: DateTime(_birthYear, _birthMonth, 1),
),
locale: LocaleType.en
);
Okay. So I am not an expert with the Flutter DateTime Picker package but I needed it for a project and so needed to figure out a way for the custom picker, and here is how I solved it.
I realized the issue was with the finalTime() method and what it returns.
I checked the implementation on the package's Github - https://github.com/Realank/flutter_datetime_picker/blob/0b0be9623e905299befc10569f83f3bd11b36125/lib/src/date_model.dart#L494 and picked the sample model for both date & time. It still didn't work until I made sure to update the current left index and the current middle index.
I don't know if my approach is the best, but here is how I solved it.
Here is my solution:
I updated the _currentLeftIndex variable in the setLeftIndex() method:
void setLeftIndex(int index) {
print('left index: '+index.toString());
_currentLeftIndex = index;
....
and then updated the _currentMiddleIndex variable in the setMiddleIndex() method:
void setMiddleIndex(int index) {
print('middle index: '+index.toString());
_currentMiddleIndex = index;
....
Find the full code implementation below:
Note: Remember to import 'date_format.dart'.
...
import 'package:flutter_datetime_picker/src/date_format.dart';
class CustomPicker extends CommonPickerModel {
List<String> leftList;
List<String> middleList;
List<String> rightList;
DateTime currentTime;
int _currentLeftIndex;
int _currentMiddleIndex;
int _currentRightIndex;
LocaleType locale;
DateTime maxTime;
DateTime minTime;
CustomPicker({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale})
: super(locale: locale) {
this.currentTime = currentTime ?? DateTime.now();
_currentLeftIndex = 0;
_currentMiddleIndex = this.currentTime.hour;
_currentRightIndex = this.currentTime.minute;
this.setLeftIndex(0);
this.setMiddleIndex(this.currentTime.hour);
this.setRightIndex(this.currentTime.minute);
if (currentTime != null) {
this.currentTime = currentTime ?? DateTime.now();
if (maxTime != null &&
(currentTime.isBefore(maxTime) || currentTime.isAtSameMomentAs(maxTime))) {
this.maxTime = maxTime;
}
if (minTime != null &&
(currentTime.isAfter(minTime) || currentTime.isAtSameMomentAs(minTime))) {
this.minTime = minTime;
}
} else {
this.maxTime = maxTime;
this.minTime = minTime;
var now = DateTime.now();
if (this.minTime != null && this.minTime.isAfter(now)) {
this.currentTime = this.minTime;
} else if (this.maxTime != null && this.maxTime.isBefore(now)) {
this.currentTime = this.maxTime;
} else {
this.currentTime = now;
}
}
if (this.minTime != null && this.maxTime != null && this.maxTime.isBefore(this.minTime)) {
// invalid
this.minTime = null;
this.maxTime = null;
}
if (this.minTime != null && isAtSameDay(this.minTime, this.currentTime)) {
_currentMiddleIndex = this.currentTime.hour - this.minTime.hour;
if (_currentMiddleIndex == 0) {
_currentRightIndex = this.currentTime.minute - this.minTime.minute;
}
}
}
bool isAtSameDay(DateTime day1, DateTime day2) {
return day1 != null &&
day2 != null &&
day1.difference(day2).inDays == 0 &&
day1.day == day2.day;
}
#override
void setLeftIndex(int index) {
print('left index: '+index.toString());
_currentLeftIndex = index;
// TODO: implement setLeftIndex
super.setLeftIndex(index);
DateTime time = currentTime.add(Duration(days: index));
if (isAtSameDay(minTime, time)) {
var index = min(24 - minTime.hour - 1, _currentMiddleIndex);
this.setMiddleIndex(index);
} else if (isAtSameDay(maxTime, time)) {
var index = min(maxTime.hour, _currentMiddleIndex);
this.setMiddleIndex(index);
}
}
#override
void setMiddleIndex(int index) {
print('middle index: '+index.toString());
_currentMiddleIndex = index;
// TODO: implement setMiddleIndex
super.setMiddleIndex(index);
DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
if (isAtSameDay(minTime, time) && index == 0) {
var maxIndex = 60 - minTime.minute - 1;
if (_currentRightIndex > maxIndex) {
_currentRightIndex = maxIndex;
}
} else if (isAtSameDay(maxTime, time) && _currentMiddleIndex == maxTime.hour) {
var maxIndex = maxTime.minute;
if (_currentRightIndex > maxIndex) {
_currentRightIndex = maxIndex;
}
}
}
#override
String leftStringAtIndex(int index) {
print('left string index: '+index.toString());
DateTime time = currentTime.add(Duration(days: index));
if (minTime != null && time.isBefore(minTime) && !isAtSameDay(minTime, time)) {
return null;
} else if (maxTime != null && time.isAfter(maxTime) && !isAtSameDay(maxTime, time)) {
return null;
}
return formatDate(time, [ymdw], locale);
}
#override
String middleStringAtIndex(int index) {
print('middle string index: '+index.toString());
if (index >= 0 && index < 24) {
DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
if (isAtSameDay(minTime, time)) {
if (index >= 0 && index < 24 - minTime.hour) {
return digits(minTime.hour + index, 2);
} else {
return null;
}
} else if (isAtSameDay(maxTime, time)) {
if (index >= 0 && index <= maxTime.hour) {
return digits(index, 2);
} else {
return null;
}
}
return digits(index, 2);
}
return null;
}
#override
String rightStringAtIndex(int index) {
print('right string index: '+index.toString());
if (index >= 0 && index < 60) {
DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
if (isAtSameDay(minTime, time) && _currentMiddleIndex == 0) {
if (index >= 0 && index < 60 - minTime.minute) {
return digits(minTime.minute + index, 2);
} else {
return null;
}
} else if (isAtSameDay(maxTime, time) && _currentMiddleIndex >= maxTime.hour) {
if (index >= 0 && index <= maxTime.minute) {
return digits(index, 2);
} else {
return null;
}
}
return digits(index, 2);
}
return null;
}
#override
DateTime finalTime() {
print('all index: ');
print('left index: '+_currentLeftIndex.toString());
print('middle index: '+_currentMiddleIndex.toString());
print('right index: '+_currentRightIndex.toString());
DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
var hour = _currentMiddleIndex;
var minute = _currentRightIndex;
if (isAtSameDay(minTime, time)) {
hour += minTime.hour;
if (minTime.hour == hour) {
minute += minTime.minute;
}
}
return currentTime.isUtc
? DateTime.utc(time.year, time.month, time.day, hour, minute)
: DateTime(time.year, time.month, time.day, hour, minute);
}
#override
List<int> layoutProportions() {
return [4, 1, 1];
}
#override
String rightDivider() {
return ':';
}
}

Flutter TextField input validation for a date

I am trying to write a date input control which accepts a date like 23/12/1997. What I would like it to do is automatically insert the / characters for the user. So as they type in 23 the listener returns 23/, so that they can then type in 12. At this point the listener again adds a / leaving the user to complete the date by typing 1997.
My TextEditingController code half works and looks like this:
final _controller = TextEditingController();
_controller.addListener(() {
String text = _controller.text;
if (text.length == 2) {
text += '/';
}
if (text.length == 5) {
text += '/';
}
_controller.value = _controller.value.copyWith(
text: text,
selection:
TextSelection(baseOffset: text.length, extentOffset: text.length),
composing: TextRange.empty,
);
print(_controller.text);
}
So it works fine until the user makes a mistake and needs to backtrack. As soon as a / is deleted it is immediately replaced stopping any further editing of the date.
In order to get it to work I need to access is the previously entered text to determine if the user is backspacing. So if text == 23/ && previous_text == 23/1 then I can remove the / from text.
I found this question textfield must only accept numbers and I think it may help me, but I am not sure how to implement an existing widget and override its methods. Of course there may be a simpler way to do this within the TextEditingController?
I have found what I needed to solve my date validation input. It is not perfect, but it is good enough for what I am trying to do. All I needed was to look at the inputFormatters method of a TextField(). This allow manipulation of the input text to put it into any number of user-defined formats. I am including a segment of my code for anyone who would like to try it out:
class _DateFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue prevText, TextEditingValue currText) {
int selectionIndex;
// Get the previous and current input strings
String pText = prevText.text;
String cText = currText.text;
// Abbreviate lengths
int cLen = cText.length;
int pLen = pText.length;
if (cLen == 1) {
// Can only be 0, 1, 2 or 3
if (int.parse(cText) > 3) {
// Remove char
cText = '';
}
} else if (cLen == 2 && pLen == 1) {
// Days cannot be greater than 31
int dd = int.parse(cText.substring(0, 2));
if (dd == 0 || dd > 31) {
// Remove char
cText = cText.substring(0, 1);
} else {
// Add a / char
cText += '/';
}
} else if (cLen == 4) {
// Can only be 0 or 1
if (int.parse(cText.substring(3, 4)) > 1) {
// Remove char
cText = cText.substring(0, 3);
}
} else if (cLen == 5 && pLen == 4) {
// Month cannot be greater than 12
int mm = int.parse(cText.substring(3, 5));
if (mm == 0 || mm > 12) {
// Remove char
cText = cText.substring(0, 4);
} else {
// Add a / char
cText += '/';
}
} else if ((cLen == 3 && pLen == 4) || (cLen == 6 && pLen == 7)) {
// Remove / char
cText = cText.substring(0, cText.length - 1);
} else if (cLen == 3 && pLen == 2) {
if (int.parse(cText.substring(2, 3)) > 1) {
// Replace char
cText = cText.substring(0, 2) + '/';
} else {
// Insert / char
cText =
cText.substring(0, pLen) + '/' + cText.substring(pLen, pLen + 1);
}
} else if (cLen == 6 && pLen == 5) {
// Can only be 1 or 2 - if so insert a / char
int y1 = int.parse(cText.substring(5, 6));
if (y1 < 1 || y1 > 2) {
// Replace char
cText = cText.substring(0, 5) + '/';
} else {
// Insert / char
cText = cText.substring(0, 5) + '/' + cText.substring(5, 6);
}
} else if (cLen == 7) {
// Can only be 1 or 2
int y1 = int.parse(cText.substring(6, 7));
if (y1 < 1 || y1 > 2) {
// Remove char
cText = cText.substring(0, 6);
}
} else if (cLen == 8) {
// Can only be 19 or 20
int y2 = int.parse(cText.substring(6, 8));
if (y2 < 19 || y2 > 20) {
// Remove char
cText = cText.substring(0, 7);
}
}
selectionIndex = cText.length;
return TextEditingValue(
text: cText,
selection: TextSelection.collapsed(offset: selectionIndex),
);
}
}
To use it simply call it from the Textfield() as shown below. I've also incorporated two built in methods as well. WhitelistingTextInputFormatter() to only allow digits and a slash(/) character to be entered and LengthLimitingTextInputFormatter() to restrict the number of characters allowed. The latter could be achieved using the maxLength parameter of TextField() but it is here by way of example. Note that there is also a BlacklistingTextInputFormatter() which does as you would expect.
WhitelistingTextInputFormatter was removed use FilteringTextInputFormatter.allow(RegExp("[0-9-]")), to replace, and If you want to change split symbol (current is "/"), Pls add it to RegExp(....).
TextField(
// maxLength: 10,
keyboardType: TextInputType.datetime,
controller: _controllerDOB,
focusNode: _focusNodeDOB,
decoration: InputDecoration(
hintText: 'DD/MM/YYYY',
counterText: '',
),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp("[0-9/]")),
LengthLimitingTextInputFormatter(10),
_DateFormatter(),
],
),
You can use datepicker dialog made by flutter.
DateTime _date = DateTime.now()
onPressed: () {
showDatePicker(
context: context,
initialDate: _date,
firstDate: DateTime(2020),
lastDate: DateTime(2021),
).then((date) {
setState(() {
_date = date;
});
});
},
I find your code to be a great utility, without any dependencies. I took the liberty to do a few mods and thought of posting it back here, as I find your concept very neat and lightweight on the UI. The requirements were;
Validating the date for non-31-day months and leap years. The mods were quite straightforward.
Preventing the user entering "/" at undesirable places which will throw the algorithm off-track. The simplest solution is to make the
keyboardType: TextInputType.number, in the TextField
This works perfectly for mobile devices.
But Flutter being cross-platform, this solution may not be foolproof when it comes to a device with physical keyboard. I tried various checks and blocks but only partially succeeded; i.e, user can still input "/" in between the digits of the Day and Month. I think there is an internal delay between KB input and programmatic formatter.
Following is the modified code for _DateFormatter. I have used the /// notion to distinguish my comments. They should be read along with the original // comments.
class _DateFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue prevText, TextEditingValue currText) {
int selectionIndex;
String date;
String month;
int year;
// Get the previous and current input strings
String pText = prevText.text;
String cText = currText.text;
cText = cText.replaceAll("//", "/");
// Abbreviate lengths
int cLen = cText.length;
int pLen = pText.length;
/// ENTERING THE DATE
if (cLen == 1) {
/// User enters the first digit of the date. The first digit
// Can only be 0, 1, 2 or 3
if (int.parse(cText) > 3) {
// Remove char
cText = '';
}
} else if (cLen == 2 && pLen == 1) {
/// User has already entered a valid first digit of the date, now he
/// enters the second digit of the date; but
// Days cannot be greater than 31
int dd = int.parse(cText.substring(0, 2));
if (dd == 0 || dd > 31) {
// Remove char
cText = cText.substring(0, 1);
} else {
/// User has entered a valid date (between 1 and 31). So now,
// Add a / char
cText += '/';
}
/// ENTERING THE MONTH
} else if (cLen == 4) {
/// after entering a valid date and programmatic insertion of '/', now User has entered
/// the first digit of the Month. But, it
// Can only be 0 or 1
/// (and, not '/' either)
if (int.parse(cText.substring(3, 4)) > 1 || cText.substring(3, 4) == "/") {
// Remove char
cText = cText.substring(0, 3);
}
} else if (cLen == 5 && pLen == 4) {
int mm = int.parse(cText.substring(3, 5));
int dd = int.parse(cText.substring(0, 2));
/// User has entered the second digit of the Month, but the
// Month cannot be greater than 12
/// Also, that entry cannot be '/'
if ((mm == 0 || mm > 12|| cText.substring(3, 5) == "/") ||
/// If the date is 31, the month cannot be Apr, Jun, Sept or Nov
(dd == 31 && (mm == 02 || mm == 04 || mm == 06 || mm == 09 || mm == 11)) ||
/// If the date is greater than 29, the month cannot be Feb
/// (Leap years will be dealt with, when user enters the Year)
(dd > 29 && (mm == 02))) {
// Remove char
cText = cText.substring(0, 4);
}
else if (cText.length == 5) {
/// the Month entered is valid; so,
// Add a / char
cText += '/';
}
} else if ((cLen == 3 && pLen == 4) || (cLen == 6 && pLen == 7)) {
// Remove / char
cText = cText.substring(0, cText.length - 1);
} else if (cLen == 3 && pLen == 2) {
if (int.parse(cText.substring(2, 3)) > 1) {
// Replace char
cText = cText.substring(0, 2) + '/';
} else {
// Insert / char
cText =
cText.substring(0, pLen) + '/' + cText.substring(pLen, pLen + 1);
}
/// ENTERING THE YEAR
} else if (cLen == 6 && pLen == 5) {
// Can only be 1 or 2 - if so insert a / char
int y1 = int.parse(cText.substring(5, 6));
if (y1 < 1 || y1 > 2) {
// Replace char
/// i.e, add '/' after the 5th position
cText = cText.substring(0, 5) + '/';
} else {
// Insert / char
cText = cText.substring(0, 5) + '/' + cText.substring(5, 6);
}
} else if (cLen == 7) {
/// the first digit of year
// Can only be 1 or 2
int y1 = int.parse(cText.substring(6, 7));
if (y1 < 1 || y1 > 2) {
// Remove char
cText = cText.substring(0, 6);
}
} else if (cLen == 8) {
// Can only be 19 or 20
/// Also, there cannot be / typed by the user
String y2 = cText.substring(6, 8);
if (y2 != "19" && y2 != "20") {
// Remove char
cText = cText.substring(0, 7);
}
} else if (cLen == 9) {
/// There cannot be / typed by the user
if (cText.substring(8, 9) == "/") {
// Remove char
cText = cText.substring(0, 8);
}
} else if (cLen == 10) {
/// There cannot be / typed by the user
if (cText.substring(9, 10) == "/") {
// Remove char
cText = cText.substring(0, 9);
}
/// If the year entered is not a leap year but the date entered is February 29,
/// it will be advanced to the next valid date
date = cText.substring(0, 2);
month = cText.substring(3, 5);
year = int.parse(cText.substring(6, 10));
bool isNotLeapYear = !((year % 4 == 0) && (year % 100 != 0) ||
(year % 400 == 0));
if (isNotLeapYear && month == "02" && date == "29") {
cText = "01/03/$year";
}
}
selectionIndex = cText.length;
return TextEditingValue(
text: cText,
selection: TextSelection.collapsed(offset: selectionIndex),
);
}
} // END OF class _DateFormatter
I found one solution for this, But not an optimized solution, but it is covering almost all the scenarios,
forward slash during adding fields
remove the forward slash on clearing fields
in between editing handling... etc
class CustomDateTextFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var text = _format(newValue.text, '/', oldValue);
return newValue.copyWith(
text: text, selection: _updateCursorPosition(text, oldValue));
}
}
String _format(String value, String seperator, TextEditingValue old) {
var finalString = '';
var dd = '';
var mm = '';
var yyy = '';
var oldVal = old.text;
print('<------------------------- start---------------------------->');
print('oldVal -> $oldVal');
print('value -> $value');
var temp_oldVal = oldVal;
var temp_value = value;
if (!oldVal.contains(seperator) ||
oldVal.isEmpty ||
seperator.allMatches(oldVal).length < 2) {
oldVal += '///';
}
if (!value.contains(seperator) || _backSlashCount(value) < 2) {
value += '///';
}
var splitArrOLD = oldVal.split(seperator);
var splitArrNEW = value.split(seperator);
print('----> splitArrOLD: $splitArrOLD');
print('----> splitArrNEW: $splitArrNEW');
for (var i = 0; i < 3; i++) {
splitArrOLD[i] = splitArrOLD[i].toString().trim();
splitArrNEW[i] = splitArrNEW[i].toString().trim();
}
// block erasing
if ((splitArrOLD[0].isNotEmpty &&
splitArrOLD[2].isNotEmpty &&
splitArrOLD[1].isEmpty &&
temp_value.length < temp_oldVal.length &&
splitArrOLD[0] == splitArrNEW[0] &&
splitArrOLD[2].toString().trim() ==
splitArrNEW[1].toString().trim()) ||
(_backSlashCount(temp_oldVal) > _backSlashCount(temp_value) &&
splitArrNEW[1].length > 2) ||
(splitArrNEW[0].length > 2 && _backSlashCount(temp_oldVal) == 1) ||
(_backSlashCount(temp_oldVal) == 2 &&
_backSlashCount(temp_value) == 1 &&
splitArrNEW[0].length > splitArrOLD[0].length)) {
finalString = temp_oldVal; // making the old date as it is
print('blocked finalString : $finalString ');
} else {
if (splitArrNEW[0].length > splitArrOLD[0].length) {
if (splitArrNEW[0].length < 3) {
dd = splitArrNEW[0];
} else {
for (var i = 0; i < 2; i++) {
dd += splitArrNEW[0][i];
}
}
if (dd.length == 2 && !dd.contains(seperator)) {
dd += seperator;
}
} else if (splitArrNEW[0].length == splitArrOLD[0].length) {
print('splitArrNEW[0].length == 2');
if (oldVal.length > value.length && splitArrNEW[1].isEmpty) {
dd = splitArrNEW[0];
} else {
dd = splitArrNEW[0] + seperator;
}
} else if (splitArrNEW[0].length < splitArrOLD[0].length) {
print('splitArrNEW[0].length < splitArrOLD[0].length');
if (oldVal.length > value.length &&
splitArrNEW[1].isEmpty &&
splitArrNEW[0].isNotEmpty) {
dd = splitArrNEW[0];
} else if (temp_oldVal.length > temp_value.length &&
splitArrNEW[0].isEmpty &&
_backSlashCount(temp_value) == 2) {
dd += seperator;
} else {
if (splitArrNEW[0].isNotEmpty) {
dd = splitArrNEW[0] + seperator;
}
}
}
print('dd value --> $dd');
if (dd.isNotEmpty) {
finalString = dd;
if (dd.length == 2 &&
!dd.contains(seperator) &&
oldVal.length < value.length &&
splitArrNEW[1].isNotEmpty) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
} else if (splitArrNEW[2].isNotEmpty &&
splitArrNEW[1].isEmpty &&
temp_oldVal.length > temp_value.length) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
} else if (oldVal.length < value.length &&
(splitArrNEW[1].isNotEmpty || splitArrNEW[2].isNotEmpty)) {
if (seperator.allMatches(dd).isEmpty) {
finalString += seperator;
}
}
} else if (_backSlashCount(temp_oldVal) == 2 && splitArrNEW[1].isNotEmpty) {
dd += seperator;
}
print('finalString after dd=> $finalString');
if (splitArrNEW[0].length == 3 && splitArrOLD[1].isEmpty) {
mm = splitArrNEW[0][2];
}
if (splitArrNEW[1].length > splitArrOLD[1].length) {
print('splitArrNEW[1].length > splitArrOLD[1].length');
if (splitArrNEW[1].length < 3) {
mm = splitArrNEW[1];
} else {
for (var i = 0; i < 2; i++) {
mm += splitArrNEW[1][i];
}
}
if (mm.length == 2 && !mm.contains(seperator)) {
mm += seperator;
}
} else if (splitArrNEW[1].length == splitArrOLD[1].length) {
print('splitArrNEW[1].length = splitArrOLD[1].length');
if (splitArrNEW[1].isNotEmpty) {
mm = splitArrNEW[1];
}
} else if (splitArrNEW[1].length < splitArrOLD[1].length) {
print('splitArrNEW[1].length < splitArrOLD[1].length');
if (splitArrNEW[1].isNotEmpty) {
mm = splitArrNEW[1] + seperator;
}
}
print('mm value --> $mm');
if (mm.isNotEmpty) {
finalString += mm;
if (mm.length == 2 && !mm.contains(seperator)) {
if (temp_oldVal.length < temp_value.length) {
finalString += seperator;
}
}
}
print('finalString after mm=> $finalString');
if (splitArrNEW[1].length == 3 && splitArrOLD[2].isEmpty) {
yyy = splitArrNEW[1][2];
}
if (splitArrNEW[2].length > splitArrOLD[2].length) {
print('splitArrNEW[2].length > splitArrOLD[2].length');
if (splitArrNEW[2].length < 5) {
yyy = splitArrNEW[2];
} else {
for (var i = 0; i < 4; i++) {
yyy += splitArrNEW[2][i];
}
}
} else if (splitArrNEW[2].length == splitArrOLD[2].length) {
print('splitArrNEW[2].length == splitArrOLD[2].length');
if (splitArrNEW[2].isNotEmpty) {
yyy = splitArrNEW[2];
}
} else if (splitArrNEW[2].length < splitArrOLD[2].length) {
print('splitArrNEW[2].length < splitArrOLD[2].length');
yyy = splitArrNEW[2];
}
print('yyy value --> $yyy');
if (yyy.isNotEmpty) {
if (_backSlashCount(finalString) < 2) {
if (splitArrNEW[0].isEmpty && splitArrNEW[1].isEmpty) {
finalString = seperator + seperator + yyy;
} else {
finalString = finalString + seperator + yyy;
}
} else {
finalString += yyy;
}
} else {
if (_backSlashCount(finalString) > 1 && oldVal.length > value.length) {
var valueUpdate = finalString.split(seperator);
finalString = valueUpdate[0] + seperator + valueUpdate[1];
}
}
print('finalString after yyyy=> $finalString');
}
print('<------------------------- finish---------------------------->');
return finalString;
}
TextSelection _updateCursorPosition(String text, TextEditingValue oldValue) {
var endOffset = max(
oldValue.text.length - oldValue.selection.end,
0,
);
var selectionEnd = text.length - endOffset;
print('My log ---> $selectionEnd');
return TextSelection.fromPosition(TextPosition(offset: selectionEnd));
}
int _backSlashCount(String value) {
return '/'.allMatches(value).length;
}
We can Use our custom formator as in inputFormatters like below
TextField(
// maxLength: 10,
keyboardType: TextInputType.datetime,
controller: _controllerDOB,
focusNode: _focusNodeDOB,
decoration: InputDecoration(
hintText: 'DD/MM/YYYY',
counterText: '',
),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp("[0-9/]")),
LengthLimitingTextInputFormatter(10),
CustomDateTextFormatter(),
],
),
try out this solution.

How can I show greetings like Good Moring, afternoon or evening base on users time in flutter

I want to greet user when they visit my app
I have tried using TimeOfDay but it isn't working.
TimeOfDay now = TimeOfDay.now();
greetings(String greeting){
var greeting = now;
if(greeting <= '11: 59'){
return 'Morning';
} else if (greeting > '11:59' && <= '16:59'){
return 'Afternoon';
} else if (greeting > '16:59' && <= '23:59'){
return 'Afternoon';
} else {
return 'Morning';
}
}
Try using DateTime.now(), for example:
String greeting() {
var hour = DateTime.now().hour;
if (hour < 12) {
return 'Morning';
}
if (hour < 17) {
return 'Afternoon';
}
return 'Evening';
}
TimeOfDay.now().period;
// This will return DayPeriod.am or DayPeriod.pm, you can show the greeting message accordingly
Link: https://api.flutter.dev/flutter/material/TimeOfDay/period.html
import 'package:flutter/material.dart';
void main(){
TimeOfDay day = TimeOfDay.now();
switch(day.period){
case DayPeriod.am: print('its morning');
break;
case DayPeriod.pm: print('its evening/night');
}
}
You are using TimeOfDay in wrong way. Your code should work if you use it properly.
String greetings(){
final hour = TimeOfDay.now().hour;
if(hour <= 12){
return 'Morning';
} else if (hour <= 17){
return 'Afternoon';
}
return 'Evening';
}