Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various issues #133

Merged
merged 15 commits into from
Aug 2, 2024
Prev Previous commit
Next Next commit
Rename calendar controllers
Pante committed Aug 1, 2024
commit fffe9719155696c44b323a98ff7d285bf1639dda
14 changes: 7 additions & 7 deletions docs/pages/docs/calendar.mdx
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ to customize the date selection behavior.
<Tabs.Tab>
```dart
FCalendar(
controller: FCalendarValueController(initialSelection: selected),
controller: FCalendarController.date(initialSelection: selected),
start: DateTime.utc(2000),
end: DateTime.utc(2030),
);
@@ -31,7 +31,7 @@ to customize the date selection behavior.

```dart
FCalendar(
controller: FCalendarValueController(
controller: FCalendarController.date(
initialSelection: DateTime.utc(2024, 9, 13),
selectable: (date) => allowedDates.contains(date),
),
@@ -55,7 +55,7 @@ FCalendar(
<Tabs.Tab>
```dart
FCalendar(
controller: FCalendarSingleValueController(),
controller: FCalendarController.date(),
start: DateTime.utc(2000),
end: DateTime.utc(2030),
);
@@ -66,12 +66,12 @@ FCalendar(
### Multiple Dates with Initial Selections
<Tabs items={['Preview', 'Code']}>
<Tabs.Tab>
<Widget name='calendar' variant='multi-value' query={{}} height={500}/>
<Widget name='calendar' variant='dates' query={{}} height={500}/>
</Tabs.Tab>
<Tabs.Tab>
```dart
FCalendar(
controller: FCalendarMultiValueController(
controller: FCalendarController.dates(
initialSelections: {DateTime.utc(2024, 7, 17), DateTime.utc(2024, 7, 20)},
),
start: DateTime.utc(2000),
@@ -90,7 +90,7 @@ FCalendar(
<Tabs.Tab>
```dart
FCalendar(
controller: FCalendarMultiValueController(
controller: FCalendarController.dates(
initialSelections: {DateTime.utc(2024, 7, 17), DateTime.utc(2024, 7, 20)},
selectable: (date) => !{DateTime.utc(2024, 7, 18), DateTime.utc(2024, 7, 19)}.contains(date),
),
@@ -110,7 +110,7 @@ FCalendar(
<Tabs.Tab>
```dart
FCalendar(
controller: FCalendarRangeController(
controller: FCalendarController.range(
initialSelection: (DateTime.utc(2024, 7, 17), DateTime.utc(2024, 7, 20)),
),
start: DateTime.utc(2000),
6 changes: 4 additions & 2 deletions forui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -18,9 +18,11 @@
* **Breaking:** Rename `FCalendarEntryStyle.focusedTextStyle` to `FCalendarEntryStyle.hoveredTextStyle`.
This only affects users that customized `FCalendarEntryStyle`.

* **Breaking:** Rename `FCalendarSingleValueController` to `FCalendarValueController`.
* **Breaking:** Move `FCalendarSingleValueController` to `FCalendarController.date(...)`.

* **Breaking:** Rename `FCalendarSingleRangeController` to `FCalendarRangeController`.
* **Breaking:** Move `FCalendarMultiValueController` to `FCalendarController.dates(...)`.

* **Breaking:** Rename `FCalendarSingleRangeController` to `FCalendarRangeController.range(...)`.

* **Breaking:** Rename `FSeparator` to `FDivider`.

4 changes: 2 additions & 2 deletions forui/lib/src/theme/theme_data.dart
Original file line number Diff line number Diff line change
@@ -199,7 +199,7 @@ final class FThemeData with Diagnosticable {
FTabsStyle? tabsStyle,
FTextFieldStyle? textFieldStyle,
FScaffoldStyle? scaffoldStyle,
FDividerStyles? separatorStyles,
FDividerStyles? dividerStyles,
FSwitchStyle? switchStyle,
}) =>
FThemeData(
@@ -215,13 +215,13 @@ final class FThemeData with Diagnosticable {
cardStyle: cardStyle ?? this.cardStyle,
checkboxStyle: checkboxStyle ?? this.checkboxStyle,
dialogStyle: dialogStyle ?? this.dialogStyle,
dividerStyles: dividerStyles ?? this.dividerStyles,
headerStyle: headerStyle ?? this.headerStyle,
progressStyle: progressStyle ?? this.progressStyle,
resizableStyle: resizableStyle ?? this.resizableStyle,
tabsStyle: tabsStyle ?? this.tabsStyle,
textFieldStyle: textFieldStyle ?? this.textFieldStyle,
scaffoldStyle: scaffoldStyle ?? this.scaffoldStyle,
dividerStyles: separatorStyles ?? this.dividerStyles,
switchStyle: switchStyle ?? this.switchStyle,
);

87 changes: 51 additions & 36 deletions forui/lib/src/widgets/calendar/calendar_controller.dart
Original file line number Diff line number Diff line change
@@ -9,10 +9,52 @@ bool _true(DateTime _) => true;
/// The [DateTime]s are always in UTC timezone and truncated to the nearest day.
///
/// This class should be extended to customize date selection. By default, the following controllers are provided:
/// * [FCalendarValueController] for selecting a single date.
/// * [FCalendarMultiValueController] for selecting multiple date.
/// * [FCalendarRangeController] for selecting a single range.
/// * [FCalendarController.date] for selecting a single date.
/// * [FCalendarController.dates] for selecting multiple date.
/// * [FCalendarController.range] for selecting a single range.
abstract class FCalendarController<T> extends ValueNotifier<T> {
/// Creates a [FCalendarController] that allows only a single date to be selected, with the given initially selected
/// date.
///
/// [selectable] will always return true if not given.
///
/// ## Contract
/// Throws [AssertionError] if [initialSelection] is not in UTC timezone.
static FCalendarController<DateTime?> date({
DateTime? initialSelection,
Predicate<DateTime>? selectable,
}) =>
_DateController(initialSelection: initialSelection, selectable: selectable);

/// Creates a [FCalendarController] that allows multiple dates to be selected, with the given initial selected dates.
///
/// [selectable] will always return true if not given.
///
/// ## Contract
/// Throws [AssertionError] if the dates in [initialSelections] are not in UTC timezone.
static FCalendarController<Set<DateTime>> dates({
Set<DateTime> initialSelections = const {},
Predicate<DateTime>? selectable,
}) =>
_DatesController(initialSelections: initialSelections, selectable: selectable);

/// Creates a [FCalendarController] that allows a single range to be selected, with the given initial range.
///
/// [selectable] will always return true if not given.
///
/// Both the start and end dates of the range is inclusive. The selected dates are always in UTC timezone and
/// truncated to the nearest day. Unselectable dates within the selected range are selected regardless.
///
/// ## Contract
/// Throws [AssertionError] if:
/// * the given dates in [value] is not in UTC timezone.
/// * the end date is less than start date.
static FCalendarController<(DateTime, DateTime)?> range({
(DateTime, DateTime)? initialSelection,
Predicate<DateTime>? selectable,
}) =>
_RangeController(initialSelection: initialSelection, selectable: selectable);

/// Creates a [FCalendarController] with the given initial [value].
FCalendarController(super._value);

@@ -36,19 +78,10 @@ abstract class FCalendarController<T> extends ValueNotifier<T> {
void select(DateTime date);
}

/// A controller that allows only a single date to be selected.
///
/// The [DateTime]s are always in UTC timezone and truncated to the nearest date.
class FCalendarValueController extends FCalendarController<DateTime?> {
class _DateController extends FCalendarController<DateTime?> {
final Predicate<DateTime> _selectable;

/// Creates a [FCalendarValueController] with the given initially selected date.
///
/// [selectable] will always return true if not given.
///
/// ## Contract
/// Throws [AssertionError] if [initialSelection] is not in UTC timezone.
FCalendarValueController({
_DateController({
DateTime? initialSelection,
Predicate<DateTime>? selectable,
}) : assert(initialSelection?.isUtc ?? true, 'value must be in UTC timezone'),
@@ -65,18 +98,10 @@ class FCalendarValueController extends FCalendarController<DateTime?> {
void select(DateTime date) => value = value?.toLocalDate() == date.toLocalDate() ? null : date;
}

/// A controller that allows multiple dates to be selected. The maximum number of dates that can be selected is
/// determined by [max].
///
/// The [DateTime]s are always in UTC timezone and truncated to the nearest day.
class FCalendarMultiValueController extends FCalendarController<Set<DateTime>> {
class _DatesController extends FCalendarController<Set<DateTime>> {
final Predicate<DateTime> _selectable;

/// Creates a [FCalendarMultiValueController] with the given initial [value].
///
/// ## Contract
/// Throws [AssertionError] if the dates in [initialSelections] are not in UTC timezone.
FCalendarMultiValueController({
_DatesController({
Set<DateTime> initialSelections = const {},
Predicate<DateTime>? selectable,
}) : assert(initialSelections.every((d) => d.isUtc), 'dates must be in UTC timezone'),
@@ -96,20 +121,10 @@ class FCalendarMultiValueController extends FCalendarController<Set<DateTime>> {
}
}

/// A date selection controller that allows a single range to be selected.
///
/// Both the start and end dates of the range is inclusive. The selected dates are always in UTC timezone and truncated
/// to the nearest day. Unselectable dates within the selected range are selected regardless.
class FCalendarRangeController extends FCalendarController<(DateTime, DateTime)?> {
class _RangeController extends FCalendarController<(DateTime, DateTime)?> {
final Predicate<DateTime> _selectable;

/// Creates a [FCalendarRangeController] with the given initial [value].
///
/// ## Contract
/// Throws [AssertionError] if:
/// * the given dates in [value] is not in UTC timezone.
/// * the end date is less than start date.
FCalendarRangeController({
_RangeController({
(DateTime, DateTime)? initialSelection,
Predicate<DateTime>? selectable,
}) : assert(
22 changes: 11 additions & 11 deletions forui/test/src/widgets/calendar/calendar_controller_test.dart
Original file line number Diff line number Diff line change
@@ -3,18 +3,18 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:forui/forui.dart';

void main() {
group('FCalendarValueController', () {
group('FCalendarController.date(...)', () {
test(
'constructor throws error',
() => expect(() => FCalendarValueController(initialSelection: DateTime.now()), throwsAssertionError),
() => expect(() => FCalendarController.date(initialSelection: DateTime.now()), throwsAssertionError),
);

for (final (date, expected) in [
(DateTime.utc(2024, 5, 4), true),
(DateTime.utc(2024, 5, 5), false),
]) {
test('selected(...) contains date', () {
final controller = FCalendarValueController(initialSelection: DateTime.utc(2024, 5, 4));
final controller = FCalendarController.date(initialSelection: DateTime.utc(2024, 5, 4));
expect(controller.selected(date), expected);
});
}
@@ -26,19 +26,19 @@ void main() {
(DateTime.utc(2024), DateTime.utc(2024), null),
]) {
test('select(...)', () {
final controller = FCalendarValueController(initialSelection: initial)..select(date);
final controller = FCalendarController.date(initialSelection: initial)..select(date);
expect(controller.value, expected);
});
}
});

group('FCalendarMultiValueController', () {
group('FCalendarController.dates', () {
for (final (date, expected) in [
(DateTime.utc(2024), true),
(DateTime.utc(2025), false),
]) {
test('selected(...)', () {
final controller = FCalendarMultiValueController(initialSelections: {DateTime.utc(2024)});
final controller = FCalendarController.dates(initialSelections: {DateTime.utc(2024)});
expect(controller.selected(date), expected);
});
}
@@ -49,17 +49,17 @@ void main() {
({DateTime.utc(2024)}, DateTime.utc(2025), {DateTime.utc(2024), DateTime.utc(2025)}),
]) {
test('select(...)', () {
final controller = FCalendarMultiValueController(initialSelections: initial)..select(date);
final controller = FCalendarController.dates(initialSelections: initial)..select(date);
expect(controller.value, expected);
});
}
});

group('FCalendarRangeController', () {
group('FCalendarController.range(...)', () {
test(
'constructor throws error',
() => expect(
() => FCalendarRangeController(initialSelection: (DateTime(2025), DateTime(2024))),
() => FCalendarController.range(initialSelection: (DateTime(2025), DateTime(2024))),
throwsAssertionError,
),
);
@@ -72,7 +72,7 @@ void main() {
(null, DateTime.utc(2023), false),
]) {
test('selected(...)', () {
final controller = FCalendarRangeController(initialSelection: initial);
final controller = FCalendarController.range(initialSelection: initial);
expect(controller.selected(date), expected);
});
}
@@ -86,7 +86,7 @@ void main() {
(null, DateTime.utc(2023), (DateTime.utc(2023), DateTime.utc(2023))),
]) {
test('select(...)', () {
final controller = FCalendarRangeController(initialSelection: initial)..select(date);
final controller = FCalendarController.range(initialSelection: initial)..select(date);
expect(controller.value, expected);
});
}
10 changes: 5 additions & 5 deletions forui/test/src/widgets/calendar/calendar_golden_test.dart
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ void main() {
child: Padding(
padding: const EdgeInsets.all(16),
child: FCalendar(
controller: FCalendarMultiValueController(
controller: FCalendarController.dates(
initialSelections: selected,
selectable: (date) => date != DateTime.utc(2024, 7, 2),
),
@@ -63,7 +63,7 @@ void main() {
child: Padding(
padding: const EdgeInsets.all(16),
child: FCalendar(
controller: FCalendarMultiValueController(initialSelections: selected),
controller: FCalendarController.dates(initialSelections: selected),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 6, 14),
@@ -88,7 +88,7 @@ void main() {
child: Padding(
padding: const EdgeInsets.all(16),
child: FCalendar(
controller: FCalendarMultiValueController(initialSelections: selected),
controller: FCalendarController.dates(initialSelections: selected),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
@@ -125,7 +125,7 @@ void main() {
child: Padding(
padding: const EdgeInsets.all(16),
child: FCalendar(
controller: FCalendarMultiValueController(initialSelections: selected),
controller: FCalendarController.dates(initialSelections: selected),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
@@ -149,7 +149,7 @@ void main() {
child: Padding(
padding: const EdgeInsets.all(16),
child: FCalendar(
controller: FCalendarMultiValueController(initialSelections: selected),
controller: FCalendarController.dates(initialSelections: selected),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
8 changes: 4 additions & 4 deletions forui/test/src/widgets/calendar/calendar_test.dart
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ void main() {
TestScaffold(
data: FThemes.zinc.light,
child: FCalendar(
controller: FCalendarMultiValueController(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
controller: FCalendarController.dates(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
@@ -32,7 +32,7 @@ void main() {
TestScaffold(
data: FThemes.zinc.light,
child: FCalendar(
controller: FCalendarMultiValueController(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
controller: FCalendarController.dates(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
start: DateTime(2024, 7),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
@@ -55,7 +55,7 @@ void main() {
TestScaffold(
data: FThemes.zinc.light,
child: FCalendar(
controller: FCalendarMultiValueController(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
controller: FCalendarController.dates(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
start: DateTime(1900, 1, 8),
end: DateTime(2024, 8, 10),
today: DateTime(2024, 7, 14),
@@ -76,7 +76,7 @@ void main() {
TestScaffold(
data: FThemes.zinc.light,
child: FCalendar(
controller: FCalendarMultiValueController(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
controller: FCalendarController.dates(selectable: (date) => date != DateTime.utc(2024, 7, 2)),
start: DateTime(2024),
end: DateTime(2024, 7, 10),
today: DateTime(2024, 7, 14),
4 changes: 2 additions & 2 deletions samples/lib/main.dart
Original file line number Diff line number Diff line change
@@ -76,8 +76,8 @@ class _AppRouter extends RootStackRouter {
page: CalendarRoute.page,
),
AutoRoute(
path: '/calendar/multi-value',
page: MultiValueCalendarRoute.page,
path: '/calendar/dates',
page: DatesCalendarRoute.page,
),
AutoRoute(
path: '/calendar/unselectable',
Loading