fix: twelve hour parsing issue (#4721)

* fix: twelve hour time format fixed

* fix: time format for 12hour

* feat: auto capitalize am-pm in formatter

* fix: time field placeholder based on user time format

* chore: bugfix + improvements

---------

Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
Ansah Mohammad 2024-04-08 07:03:18 +05:30 committed by GitHub
parent 9536cde789
commit 47d321b8c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 119 additions and 78 deletions

View File

@ -258,11 +258,11 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
} }
DateTime _parseTime(String timeStr, UserTimeFormatPB timeFormat) { DateTime _parseTime(String timeStr, UserTimeFormatPB timeFormat) {
final twelveHourFormat = DateFormat('HH:mm a'); final twelveHourFormat = DateFormat('hh:mm a');
final twentyFourHourFormat = DateFormat('HH:mm'); final twentyFourHourFormat = DateFormat('HH:mm');
try { try {
if (timeFormat == TimeFormatPB.TwelveHour) { if (timeFormat == UserTimeFormatPB.TwelveHour) {
return twelveHourFormat.parseStrict(timeStr); return twelveHourFormat.parseStrict(timeStr);
} }

View File

@ -174,7 +174,12 @@ class _AppFlowyDatePickerState extends State<AppFlowyDatePicker> {
} }
Widget buildDesktopPicker() { Widget buildDesktopPicker() {
return Padding( // GestureDetector is a workaround to stop popover from closing
// when clicking on the date picker.
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(top: 18.0, bottom: 12.0), padding: const EdgeInsets.only(top: 18.0, bottom: 12.0),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -207,8 +212,9 @@ class _AppFlowyDatePickerState extends State<AppFlowyDatePicker> {
} }
}, },
onRangeSelected: widget.onRangeSelected, onRangeSelected: widget.onRangeSelected,
selectedDay: selectedDay: widget.rebuildOnDaySelected
widget.rebuildOnDaySelected ? _selectedDay : widget.selectedDay, ? _selectedDay
: widget.selectedDay,
firstDay: widget.firstDay, firstDay: widget.firstDay,
lastDay: widget.lastDay, lastDay: widget.lastDay,
startDay: widget.startDay, startDay: widget.startDay,
@ -254,6 +260,7 @@ class _AppFlowyDatePickerState extends State<AppFlowyDatePicker> {
], ],
], ],
), ),
),
); );
} }

View File

@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart'; import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:intl/intl.dart';
const _maxLengthTwelveHour = 8; const _maxLengthTwelveHour = 8;
const _maxLengthTwentyFourHour = 5; const _maxLengthTwentyFourHour = 5;
@ -55,6 +56,13 @@ class _TimeTextFieldState extends State<TimeTextField> {
text = widget.endTimeStr!; text = widget.endTimeStr!;
} }
if (widget.timeFormat == TimeFormatPB.TwelveHour) {
final twentyFourHourFormat = DateFormat('HH:mm');
final twelveHourFormat = DateFormat('hh:mm a');
final date = twentyFourHourFormat.parse(text);
text = twelveHourFormat.format(date);
}
_focusNode.addListener(_focusNodeListener); _focusNode.addListener(_focusNodeListener);
widget.popoverMutex?.listenOnPopoverChanged(_popoverListener); widget.popoverMutex?.listenOnPopoverChanged(_popoverListener);
} }
@ -86,6 +94,7 @@ class _TimeTextFieldState extends State<TimeTextField> {
padding: const EdgeInsets.symmetric(horizontal: 18.0), padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: FlowyTextField( child: FlowyTextField(
text: text, text: text,
keyboardType: TextInputType.datetime,
focusNode: _focusNode, focusNode: _focusNode,
autoFocus: false, autoFocus: false,
controller: _textController, controller: _textController,
@ -97,7 +106,16 @@ class _TimeTextFieldState extends State<TimeTextField> {
? _maxLengthTwelveHour ? _maxLengthTwelveHour
: _maxLengthTwentyFourHour, : _maxLengthTwentyFourHour,
showCounter: false, showCounter: false,
inputFormatters: [TimeInputFormatter(widget.timeFormat)], inputFormatters: [
if (widget.timeFormat == TimeFormatPB.TwelveHour) ...[
// Allow for AM/PM if time format is 12-hour
FilteringTextInputFormatter.allow(RegExp('[0-9:aApPmM ]')),
] else ...[
// Default allow for hh:mm format
FilteringTextInputFormatter.allow(RegExp('[0-9:]')),
],
TimeInputFormatter(widget.timeFormat),
],
onSubmitted: widget.onSubmitted, onSubmitted: widget.onSubmitted,
), ),
); );
@ -134,7 +152,20 @@ class TimeInputFormatter extends TextInputFormatter {
return _formatText(newText, spacePosition, ' '); return _formatText(newText, spacePosition, ' ');
} }
return newValue; if (timeFormat == TimeFormatPB.TwentyFourHour &&
newValue.text.length == 5) {
final prefix = newValue.text.substring(0, 3);
final suffix = newValue.text.length > 5 ? newValue.text.substring(6) : '';
final minutes = int.tryParse(newValue.text.substring(3, 5));
if (minutes == null || minutes <= 0) {
return newValue.copyWith(text: '${prefix}00$suffix'.toUpperCase());
} else if (minutes > 59) {
return newValue.copyWith(text: '${prefix}59$suffix'.toUpperCase());
}
}
return newValue.copyWith(text: newText.toUpperCase());
} }
TextEditingValue _formatText(String text, int index, String separator) { TextEditingValue _formatText(String text, int index, String separator) {

View File

@ -1,9 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flowy_infra/size.dart';
class FlowyTextField extends StatefulWidget { class FlowyTextField extends StatefulWidget {
final String? hintText; final String? hintText;
final String? text; final String? text;
@ -31,6 +32,7 @@ class FlowyTextField extends StatefulWidget {
final TextStyle? hintStyle; final TextStyle? hintStyle;
final InputDecoration? decoration; final InputDecoration? decoration;
final TextAlignVertical? textAlignVertical; final TextAlignVertical? textAlignVertical;
final TextInputAction? textInputAction;
final TextInputType? keyboardType; final TextInputType? keyboardType;
final List<TextInputFormatter>? inputFormatters; final List<TextInputFormatter>? inputFormatters;
@ -62,6 +64,7 @@ class FlowyTextField extends StatefulWidget {
this.hintStyle, this.hintStyle,
this.decoration, this.decoration,
this.textAlignVertical, this.textAlignVertical,
this.textInputAction,
this.keyboardType = TextInputType.multiline, this.keyboardType = TextInputType.multiline,
this.inputFormatters, this.inputFormatters,
}); });