how to change the way DatePicker shows Date - flutter

I want to change the way DatePicker shows the Date, so that it shows
day/month/year. As of right now it shows in the format of year/month/day and I'm not sure on how to change this. I've been searching a lot but couldn't find the right way to do this.
I will show my code below, hopefully someone can help me :D
Thank you in Advance guys.
class WFDatePickerField extends DateTimeField {
final bool? hasError;
final bool hasErrorDecoration;
final double? errorHeight;
final dynamic error;
final DateTimeValue value;
final TextStyle? errorStyle;
WFDatePickerField(
{Key? key,
required this.value,
required String labelText,
String hintText = '',
TextEditingController? controller,
FormFieldValidator<DateTime>? validator,
FloatingLabelBehavior? floatingLabelBehavior =
FloatingLabelBehavior.never,
String format = 'dd.MM.yyyy',
final InputDecoration? decoration,
this.errorStyle,
this.hasError,
this.hasErrorDecoration=false,
this.error,
this.errorHeight})
: super(
key: key,
decoration: ErrorDecorationSelector(hasError, hasErrorDecoration, errorHeight, error, value, errorStyle).getDecoration(),
readOnly: true,
style: AppTheme()
.textStyles
.bodyText1!
.copyWith(color: Colors.white.withOpacity(0.5)),
initialValue: value.value,
format: DateFormat('dd/MM/yyyy'),
controller: controller,
validator: validator,
onShowPicker: (context, currentValue) async {
DateTime? newDate;
String? deviceLocale = await (Devicelocale.currentLocale);
LocaleType locale =
deviceLocale != null && deviceLocale.contains('de')
? LocaleType.de
: LocaleType.en;
await DatePicker.showDatePicker(context,
minTime: DateTime(1900, 1, 1),
maxTime: DateTime(DateTime.now().year - 18,
DateTime.now().month, DateTime.now().day),
locale: locale,
onConfirm: (date) => newDate = date);
return newDate;
},
onChanged: (newValue) {
value.value = newValue;
},
);
}

if I'M not mistaken your trying to format the date if that is what you're asking
[enter link description here][1]
// Use this link it is flutter intl dateFormater it has different style
[1]: https://pub.dev/packages/intl

Related

the events aren't showing on dates of Calendar initially?

The calendar is working fine, but the problem is whenever I change the month the events aren't visible on the calendar dates. but it appears after I click on any date. can anyone explain what is going wrong here?
Full Calendar Widget implementation
Calendar(
initialDate: month2,
startOnMonday: false,
onMonthChanged: (m) => {
print("onMonthChanged called: " + m.month.toString()),
print(month2),
if (m.month != month2.month)
{
setState(() {
month2 = m;
year2 = m.year;
eventsMap();
}),
events.clear(),
}
},
selectedColor: Colors.blue,
todayColor: Colors.red,
eventColor: Colors.green,
eventDoneColor: Colors.amber,
bottomBarColor: Colors.deepOrange,
events: events,
isExpanded: true,
dayOfWeekStyle: TextStyle(
fontSize: 12,
color: Colors.blueGrey,
fontWeight: FontWeight.bold,
),
bottomBarTextStyle: TextStyle(
color: Colors.white,
),
hideArrows: false,
weekDays: const ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
)
I'm using a calendar widget that displays events on dates in a dot form and also in a form of a list just below it. When I change the month it triggers an onMonthChanged event and fetches the events to display. The only problem I'm having is that Initially, the events aren't showing on dates but after I click on any date, then it shows the events. So, in short, the problem is events aren't displayed initially.
onMonthChanged property implementation
onMonthChanged: (m) => {
print("onMonthChanged called: " + m.month.toString()),
if (m.month != month2)
{
setState(() {
month2 = m.month;
year2 = m.year;
eventsMap();
}),
events.clear(),
}
},
Calendar class
class Calendar extends StatefulWidget {
final ValueChanged<DateTime>? onDateSelected;
final ValueChanged<DateTime>? onMonthChanged;
final ValueChanged<bool>? onExpandStateChanged;
final ValueChanged? onRangeSelected;
final ValueChanged<CleanCalendarEvent>? onEventSelected;
final bool isExpandable;
final DayBuilder? dayBuilder;
final EventListBuilder? eventListBuilder;
final bool hideArrows;
final bool hideTodayIcon;
final Map<DateTime, List<CleanCalendarEvent>>? events;
final Color? selectedColor;
final Color? todayColor;
final String todayButtonText;
final Color? eventColor;
final Color? eventDoneColor;
final DateTime? initialDate;
final bool isExpanded;
final List<String> weekDays;
final String? locale;
final bool startOnMonday;
final bool hideBottomBar;
final TextStyle? dayOfWeekStyle;
final TextStyle? bottomBarTextStyle;
final Color? bottomBarArrowColor;
final Color? bottomBarColor;
final String? expandableDateFormat;
}
provide Date and Time object to
initialDate
parameter
you are using on month changed callback so you have to use onselecteddate callback

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 create a common component in development using riverpod?

