Flutter get date format from locale to show as hint text - flutter

I have a form text field for which on tap I'm showing the flutter's datepicker. Currently I'm showing the hint text with hard coded value.
But now I have decided to format the date based on the selected locale and hence I'm passing the local information to ShowDatePicker. How can I show the date format based on the selected locale as hint text in the text field by removing hard coded value?
Ex:
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: TextField(
label: label,
hintText: 'MM-dd-yyyy', //Get the format based on selected local to show as hint
controller: selectedDate,
onTap: () async {
final DateTime? pickedDate = await _getSelectedDate(context);
if (pickedDate != null) {
selectedDate?.text = DateFormat('MM-dd-yyyy')
.format(pickedDate)
.toString();
}
},
),
),
],
);
}
Future<DateTime?> _getSelectedDate(BuildContext context) {
return showDatePicker(
context: context,
locale: context.currentLocale, // Selected locale being passed to showDatePicker
initialDate: DateTime.now(),
firstDate: firstDate,
lastDate: lastDate,
}

First of all get the package for it:
intl: ^0.17.0
import
import 'package:intl/intl.dart';
Define a variable like this:
final DateFormat formatter = DateFormat('MM-dd-yyyy');
hintText:"${formatter.format(DateTime.now())}"
This will show date as hint like this:
02-22-2022(mm-dd-yyyy)

Related

Validate date of birth in Flutter

I've created a form using Flutter which has date picker.
User is supposed to pick his/her date of birth using it to make sure if the user is 16 and above. How do I validate date of birth to age 16?
Here are the parts of the code:
class _WelcomeScreenState extends State<WelcomeScreen> {
TextEditingController dateinput = TextEditingController();
final formKey = GlobalKey<FormState>();
String name = "";
#override
void initState() {
dateinput.text = ""; //set the initial value of text field
super.initState();
}
--
GestureDetector(
child: TextField(
style: TextStyle(color: Colors.white),
controller:
dateinput, //editing controller of this TextField
decoration: InputDecoration(
labelStyle: TextStyle(color: Colors.white),
icon: Icon(Icons.calendar_today),
iconColor: Colors.white, //icon of text field
labelText: "Enter Date Of Birth" //label text of field
),
readOnly:
true, //set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(
1900), //DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2040));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('dd-MM-yyyy').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
//you can implement different kind of Date Format here according to your requirement
setState(() {
dateinput.text =
formattedDate; //set output date to TextField value.
});
} else {
print("Date is not selected");
}
},
),
),
A naive approach would be to just construct a DateTime object from the selected birth date and to then compute DateTime.now().difference(birthDate).inDays / 365. That doesn't account for leap days, and maybe it's close enough, but it's not how a human would compute age.
When attempting to solve a programming problem, one of the first things you usually should ask yourself is: How would you solve this without a computer?
To determine if someone is at least 16 years old, you would take the current date, subtract 16 from the year, use the same month and day1, and see if their birthday is on or before that date, ignoring the time. So just do that:
extension IsAtLeastYearsOld on DateTime {
bool isAtLeastYearsOld(int years) {
var now = DateTime.now();
var boundaryDate = DateTime(now.year - years, now.month, now.day);
// Discard the time from [this].
var thisDate = DateTime(year, month, day);
// Did [thisDate] occur on or before [boundaryDate]?
return thisDate.compareTo(boundaryDate) <= 0;
}
}
void main() {
// The results below were obtained with 2022-06-11 as the current date.
print(DateTime(2006, 6, 10).isAtLeastYearsOld(16)); // Prints: true
print(DateTime(2006, 6, 11).isAtLeastYearsOld(16)); // Prints: true
print(DateTime(2006, 6, 12).isAtLeastYearsOld(16)); // Prints: false
}
1 This should be fine even if the current date is a leap day since DateTime will convert February 29 into March 1 for non-leap years.
With a function for calculate :
class _WelcomeScreenState extends State<WelcomeScreen> {
TextEditingController dateinput = TextEditingController();
final formKey = GlobalKey<FormState>();
String name = "";
#override
void initState() {
dateinput.text = ""; //set the initial value of text field
super.initState();
}
int calculateAge(DateTime birthDate) {
DateTime currentDate = DateTime.now();
int age = currentDate.year - birthDate.year;
if (birthDate.month > currentDate.month) {
age--;
} else if (currentDate.month == birthDate.month) {
if (birthDate.day > currentDate.day) {
age--;
}
}
return age;
}
}
And in your TextField :
GestureDetector(
child: TextFormField(
style: TextStyle(color: Colors.white),
controller: dateinput, //editing controller of this TextField
decoration: InputDecoration(
labelStyle: TextStyle(color: Colors.white),
icon: Icon(Icons.calendar_today),
iconColor: Colors.white, //icon of text field
labelText: "Enter Date Of Birth" //label text of field
),
readOnly: true, //set it true, so that user will not able to edit text
validator: (value) {
if (calculateAge(DateTime.parse(value)) < 16 || value.isEmpty) {
return 'Please enter date.';
}
return null;
},
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1900), //DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2040));
if (pickedDate != null) {
print(pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate = DateFormat('dd-MM-yyyy').format(pickedDate);
print(formattedDate); //formatted date output using intl package => 2021-03-16
//you can implement different kind of Date Format here according to your requirement
setState(() => dateinput.text = formattedDate);
} else {
print("Date is not selected");
}
},
),
),

