Skip to content

Commit

Permalink
Merge branch 'dev' into feat/datepicker_custom_abbreviations
Browse files Browse the repository at this point in the history
  • Loading branch information
GroovinChip authored Jul 4, 2023
2 parents 60f3ad4 + 37db0c3 commit ca3b160
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [2.0.0-beta.3]
✨ New ✨
* Added support for `weekdayAbbreviations` and `monthAbbreviations` to `MacosDatePicker`.
* Added support for `dateFormat` to `MacosDatePicker`.
* Added support for `startWeekOnMonday` to `MacosDatePicker`.

🛠️ Fixed 🛠️
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,18 @@ Localization of the time picker is supported by the `weekdayAbbreviations` and `
* `weekdayAbbreviations` should be a list of 7 strings, one for each day of the week, starting with Sunday
* `monthAbbreviations` should be a list of 12 strings, one for each month of the year, starting with January

You can also define the `dateFormat` to change the way dates are displayed in the textual interface.
It takes a string of tokens (case-insensitive) and replaces them with their corresponding values.
The following tokens are supported:
* `D`: day of the month (1-31)
* `DD`: day of the month (01-31)
* `M`: month of the year (1-12)
* `MM`: month of the year (01-12)
* `YYYY`: year (0000-9999)
* Any separator between tokens is preserved (e.g. `/`, `-`, `.`)

The default format is `M/D/YYYY`.

Example usage:
```dart
MacosDatePicker(
Expand Down
133 changes: 93 additions & 40 deletions lib/src/selectors/date_picker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class MacosDatePicker extends StatefulWidget {
'Nov',
'Dec',
],
this.dateFormat,
this.startWeekOnMonday,
});

Expand All @@ -91,6 +92,19 @@ class MacosDatePicker extends StatefulWidget {
/// A list of 12 strings, one for each month of the year, starting with January.
final List<String> monthAbbreviations;

/// Changes the way dates are displayed in the textual interface.
///
/// The following tokens are supported (case-insensitive):
/// * `D`: day of the month (1-31)
/// * `DD`: day of the month (01-31)
/// * `M`: month of the year (1-12)
/// * `MM`: month of the year (01-12)
/// * `YYYY`: year (0000-9999)
/// * Any separator between tokens is preserved (e.g. `/`, `-`, `.`)
///
/// Defaults to `M/D/YYYY`.
final String? dateFormat;

/// Allows for changing the order of day headers in the graphical Date Picker
/// to Mo, Tu, We, Th, Fr, Sa, Su.
///
Expand Down Expand Up @@ -215,6 +229,84 @@ class _MacosDatePickerState extends State<MacosDatePicker> {
return result;
}

// Creates textual date presentation based on "dateFormat" property
List<Widget> _textualDateElements() {
final separator = widget.dateFormat != null
? widget.dateFormat!.toLowerCase().replaceAll(RegExp(r'[dmy]'), '')[0]
: '/';

final List<String> dateElements = widget.dateFormat != null
? widget.dateFormat!.toLowerCase().split(RegExp(r'[^dmy]'))
: ['m', 'd', 'y'];

final List<Widget> dateFields = <Widget>[];
for (var dateElement in dateElements) {
if (dateElement.startsWith('d')) {
String value = dateElement == 'dd' && _selectedDay < 10
// Add a leading zero
? '0$_selectedDay'
: '$_selectedDay';

dateFields.add(
DatePickerFieldElement(
isSelected: _isDaySelected,
element: value,
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isDaySelected = !_isDaySelected;
_isMonthSelected = false;
_isYearSelected = false;
});
},
),
);
} else if (dateElement.startsWith('m')) {
String value = dateElement == 'mm' && _selectedMonth < 10
// Add a leading zero
? '0$_selectedMonth'
: '$_selectedMonth';

dateFields.add(
DatePickerFieldElement(
isSelected: _isMonthSelected,
element: value,
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isMonthSelected = !_isMonthSelected;
_isDaySelected = false;
_isYearSelected = false;
});
},
),
);
} else if (dateElement.startsWith('y')) {
dateFields.add(
DatePickerFieldElement(
isSelected: _isYearSelected,
element: '$_selectedYear',
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isYearSelected = !_isYearSelected;
_isDaySelected = false;
_isMonthSelected = false;
});
},
),
);
}
dateFields.add(
Text(separator),
);
}

dateFields.removeLast();

return dateFields;
}

Widget _buildTextualPicker(MacosDatePickerThemeData datePickerTheme) {
return KeyboardShortcutRunner(
onUpArrowKeypress: _incrementElement,
Expand All @@ -235,46 +327,7 @@ class _MacosDatePickerState extends State<MacosDatePicker> {
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
DatePickerFieldElement(
isSelected: _isMonthSelected,
element: '$_selectedMonth',
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isMonthSelected = !_isMonthSelected;
_isDaySelected = false;
_isYearSelected = false;
});
},
),
const Text('/'),
DatePickerFieldElement(
isSelected: _isDaySelected,
element: '$_selectedDay',
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isDaySelected = !_isDaySelected;
_isMonthSelected = false;
_isYearSelected = false;
});
},
),
const Text('/'),
DatePickerFieldElement(
isSelected: _isYearSelected,
element: '$_selectedYear',
onSelected: () {
setState(() {
_focusNode.requestFocus();
_isYearSelected = !_isYearSelected;
_isDaySelected = false;
_isMonthSelected = false;
});
},
),
],
children: _textualDateElements(),
),
),
),
Expand Down
53 changes: 53 additions & 0 deletions test/selectors/date_picker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,59 @@ void main() {
},
);

testWidgets(
'Textual MacosDatePicker renders the date with respect to "dateFormat" property',
(tester) async {
renderWidget(String dateFormat) => MacosApp(
home: MacosWindow(
disableWallpaperTinting: true,
child: MacosScaffold(
children: [
ContentArea(
builder: (context, _) {
return Center(
child: MacosDatePicker(
initialDate: DateTime.parse('2023-04-01'),
onDateChanged: (date) {},
dateFormat: dateFormat,
style: DatePickerStyle.textual,
),
);
},
),
],
),
),
);

getNthTextFromWidget(int index) => (find.byType(Text).at(index).evaluate().first.widget as Text).data as String;

await tester.pumpWidget(renderWidget('dd.mm.yyyy'));
String firstDateElement = getNthTextFromWidget(0);
expect(firstDateElement, '01');
String secondDateElement = getNthTextFromWidget(1);
expect(secondDateElement, '.');
String thirdDateElement = getNthTextFromWidget(2);
expect(thirdDateElement, '04');
String fourthDateElement = getNthTextFromWidget(3);
expect(fourthDateElement, '.');
String fifthDateElement = getNthTextFromWidget(4);
expect(fifthDateElement, '2023');

await tester.pumpWidget(renderWidget('yyyy-m-d'));
firstDateElement = getNthTextFromWidget(0);
expect(firstDateElement, '2023');
secondDateElement = getNthTextFromWidget(1);
expect(secondDateElement, '-');
thirdDateElement = getNthTextFromWidget(2);
expect(thirdDateElement, '4');
fourthDateElement = getNthTextFromWidget(3);
expect(fourthDateElement, '-');
fifthDateElement = getNthTextFromWidget(4);
expect(fifthDateElement, '1');
},
);

testWidgets(
'Can select the date field element and change the value',
(tester) async {
Expand Down

0 comments on commit ca3b160

Please sign in to comment.