I use riverpod for state management in flutter development.
I'm now trying to create a common component that needs state management.
I use riverpod to make a common component with like the following code.
class InputTextareaModel with ChangeNotifier {
String text;
String error;
String Function(String text) _validator;
void Function(String text) _onChanged;
bool _autoValidation;
set validator(String Function(String text) validator) {
this._validator = validator ?? (String text) => null;
}
set onChanged(void Function(String text) onChanged) {
this._onChanged = onChanged ?? (String text) {};
}
set autoValidation(bool autoValidation) {
this._autoValidation = autoValidation ?? true;
}
InputTextareaModel() {
this.text = '';
this.error = null;
}
onChangedText(String value) {
this.text = value;
this._onChanged(value);
if (this._autoValidation) {
this.onValidation();
}
notifyListeners();
}
onValidation() {
this.error = this._validator(this.text);
notifyListeners();
}
bool isError() {
return this.error != null ? true : false;
}
}
class InputTextarea extends HookWidget {
final String label;
final int minLines;
final int maxLines;
final String placeholder;
final provider;
final String Function(String text) validator;
final void Function(String text) onChanged;
final bool autoValidation;
InputTextarea(
{Key key,
this.label,
this.placeholder,
provider,
this.validator,
this.onChanged,
this.autoValidation,
this.minLines = 3,
this.maxLines = 5})
: this.provider =
provider ?? ChangeNotifierProvider((_) => InputTextareaModel()),
super(key: key);
#override
Widget build(BuildContext context) {
final inputTextareaModel = useProvider<InputTextareaModel>(provider);
inputTextareaModel.validator = this.validator;
inputTextareaModel.onChanged = this.onChanged;
inputTextareaModel.autoValidation = this.autoValidation;
return TextField(
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: this.label,
hintText: this.placeholder,
errorText: inputTextareaModel.error,
border: OutlineInputBorder(),
),
keyboardType: TextInputType.multiline,
minLines: this.minLines,
maxLines: this.maxLines,
onChanged: (value) {
inputTextareaModel.onChangedText(value);
},
);
}
}
And I'm calling this common component with code like this:
final messageProvider =
ChangeNotifierProvider.autoDispose((_) => InputTextareaModel());
InputTextarea(
minLines: 5,
label: "message",
placeholder: "test",
provider: messageProvider, // We are injecting the provider at here.
validator: (value) {
if (value.replaceAll("\n", "").isEmpty) {
return 'required message!';
}
return null;
},
),
I can create a common component this way too, but I'm not quite happy with it.
I feel that there is a better way to create common components using riverpod.
Or is it better to create it using statefulWidget etc. without using riverpod?
If you know any good way, please let me know!
Thank you.

How to change color of particular text in a text field dynamically?