How can I update the date on the bottom sheet when I have finished selecting the date picker?

I need to update the date display on bottom sheet when I select date on date picker of another bottom sheet, please help me.
date picker
need update date text
You must use StatefulWidget in bottom sheet. With this widget you can setstate in your bottom sheet.
Example usage: https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html
//used library
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
//declare variables
String hourOfPeriod = "AM";
String hour = "00";
TimeOfDay _time = TimeOfDay(hour: 00, minute: 00);
NumberFormat f = NumberFormat("00", "en_US");
//for displaying TimePicker
void _selectTime() async {
final TimeOfDay? newTime = await showTimePicker(
context: context,
initialTime: _time,
helpText: "RESCHEDULE TIME",
);
if (newTime != null) {
setState(() {
_time = newTime;
hourOfPeriod = _time.period == DayPeriod.pm ? "PM" : "AM";
});
}
}
//code inside build(BuildContext context)
InkWell(
onTap: () {
_selectTime();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("${f.format(_time.hourOfPeriod)}:"),
Text("${f.format(_time.minute)}"),
Text("$hourOfPeriod")
],
),
)
//Output Format: HH:MM AM/PM

TimePicker output not showing the picket time correctly

I need to get a time from a timepicker and show it on a text widget.
Here you have the widget that should show the time:
pickedTime = TimeOfDay.now();
ListTile(
title: Text(
" ${pickedTime.hour}:${pickedTime.minute}"),
trailing: Icon(Icons.timer,size: 45,),
onTap: _pickTime,
),
And here you have the function _pickTime:
_pickTime() async{
TimeOfDay time = await showTimePicker(
context: context,
initialTime: pickedTime);
setState(() {
pickedTime = time;
});
}
I have detected an issue when the picked time hour or minute is smaller than 10, the output is as shown in the picture for 04:05:
I would like to show the picked time always in format HH:mm.
The following is an extension on the int class that you can use to enforce two characters for each part of the time:
extension TwoChar on int {
String toTwoChars() {
return this.toString().padLeft(2, '0');
}
}
Then modify your code to use the extension:
title: Text("${pickedTime.hour.toTwoChars()}:${pickedTime.minute.toTwoChars()}"),

Edit flutter BasicTimeField

I added in my code this class:
class BasicTimeField extends StatelessWidget {
final format = asd.DateFormat("HH:mm");
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
Text('Basic time field (${format.pattern})'),
DateTimeField(
format: format,
onShowPicker: (context, currentValue) async {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(currentValue ?? DateTime.now()),
);
return DateTimeField.convert(time);
},
),
]);
}}
And it is taken from this website:
https://pub.dev/packages/datetime_picker_formfield
I want to change the heights and border-radius of the time popup but I don't know from where I can do this. Where can I customize all the details of the widget?
You can change the dart_picker_dialog.dart file of the package. But it is not recommended as they mentioned in that comment line.
// Constrain the textScaleFactor to the largest supported value to prevent
// layout issues.
final double textScaleFactor = math.min(MediaQuery.of(context).textScaleFactor, 1.3);
Later, the textScaleFactor will be used to calculate the dialogSize.
final Size dialogSize = _dialogSize(context) * textScaleFactor;
For more, you can look here.

Reuse Datepicker for different field values

I'm trying to make my datepicker reusable, as I need three datepickers, that change different values that are stored in the same class, lets call it _object.date1 , date 2, date 3
To reuse my datepicker I tried the following and passed the variable to the datepicker that shall be changed. But then the field value isn't changed or stored and nothing happens, also no error. If I don't pass the value to _showAndroidDatePicker() and use the line in setState that I commented out below, it works properly. The Datepicker ist linked to the onTap of a TextFormField in a Form.
Can anyone explain to me what I'm missing here? It would be really great to make this reusable.
Many thanks!
void _showAndroidDatePicker(value) {
showDatePicker(
context: context,
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
primaryColor: Theme.of(context).primaryColor,
accentColor: Theme.of(context).primaryColor,
colorScheme:
ColorScheme.light(primary: Theme.of(context).primaryColor),
buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
),
child: child,
);
},
initialDate: DateTime.now(),
locale: Locale('de'),
firstDate: DateTime(1900),
helpText: 'Bitte wähle ein Datum aus',
lastDate: DateTime.now(),
).then<DateTime>(
(DateTime newDate) {
if (newDate != null) {
setState(() {
value = newDate.toIso8601String();
//Below code works if value isn't passed to datepicker, but I want it variable to avoid boilerplate
// _object.date1 =newDate.toIso8601String();
});
}
return;
},
);
}
Many thanks for your help!
You could pass it the controller and the focus node for the text field. Something like this:
datePickerListener(node, controller) {
if (node.hasFocus) {
node.unfocus();
showDatePicker(your setup).then((date){
var formatter = DateFormat('dd/MM/yyyy');
var formatted = formatter.format(date).toString();
controller.text = formatted;
});
}
}
Then:
FocusNode yourNode = FocusNode();
#override
void initState(){
yourNode.addListener(){
datePickerListener(yourNode, yourController);
};
}
TextFormField(
focusNode: yourNode,
controller: yourController,
)
Something like that. Just adjust to your needs.