Consider bellow image, I want to dynamically change the text color of part of the text based on the user input text (not the whole text) in a text field. How can i do that in flutter?
For this example we actually don't need a full blown rich-text editor.
I had a similar goal in my app to highlight tags (#flutter) or date references (next week, on Friday, etc) and I was able to implement this by extending built-in EditableText widget and posted my example as a Gist here: https://gist.github.com/pulyaevskiy/d7af7217c2e71f31dfb78699f91dfbb5
Below is full implementation of this widget which I called AnnotatedEditableText.
There is new property annotations which describes ranges of text that need to be highlighted and their style.
import 'package:flutter/widgets.dart';
class Annotation extends Comparable<Annotation> {
Annotation({#required this.range, this.style});
final TextRange range;
final TextStyle style;
#override
int compareTo(Annotation other) {
return range.start.compareTo(other.range.start);
}
#override
String toString() {
return 'Annotation(range:$range, style:$style)';
}
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
TextSelectionControls selectionControls,
this.annotations,
}) : super(
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: true,
autofocus: true,
selectionColor: selectionColor,
selectionControls: selectionControls,
onChanged: onChanged,
onSubmitted: onSubmitted,
);
final List<Annotation> annotations;
#override
AnnotatedEditableTextState createState() => new AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
#override
AnnotatedEditableText get widget => super.widget;
List<Annotation> getRanges() {
var source = widget.annotations;
source.sort();
var result = new List<Annotation>();
Annotation prev;
for (var item in source) {
if (prev == null) {
// First item, check if we need one before it.
if (item.range.start > 0) {
result.add(new Annotation(
range: TextRange(start: 0, end: item.range.start),
));
}
result.add(item);
prev = item;
continue;
} else {
// Consequent item, check if there is a gap between.
if (prev.range.end > item.range.start) {
// Invalid ranges
throw new StateError(
'Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
));
}
// Also add current annotation
result.add(item);
prev = item;
}
}
// Also check for trailing range
final String text = textEditingValue.text;
if (result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
));
}
return result;
}
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
if (widget.annotations != null) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
Rich text controller works fine!
See more on https://pub.dev/packages/rich_text_controller
First you choose your RegExp
RichTextController _controller;
Map<RegExp, TextStyle> patternUser = {
RegExp(r"\B#[a-zA-Z0-9]+\b"):
TextStyle(color: Colors.amber, fontWeight: FontWeight.bold)
};
on initState()
_controller = RichTextController(
patternMap: patternUser,
);
Add controller on your TextFormField
TextFormField(
controller: _controller,
style: TextStyle(color: Colors.white),
)

Style part of text in TextField

I'm implementing a custom text field and I would like to style certain keywords (namely hashtags) differently than the rest of the text as the user type them in.
Kind of like this:
Is there a way to do that in Flutter ?
This question is very similar to How to change color of particular text in a text field dynamically?
I answered it there in: https://stackoverflow.com/a/57846261/5280562
In short: you can extend EditableText widget including its EditableTextState class and override buildTextSpan method.
Below is a working example called AnnotatedEditableText that I use in my app.
You need to supply a list of Annotation objects which describe which ranges of text need to be highlighted and what style to use.
import 'package:flutter/widgets.dart';
class Annotation extends Comparable<Annotation> {
Annotation({#required this.range, this.style});
final TextRange range;
final TextStyle style;
#override
int compareTo(Annotation other) {
return range.start.compareTo(other.range.start);
}
#override
String toString() {
return 'Annotation(range:$range, style:$style)';
}
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
TextSelectionControls selectionControls,
this.annotations,
}) : super(
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: true,
autofocus: true,
selectionColor: selectionColor,
selectionControls: selectionControls,
onChanged: onChanged,
onSubmitted: onSubmitted,
);
final List<Annotation> annotations;
#override
AnnotatedEditableTextState createState() => new AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
#override
AnnotatedEditableText get widget => super.widget;
List<Annotation> getRanges() {
var source = widget.annotations;
source.sort();
var result = new List<Annotation>();
Annotation prev;
for (var item in source) {
if (prev == null) {
// First item, check if we need one before it.
if (item.range.start > 0) {
result.add(new Annotation(
range: TextRange(start: 0, end: item.range.start),
));
}
result.add(item);
prev = item;
continue;
} else {
// Consequent item, check if there is a gap between.
if (prev.range.end > item.range.start) {
// Invalid ranges
throw new StateError(
'Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
));
}
// Also add current annotation
result.add(item);
prev = item;
}
}
// Also check for trailing range
final String text = textEditingValue.text;
if (result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
));
}
return result;
}
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
if (widget.annotations != null) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
It's also available in this Gist: https://gist.github.com/pulyaevskiy/d7af7217c2e71f31dfb78699f91dfbb5
I actually had the same problem and found the AnnotatedEditbleText which helped me a lot.
I published the helpful package to solve this kind of problem.
https://pub.dev/packages/hashtagable
The TextField does not provide that functionality.
https://pub.dartlang.org/packages/zefyr can do that though.
I think there are some more ''hard'' ways to do this
The first one:
Make a row widget, add a part of the String until the word you want to highlight, add the special word, style it and add the rest of your string.
Or, you could try RichText
Günter post it about the zefyr package, I didn't use it yet, but if suits you, I'll be glad that helped