From 4cfa6ed58f762c59705a80a08502a0fd0403a511 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 4 Jul 2024 15:17:50 +0800 Subject: [PATCH 01/35] Prototype day widgets --- forui/lib/src/widgets/calendar/calendar.dart | 5 + forui/lib/src/widgets/calendar/day.dart | 184 +++++++++++++++++++ forui/lib/widgets.dart | 1 + samples/lib/main.dart | 5 +- 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 forui/lib/src/widgets/calendar/calendar.dart create mode 100644 forui/lib/src/widgets/calendar/day.dart diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart new file mode 100644 index 000000000..906219f63 --- /dev/null +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -0,0 +1,5 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:meta/meta.dart'; + +part 'day.dart'; \ No newline at end of file diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart new file mode 100644 index 000000000..0043280a4 --- /dev/null +++ b/forui/lib/src/widgets/calendar/day.dart @@ -0,0 +1,184 @@ +part of 'calendar.dart'; + +// Possible states +// current month, unselected +// current month, today/focused/hovered +// current month, selected +// current month, disabled + +// previous month, unselected +// previous month, today/focused/hovered +// previous month, selected +// previous month, disabled + +// class DayStyle { +// final DayStateStyle unselected; +// final DayStateStyle today; +// final DayStateStyle selected; +// +// DayStyle({ +// required this.unselected, +// required this.today, +// required this.selected, +// }); +// } + +@internal +class EnabledDay extends StatefulWidget { + final FDayStyle style; + final DateTime date; + final ValueChanged onPress; + final bool today; + final bool selected; + + const EnabledDay({ + required this.style, + required this.date, + required this.onPress, + required this.today, + required this.selected, + super.key, + }); + + @override + State createState() => _EnabledDayState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) + ..add(FlagProperty('today', value: today, ifTrue: 'today', level: DiagnosticLevel.debug)) + ..add(FlagProperty('selected', value: selected, ifTrue: 'selected', level: DiagnosticLevel.debug)); + } +} + +class _EnabledDayState extends State { + bool focused = false; + + @override + Widget build(BuildContext context) => MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => focused = true), + onExit: (_) => setState(() => focused = false), + child: Semantics( + label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization + button: true, + selected: widget.selected, + excludeSemantics: true, + child: DecoratedBox( + decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, + child: Center( + child: Text( + '${widget.date.day}', // TODO: localization + style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + ), + ), + ), + ), + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(FlagProperty('focused', value: focused, ifTrue: 'focused')); + } +} + +@internal +class DisabledDay extends StatelessWidget { + final FDayStyle style; + final DateTime date; + + const DisabledDay({ + required this.style, + required this.date, + super.key, + }); + + @override + Widget build(BuildContext context) => ExcludeSemantics( + child: DecoratedBox( + decoration: style.decoration, + child: Center( + child: Text('${date.day}', style: style.textStyle), // TODO: localization + ), + ), + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)); + } +} + + + +/// A calendar day's style. +class FDayStyle { + /// The unfocused day's decoration. + final BoxDecoration decoration; + + /// The unfocused day's text style. + final TextStyle textStyle; + + /// The focused day's decoration. + final BoxDecoration focusedDecoration; + + /// The focused day's text style. + final TextStyle focusedTextStyle; + + /// Creates a [FDayStyle]. + const FDayStyle({ + required this.decoration, + required this.textStyle, + required this.focusedDecoration, + required this.focusedTextStyle, + }); + + /// Creates a copy of this [FDayStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FDayStyle( + /// decoration: ..., + /// textStyle: ..., + /// ); + /// + /// final copy = style.copyWith( + /// textStyle: ..., + /// ); + /// + /// print(style.decoration == copy.decoration); // true + /// print(style.textStyle == copy.textStyle); // false + /// ``` + FDayStyle copyWith({ + BoxDecoration? decoration, + TextStyle? textStyle, + BoxDecoration? focusedDecoration, + TextStyle? focusedTextStyle, + }) => + FDayStyle( + decoration: decoration ?? this.decoration, + textStyle: textStyle ?? this.textStyle, + focusedDecoration: focusedDecoration ?? this.focusedDecoration, + focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, + ); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FDayStyle && + runtimeType == other.runtimeType && + decoration == other.decoration && + textStyle == other.textStyle && + focusedDecoration == other.focusedDecoration && + focusedTextStyle == other.focusedTextStyle; + + @override + int get hashCode => decoration.hashCode ^ textStyle.hashCode ^ focusedDecoration.hashCode ^ focusedTextStyle.hashCode; +} diff --git a/forui/lib/widgets.dart b/forui/lib/widgets.dart index 25e657a06..20d18c64a 100644 --- a/forui/lib/widgets.dart +++ b/forui/lib/widgets.dart @@ -4,6 +4,7 @@ library forui.widgets; export 'src/widgets/badge/badge.dart' hide Variant; export 'src/widgets/button/button.dart' hide Variant; export 'src/widgets/card/card.dart'; +export 'src/widgets/calendar/calendar.dart'; export 'src/widgets/checkbox.dart'; export 'src/widgets/dialog/dialog.dart'; export 'src/widgets/header/header.dart'; diff --git a/samples/lib/main.dart b/samples/lib/main.dart index d377b51fb..6e75d559a 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart' hide DialogRoute; import 'package:auto_route/auto_route.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import 'package:forui/forui.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; @@ -28,7 +29,9 @@ class ForuiSamples extends StatelessWidget { @RoutePage() class EmptyPage extends SampleScaffold { @override - Widget child(BuildContext context) => const Placeholder(); + Widget child(BuildContext context) => Day( + date: DateTime.now(), + ); } @AutoRouterConfig() From 6c47a7456378b01e9d84375e6bca77d316fcadb0 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 4 Jul 2024 17:48:02 +0800 Subject: [PATCH 02/35] Add styling for different day states --- forui/lib/src/widgets/calendar/calendar.dart | 1 + forui/lib/src/widgets/calendar/day.dart | 143 ++++++++++++++----- samples/lib/main.dart | 51 ++++++- 3 files changed, 160 insertions(+), 35 deletions(-) diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 906219f63..50815433b 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; part 'day.dart'; \ No newline at end of file diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index 0043280a4..304cf9e6e 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -11,21 +11,9 @@ part of 'calendar.dart'; // previous month, selected // previous month, disabled -// class DayStyle { -// final DayStateStyle unselected; -// final DayStateStyle today; -// final DayStateStyle selected; -// -// DayStyle({ -// required this.unselected, -// required this.today, -// required this.selected, -// }); -// } - @internal class EnabledDay extends StatefulWidget { - final FDayStyle style; + final FDayStateStyle style; final DateTime date; final ValueChanged onPress; final bool today; @@ -68,12 +56,15 @@ class _EnabledDayState extends State { button: true, selected: widget.selected, excludeSemantics: true, - child: DecoratedBox( - decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, - child: Center( - child: Text( - '${widget.date.day}', // TODO: localization - style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + child: GestureDetector( + onTap: () => widget.onPress(widget.date), + child: DecoratedBox( + decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, + child: Center( + child: Text( + '${widget.date.day}', // TODO: localization + style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + ), ), ), ), @@ -89,7 +80,7 @@ class _EnabledDayState extends State { @internal class DisabledDay extends StatelessWidget { - final FDayStyle style; + final FDayStateStyle style; final DateTime date; const DisabledDay({ @@ -117,34 +108,120 @@ class DisabledDay extends StatelessWidget { } } +final class FMonthStyle { + final ({FDayStyle enabled, FDayStyle disabled}) current; + final ({FDayStyle enabled, FDayStyle disabled}) enclosing; + + FMonthStyle({ + required this.current, + required this.enclosing, + }); + // factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { + // final currentEnabledTextStyle = typography.sm.copyWith(color: colorScheme.foreground); + // final currentDisabledTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); + // return FMonthStyle( + // current: ( + // enabled: FDayStyle( + // todayStyle: FDayStateStyle( + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(4), + // color: colorScheme.secondary, + // ), + // textStyle: currentEnabledTextStyle, + // ), + // unselectedStyle: FDayStateStyle( + // decoration: const BoxDecoration(), + // textStyle: currentEnabledTextStyle, + // focusedDecoration: BoxDecoration( + // borderRadius: BorderRadius.circular(4), + // color: colorScheme.secondary, + // ), + // ), + // selectedStyle: FDayStateStyle( + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(4), + // color: colorScheme.foreground, + // ), + // textStyle: typography.sm.copyWith(color: colorScheme.background), + // ), + // ), + // disabled: FDayStyle( + // todayStyle: FDayStateStyle( + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(4), + // color: colorScheme.primaryForeground, + // ), + // textStyle: currentDisabledTextStyle, + // focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + // ), + // unselectedStyle: FDayStateStyle( + // decoration: const BoxDecoration(), + // textStyle: currentDisabledTextStyle, + // ), + // selectedStyle: FDayStateStyle( + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(4), + // color: colorScheme.primaryForeground, + // ), + // textStyle: currentDisabledTextStyle, + // focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + // ), + // ), + // ), + // enclosing: ( + // enabled: + // ), + // ); + // } +} -/// A calendar day's style. +/// A calender day's style. class FDayStyle { + /// The current date's style. + final FDayStateStyle todayStyle; + + /// The unselected dates' style. + final FDayStateStyle unselectedStyle; + + /// The selected dates' style. + final FDayStateStyle selectedStyle; + + /// Creates a [FDayStyle]. + FDayStyle({ + required this.todayStyle, + required this.unselectedStyle, + required this.selectedStyle, + }); +} + +/// A calendar day state's style. +final class FDayStateStyle { /// The unfocused day's decoration. final BoxDecoration decoration; /// The unfocused day's text style. final TextStyle textStyle; - /// The focused day's decoration. + /// The focused day's decoration. Defaults to [decoration]. final BoxDecoration focusedDecoration; - /// The focused day's text style. + /// The focused day's text style. Defaults to [textStyle]. final TextStyle focusedTextStyle; - /// Creates a [FDayStyle]. - const FDayStyle({ + /// Creates a [FDayStateStyle]. + FDayStateStyle({ required this.decoration, required this.textStyle, - required this.focusedDecoration, - required this.focusedTextStyle, - }); + BoxDecoration? focusedDecoration, + TextStyle? focusedTextStyle, + }) : focusedDecoration = focusedDecoration ?? decoration, + focusedTextStyle = focusedTextStyle ?? textStyle; - /// Creates a copy of this [FDayStyle] but with the given fields replaced with the new values. + /// Creates a copy of this [FDayStateStyle] but with the given fields replaced with the new values. /// /// ```dart - /// final style = FDayStyle( + /// final style = FDayStateStyle( /// decoration: ..., /// textStyle: ..., /// ); @@ -156,13 +233,13 @@ class FDayStyle { /// print(style.decoration == copy.decoration); // true /// print(style.textStyle == copy.textStyle); // false /// ``` - FDayStyle copyWith({ + FDayStateStyle copyWith({ BoxDecoration? decoration, TextStyle? textStyle, BoxDecoration? focusedDecoration, TextStyle? focusedTextStyle, }) => - FDayStyle( + FDayStateStyle( decoration: decoration ?? this.decoration, textStyle: textStyle ?? this.textStyle, focusedDecoration: focusedDecoration ?? this.focusedDecoration, @@ -172,7 +249,7 @@ class FDayStyle { @override bool operator ==(Object other) => identical(this, other) || - other is FDayStyle && + other is FDayStateStyle && runtimeType == other.runtimeType && decoration == other.decoration && textStyle == other.textStyle && diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 6e75d559a..0352b67c2 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -6,6 +6,7 @@ import 'package:forui/forui.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; +import 'package:sugar/sugar.dart'; void main() { usePathUrlStrategy(); @@ -29,8 +30,54 @@ class ForuiSamples extends StatelessWidget { @RoutePage() class EmptyPage extends SampleScaffold { @override - Widget child(BuildContext context) => Day( - date: DateTime.now(), + Widget child(BuildContext context) => const Testing(); +} + +class Testing extends StatelessWidget { + const Testing({super.key}); + + @override + Widget build(BuildContext context) => Row( + children: [ + SizedBox( + height: 36, + width: 36, + child: EnabledDay( + style: FDayStateStyle( + decoration: const BoxDecoration(), + textStyle: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground.withOpacity(0.5), + ), + focusedTextStyle: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + date: DateTime(2024, 3, 31), + onPress: print, + today: true, + selected: true, + ), + ), + SizedBox( + height: 36, + width: 36, + child: EnabledDay( + style: FDayStateStyle( + decoration: const BoxDecoration(), + textStyle: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground.withOpacity(0.5), + ), + // focusedTextStyle: context.theme.typography.sm.copyWith( + // color: context.theme.colorScheme.mutedForeground, + // ), + ), + date: DateTime(2024, 4), + onPress: print, + today: true, + selected: true, + ), + ), + ], ); } From 2f39894ac75d45ab72f165b00da4c7406578407c Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 8 Jul 2024 09:37:12 +0800 Subject: [PATCH 03/35] wip --- forui/example/lib/main.dart | 23 ++- forui/lib/src/widgets/calendar/day.dart | 241 +++++++++++++++++------- samples/lib/sample_scaffold.dart | 2 +- 3 files changed, 200 insertions(+), 66 deletions(-) diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 4fe50a2bd..abf4cdcb1 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -16,7 +16,7 @@ class Application extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( builder: (context, child) => FTheme( - data: FThemes.zinc.light, + data: FThemes.zinc.dark, child: FScaffold( header: FHeader( title: const Text('Example Example Example Example'), @@ -30,6 +30,25 @@ class Application extends StatelessWidget { content: child ?? const SizedBox(), ), ), - home: const Example(), + home: const Testing(), + ); +} + +class Testing extends StatelessWidget { + const Testing({super.key}); + + @override + Widget build(BuildContext context) => EnabledDay( + style: FDayStateStyle( + decoration: BoxDecoration( + borderRadius: context.theme.style.borderRadius, + color: context.theme.colorScheme.border, + ), + textStyle: context.theme.typography.base, + ), + date: DateTime.now(), + onPress: print, + today: true, + selected: true, ); } diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index 304cf9e6e..5557ec397 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -16,6 +16,7 @@ class EnabledDay extends StatefulWidget { final FDayStateStyle style; final DateTime date; final ValueChanged onPress; + final ValueChanged onLongPress; final bool today; final bool selected; @@ -23,6 +24,7 @@ class EnabledDay extends StatefulWidget { required this.style, required this.date, required this.onPress, + required this.onLongPress, required this.today, required this.selected, super.key, @@ -38,6 +40,7 @@ class EnabledDay extends StatefulWidget { ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onLongPress', onLongPress, level: DiagnosticLevel.debug)) ..add(FlagProperty('today', value: today, ifTrue: 'today', level: DiagnosticLevel.debug)) ..add(FlagProperty('selected', value: selected, ifTrue: 'selected', level: DiagnosticLevel.debug)); } @@ -58,6 +61,7 @@ class _EnabledDayState extends State { excludeSemantics: true, child: GestureDetector( onTap: () => widget.onPress(widget.date), + onLongPress: () => widget.onLongPress(widget.date), child: DecoratedBox( decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, child: Center( @@ -108,76 +112,110 @@ class DisabledDay extends StatelessWidget { } } -final class FMonthStyle { +/// A month's style. +final class FMonthStyle with Diagnosticable { + /// The enabled and disabled styles for the current month on display. final ({FDayStyle enabled, FDayStyle disabled}) current; + + /// The enabled and disabled styles for the months enclosing the current month on display. final ({FDayStyle enabled, FDayStyle disabled}) enclosing; - FMonthStyle({ + /// Creates a [FMonthStyle]. + const FMonthStyle({ required this.current, required this.enclosing, }); - // factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { - // final currentEnabledTextStyle = typography.sm.copyWith(color: colorScheme.foreground); - // final currentDisabledTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); - // return FMonthStyle( - // current: ( - // enabled: FDayStyle( - // todayStyle: FDayStateStyle( - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // color: colorScheme.secondary, - // ), - // textStyle: currentEnabledTextStyle, - // ), - // unselectedStyle: FDayStateStyle( - // decoration: const BoxDecoration(), - // textStyle: currentEnabledTextStyle, - // focusedDecoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // color: colorScheme.secondary, - // ), - // ), - // selectedStyle: FDayStateStyle( - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // color: colorScheme.foreground, - // ), - // textStyle: typography.sm.copyWith(color: colorScheme.background), - // ), - // ), - // disabled: FDayStyle( - // todayStyle: FDayStateStyle( - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // color: colorScheme.primaryForeground, - // ), - // textStyle: currentDisabledTextStyle, - // focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - // ), - // unselectedStyle: FDayStateStyle( - // decoration: const BoxDecoration(), - // textStyle: currentDisabledTextStyle, - // ), - // selectedStyle: FDayStateStyle( - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(4), - // color: colorScheme.primaryForeground, - // ), - // textStyle: currentDisabledTextStyle, - // focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - // ), - // ), - // ), - // enclosing: ( - // enabled: - // ), - // ); - // } + /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. + factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { + final textStyle = typography.sm.copyWith(color: colorScheme.foreground); + final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); + + final disabled = FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: mutedTextStyle, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), + ); + + return FMonthStyle( + current: ( + enabled: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.secondary, + textStyle: textStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: textStyle, + focusedColor: colorScheme.secondary, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.foreground, + textStyle: typography.sm.copyWith(color: colorScheme.background), + ), + ), + disabled: disabled, + ), + enclosing: ( + enabled: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: mutedTextStyle, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + ), + ), + disabled: disabled, + ), + ); + } + + /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. + FMonthStyle copyWith({ + FDayStyle? currentEnabled, + FDayStyle? currentDisabled, + FDayStyle? enclosingEnabled, + FDayStyle? enclosingDisabled, + }) => + FMonthStyle( + current: ( + enabled: currentEnabled ?? current.enabled, + disabled: currentDisabled ?? current.disabled, + ), + enclosing: ( + enabled: enclosingEnabled ?? enclosing.enabled, + disabled: enclosingDisabled ?? enclosing.disabled, + ), + ); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FMonthStyle && + runtimeType == other.runtimeType && + current == other.current && + enclosing == other.enclosing; + + @override + int get hashCode => current.hashCode ^ enclosing.hashCode; } /// A calender day's style. -class FDayStyle { +final class FDayStyle with Diagnosticable { /// The current date's style. final FDayStateStyle todayStyle; @@ -188,15 +226,63 @@ class FDayStyle { final FDayStateStyle selectedStyle; /// Creates a [FDayStyle]. - FDayStyle({ + const FDayStyle({ required this.todayStyle, required this.unselectedStyle, required this.selectedStyle, }); + + /// Returns a copy of this [FDayStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FDayStyle( + /// todayStyle: ..., + /// unselectedStyle: ..., + /// // Other arguments omitted for brevity + /// ); + /// + /// final copy = style.copyWith( + /// unselectedStyle: ..., + /// ); + /// + /// print(style.todayStyle == copy.todayStyle); // true + /// print(style.unselectedStyle == copy.unselectedStyle); // false + /// ``` + FDayStyle copyWith({ + FDayStateStyle? todayStyle, + FDayStateStyle? unselectedStyle, + FDayStateStyle? selectedStyle, + }) => + FDayStyle( + todayStyle: todayStyle ?? this.todayStyle, + unselectedStyle: unselectedStyle ?? this.unselectedStyle, + selectedStyle: selectedStyle ?? this.selectedStyle, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('todayStyle', todayStyle)) + ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)) + ..add(DiagnosticsProperty('selectedStyle', selectedStyle)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FDayStyle && + runtimeType == other.runtimeType && + todayStyle == other.todayStyle && + unselectedStyle == other.unselectedStyle && + selectedStyle == other.selectedStyle; + + @override + int get hashCode => todayStyle.hashCode ^ unselectedStyle.hashCode ^ selectedStyle.hashCode; } /// A calendar day state's style. -final class FDayStateStyle { +final class FDayStateStyle with Diagnosticable { /// The unfocused day's decoration. final BoxDecoration decoration; @@ -218,7 +304,26 @@ final class FDayStateStyle { }) : focusedDecoration = focusedDecoration ?? decoration, focusedTextStyle = focusedTextStyle ?? textStyle; - /// Creates a copy of this [FDayStateStyle] but with the given fields replaced with the new values. + /// Creates a [FDayStateStyle] that inherits the given colors. + FDayStateStyle.inherit({ + required TextStyle textStyle, + Color? color, + Color? focusedColor, + TextStyle? focusedTextStyle, + }): this( + decoration: color == null ? const BoxDecoration() : BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: color, + ), + textStyle: textStyle, + focusedDecoration: (focusedColor ?? color) == null ? const BoxDecoration(): BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: focusedColor ?? color, + ), + focusedTextStyle: focusedTextStyle ?? textStyle, + ); + + /// Returns a copy of this [FDayStateStyle] but with the given fields replaced with the new values. /// /// ```dart /// final style = FDayStateStyle( @@ -246,6 +351,16 @@ final class FDayStateStyle { focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, ); + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('decoration', decoration)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(DiagnosticsProperty('focusedDecoration', focusedDecoration)) + ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)); + } + @override bool operator ==(Object other) => identical(this, other) || diff --git a/samples/lib/sample_scaffold.dart b/samples/lib/sample_scaffold.dart index 77b54a6e2..31026cbb1 100644 --- a/samples/lib/sample_scaffold.dart +++ b/samples/lib/sample_scaffold.dart @@ -12,7 +12,7 @@ abstract class SampleScaffold extends StatelessWidget { final FThemeData theme; SampleScaffold({ - String theme = 'zinc-light', + String theme = 'zinc-dark', super.key, }) : theme = themes[theme]!; From ccb6202757988e7f552e77c98ca4b7d7a7b932ef Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Jul 2024 10:54:04 +0800 Subject: [PATCH 04/35] WIP --- forui/example/lib/main.dart | 21 +-- forui/lib/src/widgets/calendar/calendar.dart | 5 +- forui/lib/src/widgets/calendar/day.dart | 130 +++--------------- forui/lib/src/widgets/calendar/month.dart | 136 +++++++++++++++++++ samples/lib/main.dart | 81 +++++------ samples/lib/sample_scaffold.dart | 2 +- 6 files changed, 199 insertions(+), 176 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/month.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index abf4cdcb1..08fe02b76 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -30,25 +30,6 @@ class Application extends StatelessWidget { content: child ?? const SizedBox(), ), ), - home: const Testing(), - ); -} - -class Testing extends StatelessWidget { - const Testing({super.key}); - - @override - Widget build(BuildContext context) => EnabledDay( - style: FDayStateStyle( - decoration: BoxDecoration( - borderRadius: context.theme.style.borderRadius, - color: context.theme.colorScheme.border, - ), - textStyle: context.theme.typography.base, - ), - date: DateTime.now(), - onPress: print, - today: true, - selected: true, + home: const Example(), ); } diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 50815433b..532d668b4 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,6 +1,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; -part 'day.dart'; \ No newline at end of file +part 'day.dart'; +part 'month.dart'; \ No newline at end of file diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index 5557ec397..bd110ccdf 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -112,108 +112,6 @@ class DisabledDay extends StatelessWidget { } } -/// A month's style. -final class FMonthStyle with Diagnosticable { - /// The enabled and disabled styles for the current month on display. - final ({FDayStyle enabled, FDayStyle disabled}) current; - - /// The enabled and disabled styles for the months enclosing the current month on display. - final ({FDayStyle enabled, FDayStyle disabled}) enclosing; - - /// Creates a [FMonthStyle]. - const FMonthStyle({ - required this.current, - required this.enclosing, - }); - - /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. - factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { - final textStyle = typography.sm.copyWith(color: colorScheme.foreground); - final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); - - final disabled = FDayStyle( - todayStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - ), - unselectedStyle: FDayStateStyle.inherit( - textStyle: mutedTextStyle, - ), - selectedStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - ), - ); - - return FMonthStyle( - current: ( - enabled: FDayStyle( - todayStyle: FDayStateStyle.inherit( - color: colorScheme.secondary, - textStyle: textStyle, - ), - unselectedStyle: FDayStateStyle.inherit( - textStyle: textStyle, - focusedColor: colorScheme.secondary, - ), - selectedStyle: FDayStateStyle.inherit( - color: colorScheme.foreground, - textStyle: typography.sm.copyWith(color: colorScheme.background), - ), - ), - disabled: disabled, - ), - enclosing: ( - enabled: FDayStyle( - todayStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - ), - unselectedStyle: FDayStateStyle.inherit( - textStyle: mutedTextStyle, - ), - selectedStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - ), - ), - disabled: disabled, - ), - ); - } - - /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. - FMonthStyle copyWith({ - FDayStyle? currentEnabled, - FDayStyle? currentDisabled, - FDayStyle? enclosingEnabled, - FDayStyle? enclosingDisabled, - }) => - FMonthStyle( - current: ( - enabled: currentEnabled ?? current.enabled, - disabled: currentDisabled ?? current.disabled, - ), - enclosing: ( - enabled: enclosingEnabled ?? enclosing.enabled, - disabled: enclosingDisabled ?? enclosing.disabled, - ), - ); - - @override - bool operator ==(Object other) => - identical(this, other) || - other is FMonthStyle && - runtimeType == other.runtimeType && - current == other.current && - enclosing == other.enclosing; - - @override - int get hashCode => current.hashCode ^ enclosing.hashCode; -} - /// A calender day's style. final class FDayStyle with Diagnosticable { /// The current date's style. @@ -310,18 +208,22 @@ final class FDayStateStyle with Diagnosticable { Color? color, Color? focusedColor, TextStyle? focusedTextStyle, - }): this( - decoration: color == null ? const BoxDecoration() : BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: color, - ), - textStyle: textStyle, - focusedDecoration: (focusedColor ?? color) == null ? const BoxDecoration(): BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: focusedColor ?? color, - ), - focusedTextStyle: focusedTextStyle ?? textStyle, - ); + }) : this( + decoration: color == null + ? const BoxDecoration() + : BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: color, + ), + textStyle: textStyle, + focusedDecoration: (focusedColor ?? color) == null + ? const BoxDecoration() + : BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: focusedColor ?? color, + ), + focusedTextStyle: focusedTextStyle ?? textStyle, + ); /// Returns a copy of this [FDayStateStyle] but with the given fields replaced with the new values. /// diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/month.dart new file mode 100644 index 000000000..65fd750da --- /dev/null +++ b/forui/lib/src/widgets/calendar/month.dart @@ -0,0 +1,136 @@ +part of 'calendar.dart'; + +@internal +class Month extends StatelessWidget { + final DateTime month; + final DateTime today; + + const Month({ + required this.month, + required this.today, + super.key, + }); + + @override + Widget build(BuildContext context) { + final first = month.firstDayOfMonth; + + return GridView.count( + scrollDirection: Axis.horizontal, + crossAxisCount: 5, + ); + } +} + + +/// A month's style. +final class FMonthStyle with Diagnosticable { + /// The enabled and disabled styles for the current month on display. + final ({FDayStyle enabled, FDayStyle disabled}) current; + + /// The enabled and disabled styles for the months enclosing the current month on display. + final ({FDayStyle enabled, FDayStyle disabled}) enclosing; + + /// Creates a [FMonthStyle]. + const FMonthStyle({ + required this.current, + required this.enclosing, + }); + + /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. + factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { + final textStyle = typography.sm.copyWith(color: colorScheme.foreground); + final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); + + final disabled = FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: mutedTextStyle, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), + ); + + return FMonthStyle( + current: ( + enabled: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.secondary, + textStyle: textStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: textStyle, + focusedColor: colorScheme.secondary, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.foreground, + textStyle: typography.sm.copyWith(color: colorScheme.background), + ), + ), + disabled: disabled, + ), + enclosing: ( + enabled: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: mutedTextStyle, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), + ), + ), + disabled: disabled, + ), + ); + } + + /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. + FMonthStyle copyWith({ + FDayStyle? currentEnabled, + FDayStyle? currentDisabled, + FDayStyle? enclosingEnabled, + FDayStyle? enclosingDisabled, + }) => + FMonthStyle( + current: ( + enabled: currentEnabled ?? current.enabled, + disabled: currentDisabled ?? current.disabled, + ), + enclosing: ( + enabled: enclosingEnabled ?? enclosing.enabled, + disabled: enclosingDisabled ?? enclosing.disabled, + ), + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('current.enabled', current.enabled)) + ..add(DiagnosticsProperty('current.disabled', current.disabled)) + ..add(DiagnosticsProperty('enclosing.enabled', enclosing.enabled)) + ..add(DiagnosticsProperty('enclosing.disabled', enclosing.disabled)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FMonthStyle && + runtimeType == other.runtimeType && + current == other.current && + enclosing == other.enclosing; + + @override + int get hashCode => current.hashCode ^ enclosing.hashCode; +} diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 0352b67c2..21dbd72fb 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -37,48 +37,49 @@ class Testing extends StatelessWidget { const Testing({super.key}); @override - Widget build(BuildContext context) => Row( - children: [ - SizedBox( - height: 36, - width: 36, - child: EnabledDay( - style: FDayStateStyle( - decoration: const BoxDecoration(), - textStyle: context.theme.typography.sm.copyWith( - color: context.theme.colorScheme.mutedForeground.withOpacity(0.5), - ), - focusedTextStyle: context.theme.typography.sm.copyWith( - color: context.theme.colorScheme.mutedForeground, - ), - ), - date: DateTime(2024, 3, 31), - onPress: print, - today: true, - selected: true, - ), + Widget build(BuildContext context) { + final style = FMonthStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); + return Row( + children: [ + SizedBox( + height: 36, + width: 36, + child: EnabledDay( + style: style.current.disabled.todayStyle, + date: DateTime(2024, 3, 31), + onPress: print, + onLongPress: print, + today: true, + selected: true, ), - SizedBox( - height: 36, - width: 36, - child: EnabledDay( - style: FDayStateStyle( - decoration: const BoxDecoration(), - textStyle: context.theme.typography.sm.copyWith( - color: context.theme.colorScheme.mutedForeground.withOpacity(0.5), - ), - // focusedTextStyle: context.theme.typography.sm.copyWith( - // color: context.theme.colorScheme.mutedForeground, - // ), + ), + SizedBox( + height: 36, + width: 36, + child: EnabledDay( + style: style.current.disabled.unselectedStyle, + date: DateTime(2024, 4), + onPress: print, + onLongPress: print, + today: true, + selected: true, + ), + ), + SizedBox( + height: 36, + width: 36, + child: EnabledDay( + style: style.current.disabled.unselectedStyle, + date: DateTime(2024, 4), + onPress: print, + onLongPress: print, + today: true, + selected: true, ), - date: DateTime(2024, 4), - onPress: print, - today: true, - selected: true, - ), - ), - ], - ); + ), + ], + ); + } } @AutoRouterConfig() diff --git a/samples/lib/sample_scaffold.dart b/samples/lib/sample_scaffold.dart index 31026cbb1..77b54a6e2 100644 --- a/samples/lib/sample_scaffold.dart +++ b/samples/lib/sample_scaffold.dart @@ -12,7 +12,7 @@ abstract class SampleScaffold extends StatelessWidget { final FThemeData theme; SampleScaffold({ - String theme = 'zinc-dark', + String theme = 'zinc-light', super.key, }) : theme = themes[theme]!; From 4577169c4a6c3b36aea94eb7da7971aa655b5447 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 8 Jul 2024 13:54:37 +0800 Subject: [PATCH 05/35] Add month --- forui/lib/src/widgets/calendar/day.dart | 12 +- forui/lib/src/widgets/calendar/month.dart | 249 +++++++++++++++++----- samples/lib/main.dart | 47 +--- 3 files changed, 207 insertions(+), 101 deletions(-) diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index bd110ccdf..a898d64f5 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -113,8 +113,12 @@ class DisabledDay extends StatelessWidget { } /// A calender day's style. +/// +/// [todayStyle] takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is +/// selected, [todayStyle] will be applied. final class FDayStyle with Diagnosticable { - /// The current date's style. + /// The current date's style. This style takes precedence over [unselectedStyle] and [selectedStyle]. For example, if + /// the current date is selected, [todayStyle] will be applied. final FDayStateStyle todayStyle; /// The unselected dates' style. @@ -161,9 +165,9 @@ final class FDayStyle with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('todayStyle', todayStyle)) - ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)) - ..add(DiagnosticsProperty('selectedStyle', selectedStyle)); + ..add(DiagnosticsProperty('todayStyle', todayStyle)) + ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)) + ..add(DiagnosticsProperty('selectedStyle', selectedStyle)); } @override diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/month.dart index 65fd750da..d98f366fe 100644 --- a/forui/lib/src/widgets/calendar/month.dart +++ b/forui/lib/src/widgets/calendar/month.dart @@ -2,40 +2,169 @@ part of 'calendar.dart'; @internal class Month extends StatelessWidget { + final FMonthStyle style; final DateTime month; final DateTime today; + final bool Function(DateTime day) enabledPredicate; + final bool Function(DateTime day) selectedPredicate; + final ValueChanged onPress; + final ValueChanged onLongPress; const Month({ + required this.style, required this.month, required this.today, + required this.enabledPredicate, + required this.selectedPredicate, + required this.onPress, + required this.onLongPress, super.key, }); @override Widget build(BuildContext context) { - final first = month.firstDayOfMonth; + final (first, last) = _range(context); + final days = _headers(context); + for (var date = first; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1)) { + final current = date.month == month.month; + final selected = selectedPredicate(date); + final today = date == this.today; - return GridView.count( - scrollDirection: Axis.horizontal, - crossAxisCount: 5, + days.add( + enabledPredicate(date) + ? EnabledDay( + style: _style(style.enabled, current: current, selected: selected, today: today), + date: date, + onPress: onPress, + onLongPress: onLongPress, + today: today, + selected: selected, + ) + : DisabledDay( + style: _style(style.disabled, current: current, selected: selected, today: today), + date: date, + ), + ); + } + + return GridView.custom( + physics: const ClampingScrollPhysics(), + gridDelegate: const _GridDelegate(), + childrenDelegate: SliverChildListDelegate( + days, + addRepaintBoundaries: false, + ), ); } + + (DateTime, DateTime) _range(BuildContext context) { + final firstDayOfWeek = style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final firstDayOfMonth = month.firstDayOfMonth; + var difference = firstDayOfMonth.weekday - firstDayOfWeek; + if (difference < 0) { + difference += 7; + } + + final first = firstDayOfMonth.minus(days: difference); + + final lastDayOfWeek = firstDayOfWeek == DateTime.monday ? DateTime.sunday : firstDayOfWeek - 1; + final lastDayOfMonth = month.lastDayOfMonth; + difference = lastDayOfWeek - lastDayOfMonth.weekday; + if (difference < 0) { + difference += 7; + } + + final last = lastDayOfMonth.plus(days: difference); + + return (first, last); + } + + List _headers(BuildContext context) { + final firstDayOfWeek = style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final narrowWeekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']; // TODO: Localization + + return [ + for (int i = firstDayOfWeek, j = 0; j < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek, j++) + ExcludeSemantics( + child: Center(child: Text(narrowWeekdays[i - 1], style: style.headerTextStyle)), + ), + ]; + } + + FDayStateStyle _style( + ({FDayStyle current, FDayStyle enclosing}) styles, { + required bool current, + required bool selected, + required bool today, + }) => + switch ((current, selected, today)) { + (true, _, true) => styles.current.todayStyle, + (false, _, true) => styles.enclosing.todayStyle, + (true, true, false) => styles.current.selectedStyle, + (false, true, false) => styles.enclosing.selectedStyle, + (true, false, false) => styles.current.unselectedStyle, + (false, false, false) => styles.enclosing.unselectedStyle, + }; } +/// Based on Material [CalendarDatePicker]'s _DayPickerGridDelegate. +class _GridDelegate extends SliverGridDelegate { + + static const _dayPickerRowHeight = 42.0; + static const _maxDayPickerRowCount = 6; // A 31 day month that starts on Saturday. + + const _GridDelegate(); + + @override + SliverGridLayout getLayout(SliverConstraints constraints) { + final tileDimension = min( + _dayPickerRowHeight, + constraints.viewportMainAxisExtent / (_maxDayPickerRowCount + 1), + ); + return SliverGridRegularTileLayout( + childCrossAxisExtent: tileDimension, + childMainAxisExtent: tileDimension, + crossAxisCount: DateTime.daysPerWeek, + crossAxisStride: tileDimension, + mainAxisStride: tileDimension, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); + } + + @override + bool shouldRelayout(_GridDelegate oldDelegate) => false; +} /// A month's style. final class FMonthStyle with Diagnosticable { - /// The enabled and disabled styles for the current month on display. - final ({FDayStyle enabled, FDayStyle disabled}) current; + /// The text style for the day of th week headers. + final TextStyle headerTextStyle; + + /// The styles for the current month on display and the enclosing months when enabled. + final ({FDayStyle current, FDayStyle enclosing}) enabled; - /// The enabled and disabled styles for the months enclosing the current month on display. - final ({FDayStyle enabled, FDayStyle disabled}) enclosing; + /// The styles for the current month on display and the enclosing months when disabled. + final ({FDayStyle current, FDayStyle enclosing}) disabled; + + /// The starting day of the week. Defaults to the current locale's preferred starting day of the week if null. + /// + /// Specifying [startDayOfWeek] will override the current locale's preferred starting day of the week. + /// + /// ## Contract: + /// Throws an [AssertionError] if: + /// * [startDayOfWeek] < [DateTime.monday] + /// * [DateTime.sunday] < [startDayOfWeek] + final int? startDayOfWeek; /// Creates a [FMonthStyle]. const FMonthStyle({ - required this.current, - required this.enclosing, - }); + required this.headerTextStyle, + required this.enabled, required this.disabled, this.startDayOfWeek, + }): + assert( + startDayOfWeek == null || (DateTime.monday <= startDayOfWeek && startDayOfWeek <= DateTime.sunday), + 'startDayOfWeek must be between DateTime.monday (1) and DateTime.sunday (7).', + ); /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { @@ -57,59 +186,63 @@ final class FMonthStyle with Diagnosticable { ); return FMonthStyle( - current: ( - enabled: FDayStyle( - todayStyle: FDayStateStyle.inherit( - color: colorScheme.secondary, - textStyle: textStyle, - ), - unselectedStyle: FDayStateStyle.inherit( - textStyle: textStyle, - focusedColor: colorScheme.secondary, + headerTextStyle: typography.sm.copyWith(color: colorScheme.secondaryForeground), + enabled: ( + current: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.secondary, + textStyle: textStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: textStyle, + focusedColor: colorScheme.secondary, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.foreground, + textStyle: typography.sm.copyWith(color: colorScheme.background), + ), ), - selectedStyle: FDayStateStyle.inherit( - color: colorScheme.foreground, - textStyle: typography.sm.copyWith(color: colorScheme.background), + enclosing: FDayStyle( + todayStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), + unselectedStyle: FDayStateStyle.inherit( + textStyle: mutedTextStyle, + focusedColor: colorScheme.primaryForeground, + ), + selectedStyle: FDayStateStyle.inherit( + color: colorScheme.primaryForeground, + textStyle: mutedTextStyle, + ), ), ), - disabled: disabled, - ), - enclosing: ( - enabled: FDayStyle( - todayStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - ), - unselectedStyle: FDayStateStyle.inherit( - textStyle: mutedTextStyle, - ), - selectedStyle: FDayStateStyle.inherit( - color: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - focusedTextStyle: typography.sm.copyWith(color: colorScheme.mutedForeground), - ), - ), - disabled: disabled, + disabled: ( + current: disabled, + enclosing: disabled, ), ); } /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// ``` FMonthStyle copyWith({ FDayStyle? currentEnabled, - FDayStyle? currentDisabled, FDayStyle? enclosingEnabled, + FDayStyle? currentDisabled, FDayStyle? enclosingDisabled, }) => FMonthStyle( - current: ( - enabled: currentEnabled ?? current.enabled, - disabled: currentDisabled ?? current.disabled, + headerTextStyle: headerTextStyle, + enabled: ( + current: currentEnabled ?? enabled.current, + enclosing: enclosingEnabled ?? enabled.enclosing, ), - enclosing: ( - enabled: enclosingEnabled ?? enclosing.enabled, - disabled: enclosingDisabled ?? enclosing.disabled, + disabled: ( + current: currentDisabled ?? disabled.current, + enclosing: enclosingDisabled ?? disabled.enclosing, ), ); @@ -117,20 +250,20 @@ final class FMonthStyle with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('current.enabled', current.enabled)) - ..add(DiagnosticsProperty('current.disabled', current.disabled)) - ..add(DiagnosticsProperty('enclosing.enabled', enclosing.enabled)) - ..add(DiagnosticsProperty('enclosing.disabled', enclosing.disabled)); + ..add(DiagnosticsProperty('enabled.current', enabled.current)) + ..add(DiagnosticsProperty('enabled.enclosing', enabled.enclosing)) + ..add(DiagnosticsProperty('disabled.current', disabled.current)) + ..add(DiagnosticsProperty('disabled.enclosing', disabled.enclosing)); } @override bool operator ==(Object other) => identical(this, other) || - other is FMonthStyle && - runtimeType == other.runtimeType && - current == other.current && - enclosing == other.enclosing; + other is FMonthStyle && + runtimeType == other.runtimeType && + enabled == other.enabled && + disabled == other.disabled; @override - int get hashCode => current.hashCode ^ enclosing.hashCode; + int get hashCode => enabled.hashCode ^ disabled.hashCode; } diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 21dbd72fb..e577e54fd 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -39,45 +39,14 @@ class Testing extends StatelessWidget { @override Widget build(BuildContext context) { final style = FMonthStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); - return Row( - children: [ - SizedBox( - height: 36, - width: 36, - child: EnabledDay( - style: style.current.disabled.todayStyle, - date: DateTime(2024, 3, 31), - onPress: print, - onLongPress: print, - today: true, - selected: true, - ), - ), - SizedBox( - height: 36, - width: 36, - child: EnabledDay( - style: style.current.disabled.unselectedStyle, - date: DateTime(2024, 4), - onPress: print, - onLongPress: print, - today: true, - selected: true, - ), - ), - SizedBox( - height: 36, - width: 36, - child: EnabledDay( - style: style.current.disabled.unselectedStyle, - date: DateTime(2024, 4), - onPress: print, - onLongPress: print, - today: true, - selected: true, - ), - ), - ], + return Month( + style: style, + month: DateTime.now().minus(months: 1), + today: DateTime(2024, 7 , 8), + enabledPredicate: (_) => true, + selectedPredicate: (_) => false, + onPress: print, + onLongPress: print, ); } } From b3c11142be5d23b953f5e3c074e17a04aa27546a Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 8 Jul 2024 17:02:27 +0800 Subject: [PATCH 06/35] Refactor month --- forui/lib/src/widgets/calendar/calendar.dart | 1 + forui/lib/src/widgets/calendar/day.dart | 91 +++++++--- forui/lib/src/widgets/calendar/header.dart | 2 + forui/lib/src/widgets/calendar/month.dart | 175 ++++++++++++------- 4 files changed, 174 insertions(+), 95 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/header.dart diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 532d668b4..ec08f584a 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -6,4 +6,5 @@ import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; part 'day.dart'; +part 'header.dart'; part 'month.dart'; \ No newline at end of file diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index a898d64f5..151d1a79e 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -1,20 +1,46 @@ part of 'calendar.dart'; -// Possible states -// current month, unselected -// current month, today/focused/hovered -// current month, selected -// current month, disabled +@internal +/// Returns the [date]. +Widget day( + FMonthStyle monthStyle, + DateTime date, + FocusNode focusNode, + ValueChanged onPress, + ValueChanged onLongPress, { + required bool enabled, + required bool current, + required bool today, + required bool selected, +}) { + final styles = enabled ? monthStyle.enabled : monthStyle.disabled; + final dayStyle = current ? styles.current : styles.enclosing; + final style = switch ((today, selected)) { + (true, _) => dayStyle.todayStyle, + (_, true) => dayStyle.selectedStyle, + (_, false) => dayStyle.unselectedStyle, + }; -// previous month, unselected -// previous month, today/focused/hovered -// previous month, selected -// previous month, disabled + if (enabled) { + return EnabledDay( + style: style, + date: date, + focusNode: focusNode, + onPress: onPress, + onLongPress: onLongPress, + today: today, + selected: selected, + ); + } else { + return DisabledDay(style: style, date: date); + } +} @internal class EnabledDay extends StatefulWidget { final FDayStateStyle style; final DateTime date; + final FocusNode focusNode; final ValueChanged onPress; final ValueChanged onLongPress; final bool today; @@ -23,6 +49,7 @@ class EnabledDay extends StatefulWidget { const EnabledDay({ required this.style, required this.date, + required this.focusNode, required this.onPress, required this.onLongPress, required this.today, @@ -39,6 +66,7 @@ class EnabledDay extends StatefulWidget { properties ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onLongPress', onLongPress, level: DiagnosticLevel.debug)) ..add(FlagProperty('today', value: today, ifTrue: 'today', level: DiagnosticLevel.debug)) @@ -50,24 +78,27 @@ class _EnabledDayState extends State { bool focused = false; @override - Widget build(BuildContext context) => MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => focused = true), - onExit: (_) => setState(() => focused = false), - child: Semantics( - label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization - button: true, - selected: widget.selected, - excludeSemantics: true, - child: GestureDetector( - onTap: () => widget.onPress(widget.date), - onLongPress: () => widget.onLongPress(widget.date), - child: DecoratedBox( - decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, - child: Center( - child: Text( - '${widget.date.day}', // TODO: localization - style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + Widget build(BuildContext context) => Focus( + focusNode: widget.focusNode, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => focused = true), + onExit: (_) => setState(() => focused = false), + child: Semantics( + label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization + button: true, + selected: widget.selected, + excludeSemantics: true, + child: GestureDetector( + onTap: () => widget.onPress(widget.date), + onLongPress: () => widget.onLongPress(widget.date), + child: DecoratedBox( + decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, + child: Center( + child: Text( + '${widget.date.day}', // TODO: localization + style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + ), ), ), ), @@ -117,8 +148,10 @@ class DisabledDay extends StatelessWidget { /// [todayStyle] takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is /// selected, [todayStyle] will be applied. final class FDayStyle with Diagnosticable { - /// The current date's style. This style takes precedence over [unselectedStyle] and [selectedStyle]. For example, if - /// the current date is selected, [todayStyle] will be applied. + /// The current date's style. + /// + /// This style takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is + /// selected, [todayStyle] will be applied. final FDayStateStyle todayStyle; /// The unselected dates' style. diff --git a/forui/lib/src/widgets/calendar/header.dart b/forui/lib/src/widgets/calendar/header.dart new file mode 100644 index 000000000..e78dcedb3 --- /dev/null +++ b/forui/lib/src/widgets/calendar/header.dart @@ -0,0 +1,2 @@ +part of 'calendar.dart'; + diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/month.dart index d98f366fe..8f613f1d0 100644 --- a/forui/lib/src/widgets/calendar/month.dart +++ b/forui/lib/src/widgets/calendar/month.dart @@ -1,10 +1,11 @@ part of 'calendar.dart'; @internal -class Month extends StatelessWidget { +class Month extends StatefulWidget { final FMonthStyle style; final DateTime month; final DateTime today; + final DateTime? focused; final bool Function(DateTime day) enabledPredicate; final bool Function(DateTime day) selectedPredicate; final ValueChanged onPress; @@ -14,6 +15,7 @@ class Month extends StatelessWidget { required this.style, required this.month, required this.today, + required this.focused, required this.enabledPredicate, required this.selectedPredicate, required this.onPress, @@ -21,45 +23,65 @@ class Month extends StatelessWidget { super.key, }); + @override + State createState() => _MonthState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('month', month)) + ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('focused', focused)) + ..add(ObjectFlagProperty('enabledPredicate', enabledPredicate, ifNull: 'null')) + ..add(ObjectFlagProperty('selectedPredicate', selectedPredicate, ifNull: 'null')) + ..add(ObjectFlagProperty('onPress', onPress, ifNull: 'null')) + ..add(ObjectFlagProperty('onLongPress', onLongPress, ifNull: 'null')); + } +} + +class _MonthState extends State { + List _dayFocusNodes = []; + + @override + void initState() { + super.initState(); + _dayFocusNodes = [ + for (int i = 1; i < widget.month.daysInMonth; i++) FocusNode(skipTraversal: true, debugLabel: 'Day $i'), + ]; + } + @override Widget build(BuildContext context) { final (first, last) = _range(context); - final days = _headers(context); - for (var date = first; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1)) { - final current = date.month == month.month; - final selected = selectedPredicate(date); - final today = date == this.today; - - days.add( - enabledPredicate(date) - ? EnabledDay( - style: _style(style.enabled, current: current, selected: selected, today: today), - date: date, - onPress: onPress, - onLongPress: onLongPress, - today: today, - selected: selected, - ) - : DisabledDay( - style: _style(style.disabled, current: current, selected: selected, today: today), - date: date, - ), - ); - } - return GridView.custom( physics: const ClampingScrollPhysics(), gridDelegate: const _GridDelegate(), childrenDelegate: SliverChildListDelegate( - days, + [ + ..._headers(context), + for (var date = first; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1)) + day( + widget.style, + date, + _dayFocusNodes[date.day - 1], + widget.onPress, + widget.onLongPress, + enabled: widget.enabledPredicate(date), + current: date.month == widget.month.month, + today: date == widget.today, + selected: widget.selectedPredicate(date), + ), + ], addRepaintBoundaries: false, ), ); } (DateTime, DateTime) _range(BuildContext context) { - final firstDayOfWeek = style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization - final firstDayOfMonth = month.firstDayOfMonth; + final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final firstDayOfMonth = widget.month.firstDayOfMonth; var difference = firstDayOfMonth.weekday - firstDayOfWeek; if (difference < 0) { difference += 7; @@ -68,48 +90,49 @@ class Month extends StatelessWidget { final first = firstDayOfMonth.minus(days: difference); final lastDayOfWeek = firstDayOfWeek == DateTime.monday ? DateTime.sunday : firstDayOfWeek - 1; - final lastDayOfMonth = month.lastDayOfMonth; + final lastDayOfMonth = widget.month.lastDayOfMonth; difference = lastDayOfWeek - lastDayOfMonth.weekday; if (difference < 0) { difference += 7; } final last = lastDayOfMonth.plus(days: difference); - + return (first, last); } List _headers(BuildContext context) { - final firstDayOfWeek = style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization final narrowWeekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']; // TODO: Localization return [ for (int i = firstDayOfWeek, j = 0; j < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek, j++) ExcludeSemantics( - child: Center(child: Text(narrowWeekdays[i - 1], style: style.headerTextStyle)), + child: Center(child: Text(narrowWeekdays[i - 1], style: widget.style.headerTextStyle)), ), ]; } - FDayStateStyle _style( - ({FDayStyle current, FDayStyle enclosing}) styles, { - required bool current, - required bool selected, - required bool today, - }) => - switch ((current, selected, today)) { - (true, _, true) => styles.current.todayStyle, - (false, _, true) => styles.enclosing.todayStyle, - (true, true, false) => styles.current.selectedStyle, - (false, true, false) => styles.enclosing.selectedStyle, - (true, false, false) => styles.current.unselectedStyle, - (false, false, false) => styles.enclosing.unselectedStyle, - }; + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final focused = widget.focused; + if (focused != null && focused.month == widget.month.month) { + _dayFocusNodes[focused.day - 1].requestFocus(); + } + } + + @override + void dispose() { + for (final node in _dayFocusNodes) { + node.dispose(); + } + super.dispose(); + } } /// Based on Material [CalendarDatePicker]'s _DayPickerGridDelegate. class _GridDelegate extends SliverGridDelegate { - static const _dayPickerRowHeight = 42.0; static const _maxDayPickerRowCount = 6; // A 31 day month that starts on Saturday. @@ -140,10 +163,10 @@ final class FMonthStyle with Diagnosticable { /// The text style for the day of th week headers. final TextStyle headerTextStyle; - /// The styles for the current month on display and the enclosing months when enabled. + /// The styles of the current month on display and the enclosing months, when enabled. final ({FDayStyle current, FDayStyle enclosing}) enabled; - /// The styles for the current month on display and the enclosing months when disabled. + /// The styles of the current month on display and the enclosing months, when disabled. final ({FDayStyle current, FDayStyle enclosing}) disabled; /// The starting day of the week. Defaults to the current locale's preferred starting day of the week if null. @@ -159,12 +182,13 @@ final class FMonthStyle with Diagnosticable { /// Creates a [FMonthStyle]. const FMonthStyle({ required this.headerTextStyle, - required this.enabled, required this.disabled, this.startDayOfWeek, - }): - assert( - startDayOfWeek == null || (DateTime.monday <= startDayOfWeek && startDayOfWeek <= DateTime.sunday), - 'startDayOfWeek must be between DateTime.monday (1) and DateTime.sunday (7).', - ); + required this.enabled, + required this.disabled, + this.startDayOfWeek, + }) : assert( + startDayOfWeek == null || (DateTime.monday <= startDayOfWeek && startDayOfWeek <= DateTime.sunday), + 'startDayOfWeek must be between DateTime.monday (1) and DateTime.sunday (7).', + ); /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { @@ -227,33 +251,50 @@ final class FMonthStyle with Diagnosticable { /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. /// /// ```dart + /// final style = FMonthStyle( + /// headerTextStyle: ..., + /// enabledCurrent: ..., + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith( + /// enabledCurrent: ..., + /// ); + /// + /// print(style.headerTextStyle == copy.headerTextStyle); // true + /// print(style.enabled.current == copy.enabled.current); // false /// ``` FMonthStyle copyWith({ - FDayStyle? currentEnabled, - FDayStyle? enclosingEnabled, - FDayStyle? currentDisabled, - FDayStyle? enclosingDisabled, + TextStyle? headerTextStyle, + FDayStyle? enabledCurrent, + FDayStyle? enabledEnclosing, + FDayStyle? disabledCurrent, + FDayStyle? disabledEnclosing, + int? startDayOfWeek, }) => FMonthStyle( - headerTextStyle: headerTextStyle, + headerTextStyle: headerTextStyle ?? this.headerTextStyle, enabled: ( - current: currentEnabled ?? enabled.current, - enclosing: enclosingEnabled ?? enabled.enclosing, + current: enabledCurrent ?? enabled.current, + enclosing: enabledEnclosing ?? enabled.enclosing, ), disabled: ( - current: currentDisabled ?? disabled.current, - enclosing: enclosingDisabled ?? disabled.enclosing, + current: disabledCurrent ?? disabled.current, + enclosing: disabledEnclosing ?? disabled.enclosing, ), + startDayOfWeek: startDayOfWeek ?? this.startDayOfWeek, ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties + ..add(DiagnosticsProperty('headerTextStyle', headerTextStyle)) ..add(DiagnosticsProperty('enabled.current', enabled.current)) ..add(DiagnosticsProperty('enabled.enclosing', enabled.enclosing)) ..add(DiagnosticsProperty('disabled.current', disabled.current)) - ..add(DiagnosticsProperty('disabled.enclosing', disabled.enclosing)); + ..add(DiagnosticsProperty('disabled.enclosing', disabled.enclosing)) + ..add(IntProperty('startDayOfWeek', startDayOfWeek)); } @override @@ -261,9 +302,11 @@ final class FMonthStyle with Diagnosticable { identical(this, other) || other is FMonthStyle && runtimeType == other.runtimeType && + headerTextStyle == other.headerTextStyle && enabled == other.enabled && - disabled == other.disabled; + disabled == other.disabled && + startDayOfWeek == other.startDayOfWeek; @override - int get hashCode => enabled.hashCode ^ disabled.hashCode; + int get hashCode => headerTextStyle.hashCode ^ enabled.hashCode ^ disabled.hashCode ^ startDayOfWeek.hashCode; } From 7ff9929b760f456daa073736edf7b08b4a0f1ed4 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 8 Jul 2024 22:15:17 +0800 Subject: [PATCH 07/35] Add calendar header --- forui/lib/src/widgets/calendar/header.dart | 129 +++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/forui/lib/src/widgets/calendar/header.dart b/forui/lib/src/widgets/calendar/header.dart index e78dcedb3..8621de899 100644 --- a/forui/lib/src/widgets/calendar/header.dart +++ b/forui/lib/src/widgets/calendar/header.dart @@ -1,2 +1,131 @@ part of 'calendar.dart'; +@internal +class Header extends StatelessWidget { + final FCalendarHeaderStyle style; + final DateTime month; + final VoidCallback? onPrevious; + final VoidCallback? onNext; + + const Header({ + required this.style, + required this.month, + required this.onPrevious, + required this.onNext, + super.key, + }); + + @override + Widget build(BuildContext context) { + final buttonStyle = context.theme.buttonStyles.outline; + final effectiveButtonStyle = buttonStyle.copyWith( + enabledBoxDecoration: buttonStyle.enabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), + disabledBoxDecoration: buttonStyle.disabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), + ); + + return Padding( + padding: const EdgeInsets.only(bottom: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 7), + child: FButton.raw( + style: effectiveButtonStyle, + onPress: onPrevious, + child: Padding( + padding: const EdgeInsets.all(5), + child: FAssets.icons.chevronLeft( + height: 16, + colorFilter: ColorFilter.mode( + style.iconColor, + BlendMode.srcIn, + ), + ), + ), + ), + ), + Text('July ${month.year}', style: style.headerTextStyle), // TODO: Localization + Padding( + padding: const EdgeInsets.only(right: 7), + child: FButton.raw( + style: effectiveButtonStyle, + onPress: onNext, + child: Padding( + padding: const EdgeInsets.all(5), + child: FAssets.icons.chevronRight( + height: 16, + colorFilter: ColorFilter.mode( + style.iconColor, + BlendMode.srcIn, + ), + ), + ), + ), + ), + ], + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('month', month)) + ..add(DiagnosticsProperty('onPrevious', onPrevious)) + ..add(DiagnosticsProperty('onNext', onNext)); + } +} + +/// The calendar header's style. +final class FCalendarHeaderStyle { + /// The header's text style. + final TextStyle headerTextStyle; + + /// The unfocused header icons' color. + final Color iconColor; + + /// Creates a [FCalendarHeaderStyle]. + FCalendarHeaderStyle({ + required this.headerTextStyle, + required this.iconColor, + }); + + /// Creates a copy of this but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarHeaderStyle( + /// headerTextStyle: ..., + /// iconColor:..., + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith( + /// iconColor: ..., + /// ); + /// + /// print(style.headerTextStyle == copy.headerTextStyle); // true + /// print(style.iconColor == copy.iconColor); // false + /// ``` + FCalendarHeaderStyle copyWith({ + TextStyle? headerTextStyle, + Color? iconColor, + }) => + FCalendarHeaderStyle( + headerTextStyle: headerTextStyle ?? this.headerTextStyle, + iconColor: iconColor ?? this.iconColor, + ); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarHeaderStyle && + runtimeType == other.runtimeType && + headerTextStyle == other.headerTextStyle && + iconColor == other.iconColor; + + @override + int get hashCode => headerTextStyle.hashCode ^ iconColor.hashCode; +} From 1e41d2c9c63453adc21bf58b482f13f53f5cfda1 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 8 Jul 2024 22:15:46 +0800 Subject: [PATCH 08/35] First working scrolling calendar prototype --- forui/example/lib/main.dart | 6 +- forui/lib/src/widgets/calendar/calendar.dart | 3 +- forui/lib/src/widgets/calendar/month.dart | 42 ++++++------ .../lib/src/widgets/calendar/paged_month.dart | 64 +++++++++++++++++++ samples/lib/main.dart | 13 +--- 5 files changed, 91 insertions(+), 37 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/paged_month.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 08fe02b76..41a50cfa7 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -30,6 +30,10 @@ class Application extends StatelessWidget { content: child ?? const SizedBox(), ), ), - home: const Example(), + home: Column( + children: [ + PagedMonth(initialDate: DateTime(2024, 7, 8)), + ], + ), ); } diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index ec08f584a..a05e874ee 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -7,4 +7,5 @@ import 'package:sugar/sugar.dart'; part 'day.dart'; part 'header.dart'; -part 'month.dart'; \ No newline at end of file +part 'month.dart'; +part 'paged_month.dart'; diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/month.dart index 8f613f1d0..cef813645 100644 --- a/forui/lib/src/widgets/calendar/month.dart +++ b/forui/lib/src/widgets/calendar/month.dart @@ -1,5 +1,8 @@ part of 'calendar.dart'; +const _maxMonthRows = 6; // A 31 day month that starts on Saturday. +const _monthDayDimension = 40.0; + @internal class Month extends StatefulWidget { final FMonthStyle style; @@ -48,7 +51,7 @@ class _MonthState extends State { void initState() { super.initState(); _dayFocusNodes = [ - for (int i = 1; i < widget.month.daysInMonth; i++) FocusNode(skipTraversal: true, debugLabel: 'Day $i'), + for (int i = 0; i < (DateTime.daysPerWeek * _maxMonthRows); i++) FocusNode(skipTraversal: true, debugLabel: 'Day $i'), ]; } @@ -56,16 +59,18 @@ class _MonthState extends State { Widget build(BuildContext context) { final (first, last) = _range(context); return GridView.custom( - physics: const ClampingScrollPhysics(), + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), gridDelegate: const _GridDelegate(), childrenDelegate: SliverChildListDelegate( [ ..._headers(context), - for (var date = first; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1)) + for (var date = first, i = 0; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1), i++) day( widget.style, date, - _dayFocusNodes[date.day - 1], + _dayFocusNodes[i], widget.onPress, widget.onLongPress, enabled: widget.enabledPredicate(date), @@ -118,7 +123,7 @@ class _MonthState extends State { super.didChangeDependencies(); final focused = widget.focused; if (focused != null && focused.month == widget.month.month) { - _dayFocusNodes[focused.day - 1].requestFocus(); + _dayFocusNodes[focused.day - 1].requestFocus(); // TODO: fix this } } @@ -133,26 +138,17 @@ class _MonthState extends State { /// Based on Material [CalendarDatePicker]'s _DayPickerGridDelegate. class _GridDelegate extends SliverGridDelegate { - static const _dayPickerRowHeight = 42.0; - static const _maxDayPickerRowCount = 6; // A 31 day month that starts on Saturday. - const _GridDelegate(); @override - SliverGridLayout getLayout(SliverConstraints constraints) { - final tileDimension = min( - _dayPickerRowHeight, - constraints.viewportMainAxisExtent / (_maxDayPickerRowCount + 1), - ); - return SliverGridRegularTileLayout( - childCrossAxisExtent: tileDimension, - childMainAxisExtent: tileDimension, + SliverGridLayout getLayout(SliverConstraints constraints) => SliverGridRegularTileLayout( + childCrossAxisExtent: _monthDayDimension, + childMainAxisExtent: _monthDayDimension, crossAxisCount: DateTime.daysPerWeek, - crossAxisStride: tileDimension, - mainAxisStride: tileDimension, + crossAxisStride: _monthDayDimension, + mainAxisStride: _monthDayDimension, reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), ); - } @override bool shouldRelayout(_GridDelegate oldDelegate) => false; @@ -192,8 +188,8 @@ final class FMonthStyle with Diagnosticable { /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { - final textStyle = typography.sm.copyWith(color: colorScheme.foreground); - final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground); + final textStyle = typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500); + final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); final disabled = FDayStyle( todayStyle: FDayStateStyle.inherit( @@ -210,7 +206,7 @@ final class FMonthStyle with Diagnosticable { ); return FMonthStyle( - headerTextStyle: typography.sm.copyWith(color: colorScheme.secondaryForeground), + headerTextStyle: typography.xs.copyWith(color: colorScheme.mutedForeground), enabled: ( current: FDayStyle( todayStyle: FDayStateStyle.inherit( @@ -223,7 +219,7 @@ final class FMonthStyle with Diagnosticable { ), selectedStyle: FDayStateStyle.inherit( color: colorScheme.foreground, - textStyle: typography.sm.copyWith(color: colorScheme.background), + textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), ), ), enclosing: FDayStyle( diff --git a/forui/lib/src/widgets/calendar/paged_month.dart b/forui/lib/src/widgets/calendar/paged_month.dart new file mode 100644 index 000000000..c9d8df4c4 --- /dev/null +++ b/forui/lib/src/widgets/calendar/paged_month.dart @@ -0,0 +1,64 @@ +part of 'calendar.dart'; + +@internal +class PagedMonth extends StatefulWidget { + final DateTime initialDate; + final PageController? controller; + + const PagedMonth({required this.initialDate, this.controller, super.key}); + + @override + State createState() => _PagedMonthState(); +} + +class _PagedMonthState extends State { + @override + Widget build(BuildContext context) { + final style = FMonthStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); + return DecoratedBox( + decoration: BoxDecoration( + borderRadius: context.theme.style.borderRadius, + border: Border.all( + color: context.theme.colorScheme.border, + )), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + child: SizedBox( + width: _monthDayDimension * DateTime.daysPerWeek, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Header( + style: FCalendarHeaderStyle( + headerTextStyle: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.primary, + fontWeight: FontWeight.w600, + ), + iconColor: context.theme.colorScheme.mutedForeground, + ), + month: widget.initialDate, + onPrevious: () {}, + onNext: () {}, + ), + SizedBox( + height: _monthDayDimension * _maxMonthRows, + child: PageView.builder( + itemBuilder: (context, index) => Month( + focused: null, + style: style, + month: widget.initialDate, + today: DateTime(2024, 7, 8), + enabledPredicate: (_) => true, + selectedPredicate: (_) => false, + onPress: print, + onLongPress: print, + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/samples/lib/main.dart b/samples/lib/main.dart index e577e54fd..fcb2bc76e 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -37,18 +37,7 @@ class Testing extends StatelessWidget { const Testing({super.key}); @override - Widget build(BuildContext context) { - final style = FMonthStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); - return Month( - style: style, - month: DateTime.now().minus(months: 1), - today: DateTime(2024, 7 , 8), - enabledPredicate: (_) => true, - selectedPredicate: (_) => false, - onPress: print, - onLongPress: print, - ); - } + Widget build(BuildContext context) => PagedMonth(initialDate: DateTime(2024, 7, 8)); } @AutoRouterConfig() From cecb055db4774259d15d4f4d836bb5e1a4bf7924 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 9 Jul 2024 16:56:39 +0800 Subject: [PATCH 09/35] Fix focusNode issue in Month --- forui/lib/src/widgets/calendar/calendar.dart | 2 + forui/lib/src/widgets/calendar/day.dart | 12 +- forui/lib/src/widgets/calendar/header.dart | 14 +- forui/lib/src/widgets/calendar/month.dart | 139 ++++++++++-------- .../lib/src/widgets/calendar/paged_month.dart | 8 +- 5 files changed, 100 insertions(+), 75 deletions(-) diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index a05e874ee..b19df5bdf 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,3 +1,5 @@ +import 'dart:collection'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index 151d1a79e..48e1141d8 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -1,10 +1,10 @@ part of 'calendar.dart'; -@internal /// Returns the [date]. +@internal Widget day( FMonthStyle monthStyle, - DateTime date, + LocalDate date, FocusNode focusNode, ValueChanged onPress, ValueChanged onLongPress, { @@ -39,7 +39,7 @@ Widget day( @internal class EnabledDay extends StatefulWidget { final FDayStateStyle style; - final DateTime date; + final LocalDate date; final FocusNode focusNode; final ValueChanged onPress; final ValueChanged onLongPress; @@ -90,8 +90,8 @@ class _EnabledDayState extends State { selected: widget.selected, excludeSemantics: true, child: GestureDetector( - onTap: () => widget.onPress(widget.date), - onLongPress: () => widget.onLongPress(widget.date), + onTap: () => widget.onPress(widget.date.toNative()), + onLongPress: () => widget.onLongPress(widget.date.toNative()), child: DecoratedBox( decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, child: Center( @@ -116,7 +116,7 @@ class _EnabledDayState extends State { @internal class DisabledDay extends StatelessWidget { final FDayStateStyle style; - final DateTime date; + final LocalDate date; const DisabledDay({ required this.style, diff --git a/forui/lib/src/widgets/calendar/header.dart b/forui/lib/src/widgets/calendar/header.dart index 8621de899..4c784fe8c 100644 --- a/forui/lib/src/widgets/calendar/header.dart +++ b/forui/lib/src/widgets/calendar/header.dart @@ -3,7 +3,7 @@ part of 'calendar.dart'; @internal class Header extends StatelessWidget { final FCalendarHeaderStyle style; - final DateTime month; + final LocalDate month; final VoidCallback? onPrevious; final VoidCallback? onNext; @@ -31,6 +31,7 @@ class Header extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 7), child: FButton.raw( + // TODO: Replace with FButton.icon. style: effectiveButtonStyle, onPress: onPrevious, child: Padding( @@ -49,6 +50,7 @@ class Header extends StatelessWidget { Padding( padding: const EdgeInsets.only(right: 7), child: FButton.raw( + // TODO: Replace with FButton.icon. style: effectiveButtonStyle, onPress: onNext, child: Padding( @@ -93,6 +95,16 @@ final class FCalendarHeaderStyle { required this.iconColor, }); + /// Creates a [FCalendarHeaderStyle] that inherits its values from the given [colorScheme] and [typography]. + FCalendarHeaderStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : this( + headerTextStyle: typography.sm.copyWith( + color: colorScheme.primary, + fontWeight: FontWeight.w600, + ), + iconColor: colorScheme.mutedForeground, + ); + /// Creates a copy of this but with the given fields replaced with the new values. /// /// ```dart diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/month.dart index cef813645..05ee4ddc3 100644 --- a/forui/lib/src/widgets/calendar/month.dart +++ b/forui/lib/src/widgets/calendar/month.dart @@ -1,14 +1,19 @@ part of 'calendar.dart'; -const _maxMonthRows = 6; // A 31 day month that starts on Saturday. -const _monthDayDimension = 40.0; +/// The maximum number of rows in a month. In this case, a 31 day month that starts on Saturday. +@internal +const maxMonthRows = 6; + +/// The height & width of a day in a [Month]. +@internal +const dayDimension = 40.0; @internal class Month extends StatefulWidget { final FMonthStyle style; - final DateTime month; - final DateTime today; - final DateTime? focused; + final LocalDate month; + final LocalDate today; + final LocalDate? focused; final bool Function(DateTime day) enabledPredicate; final bool Function(DateTime day) selectedPredicate; final ValueChanged onPress; @@ -45,46 +50,69 @@ class Month extends StatefulWidget { } class _MonthState extends State { - List _dayFocusNodes = []; + final SplayTreeMap _days = SplayTreeMap(); @override void initState() { super.initState(); - _dayFocusNodes = [ - for (int i = 0; i < (DateTime.daysPerWeek * _maxMonthRows); i++) FocusNode(skipTraversal: true, debugLabel: 'Day $i'), - ]; + _updateMonth(); } @override - Widget build(BuildContext context) { - final (first, last) = _range(context); - return GridView.custom( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const _GridDelegate(), - childrenDelegate: SliverChildListDelegate( - [ - ..._headers(context), - for (var date = first, i = 0; date.isBefore(last) || date.isAtSameMomentAs(last); date = date.plus(days: 1), i++) - day( - widget.style, - date, - _dayFocusNodes[i], - widget.onPress, - widget.onLongPress, - enabled: widget.enabledPredicate(date), - current: date.month == widget.month.month, - today: date == widget.today, - selected: widget.selectedPredicate(date), - ), - ], - addRepaintBoundaries: false, + Widget build(BuildContext context) => SizedBox( + height: maxMonthRows * dayDimension, + width: DateTime.daysPerWeek * dayDimension, + child: GridView.custom( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const _GridDelegate(), + childrenDelegate: SliverChildListDelegate( + [ + ..._headers(context), + for (final MapEntry(key: date, value: focusNode) in _days.entries) + day( + widget.style, + date, + focusNode, + widget.onPress, + widget.onLongPress, + enabled: widget.enabledPredicate(date.toNative()), + current: date.month == widget.month.month, + today: date == widget.today, + selected: widget.selectedPredicate(date.toNative()), + ), + ], + addRepaintBoundaries: false, + ), ), ); + + List _headers(BuildContext context) { + final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final narrowWeekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']; // TODO: Localization + + return [ + for (int i = firstDayOfWeek, j = 0; j < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek, j++) + ExcludeSemantics( + child: Center(child: Text(narrowWeekdays[i - 1], style: widget.style.headerTextStyle)), + ), + ]; } - (DateTime, DateTime) _range(BuildContext context) { + @override + void didUpdateWidget(Month old) { + super.didUpdateWidget(old); + if (old.month != widget.month) { + _updateMonth(); + } + + if (_days[widget.focused] case final focusNode? when old.focused != widget.focused) { + focusNode.requestFocus(); + } + } + + void _updateMonth() { final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization final firstDayOfMonth = widget.month.firstDayOfMonth; var difference = firstDayOfMonth.weekday - firstDayOfWeek; @@ -103,33 +131,15 @@ class _MonthState extends State { final last = lastDayOfMonth.plus(days: difference); - return (first, last); - } - - List _headers(BuildContext context) { - final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization - final narrowWeekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']; // TODO: Localization - - return [ - for (int i = firstDayOfWeek, j = 0; j < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek, j++) - ExcludeSemantics( - child: Center(child: Text(narrowWeekdays[i - 1], style: widget.style.headerTextStyle)), - ), - ]; - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final focused = widget.focused; - if (focused != null && focused.month == widget.month.month) { - _dayFocusNodes[focused.day - 1].requestFocus(); // TODO: fix this + _days.clear(); + for (var date = first; date <= last; date = date.tomorrow) { + _days[date] = FocusNode(skipTraversal: true, debugLabel: '$date'); } } @override void dispose() { - for (final node in _dayFocusNodes) { + for (final node in _days.values) { node.dispose(); } super.dispose(); @@ -142,13 +152,13 @@ class _GridDelegate extends SliverGridDelegate { @override SliverGridLayout getLayout(SliverConstraints constraints) => SliverGridRegularTileLayout( - childCrossAxisExtent: _monthDayDimension, - childMainAxisExtent: _monthDayDimension, - crossAxisCount: DateTime.daysPerWeek, - crossAxisStride: _monthDayDimension, - mainAxisStride: _monthDayDimension, - reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), - ); + childCrossAxisExtent: dayDimension, + childMainAxisExtent: dayDimension, + crossAxisCount: DateTime.daysPerWeek, + crossAxisStride: dayDimension, + mainAxisStride: dayDimension, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); @override bool shouldRelayout(_GridDelegate oldDelegate) => false; @@ -189,7 +199,8 @@ final class FMonthStyle with Diagnosticable { /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { final textStyle = typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500); - final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); + final mutedTextStyle = + typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); final disabled = FDayStyle( todayStyle: FDayStateStyle.inherit( diff --git a/forui/lib/src/widgets/calendar/paged_month.dart b/forui/lib/src/widgets/calendar/paged_month.dart index c9d8df4c4..68dfd1267 100644 --- a/forui/lib/src/widgets/calendar/paged_month.dart +++ b/forui/lib/src/widgets/calendar/paged_month.dart @@ -24,7 +24,7 @@ class _PagedMonthState extends State { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), child: SizedBox( - width: _monthDayDimension * DateTime.daysPerWeek, + width: dayDimension * DateTime.daysPerWeek, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -41,13 +41,13 @@ class _PagedMonthState extends State { onNext: () {}, ), SizedBox( - height: _monthDayDimension * _maxMonthRows, + height: dayDimension * maxMonthRows, child: PageView.builder( itemBuilder: (context, index) => Month( focused: null, style: style, - month: widget.initialDate, - today: DateTime(2024, 7, 8), + month: widget.initialDate.toLocalDate(), + today: DateTime(2024, 7, 8).toLocalDate(), enabledPredicate: (_) => true, selectedPredicate: (_) => false, onPress: print, From 6eaeaa7c94361f3e336760dc309a467b0f415891 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 9 Jul 2024 17:13:38 +0800 Subject: [PATCH 10/35] Rename month to day_picker & fix focusNode issue in EnabledDay --- forui/lib/src/widgets/calendar/calendar.dart | 2 +- forui/lib/src/widgets/calendar/day.dart | 86 ++++++++++++------- .../calendar/{month.dart => day_picker.dart} | 72 ++++++++-------- .../lib/src/widgets/calendar/paged_month.dart | 12 +-- 4 files changed, 95 insertions(+), 77 deletions(-) rename forui/lib/src/widgets/calendar/{month.dart => day_picker.dart} (83%) diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index b19df5bdf..07c1852ec 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -9,5 +9,5 @@ import 'package:sugar/sugar.dart'; part 'day.dart'; part 'header.dart'; -part 'month.dart'; +part 'day_picker.dart'; part 'paged_month.dart'; diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day.dart index 48e1141d8..fa8f83511 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day.dart @@ -3,7 +3,7 @@ part of 'calendar.dart'; /// Returns the [date]. @internal Widget day( - FMonthStyle monthStyle, + FCalendarDayPickerStyle monthStyle, LocalDate date, FocusNode focusNode, ValueChanged onPress, @@ -38,7 +38,7 @@ Widget day( @internal class EnabledDay extends StatefulWidget { - final FDayStateStyle style; + final FCalendarDayStateStyle style; final LocalDate date; final FocusNode focusNode; final ValueChanged onPress; @@ -75,15 +75,30 @@ class EnabledDay extends StatefulWidget { } class _EnabledDayState extends State { - bool focused = false; + bool _focused = false; + bool _hovered = false; + + + @override + void initState() { + super.initState(); + widget.focusNode.addListener(_updateFocused); + } + + @override + void didUpdateWidget(EnabledDay old) { + super.didUpdateWidget(old); + old.focusNode.removeListener(_updateFocused); + widget.focusNode.addListener(_updateFocused); + } @override Widget build(BuildContext context) => Focus( focusNode: widget.focusNode, child: MouseRegion( cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => focused = true), - onExit: (_) => setState(() => focused = false), + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), child: Semantics( label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization button: true, @@ -93,11 +108,11 @@ class _EnabledDayState extends State { onTap: () => widget.onPress(widget.date.toNative()), onLongPress: () => widget.onLongPress(widget.date.toNative()), child: DecoratedBox( - decoration: focused ? widget.style.focusedDecoration : widget.style.decoration, + decoration: _focused || _hovered ? widget.style.focusedDecoration : widget.style.decoration, child: Center( child: Text( '${widget.date.day}', // TODO: localization - style: focused ? widget.style.focusedTextStyle : widget.style.textStyle, + style: _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle, ), ), ), @@ -106,16 +121,25 @@ class _EnabledDayState extends State { ), ); + + @override + void dispose() { + widget.focusNode.removeListener(_updateFocused); + super.dispose(); + } + + void _updateFocused() => setState(() => _focused = widget.focusNode.hasFocus); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(FlagProperty('focused', value: focused, ifTrue: 'focused')); + properties.add(FlagProperty('focused', value: _hovered, ifTrue: 'focused')); } } @internal class DisabledDay extends StatelessWidget { - final FDayStateStyle style; + final FCalendarDayStateStyle style; final LocalDate date; const DisabledDay({ @@ -147,27 +171,27 @@ class DisabledDay extends StatelessWidget { /// /// [todayStyle] takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is /// selected, [todayStyle] will be applied. -final class FDayStyle with Diagnosticable { +final class FCalendarDayStyle with Diagnosticable { /// The current date's style. /// /// This style takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is /// selected, [todayStyle] will be applied. - final FDayStateStyle todayStyle; + final FCalendarDayStateStyle todayStyle; /// The unselected dates' style. - final FDayStateStyle unselectedStyle; + final FCalendarDayStateStyle unselectedStyle; /// The selected dates' style. - final FDayStateStyle selectedStyle; + final FCalendarDayStateStyle selectedStyle; - /// Creates a [FDayStyle]. - const FDayStyle({ + /// Creates a [FCalendarDayStyle]. + const FCalendarDayStyle({ required this.todayStyle, required this.unselectedStyle, required this.selectedStyle, }); - /// Returns a copy of this [FDayStyle] but with the given fields replaced with the new values. + /// Returns a copy of this [FCalendarDayStyle] but with the given fields replaced with the new values. /// /// ```dart /// final style = FDayStyle( @@ -183,12 +207,12 @@ final class FDayStyle with Diagnosticable { /// print(style.todayStyle == copy.todayStyle); // true /// print(style.unselectedStyle == copy.unselectedStyle); // false /// ``` - FDayStyle copyWith({ - FDayStateStyle? todayStyle, - FDayStateStyle? unselectedStyle, - FDayStateStyle? selectedStyle, + FCalendarDayStyle copyWith({ + FCalendarDayStateStyle? todayStyle, + FCalendarDayStateStyle? unselectedStyle, + FCalendarDayStateStyle? selectedStyle, }) => - FDayStyle( + FCalendarDayStyle( todayStyle: todayStyle ?? this.todayStyle, unselectedStyle: unselectedStyle ?? this.unselectedStyle, selectedStyle: selectedStyle ?? this.selectedStyle, @@ -206,7 +230,7 @@ final class FDayStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FDayStyle && + other is FCalendarDayStyle && runtimeType == other.runtimeType && todayStyle == other.todayStyle && unselectedStyle == other.unselectedStyle && @@ -217,7 +241,7 @@ final class FDayStyle with Diagnosticable { } /// A calendar day state's style. -final class FDayStateStyle with Diagnosticable { +final class FCalendarDayStateStyle with Diagnosticable { /// The unfocused day's decoration. final BoxDecoration decoration; @@ -230,8 +254,8 @@ final class FDayStateStyle with Diagnosticable { /// The focused day's text style. Defaults to [textStyle]. final TextStyle focusedTextStyle; - /// Creates a [FDayStateStyle]. - FDayStateStyle({ + /// Creates a [FCalendarDayStateStyle]. + FCalendarDayStateStyle({ required this.decoration, required this.textStyle, BoxDecoration? focusedDecoration, @@ -239,8 +263,8 @@ final class FDayStateStyle with Diagnosticable { }) : focusedDecoration = focusedDecoration ?? decoration, focusedTextStyle = focusedTextStyle ?? textStyle; - /// Creates a [FDayStateStyle] that inherits the given colors. - FDayStateStyle.inherit({ + /// Creates a [FCalendarDayStateStyle] that inherits the given colors. + FCalendarDayStateStyle.inherit({ required TextStyle textStyle, Color? color, Color? focusedColor, @@ -262,7 +286,7 @@ final class FDayStateStyle with Diagnosticable { focusedTextStyle: focusedTextStyle ?? textStyle, ); - /// Returns a copy of this [FDayStateStyle] but with the given fields replaced with the new values. + /// Returns a copy of this [FCalendarDayStateStyle] but with the given fields replaced with the new values. /// /// ```dart /// final style = FDayStateStyle( @@ -277,13 +301,13 @@ final class FDayStateStyle with Diagnosticable { /// print(style.decoration == copy.decoration); // true /// print(style.textStyle == copy.textStyle); // false /// ``` - FDayStateStyle copyWith({ + FCalendarDayStateStyle copyWith({ BoxDecoration? decoration, TextStyle? textStyle, BoxDecoration? focusedDecoration, TextStyle? focusedTextStyle, }) => - FDayStateStyle( + FCalendarDayStateStyle( decoration: decoration ?? this.decoration, textStyle: textStyle ?? this.textStyle, focusedDecoration: focusedDecoration ?? this.focusedDecoration, @@ -303,7 +327,7 @@ final class FDayStateStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FDayStateStyle && + other is FCalendarDayStateStyle && runtimeType == other.runtimeType && decoration == other.decoration && textStyle == other.textStyle && diff --git a/forui/lib/src/widgets/calendar/month.dart b/forui/lib/src/widgets/calendar/day_picker.dart similarity index 83% rename from forui/lib/src/widgets/calendar/month.dart rename to forui/lib/src/widgets/calendar/day_picker.dart index 05ee4ddc3..ce730b2b3 100644 --- a/forui/lib/src/widgets/calendar/month.dart +++ b/forui/lib/src/widgets/calendar/day_picker.dart @@ -4,13 +4,13 @@ part of 'calendar.dart'; @internal const maxMonthRows = 6; -/// The height & width of a day in a [Month]. +/// The height & width of a day in a [DayPicker]. @internal const dayDimension = 40.0; @internal -class Month extends StatefulWidget { - final FMonthStyle style; +class DayPicker extends StatefulWidget { + final FCalendarDayPickerStyle style; final LocalDate month; final LocalDate today; final LocalDate? focused; @@ -19,7 +19,7 @@ class Month extends StatefulWidget { final ValueChanged onPress; final ValueChanged onLongPress; - const Month({ + const DayPicker({ required this.style, required this.month, required this.today, @@ -32,7 +32,7 @@ class Month extends StatefulWidget { }); @override - State createState() => _MonthState(); + State createState() => _DayPickerState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -49,7 +49,7 @@ class Month extends StatefulWidget { } } -class _MonthState extends State { +class _DayPickerState extends State { final SplayTreeMap _days = SplayTreeMap(); @override @@ -101,7 +101,7 @@ class _MonthState extends State { } @override - void didUpdateWidget(Month old) { + void didUpdateWidget(DayPicker old) { super.didUpdateWidget(old); if (old.month != widget.month) { _updateMonth(); @@ -164,16 +164,16 @@ class _GridDelegate extends SliverGridDelegate { bool shouldRelayout(_GridDelegate oldDelegate) => false; } -/// A month's style. -final class FMonthStyle with Diagnosticable { +/// A day picker's style. +final class FCalendarDayPickerStyle with Diagnosticable { /// The text style for the day of th week headers. final TextStyle headerTextStyle; /// The styles of the current month on display and the enclosing months, when enabled. - final ({FDayStyle current, FDayStyle enclosing}) enabled; + final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) enabled; /// The styles of the current month on display and the enclosing months, when disabled. - final ({FDayStyle current, FDayStyle enclosing}) disabled; + final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) disabled; /// The starting day of the week. Defaults to the current locale's preferred starting day of the week if null. /// @@ -185,8 +185,8 @@ final class FMonthStyle with Diagnosticable { /// * [DateTime.sunday] < [startDayOfWeek] final int? startDayOfWeek; - /// Creates a [FMonthStyle]. - const FMonthStyle({ + /// Creates a [FCalendarDayPickerStyle]. + const FCalendarDayPickerStyle({ required this.headerTextStyle, required this.enabled, required this.disabled, @@ -196,53 +196,53 @@ final class FMonthStyle with Diagnosticable { 'startDayOfWeek must be between DateTime.monday (1) and DateTime.sunday (7).', ); - /// Creates a [FMonthStyle] that inherits from the given [colorScheme] and [typography]. - factory FMonthStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { + /// Creates a [FCalendarDayPickerStyle] that inherits from the given [colorScheme] and [typography]. + factory FCalendarDayPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) { final textStyle = typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500); final mutedTextStyle = typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); - final disabled = FDayStyle( - todayStyle: FDayStateStyle.inherit( + final disabled = FCalendarDayStyle( + todayStyle: FCalendarDayStateStyle.inherit( color: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), - unselectedStyle: FDayStateStyle.inherit( + unselectedStyle: FCalendarDayStateStyle.inherit( textStyle: mutedTextStyle, ), - selectedStyle: FDayStateStyle.inherit( + selectedStyle: FCalendarDayStateStyle.inherit( color: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), ); - return FMonthStyle( + return FCalendarDayPickerStyle( headerTextStyle: typography.xs.copyWith(color: colorScheme.mutedForeground), enabled: ( - current: FDayStyle( - todayStyle: FDayStateStyle.inherit( + current: FCalendarDayStyle( + todayStyle: FCalendarDayStateStyle.inherit( color: colorScheme.secondary, textStyle: textStyle, ), - unselectedStyle: FDayStateStyle.inherit( + unselectedStyle: FCalendarDayStateStyle.inherit( textStyle: textStyle, focusedColor: colorScheme.secondary, ), - selectedStyle: FDayStateStyle.inherit( + selectedStyle: FCalendarDayStateStyle.inherit( color: colorScheme.foreground, textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), ), ), - enclosing: FDayStyle( - todayStyle: FDayStateStyle.inherit( + enclosing: FCalendarDayStyle( + todayStyle: FCalendarDayStateStyle.inherit( color: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), - unselectedStyle: FDayStateStyle.inherit( + unselectedStyle: FCalendarDayStateStyle.inherit( textStyle: mutedTextStyle, focusedColor: colorScheme.primaryForeground, ), - selectedStyle: FDayStateStyle.inherit( + selectedStyle: FCalendarDayStateStyle.inherit( color: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), @@ -255,7 +255,7 @@ final class FMonthStyle with Diagnosticable { ); } - /// Returns a copy of this [FMonthStyle] but with the given fields replaced with the new values. + /// Returns a copy of this [FCalendarDayPickerStyle] but with the given fields replaced with the new values. /// /// ```dart /// final style = FMonthStyle( @@ -271,15 +271,15 @@ final class FMonthStyle with Diagnosticable { /// print(style.headerTextStyle == copy.headerTextStyle); // true /// print(style.enabled.current == copy.enabled.current); // false /// ``` - FMonthStyle copyWith({ + FCalendarDayPickerStyle copyWith({ TextStyle? headerTextStyle, - FDayStyle? enabledCurrent, - FDayStyle? enabledEnclosing, - FDayStyle? disabledCurrent, - FDayStyle? disabledEnclosing, + FCalendarDayStyle? enabledCurrent, + FCalendarDayStyle? enabledEnclosing, + FCalendarDayStyle? disabledCurrent, + FCalendarDayStyle? disabledEnclosing, int? startDayOfWeek, }) => - FMonthStyle( + FCalendarDayPickerStyle( headerTextStyle: headerTextStyle ?? this.headerTextStyle, enabled: ( current: enabledCurrent ?? enabled.current, @@ -307,7 +307,7 @@ final class FMonthStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FMonthStyle && + other is FCalendarDayPickerStyle && runtimeType == other.runtimeType && headerTextStyle == other.headerTextStyle && enabled == other.enabled && diff --git a/forui/lib/src/widgets/calendar/paged_month.dart b/forui/lib/src/widgets/calendar/paged_month.dart index 68dfd1267..cb883b04a 100644 --- a/forui/lib/src/widgets/calendar/paged_month.dart +++ b/forui/lib/src/widgets/calendar/paged_month.dart @@ -14,7 +14,7 @@ class PagedMonth extends StatefulWidget { class _PagedMonthState extends State { @override Widget build(BuildContext context) { - final style = FMonthStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); + final style = FCalendarDayPickerStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); return DecoratedBox( decoration: BoxDecoration( borderRadius: context.theme.style.borderRadius, @@ -29,13 +29,7 @@ class _PagedMonthState extends State { mainAxisSize: MainAxisSize.min, children: [ Header( - style: FCalendarHeaderStyle( - headerTextStyle: context.theme.typography.sm.copyWith( - color: context.theme.colorScheme.primary, - fontWeight: FontWeight.w600, - ), - iconColor: context.theme.colorScheme.mutedForeground, - ), + style: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), month: widget.initialDate, onPrevious: () {}, onNext: () {}, @@ -43,7 +37,7 @@ class _PagedMonthState extends State { SizedBox( height: dayDimension * maxMonthRows, child: PageView.builder( - itemBuilder: (context, index) => Month( + itemBuilder: (context, index) => DayPicker( focused: null, style: style, month: widget.initialDate.toLocalDate(), From 3a4f625f29fac9b5fcd95832d041aedbb7084be0 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 9 Jul 2024 18:24:27 +0800 Subject: [PATCH 11/35] Add offset logic --- forui/lib/src/widgets/calendar/calendar.dart | 6 +- .../src/widgets/calendar/{ => day}/day.dart | 2 +- .../calendar/{ => day}/day_picker.dart | 3 +- .../calendar/day/paged_day_picker.dart | 66 +++++++++++++ .../lib/src/widgets/calendar/paged_month.dart | 97 ++++++++----------- 5 files changed, 113 insertions(+), 61 deletions(-) rename forui/lib/src/widgets/calendar/{ => day}/day.dart (99%) rename forui/lib/src/widgets/calendar/{ => day}/day_picker.dart (99%) create mode 100644 forui/lib/src/widgets/calendar/day/paged_day_picker.dart diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 07c1852ec..4a274704b 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -7,7 +7,9 @@ import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; -part 'day.dart'; +part 'day/day.dart'; +part 'day/day_picker.dart'; +part 'day/paged_day_picker.dart'; + part 'header.dart'; -part 'day_picker.dart'; part 'paged_month.dart'; diff --git a/forui/lib/src/widgets/calendar/day.dart b/forui/lib/src/widgets/calendar/day/day.dart similarity index 99% rename from forui/lib/src/widgets/calendar/day.dart rename to forui/lib/src/widgets/calendar/day/day.dart index fa8f83511..6407ebd8d 100644 --- a/forui/lib/src/widgets/calendar/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -1,4 +1,4 @@ -part of 'calendar.dart'; +part of '../calendar.dart'; /// Returns the [date]. @internal diff --git a/forui/lib/src/widgets/calendar/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart similarity index 99% rename from forui/lib/src/widgets/calendar/day_picker.dart rename to forui/lib/src/widgets/calendar/day/day_picker.dart index ce730b2b3..afb3aca9d 100644 --- a/forui/lib/src/widgets/calendar/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -1,4 +1,4 @@ -part of 'calendar.dart'; +part of '../calendar.dart'; /// The maximum number of rows in a month. In this case, a 31 day month that starts on Saturday. @internal @@ -60,7 +60,6 @@ class _DayPickerState extends State { @override Widget build(BuildContext context) => SizedBox( - height: maxMonthRows * dayDimension, width: DateTime.daysPerWeek * dayDimension, child: GridView.custom( padding: EdgeInsets.zero, diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart new file mode 100644 index 000000000..6be32296c --- /dev/null +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -0,0 +1,66 @@ +part of '../calendar.dart'; + +@internal +class PagedDayPicker extends StatefulWidget { + final FCalendarDayPickerStyle style; + final PageController controller; + final LocalDate first; + final LocalDate last; + final LocalDate today; + final LocalDate? focused; + final bool Function(DateTime day) enabledPredicate; + final bool Function(DateTime day) selectedPredicate; + final ValueChanged onPress; + final ValueChanged onLongPress; + + const PagedDayPicker({ + required this.controller, + required this.style, + required this.first, + required this.last, + required this.today, + required this.enabledPredicate, + required this.selectedPredicate, + required this.onPress, + required this.onLongPress, + this.focused, + super.key, + }); + + @override + State createState() => _PageDayPickerState(); +} + +class _PageDayPickerState extends State { + static int offset(LocalDate first, LocalDate last) { + if (last.year == first.year) { + return last.month - first.month; + } + + final years = min(0, last.year - first.year - 1); + final months = last.month + 12 - first.month; + + return years * 12 + months; + } + + final GlobalKey _pageViewKey = GlobalKey(); + + @override + Widget build(BuildContext context) => SizedBox( + height: dayDimension * maxMonthRows, + child: PageView.builder( + key: _pageViewKey, + itemBuilder: (context, index) => DayPicker( + focused: widget.focused, + style: widget.style, + month: widget.first.plus(months: index), + today: widget.today, + enabledPredicate: (_) => true, + selectedPredicate: widget.selectedPredicate, + onPress: print, + onLongPress: print, + ), + itemCount: offset(widget.first, widget.last), + ), + ); +} diff --git a/forui/lib/src/widgets/calendar/paged_month.dart b/forui/lib/src/widgets/calendar/paged_month.dart index cb883b04a..7d80b7f85 100644 --- a/forui/lib/src/widgets/calendar/paged_month.dart +++ b/forui/lib/src/widgets/calendar/paged_month.dart @@ -1,58 +1,43 @@ part of 'calendar.dart'; -@internal -class PagedMonth extends StatefulWidget { - final DateTime initialDate; - final PageController? controller; - - const PagedMonth({required this.initialDate, this.controller, super.key}); - - @override - State createState() => _PagedMonthState(); -} - -class _PagedMonthState extends State { - @override - Widget build(BuildContext context) { - final style = FCalendarDayPickerStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); - return DecoratedBox( - decoration: BoxDecoration( - borderRadius: context.theme.style.borderRadius, - border: Border.all( - color: context.theme.colorScheme.border, - )), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), - child: SizedBox( - width: dayDimension * DateTime.daysPerWeek, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Header( - style: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), - month: widget.initialDate, - onPrevious: () {}, - onNext: () {}, - ), - SizedBox( - height: dayDimension * maxMonthRows, - child: PageView.builder( - itemBuilder: (context, index) => DayPicker( - focused: null, - style: style, - month: widget.initialDate.toLocalDate(), - today: DateTime(2024, 7, 8).toLocalDate(), - enabledPredicate: (_) => true, - selectedPredicate: (_) => false, - onPress: print, - onLongPress: print, - ), - ), - ), - ], - ), - ), - ), - ); - } -} +// @internal +// class PagedMonth extends StatefulWidget { +// final DateTime initialDate; +// final PageController? controller; +// +// const PagedMonth({required this.initialDate, this.controller, super.key}); +// +// @override +// State createState() => _PagedMonthState(); +// } +// +// class _PagedMonthState extends State { +// @override +// Widget build(BuildContext context) { +// final style = FCalendarDayPickerStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); +// return DecoratedBox( +// decoration: BoxDecoration( +// borderRadius: context.theme.style.borderRadius, +// border: Border.all( +// color: context.theme.colorScheme.border, +// )), +// child: Padding( +// padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), +// child: SizedBox( +// width: dayDimension * DateTime.daysPerWeek, +// child: Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// Header( +// style: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), +// month: widget.initialDate, +// onPrevious: () {}, +// onNext: () {}, +// ), +// ], +// ), +// ), +// ), +// ); +// } +// } From 6ed91ca5e54d0cf441a342a86d48b5dfcba997a3 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 9 Jul 2024 22:24:55 +0800 Subject: [PATCH 12/35] Semi-functioning calendar We still need to test the focusNode stuff. IDK how though. The scrolling animation is pretty jank too. We need to move the scroll animation thing to style too --- forui/example/lib/main.dart | 31 +- forui/lib/src/widgets/calendar/calendar.dart | 32 +- forui/lib/src/widgets/calendar/day/day.dart | 26 +- .../src/widgets/calendar/day/day_picker.dart | 14 +- .../widgets/calendar/{ => day}/header.dart | 12 +- .../calendar/day/paged_day_picker.dart | 326 ++++++++++++++++-- .../lib/src/widgets/calendar/paged_month.dart | 43 --- 7 files changed, 372 insertions(+), 112 deletions(-) rename forui/lib/src/widgets/calendar/{ => day}/header.dart (93%) delete mode 100644 forui/lib/src/widgets/calendar/paged_month.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 41a50cfa7..d752d6cdd 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; -import 'package:forui_example/example.dart'; +import 'package:sugar/sugar.dart'; void main() { runApp(const Application()); @@ -16,7 +16,7 @@ class Application extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( builder: (context, child) => FTheme( - data: FThemes.zinc.dark, + data: FThemes.zinc.light, child: FScaffold( header: FHeader( title: const Text('Example Example Example Example'), @@ -32,8 +32,33 @@ class Application extends StatelessWidget { ), home: Column( children: [ - PagedMonth(initialDate: DateTime(2024, 7, 8)), + const Testing(), + // FHeaderAction( + // icon: FAssets.icons.plus, + // onPress: () => showDatePicker(context: context, firstDate: DateTime(2024, 7, 1), lastDate: DateTime(2024, 7, 31), initialDate: DateTime(2024, 7, 8)), + // ), ], ), ); } + +class Testing extends StatelessWidget { + const Testing({super.key}); + + @override + Widget build(BuildContext context) { + return PagedDayPicker( + style: FCalendarStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography, style: context.theme.style), + start: LocalDate(2023, 1, 8), + end: LocalDate(2025, 7, 10), + today: LocalDate.now(), + initialMonth: LocalDate(2024, 7), + enabledPredicate: (_) => true, + selectedPredicate: (a) => a == LocalDate(2024, 7, 11), + onMonthChange: print, + onPress: print, + onLongPress: print, + ); + } +} + diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 4a274704b..43f3f001c 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -3,13 +3,41 @@ import 'dart:collection'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; part 'day/day.dart'; part 'day/day_picker.dart'; +part 'day/header.dart'; part 'day/paged_day_picker.dart'; -part 'header.dart'; -part 'paged_month.dart'; +final class FCalendarStyle with Diagnosticable { + final FCalendarHeaderStyle headerStyle; + final FCalendarDayPickerStyle dayPickerStyle; + final BoxDecoration decoration; + final EdgeInsets padding; + + FCalendarStyle({ + required this.headerStyle, + required this.dayPickerStyle, + required this.decoration, + this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + }); + + FCalendarStyle.inherit({ + required FColorScheme colorScheme, + required FTypography typography, + required FStyle style, + }) : this( + headerStyle: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), + dayPickerStyle: FCalendarDayPickerStyle.inherit(colorScheme: colorScheme, typography: typography), + decoration: BoxDecoration( + borderRadius: style.borderRadius, + border: Border.all( + color: colorScheme.border, + ), + ), + ); +} diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/calendar/day/day.dart index 6407ebd8d..2082b7a5f 100644 --- a/forui/lib/src/widgets/calendar/day/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -6,8 +6,8 @@ Widget day( FCalendarDayPickerStyle monthStyle, LocalDate date, FocusNode focusNode, - ValueChanged onPress, - ValueChanged onLongPress, { + ValueChanged onPress, + ValueChanged onLongPress, { required bool enabled, required bool current, required bool today, @@ -16,9 +16,9 @@ Widget day( final styles = enabled ? monthStyle.enabled : monthStyle.disabled; final dayStyle = current ? styles.current : styles.enclosing; final style = switch ((today, selected)) { - (true, _) => dayStyle.todayStyle, (_, true) => dayStyle.selectedStyle, - (_, false) => dayStyle.unselectedStyle, + (false, _) => dayStyle.unselectedStyle, + (true, _) => dayStyle.todayStyle, }; if (enabled) { @@ -41,8 +41,8 @@ class EnabledDay extends StatefulWidget { final FCalendarDayStateStyle style; final LocalDate date; final FocusNode focusNode; - final ValueChanged onPress; - final ValueChanged onLongPress; + final ValueChanged onPress; + final ValueChanged onLongPress; final bool today; final bool selected; @@ -105,8 +105,8 @@ class _EnabledDayState extends State { selected: widget.selected, excludeSemantics: true, child: GestureDetector( - onTap: () => widget.onPress(widget.date.toNative()), - onLongPress: () => widget.onLongPress(widget.date.toNative()), + onTap: () => widget.onPress(widget.date), + onLongPress: () => widget.onLongPress(widget.date), child: DecoratedBox( decoration: _focused || _hovered ? widget.style.focusedDecoration : widget.style.decoration, child: Center( @@ -169,19 +169,19 @@ class DisabledDay extends StatelessWidget { /// A calender day's style. /// -/// [todayStyle] takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is -/// selected, [todayStyle] will be applied. +/// [selectedStyle] takes precedence over [unselectedStyle] and [todayStyle]. For example, if the current date is +/// selected, [selectedStyle] will be applied. final class FCalendarDayStyle with Diagnosticable { /// The current date's style. - /// - /// This style takes precedence over [unselectedStyle] and [selectedStyle]. For example, if the current date is - /// selected, [todayStyle] will be applied. final FCalendarDayStateStyle todayStyle; /// The unselected dates' style. final FCalendarDayStateStyle unselectedStyle; /// The selected dates' style. + /// + /// This style takes precedence over [unselectedStyle] and [todayStyle]. For example, if the current date is + /// selected, [todayStyle] will be applied. final FCalendarDayStateStyle selectedStyle; /// Creates a [FCalendarDayStyle]. diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index afb3aca9d..3e97eb34f 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -6,7 +6,7 @@ const maxMonthRows = 6; /// The height & width of a day in a [DayPicker]. @internal -const dayDimension = 40.0; +const dayDimension = 42.0; @internal class DayPicker extends StatefulWidget { @@ -14,10 +14,10 @@ class DayPicker extends StatefulWidget { final LocalDate month; final LocalDate today; final LocalDate? focused; - final bool Function(DateTime day) enabledPredicate; - final bool Function(DateTime day) selectedPredicate; - final ValueChanged onPress; - final ValueChanged onLongPress; + final bool Function(LocalDate day) enabledPredicate; + final bool Function(LocalDate day) selectedPredicate; + final ValueChanged onPress; + final ValueChanged onLongPress; const DayPicker({ required this.style, @@ -76,10 +76,10 @@ class _DayPickerState extends State { focusNode, widget.onPress, widget.onLongPress, - enabled: widget.enabledPredicate(date.toNative()), + enabled: widget.enabledPredicate(date), current: date.month == widget.month.month, today: date == widget.today, - selected: widget.selectedPredicate(date.toNative()), + selected: widget.selectedPredicate(date), ), ], addRepaintBoundaries: false, diff --git a/forui/lib/src/widgets/calendar/header.dart b/forui/lib/src/widgets/calendar/day/header.dart similarity index 93% rename from forui/lib/src/widgets/calendar/header.dart rename to forui/lib/src/widgets/calendar/day/header.dart index 4c784fe8c..d23182db3 100644 --- a/forui/lib/src/widgets/calendar/header.dart +++ b/forui/lib/src/widgets/calendar/day/header.dart @@ -1,4 +1,4 @@ -part of 'calendar.dart'; +part of '../calendar.dart'; @internal class Header extends StatelessWidget { @@ -35,9 +35,9 @@ class Header extends StatelessWidget { style: effectiveButtonStyle, onPress: onPrevious, child: Padding( - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(7), child: FAssets.icons.chevronLeft( - height: 16, + height: 17, colorFilter: ColorFilter.mode( style.iconColor, BlendMode.srcIn, @@ -46,7 +46,7 @@ class Header extends StatelessWidget { ), ), ), - Text('July ${month.year}', style: style.headerTextStyle), // TODO: Localization + Text('${month.month} ${month.year}', style: style.headerTextStyle), // TODO: Localization Padding( padding: const EdgeInsets.only(right: 7), child: FButton.raw( @@ -54,9 +54,9 @@ class Header extends StatelessWidget { style: effectiveButtonStyle, onPress: onNext, child: Padding( - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(7), child: FAssets.icons.chevronRight( - height: 16, + height: 17, colorFilter: ColorFilter.mode( style.iconColor, BlendMode.srcIn, diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 6be32296c..62aa75497 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,66 +1,316 @@ part of '../calendar.dart'; +const Duration _monthScrollDuration = Duration(milliseconds: 200); + @internal class PagedDayPicker extends StatefulWidget { - final FCalendarDayPickerStyle style; - final PageController controller; - final LocalDate first; - final LocalDate last; + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; final LocalDate today; - final LocalDate? focused; - final bool Function(DateTime day) enabledPredicate; - final bool Function(DateTime day) selectedPredicate; - final ValueChanged onPress; - final ValueChanged onLongPress; + final LocalDate initialMonth; + final bool Function(LocalDate day) enabledPredicate; + final bool Function(LocalDate day) selectedPredicate; + final ValueChanged? onMonthChange; + final ValueChanged onPress; + final ValueChanged onLongPress; const PagedDayPicker({ - required this.controller, required this.style, - required this.first, - required this.last, + required this.start, + required this.end, required this.today, + required this.initialMonth, required this.enabledPredicate, required this.selectedPredicate, + required this.onMonthChange, required this.onPress, required this.onLongPress, - this.focused, super.key, }); @override State createState() => _PageDayPickerState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('start', start)) + ..add(DiagnosticsProperty('end', end)) + ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('initialMonth', initialMonth)) + ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)) + ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) + ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) + ..add(DiagnosticsProperty('onPress', onPress)) + ..add(DiagnosticsProperty('onLongPress', onLongPress)); + } } +// Most of the traversal logic is copied from Material's _MonthPickerState. class _PageDayPickerState extends State { - static int offset(LocalDate first, LocalDate last) { - if (last.year == first.year) { - return last.month - first.month; - } + static int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; - final years = min(0, last.year - first.year - 1); - final months = last.month + 12 - first.month; + static const _shortcuts = { + SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), + SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), + SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), + SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), + }; - return years * 12 + months; - } + static const _directionOffset = { + TraversalDirection.up: -DateTime.daysPerWeek, + TraversalDirection.right: 1, + TraversalDirection.down: DateTime.daysPerWeek, + TraversalDirection.left: -1, + }; final GlobalKey _pageViewKey = GlobalKey(); + late LocalDate _currentMonth; + late PageController _controller; + late TextDirection _textDirection; + late Map> _actions; + late FocusNode _dayGridFocus; + LocalDate? _focusedDay; + + @override + void initState() { + super.initState(); + _currentMonth = widget.initialMonth; + _controller = PageController(initialPage: delta(widget.start, widget.initialMonth)); + _actions = { + NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), + PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), + DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), + }; + _dayGridFocus = FocusNode(debugLabel: 'Day Grid'); + } + + @override + Widget build(BuildContext context) => DecoratedBox( + decoration: widget.style.decoration, + child: Padding( + padding: widget.style.padding, + child: SizedBox( + width: dayDimension * DateTime.daysPerWeek, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Header( + style: widget.style.headerStyle, + month: _currentMonth, + onPrevious: _first ? null : _handlePreviousMonth, + onNext: _last ? null : _handleNextMonth, + ), + SizedBox( + height: dayDimension * maxMonthRows, + child: FocusableActionDetector( + shortcuts: _shortcuts, + actions: _actions, + focusNode: _dayGridFocus, + onFocusChange: _handleGridFocusChange, + child: PageView.builder( + key: _pageViewKey, + controller: _controller, + itemBuilder: (context, index) => DayPicker( + focused: _focusedDay, + style: widget.style.dayPickerStyle, + month: _currentMonth, + today: widget.today, + enabledPredicate: (date) => + widget.start <= date && date <= widget.end && widget.enabledPredicate(date), + selectedPredicate: widget.selectedPredicate, + onPress: (date) { + setState(() => _focusedDay = date); + widget.onPress(date); + }, + onLongPress: (date) { + setState(() => _focusedDay = date); + widget.onLongPress(date); + }, + ), + itemCount: delta(widget.start, widget.end), + onPageChanged: _handleMonthPageChanged, + ), + ), + ), + ], + ), + ), + ), + ); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _textDirection = Directionality.of(context); + } @override - Widget build(BuildContext context) => SizedBox( - height: dayDimension * maxMonthRows, - child: PageView.builder( - key: _pageViewKey, - itemBuilder: (context, index) => DayPicker( - focused: widget.focused, - style: widget.style, - month: widget.first.plus(months: index), - today: widget.today, - enabledPredicate: (_) => true, - selectedPredicate: widget.selectedPredicate, - onPress: print, - onLongPress: print, - ), - itemCount: offset(widget.first, widget.last), - ), - ); + void dispose() { + _controller.dispose(); + _dayGridFocus.dispose(); + super.dispose(); + } + + /// Navigate to the next month. + void _handleNextMonth() { + if (!_last) { + _controller.nextPage( + duration: _monthScrollDuration, + curve: Curves.ease, + ); + } + } + + /// Navigate to the previous month. + void _handlePreviousMonth() { + if (!_first) { + _controller.previousPage( + duration: _monthScrollDuration, + curve: Curves.ease, + ); + } + } + + /// True if the earliest allowable month is displayed. + bool get _first => widget.start.truncate(to: DateUnit.months) == _currentMonth; + + /// True if the latest allowable month is displayed. + bool get _last => widget.end.truncate(to: DateUnit.months) == _currentMonth; + + /// Navigate to the given month. + void _showMonth(LocalDate month, {bool jump = false}) { + final page = delta(widget.start, month); + if (jump) { + _controller.jumpToPage(page); + } else { + _controller.animateToPage( + page, + duration: _monthScrollDuration, + curve: Curves.ease, + ); + } + } + + void _handleMonthPageChanged(int page) { + setState(() { + final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); + if (_currentMonth == changed) { + return; + } + + _currentMonth = changed; + widget.onMonthChange?.call(_currentMonth.toNative()); + if (_focusedDay case final focused? when focused.truncate(to: DateUnit.months) == _currentMonth) { + // We have navigated to a new month with the grid focused, but the + // focused day is not in this month. Choose a new one trying to keep + // the same day of the month. + _focusedDay = _focusableDayForMonth(_currentMonth, _focusedDay!.day); + } + + SemanticsService.announce( + _currentMonth.toString(), // TODO: localization + _textDirection, + ); + }); + } + + /// Returns a focusable date for the given month. + /// + /// If the preferredDay is available in the month it will be returned, + /// otherwise the first selectable day in the month will be returned. If + /// no dates are selectable in the month, then it will return null. + LocalDate? _focusableDayForMonth(LocalDate month, int preferredDay) { + // Can we use the preferred day in this month? + if (preferredDay <= month.daysInMonth) { + final newFocus = month.copyWith(day: preferredDay); + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + // Start at the 1st and take the first enabled date. + for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + return null; + } + + /// Handler for when the overall day grid obtains or loses focus. + void _handleGridFocusChange(bool focused) { + setState(() { + if (focused && _focusedDay == null) { + if (widget.today.truncate(to: DateUnit.months) == _currentMonth) { + _focusedDay = _focusableDayForMonth(_currentMonth, widget.today.day); + } else { + _focusedDay = _focusableDayForMonth(_currentMonth, 1); + } + } + }); + } + + /// Move focus to the next element after the day grid. + void _handleGridNextFocus(NextFocusIntent intent) { + _dayGridFocus + ..requestFocus() + ..nextFocus(); + } + + /// Move focus to the previous element before the day grid. + void _handleGridPreviousFocus(PreviousFocusIntent intent) { + _dayGridFocus + ..requestFocus() + ..previousFocus(); + } + + /// Move the internal focus date in the direction of the given intent. + /// + /// This will attempt to move the focused day to the next selectable day in + /// the given direction. If the new date is not in the current month, then + /// the page view will be scrolled to show the new date's month. + /// + /// For horizontal directions, it will move forward or backward a day (depending + /// on the current [TextDirection]). For vertical directions it will move up and + /// down a week at a time. + void _handleDirectionFocus(DirectionalFocusIntent intent) { + assert(_focusedDay != null, 'Cannot move focus without a focused day.'); + setState(() { + final nextDate = _nextDateInDirection(_focusedDay!, intent.direction); + if (nextDate != null) { + _focusedDay = nextDate; + if (_focusedDay?.truncate(to: DateUnit.months) != _currentMonth) { + _showMonth(_focusedDay!); + } + } + }); + } + + // Swap left and right if the text direction if RTL + int _dayDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => + _directionOffset[switch ((traversalDirection, textDirection)) { + (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, + (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, + _ => traversalDirection, + }]!; + + LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { + final textDirection = Directionality.of(context); + + var next = date.plus(days: _dayDirectionOffset(direction, textDirection)); + while (widget.start <= next && next <= widget.end) { + if (widget.enabledPredicate(next)) { + return next; + } + + next = date.plus(days: _dayDirectionOffset(direction, textDirection)); + } + + return null; + } } diff --git a/forui/lib/src/widgets/calendar/paged_month.dart b/forui/lib/src/widgets/calendar/paged_month.dart deleted file mode 100644 index 7d80b7f85..000000000 --- a/forui/lib/src/widgets/calendar/paged_month.dart +++ /dev/null @@ -1,43 +0,0 @@ -part of 'calendar.dart'; - -// @internal -// class PagedMonth extends StatefulWidget { -// final DateTime initialDate; -// final PageController? controller; -// -// const PagedMonth({required this.initialDate, this.controller, super.key}); -// -// @override -// State createState() => _PagedMonthState(); -// } -// -// class _PagedMonthState extends State { -// @override -// Widget build(BuildContext context) { -// final style = FCalendarDayPickerStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography); -// return DecoratedBox( -// decoration: BoxDecoration( -// borderRadius: context.theme.style.borderRadius, -// border: Border.all( -// color: context.theme.colorScheme.border, -// )), -// child: Padding( -// padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), -// child: SizedBox( -// width: dayDimension * DateTime.daysPerWeek, -// child: Column( -// mainAxisSize: MainAxisSize.min, -// children: [ -// Header( -// style: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), -// month: widget.initialDate, -// onPrevious: () {}, -// onNext: () {}, -// ), -// ], -// ), -// ), -// ), -// ); -// } -// } From 4c097abb7c86f0dd1e1a8d9df78091e26082e1ed Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 10:45:06 +0800 Subject: [PATCH 13/35] Add web and macos run configuration to forui example. Fix animation and traversal issues --- forui/example/.metadata | 18 +- forui/example/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + forui/example/macos/Podfile | 43 + forui/example/macos/Podfile.lock | 23 + .../macos/Runner.xcodeproj/project.pbxproj | 801 ++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + forui/example/macos/Runner/AppDelegate.swift | 9 + .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 ++++++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + forui/example/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../example/macos/Runner/Release.entitlements | 8 + .../macos/RunnerTests/RunnerTests.swift | 12 + forui/lib/src/widgets/calendar/calendar.dart | 2 + .../src/widgets/calendar/day/day_picker.dart | 57 +- .../calendar/day/paged_day_picker.dart | 42 +- 33 files changed, 1587 insertions(+), 64 deletions(-) create mode 100644 forui/example/macos/.gitignore create mode 100644 forui/example/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 forui/example/macos/Flutter/Flutter-Release.xcconfig create mode 100644 forui/example/macos/Podfile create mode 100644 forui/example/macos/Podfile.lock create mode 100644 forui/example/macos/Runner.xcodeproj/project.pbxproj create mode 100644 forui/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 forui/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 forui/example/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 forui/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 forui/example/macos/Runner/AppDelegate.swift create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 forui/example/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 forui/example/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 forui/example/macos/Runner/Configs/Debug.xcconfig create mode 100644 forui/example/macos/Runner/Configs/Release.xcconfig create mode 100644 forui/example/macos/Runner/Configs/Warnings.xcconfig create mode 100644 forui/example/macos/Runner/DebugProfile.entitlements create mode 100644 forui/example/macos/Runner/Info.plist create mode 100644 forui/example/macos/Runner/MainFlutterWindow.swift create mode 100644 forui/example/macos/Runner/Release.entitlements create mode 100644 forui/example/macos/RunnerTests/RunnerTests.swift diff --git a/forui/example/.metadata b/forui/example/.metadata index 62095849c..bb11ee0c9 100644 --- a/forui/example/.metadata +++ b/forui/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "bae5e49bc2a867403c43b2aae2de8f8c33b037e4" + revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" channel: "stable" project_type: app @@ -13,17 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: android - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: ios - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - - platform: web - create_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 - base_revision: bae5e49bc2a867403c43b2aae2de8f8c33b037e4 + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: macos + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 # User provided section diff --git a/forui/example/macos/.gitignore b/forui/example/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/forui/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/forui/example/macos/Flutter/Flutter-Debug.xcconfig b/forui/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..4b81f9b2d --- /dev/null +++ b/forui/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/forui/example/macos/Flutter/Flutter-Release.xcconfig b/forui/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..5caa9d157 --- /dev/null +++ b/forui/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/forui/example/macos/Podfile b/forui/example/macos/Podfile new file mode 100644 index 000000000..c795730db --- /dev/null +++ b/forui/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/forui/example/macos/Podfile.lock b/forui/example/macos/Podfile.lock new file mode 100644 index 000000000..a83eba5b7 --- /dev/null +++ b/forui/example/macos/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + +SPEC CHECKSUMS: + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.15.2 diff --git a/forui/example/macos/Runner.xcodeproj/project.pbxproj b/forui/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..20f21ad0a --- /dev/null +++ b/forui/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 156C1B9468344A0D7441B641 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FB2F8172F2DE440F71D5029 /* Pods_Runner.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + ECE7C92D21414069E3C48C40 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80A04D67BBD004997223452D /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2FB2F8172F2DE440F71D5029 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3DAD8F25A2AB4A7DBB75FC6F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 4958E3937C0A70E735B4DDD7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 56B8E47EFD637C217518CBDD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 80A04D67BBD004997223452D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + C13BA42F9034C705246445D5 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + CCF8DB4CCC737BEAD46CAD00 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + DBACD1025B85B50A10E7DD41 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ECE7C92D21414069E3C48C40 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 156C1B9468344A0D7441B641 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 3EE9245861A5305E78613D5F /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 3EE9245861A5305E78613D5F /* Pods */ = { + isa = PBXGroup; + children = ( + 3DAD8F25A2AB4A7DBB75FC6F /* Pods-Runner.debug.xcconfig */, + 56B8E47EFD637C217518CBDD /* Pods-Runner.release.xcconfig */, + CCF8DB4CCC737BEAD46CAD00 /* Pods-Runner.profile.xcconfig */, + C13BA42F9034C705246445D5 /* Pods-RunnerTests.debug.xcconfig */, + 4958E3937C0A70E735B4DDD7 /* Pods-RunnerTests.release.xcconfig */, + DBACD1025B85B50A10E7DD41 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2FB2F8172F2DE440F71D5029 /* Pods_Runner.framework */, + 80A04D67BBD004997223452D /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + B7E3014888957E4A9ABCF014 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 189688E4FB54772A33DBC4D9 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 83F050BBD0D3DF2DC03A970A /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 189688E4FB54772A33DBC4D9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 83F050BBD0D3DF2DC03A970A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B7E3014888957E4A9ABCF014 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C13BA42F9034C705246445D5 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.foruslabs.forui.samples.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4958E3937C0A70E735B4DDD7 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.foruslabs.forui.samples.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DBACD1025B85B50A10E7DD41 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.foruslabs.forui.samples.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/forui/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/forui/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/forui/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/forui/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/forui/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..15368eccb --- /dev/null +++ b/forui/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forui/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/forui/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..21a3cc14c --- /dev/null +++ b/forui/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/forui/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/forui/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/forui/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/forui/example/macos/Runner/AppDelegate.swift b/forui/example/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..d53ef6437 --- /dev/null +++ b/forui/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K#jR^;j87-Auq zoUlN^K{r-Q+XN;zI ze|?*NFmgt#V#GwrSWaz^2G&@SBmck6ZcIFMww~vE<1E?M2#KUn1CzsB6D2+0SuRV@ zV2kK5HvIGB{HX-hQzs0*AB%5$9RJ@a;)Ahq#p$GSP91^&hi#6sg*;a~dt}4AclK>h z_3MoPRQ{i;==;*1S-mY<(JFzhAxMI&<61&m$J0NDHdJ3tYx~j0%M-uN6Zl8~_0DOkGXc0001@sz3l12C6Xg{AT~( zm6w64BA|AX`Ve)YY-glyudNN>MAfkXz-T7`_`fEolM;0T0BA)(02-OaW z0*cW7Z~ec94o8&g0D$N>b!COu{=m}^%oXZ4?T8ZyPZuGGBPBA7pbQMoV5HYhiT?%! zcae~`(QAN4&}-=#2f5fkn!SWGWmSeCISBcS=1-U|MEoKq=k?_x3apK>9((R zuu$9X?^8?@(a{qMS%J8SJPq))v}Q-ZyDm6Gbie0m92=`YlwnQPQP1kGSm(N2UJ3P6 z^{p-u)SSCTW~c1rw;cM)-uL2{->wCn2{#%;AtCQ!m%AakVs1K#v@(*-6QavyY&v&*wO_rCJXJuq$c$7ZjsW+pJo-$L^@!7X04CvaOpPyfw|FKvu;e(&Iw>Tbg zL}#8e^?X%TReXTt>gsBByt0kSU20oQx*~P=4`&tcZ7N6t-6LiK{LxX*p6}9c<0Pu^ zLx1w_P4P2V>bX=`F%v$#{sUDdF|;rbI{p#ZW`00Bgh(eB(nOIhy8W9T>3aQ=k8Z9% zB+TusFABF~J?N~fAd}1Rme=@4+1=M{^P`~se7}e3;mY0!%#MJf!XSrUC{0uZqMAd7%q zQY#$A>q}noIB4g54Ue)x>ofVm3DKBbUmS4Z-bm7KdKsUixva)1*&z5rgAG2gxG+_x zqT-KNY4g7eM!?>==;uD9Y4iI(Hu$pl8!LrK_Zb}5nv(XKW{9R144E!cFf36p{i|8pRL~p`_^iNo z{mf7y`#hejw#^#7oKPlN_Td{psNpNnM?{7{R-ICBtYxk>?3}OTH_8WkfaTLw)ZRTfxjW+0>gMe zpKg~`Bc$Y>^VX;ks^J0oKhB#6Ukt{oQhN+o2FKGZx}~j`cQB%vVsMFnm~R_1Y&Ml? zwFfb~d|dW~UktY@?zkau>Owe zRroi(<)c4Ux&wJfY=3I=vg)uh;sL(IYY9r$WK1$F;jYqq1>xT{LCkIMb3t2jN8d`9 z=4(v-z7vHucc_fjkpS}mGC{ND+J-hc_0Ix4kT^~{-2n|;Jmn|Xf9wGudDk7bi*?^+ z7fku8z*mbkGm&xf&lmu#=b5mp{X(AwtLTf!N`7FmOmX=4xwbD=fEo8CaB1d1=$|)+ z+Dlf^GzGOdlqTO8EwO?8;r+b;gkaF^$;+#~2_YYVH!hD6r;PaWdm#V=BJ1gH9ZK_9 zrAiIC-)z)hRq6i5+$JVmR!m4P>3yJ%lH)O&wtCyum3A*})*fHODD2nq!1@M>t@Za+ zH6{(Vf>_7!I-APmpsGLYpl7jww@s5hHOj5LCQXh)YAp+y{gG(0UMm(Ur z3o3n36oFwCkn+H*GZ-c6$Y!5r3z*@z0`NrB2C^q#LkOuooUM8Oek2KBk}o1PU8&2L z4iNkb5CqJWs58aR394iCU^ImDqV;q_Pp?pl=RB2372(Io^GA^+oKguO1(x$0<7w3z z)j{vnqEB679Rz4i4t;8|&Zg77UrklxY9@GDq(ZphH6=sW`;@uIt5B?7Oi?A0-BL}(#1&R;>2aFdq+E{jsvpNHjLx2t{@g1}c~DQcPNmVmy| zNMO@ewD^+T!|!DCOf}s9dLJU}(KZy@Jc&2Nq3^;vHTs}Hgcp`cw&gd7#N}nAFe3cM1TF%vKbKSffd&~FG9y$gLyr{#to)nxz5cCASEzQ}gz8O)phtHuKOW6p z@EQF(R>j%~P63Wfosrz8p(F=D|Mff~chUGn(<=CQbSiZ{t!e zeDU-pPsLgtc#d`3PYr$i*AaT!zF#23htIG&?QfcUk+@k$LZI}v+js|yuGmE!PvAV3 ztzh90rK-0L6P}s?1QH`Ot@ilbgMBzWIs zIs6K<_NL$O4lwR%zH4oJ+}JJp-bL6~%k&p)NGDMNZX7)0kni&%^sH|T?A)`z z=adV?!qnWx^B$|LD3BaA(G=ePL1+}8iu^SnnD;VE1@VLHMVdSN9$d)R(Wk{JEOp(P zm3LtAL$b^*JsQ0W&eLaoYag~=fRRdI>#FaELCO7L>zXe6w*nxN$Iy*Q*ftHUX0+N- zU>{D_;RRVPbQ?U+$^%{lhOMKyE5>$?U1aEPist+r)b47_LehJGTu>TcgZe&J{ z{q&D{^Ps~z7|zj~rpoh2I_{gAYNoCIJmio3B}$!5vTF*h$Q*vFj~qbo%bJCCRy509 zHTdDh_HYH8Zb9`}D5;;J9fkWOQi%Y$B1!b9+ESj+B@dtAztlY2O3NE<6HFiqOF&p_ zW-K`KiY@RPSY-p9Q99}Hcd05DT79_pfb{BV7r~?9pWh=;mcKBLTen%THFPo2NN~Nf zriOtFnqx}rtO|A6k!r6 zf-z?y-UD{dT0kT9FJ`-oWuPHbo+3wBS(}?2ql(+e@VTExmfnB*liCb zmeI+v5*+W_L;&kQN^ChW{jE0Mw#0Tfs}`9bk3&7UjxP^Ke(%eJu2{VnW?tu7Iqecm zB5|=-QdzK$=h50~{X3*w4%o1FS_u(dG2s&427$lJ?6bkLet}yYXCy)u_Io1&g^c#( z-$yYmSpxz{>BL;~c+~sxJIe1$7eZI_9t`eB^Pr0)5CuA}w;;7#RvPq|H6!byRzIJG ziQ7a4y_vhj(AL`8PhIm9edCv|%TX#f50lt8+&V+D4<}IA@S@#f4xId80oH$!_!q?@ zFRGGg2mTv&@76P7aTI{)Hu%>3QS_d)pQ%g8BYi58K~m-Ov^7r8BhX7YC1D3vwz&N8{?H*_U7DI?CI)+et?q|eGu>42NJ?K4SY zD?kc>h@%4IqNYuQ8m10+8xr2HYg2qFNdJl=Tmp&ybF>1>pqVfa%SsV*BY$d6<@iJA ziyvKnZ(~F9xQNokBgMci#pnZ}Igh0@S~cYcU_2Jfuf|d3tuH?ZSSYBfM(Y3-JBsC|S9c;# zyIMkPxgrq};0T09pjj#X?W^TFCMf1-9P{)g88;NDI+S4DXe>7d3Mb~i-h&S|Jy{J< zq3736$bH?@{!amD!1Ys-X)9V=#Z={fzsjVYMX5BG6%}tkzwC#1nQLj1y1f#}8**4Y zAvDZHw8)N)8~oWC88CgzbwOrL9HFbk4}h85^ptuu7A+uc#$f^9`EWv1Vr{5+@~@Uv z#B<;-nt;)!k|fRIg;2DZ(A2M2aC65kOIov|?Mhi1Sl7YOU4c$T(DoRQIGY`ycfkn% zViHzL;E*A{`&L?GP06Foa38+QNGA zw3+Wqs(@q+H{XLJbwZzE(omw%9~LPZfYB|NF5%j%E5kr_xE0u;i?IOIchn~VjeDZ) zAqsqhP0vu2&Tbz3IgJvMpKbThC-@=nk)!|?MIPP>MggZg{cUcKsP8|N#cG5 zUXMXxcXBF9`p>09IR?x$Ry3;q@x*%}G#lnB1}r#!WL88I@uvm}X98cZ8KO&cqT1p> z+gT=IxPsq%n4GWgh-Bk8E4!~`r@t>DaQKsjDqYc&h$p~TCh8_Mck5UB84u6Jl@kUZCU9BA-S!*bf>ZotFX9?a_^y%)yH~rsAz0M5#^Di80_tgoKw(egN z`)#(MqAI&A84J#Z<|4`Co8`iY+Cv&iboMJ^f9ROUK0Lm$;-T*c;TCTED_0|qfhlcS zv;BD*$Zko#nWPL}2K8T-?4}p{u)4xon!v_(yVW8VMpxg4Kh^J6WM{IlD{s?%XRT8P|yCU`R&6gwB~ zg}{At!iWCzOH37!ytcPeC`(({ovP7M5Y@bYYMZ}P2Z3=Y_hT)4DRk}wfeIo%q*M9UvXYJq!-@Ly79m5aLD{hf@BzQB>FdQ4mw z6$@vzSKF^Gnzc9vbccii)==~9H#KW<6)Uy1wb~auBn6s`ct!ZEos`WK8e2%<00b%# zY9Nvnmj@V^K(a_38dw-S*;G-(i(ETuIwyirs?$FFW@|66a38k+a%GLmucL%Wc8qk3 z?h_4!?4Y-xt)ry)>J`SuY**fuq2>u+)VZ+_1Egzctb*xJ6+7q`K$^f~r|!i?(07CD zH!)C_uerf-AHNa?6Y61D_MjGu*|wcO+ZMOo4q2bWpvjEWK9yASk%)QhwZS%N2_F4& z16D18>e%Q1mZb`R;vW{+IUoKE`y3(7p zplg5cBB)dtf^SdLd4n60oWie|(ZjgZa6L*VKq02Aij+?Qfr#1z#fwh92aV-HGd^_w zsucG24j8b|pk>BO7k8dS86>f-jBP^Sa}SF{YNn=^NU9mLOdKcAstv&GV>r zLxKHPkFxpvE8^r@MSF6UA}cG`#yFL8;kA7ccH9D=BGBtW2;H>C`FjnF^P}(G{wU;G z!LXLCbPfsGeLCQ{Ep$^~)@?v`q(uI`CxBY44osPcq@(rR-633!qa zsyb>?v%@X+e|Mg`+kRL*(;X>^BNZz{_kw5+K;w?#pReiw7eU8_Z^hhJ&fj80XQkuU z39?-z)6Fy$I`bEiMheS(iB6uLmiMd1i)cbK*9iPpl+h4x9ch7x- z1h4H;W_G?|)i`z??KNJVwgfuAM=7&Apd3vm#AT8uzQZ!NII}}@!j)eIfn53h{NmN7 zAKG6SnKP%^k&R~m5#@_4B@V?hYyHkm>0SQ@PPiw*@Tp@UhP-?w@jW?nxXuCipMW=L zH*5l*d@+jXm0tIMP_ec6Jcy6$w(gKK@xBX8@%oPaSyG;13qkFb*LuVx3{AgIyy&n3 z@R2_DcEn|75_?-v5_o~%xEt~ONB>M~tpL!nOVBLPN&e5bn5>+7o0?Nm|EGJ5 zmUbF{u|Qn?cu5}n4@9}g(G1JxtzkKv(tqwm_?1`?YSVA2IS4WI+*(2D*wh&6MIEhw z+B+2U<&E&|YA=3>?^i6)@n1&&;WGHF-pqi_sN&^C9xoxME5UgorQ_hh1__zzR#zVC zOQt4q6>ME^iPJ37*(kg4^=EFqyKH@6HEHXy79oLj{vFqZGY?sVjk!BX^h$SFJlJnv z5uw~2jLpA)|0=tp>qG*tuLru?-u`khGG2)o{+iDx&nC}eWj3^zx|T`xn5SuR;Aw8U z`p&>dJw`F17@J8YAuW4=;leBE%qagVTG5SZdh&d)(#ZhowZ|cvWvGMMrfVsbg>_~! z19fRz8CSJdrD|Rl)w!uznBF&2-dg{>y4l+6(L(vzbLA0Bk&`=;oQQ>(M8G=3kto_) zP8HD*n4?MySO2YrG6fwSrVmnesW+D&fxjfEmp=tPd?RKLZJcH&K(-S+x)2~QZ$c(> zru?MND7_HPZJVF%wX(49H)+~!7*!I8w72v&{b={#l9yz+S_aVPc_So%iF8>$XD1q1 zFtucO=rBj0Ctmi0{njN8l@}!LX}@dwl>3yMxZ;7 z0Ff2oh8L)YuaAGOuZ5`-p%Z4H@H$;_XRJQ|&(MhO78E|nyFa158gAxG^SP(vGi^+< zChY}o(_=ci3Wta#|K6MVljNe0T$%Q5ylx-v`R)r8;3+VUpp-)7T`-Y&{Zk z*)1*2MW+_eOJtF5tCMDV`}jg-R(_IzeE9|MBKl;a7&(pCLz}5<Zf+)T7bgNUQ_!gZtMlw=8doE}#W+`Xp~1DlE=d5SPT?ymu!r4z%&#A-@x^=QfvDkfx5-jz+h zoZ1OK)2|}_+UI)i9%8sJ9X<7AA?g&_Wd7g#rttHZE;J*7!e5B^zdb%jBj&dUDg4&B zMMYrJ$Z%t!5z6=pMGuO-VF~2dwjoXY+kvR>`N7UYfIBMZGP|C7*O=tU z2Tg_xi#Q3S=1|=WRfZD;HT<1D?GMR%5kI^KWwGrC@P2@R>mDT^3qsmbBiJc21kip~ zZp<7;^w{R;JqZ)C4z-^wL=&dBYj9WJBh&rd^A^n@07qM$c+kGv^f+~mU5_*|eePF| z3wDo-qaoRjmIw<2DjMTG4$HP{z54_te_{W^gu8$r=q0JgowzgQPct2JNtWPUsjF8R zvit&V8$(;7a_m%%9TqPkCXYUp&k*MRcwr*24>hR! z$4c#E=PVE=P4MLTUBM z7#*RDe0}=B)(3cvNpOmWa*eH#2HR?NVqXdJ=hq);MGD07JIQQ7Y0#iD!$C+mk7x&B zMwkS@H%>|fmSu#+ zI!}Sb(%o29Vkp_Th>&&!k7O>Ba#Om~B_J{pT7BHHd8(Ede(l`7O#`_}19hr_?~JP9 z`q(`<)y>%)x;O7)#-wfCP{?llFMoH!)ZomgsOYFvZ1DxrlYhkWRw#E-#Qf*z@Y-EQ z1~?_=c@M4DO@8AzZ2hKvw8CgitzI9yFd&N1-{|vP#4IqYb*#S0e3hrjsEGlnc4xwk z4o!0rxpUt8j&`mJ8?+P8G{m^jbk)bo_UPM+ifW*y-A*et`#_Ja_3nYyRa9fAG1Xr5 z>#AM_@PY|*u)DGRWJihZvgEh#{*joJN28uN7;i5{kJ*Gb-TERfN{ERe_~$Es~NJCpdKLRvdj4658uYYx{ng7I<6j~w@p%F<7a(Ssib|j z51;=Py(Nu*#hnLx@w&8X%=jrADn3TW>kplnb zYbFIWWVQXN7%Cwn6KnR)kYePEBmvM45I)UJb$)ninpdYg3a5N6pm_7Q+9>!_^xy?k za8@tJ@OOs-pRAAfT>Nc2x=>sZUs2!9Dwa%TTmDggH4fq(x^MW>mcRyJINlAqK$YQCMgR8`>6=Sg$ zFnJZsA8xUBXIN3i70Q%8px@yQPMgVP=>xcPI38jNJK<=6hC={a07+n@R|$bnhB)X$ z(Zc%tadp70vBTnW{OUIjTMe38F}JIH$#A}PB&RosPyFZMD}q}5W%$rh>5#U;m`z2K zc(&WRxx7DQLM-+--^w*EWAIS%bi>h587qkwu|H=hma3T^bGD&Z!`u(RKLeNZ&pI=q$|HOcji(0P1QC!YkAp*u z3%S$kumxR}jU<@6`;*-9=5-&LYRA<~uFrwO3U0k*4|xUTp4ZY7;Zbjx|uw&BWU$zK(w55pWa~#=f$c zNDW0O68N!xCy>G}(CX=;8hJLxAKn@Aj(dbZxO8a$+L$jK8$N-h@4$i8)WqD_%Snh4 zR?{O%k}>lr>w$b$g=VP8mckcCrjnp>uQl5F_6dPM8FWRqs}h`DpfCv20uZhyY~tr8 zkAYW4#yM;*je)n=EAb(q@5BWD8b1_--m$Q-3wbh1hM{8ihq7UUQfg@)l06}y+#=$( z$x>oVYJ47zAC^>HLRE-!HitjUixP6!R98WU+h>zct7g4eD;Mj#FL*a!VW!v-@b(Jv zj@@xM5noCp5%Vk3vY{tyI#oyDV7<$`KG`tktVyC&0DqxA#>V;-3oH%NW|Q&=UQ&zU zXNIT67J4D%5R1k#bW0F}TD`hlW7b)-=-%X4;UxQ*u4bK$mTAp%y&-(?{sXF%e_VH6 zTkt(X)SSN|;8q@8XX6qfR;*$r#HbIrvOj*-5ND8RCrcw4u8D$LXm5zlj@E5<3S0R# z??=E$p{tOk96$SloZ~ARe5`J=dB|Nj?u|zy2r(-*(q^@YwZiTF@QzQyPx_l=IDKa) zqD@0?IHJqSqZ_5`)81?4^~`yiGh6>7?|dKa8!e|}5@&qV!Iu9<@G?E}Vx9EzomB3t zEbMEm$TKGwkHDpirp;FZD#6P5qIlQJ8}rf;lHoz#h4TFFPYmS3+8(13_Mx2`?^=8S z|0)0&dQLJTU6{b%*yrpQe#OKKCrL8}YKw+<#|m`SkgeoN69TzIBQOl_Yg)W*w?NW) z*WxhEp$zQBBazJSE6ygu@O^!@Fr46j=|K`Mmb~xbggw7<)BuC@cT@Bwb^k?o-A zKX^9AyqR?zBtW5UA#siILztgOp?r4qgC`9jYJG_fxlsVSugGprremg-W(K0{O!Nw-DN%=FYCyfYA3&p*K>+|Q}s4rx#CQK zNj^U;sLM#q8}#|PeC$p&jAjqMu(lkp-_50Y&n=qF9`a3`Pr9f;b`-~YZ+Bb0r~c+V z*JJ&|^T{}IHkwjNAaM^V*IQ;rk^hnnA@~?YL}7~^St}XfHf6OMMCd9!vhk#gRA*{L zp?&63axj|Si%^NW05#87zpU_>QpFNb+I00v@cHwvdBn+Un)n2Egdt~LcWOeBW4Okm zD$-e~RD+W|UB;KQ;a7GOU&%p*efGu2$@wR74+&iP8|6#_fmnh^WcJLs)rtz{46);F z4v0OL{ZP9550>2%FE(;SbM*#sqMl*UXOb>ch`fJ|(*bOZ9=EB1+V4fkQ)hjsm3-u^Pk-4ji_uDDHdD>84tER!MvbH`*tG zzvbhBR@}Yd`azQGavooV=<WbvWLlO#x`hyO34mKcxrGv=`{ssnP=0Be5#1B;Co9 zh{TR>tjW2Ny$ZxJpYeg57#0`GP#jxDCU0!H15nL@@G*HLQcRdcsUO3sO9xvtmUcc{F*>FQZcZ5bgwaS^k-j5mmt zI7Z{Xnoml|A(&_{imAjK!kf5>g(oDqDI4C{;Bv162k8sFNr;!qPa2LPh>=1n z=^_9)TsLDvTqK7&*Vfm5k;VXjBW^qN3Tl&}K=X5)oXJs$z3gk0_+7`mJvz{pK|FVs zHw!k&7xVjvY;|(Py<;J{)b#Yjj*LZO7x|~pO4^MJ2LqK3X;Irb%nf}L|gck zE#55_BNsy6m+W{e zo!P59DDo*s@VIi+S|v93PwY6d?CE=S&!JLXwE9{i)DMO*_X90;n2*mPDrL%{iqN!?%-_95J^L z=l<*{em(6|h7DR4+4G3Wr;4*}yrBkbe3}=p7sOW1xj!EZVKSMSd;QPw>uhKK z#>MlS@RB@-`ULv|#zI5GytO{=zp*R__uK~R6&p$q{Y{iNkg61yAgB8C^oy&``{~FK z8hE}H&nIihSozKrOONe5Hu?0Zy04U#0$fB7C6y~?8{or}KNvP)an=QP&W80mj&8WL zEZQF&*FhoMMG6tOjeiCIV;T{I>jhi9hiUwz?bkX3NS-k5eWKy)Mo_orMEg4sV6R6X&i-Q%JG;Esl+kLpn@Bsls9O|i9z`tKB^~1D5)RIBB&J<6T@a4$pUvh$IR$%ubH)joi z!7>ON0DPwx=>0DA>Bb^c?L8N0BBrMl#oDB+GOXJh;Y&6I)#GRy$W5xK%a;KS8BrER zX)M>Rdoc*bqP*L9DDA3lF%U8Yzb6RyIsW@}IKq^i7v&{LeIc=*ZHIbO68x=d=+0T( zev=DT9f|x!IWZNTB#N7}V4;9#V$%Wo0%g>*!MdLOEU>My0^gni9ocID{$g9ytD!gy zKRWT`DVN(lcYjR|(}f0?zgBa3SwunLfAhx><%u0uFkrdyqlh8_g zDKt#R6rA2(Vm2LW_>3lBNYKG_F{TEnnKWGGC15y&OebIRhFL4TeMR*v9i0wPoK#H< zu4){s4K&K)K(9~jgGm;H7lS7y_RYfS;&!Oj5*eqbvEcW^a*i67nevzOZxN6F+K~A%TYEtsAVsR z@J=1hc#Dgs7J2^FL|qV&#WBFQyDtEQ2kPO7m2`)WFhqAob)Y>@{crkil6w9VoA?M6 zADGq*#-hyEVhDG5MQj677XmcWY1_-UO40QEP&+D)rZoYv^1B_^w7zAvWGw&pQyCyx zD|ga$w!ODOxxGf_Qq%V9Z7Q2pFiUOIK818AGeZ-~*R zI1O|SSc=3Z?#61Rd|AXx2)K|F@Z1@x!hBBMhAqiU)J=U|Y)T$h3D?ZPPQgkSosnN! zIqw-t$0fqsOlgw3TlHJF*t$Q@bg$9}A3X=cS@-yU3_vNG_!#9}7=q7!LZ?-%U26W4 z$d>_}*s1>Ac%3uFR;tnl*fNlylJ)}r2^Q3&@+is3BIv<}x>-^_ng;jhdaM}6Sg3?p z0jS|b%QyScy3OQ(V*~l~bK>VC{9@FMuW_JUZO?y(V?LKWD6(MXzh}M3r3{7b4eB(#`(q1m{>Be%_<9jw8HO!x#yF6vez$c#kR+}s zZO-_;25Sxngd(}){zv?ccbLqRAlo;yog>4LH&uZUK1n>x?u49C)Y&2evH5Zgt~666 z_2_z|H5AO5Iqxv_Bn~*y1qzRPcob<+Otod5Xd2&z=C;u+F}zBB@b^UdGdUz|s!H}M zXG%KiLzn3G?FZgdY&3pV$nSeY?ZbU^jhLz9!t0K?ep}EFNqR1@E!f*n>x*!uO*~JF zW9UXWrVgbX1n#76_;&0S7z}(5n-bqnII}_iDsNqfmye@)kRk`w~1 z6j4h4BxcPe6}v)xGm%=z2#tB#^KwbgMTl2I*$9eY|EWAHFc3tO48Xo5rW z5oHD!G4kb?MdrOHV=A+8ThlIqL8Uu+7{G@ zb)cGBm|S^Eh5= z^E^SZ=yeC;6nNCdztw&TdnIz}^Of@Ke*@vjt)0g>Y!4AJvWiL~e7+9#Ibhe)> ziNwh>gWZL@FlWc)wzihocz+%+@*euwXhW%Hb>l7tf8aJe5_ZSH1w-uG|B;9qpcBP0 zM`r1Hu#htOl)4Cl1c7oY^t0e4Jh$-I(}M5kzWqh{F=g&IM#JiC`NDSd@BCKX#y<P@Gwl$3a3w z6<(b|K(X5FIR22M)sy$4jY*F4tT{?wZRI+KkZFb<@j@_C316lu1hq2hA|1wCmR+S@ zRN)YNNE{}i_H`_h&VUT5=Y(lN%m?%QX;6$*1P}K-PcPx>*S55v)qZ@r&Vcic-sjkm z! z=nfW&X`}iAqa_H$H%z3Tyz5&P3%+;93_0b;zxLs)t#B|up}JyV$W4~`8E@+BHQ+!y zuIo-jW!~)MN$2eHwyx-{fyGjAWJ(l8TZtUp?wZWBZ%}krT{f*^fqUh+ywHifw)_F> zp76_kj_B&zFmv$FsPm|L7%x-j!WP>_P6dHnUTv!9ZWrrmAUteBa`rT7$2ixO;ga8U z3!91micm}{!Btk+I%pMgcKs?H4`i+=w0@Ws-CS&n^=2hFTQ#QeOmSz6ttIkzmh^`A zYPq)G1l3h(E$mkyr{mvz*MP`x+PULBn%CDhltKkNo6Uqg!vJ#DA@BIYr9TQ`18Un2 zv$}BYzOQuay9}w(?JV63F$H6WmlYPPpH=R|CPb%C@BCv|&Q|&IcW7*LX?Q%epS z`=CPx{1HnJ9_46^=0VmNb>8JvMw-@&+V8SDLRYsa>hZXEeRbtf5eJ>0@Ds47zIY{N z42EOP9J8G@MXXdeiPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91AfN*P1ONa40RR91AOHXW0IY^$^8f$?lu1NER9Fe^SItioK@|V(ZWmgL zZT;XwPgVuWM>O%^|Dc$VK;n&?9!&g5)aVsG8cjs5UbtxVVnQNOV~7Mrg3+jnU;rhE z6fhW6P)R>_eXrXo-RW*y6RQ_qcb^s1wTu$TwriZ`=JUws>vRi}5x}MW1MR#7p|gIWJlaLK;~xaN}b< z<-@=RX-%1mt`^O0o^~2=CD7pJ<<$Rp-oUL-7PuG>do^5W_Mk#unlP}6I@6NPxY`Q} zuXJF}!0l)vwPNAW;@5DjPRj?*rZxl zwn;A(cFV!xe^CUu+6SrN?xe#mz?&%N9QHf~=KyK%DoB8HKC)=w=3E?1Bqj9RMJs3U z5am3Uv`@+{jgqO^f}Lx_Jp~CoP3N4AMZr~4&d)T`R?`(M{W5WWJV^z~2B|-oih@h^ zD#DuzGbl(P5>()u*YGo*Och=oRr~3P1wOlKqI)udc$|)(bacG5>~p(y>?{JD7nQf_ z*`T^YL06-O>T(s$bi5v~_fWMfnE7Vn%2*tqV|?~m;wSJEVGkNMD>+xCu#um(7}0so zSEu7?_=Q64Q5D+fz~T=Rr=G_!L*P|(-iOK*@X8r{-?oBlnxMNNgCVCN9Y~ocu+?XA zjjovJ9F1W$Nf!{AEv%W~8oahwM}4Ruc+SLs>_I_*uBxdcn1gQ^2F8a*vGjgAXYyh? zWCE@c5R=tbD(F4nL9NS?$PN1V_2*WR?gjv3)4MQeizuH`;sqrhgykEzj z593&TGlm3h`sIXy_U<7(dpRXGgp0TB{>s?}D{fwLe>IV~exweOfH!qM@CV5kib!YA z6O0gvJi_0J8IdEvyP#;PtqP*=;$iI2t(xG2YI-e!)~kaUn~b{6(&n zp)?iJ`z2)Xh%sCV@BkU`XL%_|FnCA?cVv@h*-FOZhY5erbGh)%Q!Av#fJM3Csc_g zC2I6x%$)80`Tkz#KRA!h1FzY`?0es3t!rKDT5EjPe6B=BLPr7s0GW!if;Ip^!AmGW zL;$`Vdre+|FA!I4r6)keFvAx3M#1`}ijBHDzy)3t0gwjl|qC2YB`SSxFKHr(oY#H$)x{L$LL zBdLKTlsOrmb>T0wd=&6l3+_Te>1!j0OU8%b%N342^opKmT)gni(wV($s(>V-fUv@0p8!f`=>PxC|9=nu ze{ToBBj8b<{PLfXV$h8YPgA~E!_sF9bl;QOF{o6t&JdsX?}rW!_&d`#wlB6T_h;Xf zl{4Tz5>qjF4kZgjO7ZiLPRz_~U@k5%?=30+nxEh9?s78gZ07YHB`FV`4%hlQlMJe@J`+e(qzy+h(9yY^ckv_* zb_E6o4p)ZaWfraIoB2)U7_@l(J0O%jm+Or>8}zSSTkM$ASG^w3F|I? z$+eHt7T~04(_WfKh27zqS$6* zzyy-ZyqvSIZ0!kkSvHknm_P*{5TKLQs8S6M=ONuKAUJWtpxbL#2(_huvY(v~Y%%#~ zYgsq$JbLLprKkV)32`liIT$KKEqs$iYxjFlHiRNvBhxbDg*3@Qefw4UM$>i${R5uB zhvTgmqQsKA{vrKN;TSJU2$f9q=y{$oH{<)woSeV>fkIz6D8@KB zf4M%v%f5U2?<8B(xn}xV+gWP?t&oiapJhJbfa;agtz-YM7=hrSuxl8lAc3GgFna#7 zNjX7;`d?oD`#AK+fQ=ZXqfIZFEk{ApzjJF0=yO~Yj{7oQfXl+6v!wNnoqwEvrs81a zGC?yXeSD2NV!ejp{LdZGEtd1TJ)3g{P6j#2jLR`cpo;YX}~_gU&Gd<+~SUJVh+$7S%`zLy^QqndN<_9 zrLwnXrLvW+ew9zX2)5qw7)zIYawgMrh`{_|(nx%u-ur1B7YcLp&WFa24gAuw~& zKJD3~^`Vp_SR$WGGBaMnttT)#fCc^+P$@UHIyBu+TRJWbcw4`CYL@SVGh!X&y%!x~ zaO*m-bTadEcEL6V6*{>irB8qT5Tqd54TC4`h`PVcd^AM6^Qf=GS->x%N70SY-u?qr>o2*OV7LQ=j)pQGv%4~z zz?X;qv*l$QSNjOuQZ>&WZs2^@G^Qas`T8iM{b19dS>DaXX~=jd4B2u`P;B}JjRBi# z_a@&Z5ev1-VphmKlZEZZd2-Lsw!+1S60YwW6@>+NQ=E5PZ+OUEXjgUaXL-E0fo(E* zsjQ{s>n33o#VZm0e%H{`KJi@2ghl8g>a~`?mFjw+$zlt|VJhSU@Y%0TWs>cnD&61fW4e0vFSaXZa4-c}U{4QR8U z;GV3^@(?Dk5uc@RT|+5C8-24->1snH6-?(nwXSnPcLn#X_}y3XS)MI_?zQ$ZAuyg+ z-pjqsw}|hg{$~f0FzmmbZzFC0He_*Vx|_uLc!Ffeb8#+@m#Z^AYcWcZF(^Os8&Z4g zG)y{$_pgrv#=_rV^D|Y<_b@ICleUv>c<0HzJDOsgJb#Rd-Vt@+EBDPyq7dUM9O{Yp zuGUrO?ma2wpuJuwl1M=*+tb|qx7Doj?!F-3Z>Dq_ihFP=d@_JO;vF{iu-6MWYn#=2 zRX6W=`Q`q-+q@Db|6_a1#8B|#%hskH82lS|9`im0UOJn?N#S;Y0$%xZw3*jR(1h5s z?-7D1tnIafviko>q6$UyqVDq1o@cwyCb*})l~x<@s$5D6N=-Uo1yc49p)xMzxwnuZ zHt!(hu-Ek;Fv4MyNTgbW%rPF*dB=;@r3YnrlFV{#-*gKS_qA(G-~TAlZ@Ti~Yxw;k za1EYyX_Up|`rpbZ0&Iv#$;eC|c0r4XGaQ-1mw@M_4p3vKIIpKs49a8Ns#ni)G314Z z8$Ei?AhiT5dQGWUYdCS|IC7r z=-8ol>V?u!n%F*J^^PZ(ONT&$Ph;r6X;pj|03HlDY6r~0g~X#zuzVU%a&!fs_f|m?qYvg^Z{y?9Qh7Rn?T*F%7lUtA6U&={HzhYEzA`knx1VH> z{tqv?p@I(&ObD5L4|YJV$QM>Nh-X3cx{I&!$FoPC_2iIEJfPk-$;4wz>adRu@n`_y z_R6aN|MDHdK;+IJmyw(hMoDCFCQ(6?hCAG5&7p{y->0Uckv# zvooVuu04$+pqof777ftk<#42@KQ((5DPcSMQyzGOJ{e9H$a9<2Qi_oHjl{#=FUL9d z+~0^2`tcvmp0hENwfHR`Ce|<1S@p;MNGInXCtHnrDPXCKmMTZQ{HVm_cZ>@?Wa6}O zHsJc7wE)mc@1OR2DWY%ZIPK1J2p6XDO$ar`$RXkbW}=@rFZ(t85AS>>U0!yt9f49^ zA9@pc0P#k;>+o5bJfx0t)Lq#v4`OcQn~av__dZ-RYOYu}F#pdsl31C^+Qgro}$q~5A<*c|kypzd} ziYGZ~?}5o`S5lw^B{O@laad9M_DuJle- z*9C7o=CJh#QL=V^sFlJ0c?BaB#4bV^T(DS6&Ne&DBM_3E$S^S13qC$7_Z?GYXTpR@wqr70wu$7+qvf-SEUa5mdHvFbu^7ew!Z1a^ zo}xKOuT*gtGws-a{Tx}{#(>G~Y_h&5P@Q8&p!{*s37^QX_Ibx<6XU*AtDOIvk|^{~ zPlS}&DM5$Ffyu-T&0|KS;Wnaqw{9DB&B3}vcO14wn;)O_e@2*9B&0I_ zZz{}CMxx`hv-XouY>^$Y@J(_INeM>lIQI@I>dBAqq1)}?Xmx(qRuX^i4IV%=MF306 z9g)i*79pP%_7Ex?m6ag-4Tlm=Z;?DQDyC-NpUIb#_^~V_tsL<~5<&;Gf2N+p?(msn zzUD~g>OoW@O}y0@Z;RN)wjam`CipmT&O7a|YljZqU=U86 zedayEdY)2F#BJ6xvmW8K&ffdS*0!%N<%RB!2~PAT4AD*$W7yzHbX#Eja9%3aD+Ah2 zf#T;XJW-GMxpE=d4Y>}jE=#U`IqgSoWcuvgaWQ9j1CKzG zDkoMDDT)B;Byl3R2PtC`ip=yGybfzmVNEx{xi_1|Cbqj>=FxQc{g`xj6fIfy`D8fA z##!-H_e6o0>6Su&$H2kQTujtbtyNFeKc}2=|4IfLTnye#@$Au7Kv4)dnA;-fz@D_8 z)>irG$)dkBY~zX zC!ZXLy*L3xr6cb70QqfN#Q>lFIc<>}>la4@3%7#>a1$PU&O^&VszpxLC%*!m-cO{B z-Y}rQr4$84(hvy#R69H{H zJ*O#uJh)TF6fbXy;fZkk%X=CjsTK}o5N1a`d7kgYYZLPxsHx%9*_XN8VWXEkVJZ%A z1A+5(B;0^{T4aPYr8%i@i32h)_)|q?9vws)r+=5u)1YNftF5mknwfd*%jXA2TeP}Z zQ!m?xJ3?9LpPM?_A3$hQ1QxNbR&}^m z!F999s?p^ak#C4NM_x2p9FoXWJ$>r?lJ)2bG)sX{gExgLA2s5RwHV!h6!C~d_H||J z>9{E{mEv{Z1z~65Vix@dqM4ZqiU|!)eWX$mwS5mLSufxbpBqqS!jShq1bmwCR6 z4uBri7ezMeS6ycaXPVu(i2up$L; zjpMtB`k~WaNrdgM_R=e#SN?Oa*u%nQy01?()h4A(jyfeNfx;5o+kX?maO4#1A^L}0 zYNyIh@QVXIFiS0*tE}2SWTrWNP3pH}1Vz1;E{@JbbgDFM-_Mky^7gH}LEhl~Ve5PexgbIyZ(IN%PqcaV@*_`ZFb=`EjspSz%5m2E34BVT)d=LGyHVz@-e%9Ova*{5@RD;7=Ebkc2GP%pIP^P7KzKapnh`UpH?@h z$RBpD*{b?vhohOKf-JG3?A|AX|2pQ?(>dwIbWhZ38GbTm4AImRNdv_&<99ySX;kJ| zo|5YgbHZC#HYgjBZrvGAT4NZYbp}qkVSa;C-LGsR26Co+i_HM&{awuO9l)Ml{G8zD zs$M8R`r+>PT#Rg!J(K6T4xHq7+tscU(}N$HY;Yz*cUObX7J7h0#u)S7b~t^Oj}TBF zuzsugnst;F#^1jm>22*AC$heublWtaQyM6RuaquFd8V#hJ60Z3j7@bAs&?dD#*>H0SJaDwp%U~27>zdtn+ z|8sZzklZy$%S|+^ie&P6++>zbrq&?+{Yy11Y>@_ce@vU4ZulS@6yziG6;iu3Iu`M= zf3rcWG<+3F`K|*(`0mE<$89F@jSq;j=W#E>(R}2drCB7D*0-|D;S;(;TwzIJkGs|q z2qH{m_zZ+el`b;Bv-#bQ>}*VPYC|7`rgBFf2oivXS^>v<&HHTypvd4|-zn|=h=TG{ z05TH2+{T%EnADO>3i|CB zCu60#qk`}GW{n4l-E$VrqgZGbI zbQW690KgZt4U3F^5@bdO1!xu~p@7Y~*_FfWg2CdvED5P5#w#V46LH`<&V0{t&Ml~4 zHNi7lIa+#i+^Z6EnxO7KJQw)wD)4~&S-Ki8)3=jpqxmx6c&zU&<&h%*c$I(5{1HZT zc9WE}ijcWJiVa^Q^xC|WX0habl89qycOyeViIbi(LFsEY_8a|+X^+%Qv+W4vzj>`y zpuRnjc-eHNkvXvI_f{=*FX=OKQzT?bck#2*qoKTHmDe>CDb&3AngA1O)1b}QJ1Tun z_<@yVEM>qG7664Pa@dzL@;DEh`#?yM+M|_fQS<7yv|i*pw)|Z8)9IR+QB7N3v3K(wv4OY*TXnH&X0nQB}?|h2XQeGL^q~N7N zDFa@x0E(UyN7k9g%IFq7Sf+EAfE#K%%#`)!90_)Dmy3Bll&e1vHQyPA87TaF(xbqMpDntVp?;8*$87STop$!EAnGhZ?>mqPJ(X zFsr336p3P{PpZCGn&^LP(JjnBbl_3P3Kcq+m}xVFMVr1zdCPJMDIV_ki#c=vvTwbU z*gKtfic&{<5ozL6Vfpx>o2Tts?3fkhWnJD&^$&+Mh5WGGyO7fG@6WDE`tEe(8<;+q z@Ld~g08XDzF8xtmpIj`#q^(Ty{Hq>t*v`pedHnuj(0%L(%sjkwp%s}wMd!a<*L~9T z9MM@s)Km~ogxlqEhIw5(lc46gCPsSosUFsgGDr8H{mj%OzJz{N#;bQ;KkV+ZWA1(9 zu0PXzyh+C<4OBYQ0v3z~Lr;=C@qmt8===Ov2lJ1=DeLfq*#jgT{YQCuwz?j{&3o_6 zsqp2Z_q-YWJg?C6=!Or|b@(zxTlg$ng2eUQzuC<+o)k<6^9ju_Z*#x+oioZ5T8Z_L zz9^A1h2eFS0O5muq8;LuDKwOv4A9pxmOjgb6L*i!-(0`Ie^d5Fsgspon%X|7 zC{RRXEmYn!5zP9XjG*{pLa)!2;PJB2<-tH@R7+E1cRo=Wz_5Ko8h8bB$QU%t9#vol zAoq?C$~~AsYC|AQQ)>>7BJ@{Cal)ZpqE=gjT+Juf!RD-;U0mbV1ED5PbvFD6M=qj1 zZ{QERT5@(&LQ~1X9xSf&@%r|3`S#ZCE=sWD`D4YQZ`MR`G&s>lN{y2+HqCfvgcw3E z-}Kp(dfGG?V|97kAHQX+OcKCZS`Q%}HD6u*e$~Ki&Vx53&FC!x94xJd4F2l^qQeFO z?&JdmgrdVjroKNJx64C!H&Vncr^w zzR#XI}Dn&o8jB~_YlVM^+#0W(G1LZH5K^|uYT@KSR z^Y5>^*Bc45E1({~EJB(t@4n9gb-eT#s@@7)J^^<_VV`Pm!h7av8XH6^5zO zOcQBhTGr;|MbRsgxCW69w{bl4EW#A~);L?d4*y#j8Ne=Z@fmJP0k4{_cQ~KA|Y#_#BuUiYx8y*za3_6Y}c=GSe7(2|KAfhdzud!Zq&}j)=o4 z7R|&&oX7~e@~HmyOOsCCwy`AR+deNjZ3bf6ijI_*tKP*_5JP3;0d;L_p(c>W1b%sG zJ*$wcO$ng^aW0E(5ldckV9unU7}OB7s?Wx(761?1^&8tA5y0_(ieV>(x-e@}1`lWC z-YH~G$D>#ud!SxK2_Iw{K%92=+{4yb-_XC>ji&j7)1ofp(OGa4jjF;Hd*`6YQL+Jf zffg+6CPc8F@EDPN{Kn96yip;?g@)qgkPo^nVKFqY?8!=h$G$V=<>%5J&iVjwR!7H0 z$@QL|_Q81I;Bnq8-5JyNRv$Y>`sWl{qhq>u+X|)@cMlsG!{*lu?*H`Tp|!uv z9oEPU1jUEj@ueBr}%Y)7Luyi)REaJV>eQ{+uy4uh0ep0){t;OU8D*RZ& zE-Z-&=BrWQLAD^A&qut&4{ZfhqK1ZQB0fACP)=zgx(0(o-`U62EzTkBkG@mXqbjXm z>w`HNeQM?Is&4xq@BB(K;wv5nI6EXas)XXAkUuf}5uSrZLYxRCQPefn-1^#OCd4aO zzF=dQ*CREEyWf@n6h7(uXLNgJIwGp#Xrsj6S<^bzQ7N0B0N{XlT;`=m9Olg<>KL}9 zlp>EKTx-h|%d1Ncqa=wnQEuE;sIO-f#%Bs?g4}&xS?$9MG?n$isHky0caj za8W+B^ERK#&h?(x)7LLpOqApV5F>sqB`sntV%SV>Q1;ax67qs+WcssfFeF3Xk=e4^ zjR2^(%K1oBq%0%Rf!y&WT;lu2Co(rHi|r1_uW)n{<7fGc-c=ft7Z0Q}r4W$o$@tQF#i?jDBwZ8h+=SC}3?anUp3mtRVv9l#H?-UD;HjTF zQ*>|}e=6gDrgI9p%c&4iMUkQa4zziS$bO&i#DI$Wu$7dz7-}XLk%!US^XUIFf2obO zFCTjVEtkvYSKWB;<0C;_B{HHs~ax_48^Cml*mjfBC5*7^HJZiLDir(3k&BerVIZF8zF;0q80eX8c zPN4tc+Dc5DqEAq$Y3B3R&XPZ=AQfFMXv#!RQnGecJONe0H;+!f^h5x0wS<+%;D}MpUbTNUBA}S2n&U59-_5HKr{L^jPsV8B^%NaH|tUr)mq=qCBv_- ziZ1xUp(ZzxUYTCF@C}To;u60?RIfTGS?#JnB8S8@j`TKPkAa)$My+6ziGaBcA@){d z91)%+v2_ba7gNecdj^8*I4#<11l!{XKl6s0zkXfJPxhP+@b+5ev{a>p*W-3*25c&} zmCf{g9mPWVQ$?Sp*4V|lT@~>RR)9iNdN^7KT@>*MU3&v^3e?=NTbG9!h6C|9zO097 zN{Qs6YwR-5$)~ z`b~qs`a1Dbx8P>%V=1XGjBptMf%P~sl1qbHVm1HYpY|-Z^Dar8^HqjIw}xaeRlsYa zJ_@Apy-??`gxPmb`m`0`z`#G7*_C}qiSZe~l2z65tE~IwMw$1|-u&t|z-8SxliH00 zlh1#kuqB56s+E&PWQ7Nz17?c}pN+A@-c^xLqh(j;mS|?>(Pf7(?qd z5q@jkc^nA&!K-}-1P=Ry0yyze0W!+h^iW}7jzC1{?|rEFFWbE^Yu7Y}t?jmP-D$f+ zmqFT7nTl0HL|4jwGm7w@a>9 zKD)V~+g~ysmei$OT5}%$&LK8?ib|8aY|>W3;P+0B;=oD=?1rg+PxKcP(d;OEzq1CKA&y#boc51P^ZJPPS)z5 zAZ)dd2$glGQXFj$`XBBJyl2y-aoBA8121JC9&~|_nY>nkmW>TLi%mWdn-^Jks-Jv| zSR*wij;A3Fcy8KsDjQ15?Z9oOj|Qw2;jgJiq>dxG(2I2RE- z$As!#zSFIskebqU2bnoM^N<4VWD2#>!;saPSsY8OaCCQqkCMdje$C?Sp%V}f2~tG5 z0whMYk6tcaABwu*x)ak@n4sMElGPX1_lmv@bgdI2jPdD|2-<~Jf`L`@>Lj7{<-uLQ zE3S_#3e10q-ra=vaDQ42QUY^@edh>tnTtpBiiDVUk5+Po@%RmuTntOlE29I4MeJI?;`7;{3e4Qst#i-RH6s;>e(Sc+ubF2_gwf5Qi%P!aa89fx6^{~A*&B4Q zKTF|Kx^NkiWx=RDhe<{PWXMQ;2)=SC=yZC&mh?T&CvFVz?5cW~ritRjG2?I0Av_cI z)=s!@MXpXbarYm>Kj0wOxl=eFMgSMc?62U#2gM^li@wKPK9^;;0_h7B>F>0>I3P`{ zr^ygPYp~WVm?Qbp6O3*O2)(`y)x>%ZXtztz zMAcwKDr=TCMY!S-MJ8|2MJCVNUBI0BkJV6?(!~W!_dC{TS=eh}t#X+2D>Kp&)ZN~q zvg!ogxUXu^y(P*;Q+y_rDoGeSCYxkaGPldDDx)k;ocJvvGO#1YKoQLHUf2h_pjm&1 zqh&!_KFH03FcJvSdfgUYMp=5EpigZ*8}7N_W%Ms^WSQ4hH`9>3061OEcxmf~TcYn5_oHtscWn zo5!ayj<_fZ)vHu3!A!7M;4y1QIr8YGy$P2qDD_4+T8^=^dB6uNsz|D>p~4pF3Nrb6 zcpRK*($<~JUqOya#M1=#IhOZ zG)W+rJS-x(6EoVz)P zsSo>JtnChdj9^);su%SkFG~_7JPM zEDz3gk2T7Y%x>1tWyia|op(ilEzvAujW?Xwlw>J6d7yEi8E zv30riR|a_MM%ZZX&n!qm0{2agq(s?x9E@=*tyT$nND+{Djpm7Rsy!+c$j+wqMwTOF zZL8BQ|I`<^bGW)5apO{lh(Asqen?_U`$_n0-Ob~Yd%^89oEe%9yGumQ_8Be+l2k+n zCxT%s?bMpv|AdWP7M1LQwLm|x+igA~;+iK-*+tClF&ueX_V}>=4gvZ01xpubQWXD_ zi?Un>&3=$fu)dgk-Z;0Ll}HK5_YM->l^Czrd0^cJ))(DwL2g3aZuza7ga9^|mT_70 z))}A}r1#-(9cxtn<9jGRwOB4hb9kK@YCgjfOM-90I$8@l=H^`K$cyhe2mTM|FY9vW znH~h)I<_aa#V1xmhk?Ng@$Jw-s%a!$BI4Us+Df+?J&gKAF-M`v}j`OWKP3>6`X`tEmhe#y*(Xm$_^Ybbs=%;L7h zp7q^C*qM}Krqsinq|WolR99>_!GL#Z71Hhz|IwQQv<>Ds09B?Je(lhI1(FInO8mc} zl$RyKCUmfku+Cd^8s0|t+e}5g7M{ZPJQH=UB3(~U&(w#Bz#@DTDHy>_UaS~AtN>4O zJ-I#U@R($fgupHebcpuEBX`SZ>kN!rW$#9>s{^3`86ZRQRtYTY)hiFm_9wU3c`SC8 z-5M%g)h}3Pt|wyj#F%}pGC@VL`9&>9P+_UbudCkS%y2w&*o})hBplrB*@Z?gel5q+ z%|*59(sR9GMk3xME}wd%&k?7~J)OL`rK#4d-haC7uaU8-L@?$K6(r<0e<;y83rK&` z3Q!1rD9WkcB8WBQ|WT|$u^lkr0UL4WH4EQTJyk@5gzHb18cOte4w zS`fLv8q;PvAZyY;*Go3Qw1~5#gP0D0ERla6M6#{; zr1l?bR}Nh+OC7)4bfAs(0ZD(axaw6j9v`^jh5>*Eo&$dAnt?c|Y*ckEORIiJXfGcM zEo`bmIq6rJm`XhkXR-^3d8^RTK2;nmVetHfUNugJG(4XLOu>HJA;0EWb~?&|0abr6 zxqVp@p=b3MN^|~?djPe!=eex(u!x>RYFAj|*T$cTi*Sd3Bme7Pri1tkK9N`KtRmXf zZYNBNtik97ct1R^vamQBfo9ZUR@k*LhIg8OR9d_{iv#t)LQV91^5}K5u{eyxwOFoU zHMVq$C>tfa@uNDW^_>EmO~WYQd(@!nKmAvSSIb&hPO|}g-3985t?|R&WZXvxS}Kt2i^eRe>WHb_;-K5cM4=@AN1>E&1c$k!w4O*oscx(f=<1K6l#8Exi)U(ZiZ zdr#YTP6?m1e1dOKysUjQ^>-MR={OuD00g6+(a^cvcmn#A_%Fh3Of%(qP5nvjS1=(> z|Ld8{u%(J}%2SY~+$4pjy{()5HN2MYUjg1X9umxOMFFPdM+IwOVEs4Z(olynvT%G) zt9|#VR}%O2@f6=+6uvbZv{3U)l;C{tuc zZ{K$rut=eS%3_~fQv^@$HV6#9)K9>|0qD$EV2$G^XUNBLM|5-ZmFF!KV)$4l^KVj@ zZ4fI}Knv*K%zPqK77}B-h_V{66VrmoZP2>@^euu8Rc}#qwRwt5uEBWcJJE5*5rT2t zA4Jpx`QQ~1Sh_n_a9x%Il!t1&B~J6p54zxAJx`REov${jeuL8h8x-z=?qwMAmPK5i z_*ES)BW(NZluu#Bmn1-NUKQip_X&_WzJy~J`WYxEJQ&Gu7DD< z&F9urE;}8S{x4{yB zaq~1Zrz%8)<`prSQv$eu5@1RY2WLu=waPTrn`WK%;G5(jt^FeM;gOdvXQjYhax~_> z{bS_`;t#$RYMu-;_Dd&o+LD<5Afg6v{NK?0d8dD5ohAN?QoocETBj?y{MB)jQ%UQ}#t3j&iL!qr@#6JEajR3@^k5wgLfI9S9dT2^f`2wd z%I#Q*@Ctk@w=(u)@QC}yBvUP&fFRR-uYKJ){Wp3&$s(o~W7OzgsUIPx0|ph2L1(r*_Pa@T@mcH^JxBjh09#fgo|W#gG7}|)k&uD1iZxb0 z@|Y)W79SKj9sS&EhmTD;uI#)FE6VwQ*YAr&foK$RI5H8_ripb$^=;U%gWbrrk4!5P zXDcyscEZoSH~n6VJu8$^6LE6)>+=o#Q-~*jmob^@191+Ot1w454e3)WMliLtY6~^w zW|n#R@~{5K#P+(w+XC%(+UcOrk|yzkEes=!qW%imu6>zjdb!B#`efaliKtN}_c!Jp zfyZa`n+Nx8;*AquvMT2;c8fnYszdDA*0(R`bsof1W<#O{v%O!1IO4WZe=>XBu_D%d zOwWDaEtX%@B>4V%f1+dKqcXT>m2!|&?}(GK8e&R=&w?V`*Vj)sCetWp9lr@@{xe6a zE)JL&;p}OnOO}Nw?vFyoccXT*z*?r}E8{uPtd;4<(hmX;d$rqJhEF}I+kD+m(ke;J z7Cm$W*CSdcD=RYEBhedg>tuT{PHqwCdDP*NkHv4rvQTXkzEn*Mb0oJz&+WfWIOS4@ zzpPJ|e%a-PIwOaOC7uQcHQ-q(SE(e@fj+7oC@34wzaBNaP;cw&gm{Z8yYX?V(lIv5 zKbg*zo1m5aGA4^lwJ|bAU=j3*d8S{vp!~fLFcK8s6%Ng55_qW_d*3R%e=34aDZPfD z&Le39j|ahp6E7B0*9OVdeMNrTErFatiE+=Z!XZ^tv0y%zZKXRTBuPyP&C{5(H?t)S zKV24_-TKpOmCPzU&by8R1Q5HY^@IDoeDA9MbgizgQ*F1Er~HVmvSU>vx}pZVQ&tr| zOtZl8vfY2#L<)gZ=ba&wG~EI*Vd?}lRMCf+!b5CDz$8~be-HKMo5omk$w7p4`Mym*IR8WiTz4^kKcUo^8Hkcsu14u z`Pkg`#-Y^A%CqJ0O@UF|caAulf68@(zhqp~YjzInh7qSN7Ov%Aj(Qz%{3zW|xubJ- ztNE_u_MO7Q_585r;xD?e=Er}@U1G@BKW5v$UM((eByhH2p!^g9W}99OD8VV@7d{#H zv)Eam+^K(5>-Ot~U!R$Um3prQmM)7DyK=iM%vy>BRX4#aH7*oCMmz07YB(EL!^%F7?CA#>zXqiYDhS;e?LYPTf(bte6B ztrfvDXYG*T;ExK-w?Knt{jNv)>KMk*sM^ngZ-WiUN;=0Ev^GIDMs=AyLg2V@3R z7ugNc45;4!RPxvzoT}3NCMeK$7j#q3r_xV(@t@OPRyoKBzHJ#IepkDsm$EJRxL)A* zf{_GQYttu^OXr$jHQn}zs$Eh|s|Z!r?Yi+bS-bi+PE*lH zo|6ztu6$r_?|B~S#m>imI!kQP9`6X426uHRri!wGcK;J;`%sFM(D#*Le~W*t2uH`Q z(HEO9-c_`mhA@4QhbW+tgtt9Pzx=_*3Kh~TB$SKmU4yx-Ay&)n%PZPKg#rD4H{%Ke zdMY@rf5EAFfqtrf?Vmk&N(_d-<=bvfOdPrYwY*;5%j@O6@O#Qj7LJTk-x3LN+dEKy+X z>~U8j3Ql`exr1jR>+S4nEy+4c2f{-Q!3_9)yY758tLGg7k^=nt<6h$YE$ltA+13S<}uOg#XHe6 zZHKdNsAnMQ_RIuB;mdoZ%RWpandzLR-BnjN2j@lkBbBd+?i ze*!5mC}!Qj(Q!rTu`KrRRqp22c=hF6<^v&iCDB`n7mHl;vdclcer%;{;=kA(PwdGG zdX#BWoC!leBC4);^J^tPkPbIe<)~nYb6R3u{HvC!NOQa?DC^Q`|_@ zcz;rk`a!4rSLAS>_=b@g?Yab4%=J3Cc7pRv8?_rHMl_aK*HSPU%0pG2Fyhef_biA!aW|-(( z*RIdG&Lmk(=(nk28Q1k1Oa$8Oa-phG%Mc6dT3>JIylcMMIc{&FsBYBD^n@#~>C?HG z*1&FpYVvXOU@~r2(BUa+KZv;tZ15#RewooEM0LFb>guQN;Z0EBFMFMZ=-m$a3;gVD z)2EBD4+*=6ZF?+)P`z@DOT;azK0Q4p4>NfwDR#Pd;no|{q_qB!zk1O8QojE;>zhPu z1Q=1z^0MYHo1*``H3ex|bW-Zy==5J4fE2;g6sq6YcXMYK5i|S^9(OSw#v!3^!EB<% zZF~J~CleS`V-peStyf*I%1^R88D;+8{{qN6-t!@gTARDg^w2`uSzFZbPQ!)q^oC}m zPo8VOQxq2BaIN`pAVFGu8!{p3}(+iZ`f4ck2ygVpEZMQW38nLpj3NQx+&sAkb8`}P3- zc>N*k6AG?r}bfO6_vccTuKX+*- z7W4Q#2``P0jIHYs)F>uG#AM#I6W2)!Nu2nD5{CRV_PmkDS2ditmbd#pggqEgAo%5oC?|CP zGa0CV)wA*ko!xC7pZYkqo{10CN_e00FX5SjWkI3?@XG}}bze!(&+k2$C-C`6temSk z_YyYpB^wh3woo`B zrMSTd4T?(X-jh`FeO76C(3xsOm9s2BP_b%ospg^!#*2*o9N;tf4(X9$qc_d(()yz5 zDk@1}u_Xd+86vy5RBs?LQCuYKCGPS;E4uFOi@V%1JTK&|eRf~lp$AV#;*#O}iRI2=i3rFL8{ zA^ptDZ0l6k-mq=hUJ0x$Y@J>UNfz~I5l63H(`~*v;qX`Z{zwsQQD-!wp0D&hyB8&Z z7$R07gIKGJ^%AvQ{4KM0edM39iFRx=P^6`!<1(s0t|JbB2tXs_B_IH9#ajH0C=-n+ z`nz`fKMBKLlf?2AC+|83M+0rqR%uhNGD;uKA6jOjp7YDe^4%0fRB<^bcjlS2KF~F; zu09wh1x0&4pG&76M;x8$u`b134t=dEPBn6PV|X29<#T4F1mxGF*HOgiWU8tN@cguI z_F@o+XL7FJztR63wC|j4x_DANzcX94r7Iz-O2x$({&qd*mdLG=-Rv)uZ}UlMR+F&q zU}=lkfb0p1>1Ho){o$@}mSKIV;h*$AND7~Dl)QzpFBlSM99Kx+F7GsVK5xcR? z_4Q(Z%cgk8ST}U;;=!LwyZVu^S$>B-Waeik%wzcKTIqeX=0FP(TGQ=nxi=dsS5BYF zl@?}NT!Y!Iyos^@v7XWXA{_bV~1lxz7gC?xuXxy0_?GaN!AhRRM5>)^t%&ODd;@HN5L{MD3 zc>i2keQZVm#?NrDwbfd}_<*5^U&w0zv~n-y8=GGN-!=_`FU^cM8oVCWRFxw?BM^YD zi=Vxz4q|jwPTg+?q7_XI)-S@gQkh>w0ZUB}a{^ z_i;`Y(~fvpI!vmW*A^|P7(6+@C4UeL2WATf{P1?H5rk`5{TL zcf!CgP6Mi{MvjZS)rfo7JLDZK7M7ANd$3`{j9baD*7{#Zu-33fOYUzjvtKzR2)_T1I1s7fe&z|=)QkX;=`zX8!Byw-veM#yr;|wjO^II>!B*B z0+w%;0(=*G3V@88t!}~zx)&do(uF=073Yeh*fEhZb3Vn>t!m(9p~Y_FdV3IgR)9eT z)~e9xpI%2deTWyHlXA(7srrfc_`7ACm!R>SoIgkuF8 z!wkOhrixFy9y@)GdxAntd!!7@=L_tFD2T5OdSUO)I%yj02le`qeQ=yKq$g^h)NG;# za(0J@#VBi^5YI|QI=rq{KlxwGabZJ0dKmfWDROkcM}lUN$@DV`K7fU?8CP2H23QPi zG?YF*=Vn=kTK*#Y_{AQN&oLju|0#E=fx%YVh>S{puu&K$b;BN*jIo@VYhqPiJPzzM>#kxoy0vW9i;ne2_BIG0zyRFp<3M(iY(%*M_>q0ulV2K}Tg zkG{EWKS{i%4DUuHi%DVKy%e+Q!~Uf`>>F6NgD{{I8~nO4!VgOvtFOc7(O)X`|7n*f zxBa4CJ-v9fUUH+`7sPVvpM_C*udZ@OTGTzx56QM5y~OlrZc&w9=)B?nmd@keRn+^= zvm~4sa5987LFDnU{(N|N zJAR8H@}p1fC+H(yTI4n#%~TbImMpuqYn9cQ<0QQ%=PzZItLkC*ef9WJUvfITKWh#D zc#__8`4am9%#NslIUw+<82#SR8AYG|woLfBg#!-&dqq}@P>|I0%lbdy0lSMmNe+}o zj0zZuFr6Wb?Y{Qy-S=|r`bdrDmhnmvkRnkdn`YCleU>Q$=je}LGhh>_QAj6aa_0Oc z%Swsmui;IRx7bN*=AAS@5yW&Y2hy;3&|HAiA8}!HT6!Z!RVn~MZg`RmI6&%#tBZDx zfD+y@Z~NWlk*4l13vmt3AK2wP!fQlnBbECL>?p)F?T)<`w&QN>cP_V>r7UTcsTaaP zTOb$f!P@zf$6>890NVKbIkG8rE?9!Y97sMSZjfF?A zYR8lp`LMoz~O?iaZN;gcX;LC-%Ia*R%A&SLx!YIf29?P+=XAAojK8!^OU*@?R&DK!#G_lsn!#;S375uZ&B0HH1|BO0R90$U>qs zSvHv>H~mAgNCcjo-e+;RjY6B9NCbQrZ|BHjTkehaU<9CSkdd>Vl*ifA2LNOP&R2Qdy3k3-TQ+ zbq=#vI43x`s=%~cGyN&y4Y!FxhwgDe@i6uv8^BLL&3z*SO=D0aLjih?gY4-9uWp5or)H+v~w6n5X#F-I52z=Z_p4JB(;M| zeaVFhuR2|3UD2MzVc~^nSoD2(dD#uL_1PdnIxeA{V5n`#3xf1Zx@4lw(DsQ&H$h zw#%3O<1173hjg2_nhKi!d1ej=h7y`hVjCNB6|HTnx>SWuCE-kgTnfT+YGX4_Lun({ zDv2`>d3vrS)tTf7ps_vvh!Cx^e1BFuWnEAh0(7fkNk|-3oU|iRWdsC6U)?Raft~HN z;^$U}vZK5O8|LV$>6X5T(uYkblv{zwPxnQBh(BQ5tA~J!vGiAMYP^_ki~pkIxDfOZ zUJDwq%O~WueeV6%uN<54&u*c&E4y431cklBNrb06zGOOy4XNT~JS-q(s6@)F@ovbe ze`fial(O4(-su%6@@1+V0MsdLLMyE8;)nou(7}czU(5ASaZYDT(kUZ0L(&g$nF^n9 z9-Pi`ZZLX&)^*M6As4_2Mmc9S7OT)F8KkL2NJ)KJcnCuWU=Wy402A&45#Q9Id~BBH z0cY*xlv!uXzKrXLH!xQu(OtJvEj|0-DmRj1vjFz{c*I4$Pe(+_V|^b~S!0xm{8lq= zZv)@NlcyL3Xdz+*|L137F7y6L-2VsrKw=q^S>F6i%<{Fr8zk06$Ay-(!L$fY@7mcng!2}L0t zgi|KxfB63Xtk_Q8#ZPipQ@!zgjdpEIbK_?q17Hoi4Eiyun$hrc>T(7pOLVLQE=lgGwA+A308p& z7@=09(|$>eLy5gLe{*|3b(M;1n;C^~v?o88jYib48eR4$QGsBFzd}3QuwO^_XE(=B zq+hMi0UFC|dB{LCwch7;zYT=NK})O%sgi0k#yV;My@24^B1+CuZmYOh0^b)5Ba_)) zC%i#_Iev&nsu%I|1N5=MVc#PrlunKAs&hY|3s5;@}`>sB>}gzxuB zB=2vrRyB3uiyW(hkDUNe1@&(b`;>ZvGgw|@s{zVC#_`HXIN_^J@Etb zA7A+F?ot37T{<-vTy8h&b3e+WKHE1oh;pUQrN4yRRrx?mT_9jRa2i4l1fUnLW^Cbl z!I1>VzyFe?VELWWhM?@?t-YPZkD-Qjo@bC2(o#ZtZmr{KZsdFWItV`rs$gp{724@C zL8K5}E0+DHcWcL^{BGei4>@J-3%a#$y6;I}=upc};-NDv-z#kPX26ylOpH)Ov1uU{ zkLj6oiH6l_s+B~_z;|Jc2oi?naS7#3H63~~lWj4rUnd=fCnKdkik<@R&kch9q##G{ z4u!%=rlM~Yp3jk*t8}1B`Sv6<%Z^}~1e@aq zg|JQ`QO2pSjAm-g*?IrNc$^~sIrNBo2$m|Sxanr?Mfs>2@Auu49 zGXlsS<9XS1&8h(dD*Hl&5HBDG!^pJ*lkau_Ur+7`7z;rcs$hT4we?3bT=7Fe<>{5( z2m2(c+hUz2BTHM8dCe*Z3XX&Av;b~a=$6EF>&^E8%nyxO@m_n!q&XD^A{SRjRZQ0L~qDeC=j&0$j6=LNIz@`ni^>ch|sv}^6 zlm>?28yPl@WmDPR?Y-A9X{U9Dv_IsbXJnzKCjkRksLOg#42uG2mE_acbTQ4)J|1V>%U@K(FP3AYhL0U zdeOCPN1qLv!|#c=p!_+%VNV(GHt`RuLRV^vz<5tt-r)yOK**kUWPspVAf|}ZL{LS= z@k(@@!P&W!>wwe`x{+GrFSWhHov7hu?{KuuT%kl#WO@*WX$i_@retlhQBj++SVNCx z5$78LxP>Z=^aJ)D280r_jj=zFfMJFXCIe^B{~V@d1rl_F(qo&AB4bC-vYL>x2jSKX zpuTG-6kgp3e^T&+dtV*i6a~)v@n?n*MffN59y}<0djUX zt27R+SE#hp8bzc#;rk$jw3r4)Q@eI$*`_)=Pvge8@8|8>H3X)<9YX6cXa=ii#Le;(qKm@%0-7$>2ShnYc`j#zJ7gu_FE^?uAkL|H)UIH#gPu^40!6^J=^ zr`}iwa^!4tzW~vOMZAaKF>*8A{^8m$i(VK)>?=#l`xrVe>wseSvM_aF zATNkY>kM_P3?1kE`uIq#mvr-wuTgUH0N<&JhF=(E9%^NS*HLm!4GZ4_XI zL=R5tlG5Mk_1rPfg)sk^llFuKPMPBhuU|L5q#yP_mzxp1o&pAzi-X31sgFpIHn@($ z_>=`AB5(8tP6p2zS5VEvH5J$M` z_much3>S7t3Yo`Yx!>83-hW9LYzDKP?mKdkD#QAK8*M((sx{eBQdrR<^3ZhFP81+& zBnJMUefQyNBji~$5d88Wfw1Lv59aJN9t2!pABLg;ewJ#LXL-10;QcJl+Y4Mtngb)k6JZlCf)3uD_u)J3sYyN;NN5hNbg$%W!i-GK%e&!Us)2IExWSss$YG(hm3kJ-h%yD z>8q^n$+4I(_y_mbT{du4P%h1j3oSpjhY97{+IZ`aA4ug!vNJ6*p?<2H(2w+GD3j$I z1TUXGyNzdf>_yB3grP~FZUs<2Quw;eEi*7s(-MiIkQ%@J^+WGdQvYSUN+TRiD-xto zJ=OUU+kxGYc!HCLNbCvR4lGTp~#L;DFzGd-#gJe*xf(P3hDQz|y)?b9mwU3WUVnpcqXM<@w%r-k*Wr^gzAv)8T^sqA=Ye z!7qy&exJmAcAt~CwS#@yNmjr8*T*!A6w4~E*ibaLRs0CFo(;R3=ODhDt6zWNodmo0 zXx&bT$6&+5c>a|WJ)F4G-^GjY0H#*tY=UNyYr_q5fsrcjk(c^~e*7Lf`!Jd`)p412 zn|^*hV= zFI4UbwA%X@smDd$cQOiMC%jfitTxTb+#`9`G=2rJDfK!E=5ra|So>lc{X1$~w28i+ z4p&cTGwZ#5VueiXS9O8#;RR$yg7tL9!^)Sz&pZYIzlSh}0}V{LxL$Cu%B4U5_}k}- zm~|CsD<076x@<>m=6w6N?WaThIBP`!u{-;WF)xc=2otx*lwf|5+MkdJePjh(B z9SH+%cHGCMAXNxB{_3^otDWdsV7Ob6n{0 z+&!(;iaHOX__5z_$Qk{%xYV%Ig@7iokGBwR`3642ZP#H#v9QGbWl8<|MS*=@qO@Uj z6+SZ_v9`1paUe5tFN~v(b#J3a_Lx0+;r9giZIx-A5TxdbG>xi#AZ5_z1V}B^n)sxT zz49}eK7EWb6wR!6-qQOrHQHkUvshvq%=G2d&@(#XM*Am1;WbnJ{X_!a{ZkphD$^TQ z=Iskb&}=lBm(RHiwJoGg`*NiQ6#RB$T#LF+>#ef;Jne&MxKPX!#r`&TVEFsp2jnNx>dClzpcPy&G&13a_<0qaR3i+k212~hoQ z8nMk{JP-t04I{GW5gUBqcJW-jSMrlw}>p)ptx?WKuCUV77taMiV zHok9V=6yv+Uts@fMY&A}amC=!Yj}eL@=e%XJ#%?agkt1jWF+10{(E9mHLDa>Ll7Vj zG=3cp%ljIB-6pC}6&`xJ*6WCP|IlglLWJ^?yviI8Ve)?V_i4%n;olzny62_`-|IGi z^=}p_O>Z8M;c4|RExu70E7ePW(HWVS&E$+LL6xSQgB`QfMQJ|4pCTFowA39p5P-|$ zUtM_H2HnP8_RoS~Vwk(FhbG zH41licj%=0a;Ln2STFBvU}Ne&O&%8bYKj!h1FA#sNM`232fX|U3QPp#3C?mN2;hE9 z;)!@5ixSPl<89^7gwhHc2YAX1KJK$#*3`KOMIQ253q7-*RJ5k)zp9GBO|Ga~X*^}US5oN@aG&waHV%vi~r{t^`ptTxb zL}q1W8S7*>7oWwvgV4uFLZ(@k`R*=LO_|Gu`prs~!WQXj-NLIa^2(7IHg>BG^N zc|i{-^=&Cek9dkJFQys|sjG9i>LLz|;yCv{^1i%c*h>8zF91kLvS9HBQi~ZU!JL`B zK8N+U0fr1*6??Ium)AF!6tc1eGhXIYL6IRT7rmKp7+>?%5Pa6zC5)KY$ycF0ZJ`G5nEQDG100U-jLkH8^UE4g6wq?sg%pP=-$&G#bcN`^?w3a6 z((s$6eRKcSEIslW-kk5Qi|5Mg-(xdLF}PxxVh$PuO}#aR6pW1kV4Af!Bqh*btXNNZ z>-4(IUl+L4dw+3LcpGut=qB45O+W)Q5?*zZ2A6rJcg`qkSvWA!j^r2mqKuCm6`Py? z@^T#Ux04HemPGd!Hs7NkZdVn1}8_j`o?)*OKZGS!`ff)gF zG?v-lj$wWNWCcw2Mg2o18D~1?3_b0XzdiKBNkYSDpcv@&kp0POmweJE2ZkIQ3B!a! zIgIoE+Xv?;34kyo^QYjZk+tEqZvq^#QG(OzX4~X+KtsoQoddTWUR(yo8R+ObEF1j<-syWOb>)JQ&Zbdu(sctU%Mt zW&YR0{ttY2TTXYZ?~WNU&cES1Z2q(7SrWDh``!J(JM+Nk$!hu&Y;(7E`ZNKTe0w+% zJc?Qnw2B+%UR}0;cB0Rufa(7-3FF}?629@LgTiEC&2uyL6NxexOp?AKT^aAx3gi(W zao>r>MPw0eQ3>IV02uLsC@>yK_epX6GRg4{NEL2wPPF9=*L2RV3yyK8DhuEK>rmmV z`&Q~#c`lgR&93TdOCja|ewOXmPNRh7!&dMT(1ett#iDr8HZW~VqWW@7fe9B6;7S+? zbC`d4@MEau&mKlOPKd>*10q0c{~^baw6!a*w^sY#0Xim{oOsiXiDOhbG&kl3c$$n1 zMRrD83&QucDSEcV*7LIp8VTA@F<%qe+_c`L;6on(>SjAU^}5c9!BCffT>$VQhe=)z z8(=Ej{5>jhmjB3{xDfj2R@VmHQ!CqjlO4KnuOmvHy3K#po$yp_V;p_MKjh1`(rzj6 zHW956k1yvntz{_g?Xbs`avK(IjlTnsu%htO;D7 z?J#x^EzuvVn&NA=!MEj7cwe5A-Z$Zk2LBZH$~%E* zf`((xH0?`}hs|HA%mtwfOEsZJxxrennkTYcwP#FKO5%Lpc^JXhSpV|ZH$Wr;`}`_( zIP==gd3LYyVtwD|*ZJGi{7~x8{=^bGVqu0RJ`n_BZH9+}kz%-4ZRsImi@rx%=ZEKs zcPnUXo6hbJV>fH;@1|bAHIe0ijYI*&kdT|HkDS$9No9 zCHo=*HWb~U+Dtzxr+Esao}6@|;Pf+E$ay0$kQp#s{wlw+7aIKbMdf`OqhoG*;Tco0 zjrP}VQG#Y2cJuqoJg&5({)S(BA}q9T1lGeWRyu=Je|)I!6a+aj!IP^1({)ZYe&x6w zt3a)Dq^TB+A7CdB0-}#z2Ur$W&h3YVw8==!xONy$uQmDWh-@15iEOt!q2m&?ZLA|w z8loSb(0}7y6Xu0?M5Uf4>VZGluB`wMf2oh;m)ghxVda>3m}4%V)r^0nVQ5V6f3>*) z0&VN!N0~GC^P}vj$`EDMZEmVV;N&RISY2C;$0;2(<{Lt&PKzqRByQdiEHGAbwtbS zPj`Da5%U6k1oEtVzI}QNw;!hT6F+~|@=c@$C4NtO@=xgP?|5MyZAyuCzcvq4rdAv@C06%gZ`9%I);R6UGiGJobfux+<0DLS&|MSG4UH z_~o{^^9>ixMg~mY!-@Fai{xaE4^;qy9iZN15Gbn5ZqHWf>Jc5Rv6(#n8`1NcCsdmG zab*dSXVPaE?)wCalD;$ivF%@nB#7D`@YG04p6ed9m}4iJW|pfVMLE<-c{=-8$e?cH zUdU#mCj4gb zZKA^b9p*9S(}8@tw~1RNPHr7tQr;P+-)D8|sq=*o)G%RGqt> zzP5yf`pVxb)I51D_G~Xp^GNK zVI6sAX)a9s)e{8N3?35YA6aQTXuyszK3ah~CemzA&CII#8F&F#KN41~8I^&_%}6MCNb{W87qAF`zj_Y^szhb> z3p3}KbOxotY|(lD=;)`fYE_*{S}x;f^SW#)SU&5X#o|-R|trpa|L5PS5aa0 zTHw8%SDSVtU4?vyrhnq+^@dgFS)|(y{~(4j%3UEiO-rBM9%`)8(dh33pMLiuurNY# z#10AsQ7%*0Cu_DSAU}P;X(JwA64~Q_^R%d_zSm^6Aux?Pn70PM>9EvLeOX z&w9c)pGmcL22;MO3C_B>=NC0RJpMp8?#ZUf=GWRvy z6RHq3B}=MGVg?9@iKFBpsvnkVh3{Vpp=`CcD=u~@ql{my|6?3ssi3mCOPnjI&E}VC zc@X+Yl>;;DNo0W0`0th!X{?luDhOC{E8N=?!w}K1{V=)+1={m(f`Oc|N=07>}3;z{-(A zm{JL=j?Sro5iecmE2-pWlRf(r%|HEQ7kgwQ9+kt=NBhtQI7OwcZ#3%$Uf%^r2nhjY zoQ08MfC%_X{O9~WcirMZMhn#z^ux4Erx-tf-6bHD)9eH&^L>^jvAd^9A^DCDs?0;k zkm7LE*KjP6`2d17MrQaaLqd_Rka}J$csvUec#hw78<=s(hyR>065~YCVCA9+#Q+; za(*L0IEw!r5P|@-;x33L$Lv9 zcuN8YG&g{<(SeJG18~(b!5yywSqQiLAX0;---;}mF5&b4lg|T?LwKREa{9YX_-zL@ZE?Zqi@HxK^2KO1>0LATu{te=T zprmHtY)bDVfxI1S}KBE7V zznP7KQ8HekWU#W6mw`dr-boV}pMQR==&5=Q5T=_q091jfc;R*jX#&=MQ%~@E@9^?`$v48ks<>(fI(F6L(5ppKy|$HWng*bKOb(4|cMUB&z$#ob#XV z5-mg)gmFIybZf=znm3ZPyUO^GJfxt0kmHjaTZ|sthsxXw&}Y)fOUSg=JhRSR^UjZ- zhqqb}Wsyw4zdnj6@#BAJa#-PdI4_dgafFXh85DsEQ_cT+5)XpZq$fZlBA_9UsE9r6 zEFec5?uqN@QhJ^IzwZrwl-5J`CmVPv{(YDTqEqWR^dI;5hXc~cxP%B3v&~s0`Ct89 z@S`i~a^c%V^N81dDT*ItFS*&IN;@O$EgzX0e7x&}TD=!zS}hTpezBLS>mdX(5< z)8DEI(-o_D)c-UX@dA1MuJ*yc>Hf4|`*B2S_O>w*-tbUwtiu`;W(Ud{HTty@(&x(T(F&;M zJ=?H>6`B7nf-90e8V`WSVp|0oEKB-P2M{}4ZDawzvM&a!y>`Y#jCsD%T_l``@ah(I2nJs~Q|%uSKu@k!m~*8B*IoA{*TgtF<(5sHCGG;n@NE%~Xt(G$^&<87u;}Na zx-8cq0g`uA(&RBFo=-4Y1GUZ<``Zw{xL4jfHkZw~%~wvtGueszcXt)_QwH8g!; z%s&3kSa~R$dO$-%L-)c@_hi7&>{6L_M>OZFkUQu;{sL_bUMStNrt{{&O(Wn~*zPOk zB>dnfszb29NSTf2pqIs68k|p-UrSrxgLHqi?3N-UFa!LHy9n1)=s>`yS+J{MEzS@ zNlfGtpma7kG&LR3JE@wB%rFA*h~~KitlO=IP)ZjN6dQLM6qsry zHkB#cyNh#n`)}bCrN1My*;k)^@>e4gJ`LJK?2)Pwp?4Tl4)4FA0(tvY+#1jOUM)xw zlMz4x-f@g^+yKUN`?Vu)|AwujArnM~Pa@y*Q9S8eS(u{-S%(Z5=R~pRl5ZGDjdqH% zC8rW&{##wOpU_oTIG4WXMk4&%2t1;lWcW5&!yxmOT*!hBcKyTqEcNoO+R2;Q?Yj+W z1-Y4?59fijz4(MIDwGe4-baYf08UCs;r|YefD-Md2ST;=cxwpgW=tR76-dQVAhn^= zG9Wk5lQk%jIR@KNU!UMp6@BfU;r+;y4VQ)D2!Il9HX%yW-9nOzV+m$YKzVaO`B8S7t z$!S2Mz`xw>V(RjE`0>bQp<0y&h~Y=M#jpy!#=dE>`=e_AjSZq6u!Dy1xJf~-7|0F! zPR9|n`e_7D2DIV2H(CESQ}hA>U>n|6`%z?YKEA~)BOVY%y=jPV zT=44R!L?J)736X#csn|lfBJ)o8ixaZclguWgrGO<`TN2FMfO}7;5}d+BlK0yTSH3* z4!=;5rOh85&2|x=46hkNaz?)U8&=bcfh=N_#8BNpZ2v$aVBo;sk^*X`v;4-LU;D>! zM*h12MxXIQy)SfAqE4;jY)wgnppazZkdNNVVF;(PLf^qK$FgY9+VFyBKE7UC|f z`R|?&egV11K3s$rJ6!GvoeW=jV*!-e(wA;x(2=d0E_e_%0x--0o8#~m^H1%AH5Z^B zn!TNPn927*bvaf0pt}zhK0o^V@WlGwwKo(*nQ|Q~4_;>~-8y20`HP>@UJa)3nEnGG z5Hwhs|FcmFG16ZVNb5hL`2Gc1{zWIMM{_OiKewV!hCi}U!VuE?s9wU-QbZ!)+Y^tS zGzp5OSi5iq6hmEr$w}&9DFgoB+i*`q`8TBi^MVS{SKEb8Aw%@K7@XCo(De2A`6%mf&a2#~y1N)+kJLD$1HCP!22)(U}xo2|j?WRzt(11j8Z_*v;P$R+Ug*Gy3VxV4K; zGGUGabnW*`Z}~`ydXL-l9e=GC$pY#z|63vy>E*m=$=j}iWP{sRTh0%H54`t>2xYH% zsk+M&u&pNgMCM@3e)Xc?jBWX-TIR_cQ1Z!RW7!B zBjZX=+^3}?SE)B+$EP+0oi1Fp5blDT?*}nsP>filqXH{ms zxU<$hetC`u)Wi+x|EKL-`y^#aQX+sDYIa{M;V%LqLrOk~lR>u0Q!+pyQSU4zY`?E^ z|5@)C)w6G_=i5YYC5SE_u(7hDNYr}uKT|@DSqF%S++lTIbIk^$a>{~0IH8KNFEy%+ zW#$&!ynpgNJh>6uR~?2c)ZMW+h0OKu231(7L_vETPaR+(P)Zy%0~yGm>E9?@@x!Jy z3PYgS}Q@b}x}E#F27@F+j}0=&Ql4gES&f8acMrPAVlVs9$97`FR))R5wI zc&}KFI1UIewh>3PkhnB7u zS3AT8_*|nexznG|Z*DU0c!K@jsI4J)5#DyNi#|e#`l1Vv1`1)*NVcy0LZ``aL0n8B zecupJ(rhq3u8bW0NIRhKYq$v1li+jp*4hfAd&wxYDE8vn1TQ7S@bTM|I2Ob z8vMOIxA7&_j{AKmD+O@EyXT`|dElt0pED^@IV0m)RPBUs*5jW60>>w1!@_G3aBKzG z_f(KfAPBk}-jQtR*Sroq!*3rbQ_m27e+YdzQjUb<_*k8vc_C)y!@cj5E>NxUhPu&g z@Z2<~esU`)ih+4opWe+K7sbN9n*9@n>#@n3*o z?xoROgDuvhq>jJ;Ve{6i<3roQNfgo5^4Q4(|GNExO2Dr7GjgA2zWuKp_K)K0R(6lv z!l$!zW-+T6mb3gQaAFviTQi{|*t%>{(mhTdy+y;Re4qT@kccy#{b z&zWy~kLO@>*WPj2k#H)|7L&gAJ37DmHQAme#@m;(Y8Nu^`D5vf8sZFW#+lA2!HK=( zJ)#hO6JD*`o~&c*&46d}g=Qj@SsoB5ikC z^1V8E+&<-OzuS_C`p5<<(A6fB`LXT(!kV^0_~hL6PpW4={l%|#xgdh?5EIk~lu8{D z2hiyhv3Yxij_#$Wu>P@7SYsl`-~3;}Ktx{34_NL^Kwin&=?!HDv3elQDbcU*qyYpN z(#yw~f1vFGK-t%CC-qa-4FYHbA^h>bag-I&*qaxwn?Qv|idE$<>1H|Gr6JtUu(he2$eg!N z@HTF@dG1)*y;4fxe)4_ZkpaBHH9hXp9p4|gLrRQyuevRd@gSS}JhRnWqrvm|U@>qM z=yl7RQROTKwQtzP3!zUF)_6Ld#NGA6v~2{J9Dd`h6{%+XsU#qGLh%`fB1Hc?wfayK zN`H4BpDp)npVQuu$DVW1qsBS&AJ2eP%6Qw>;k{)Z$8%HL=Q4(a$Ng2_vHw&vA!1L+9zc8vaX2GtqJ{L-;gvF0IR$em zMQ8@{Qp3+3Quk)TJ$?I<8KmwzD*7#(q<@Mc`dchngW}cRG14(Z6K7{T|LhFXwhqUQ;BET;cYqPcAcMgt6M$V9$(?jHo@Sud$an$U&5F zZ1QNh^ztt)E*d#Ij;<43oSKKnd+WNr$_r}+s_O_x6DZSB10*5Q{ourqq>mTl| zx4y^(cy+9;t@R=*j>3_dmm_m)$k$#937V(sllby&5)Xex^UD-|m|q<(jEd#@DV(of zAd7sSdmS*zUDqJ9|K%O2J2OfdUiK{{b{PCy)pi<;hp~7v1CQj&4-10 zgO<3dqhYH1#-Fa}Q{pjql5>>P6gZH21zLfxZ4$SK4T@7b!|`nWF9b*84Bq8&Eht;9 z*P72x&NUCZ7*@B$`FtE=hz5b}S`|c6Ey+j@D1ZibjJaRlR;{cxAWv z?Nqa>QqV*H-*zzaPvpLMHt~nl(x6?vrPpR?zn7~wow?oj*1TKmx4j71>$hvtC$DLD zUrz0^tiP0792U&dxJxNv@r}Elsjn^aSLUu=9#mD{&9n8|ayIL$!H3s>%KEvbchBFW z%cd?VU83mGF#Dar9*s~w&AnmQRQIOvR+uWsuZ?+|a=TzApXO@q^(r%8=}iv#wCnFq z=K9}JbqU@k99Q%j-}NNk+qLCP)jXfmOO|)@?mHcnynd6({mJisP1_}u7k)|eYHXWK z63eQ)E$ufFi!3CWUY2gw%e>omCv}qEX66aH-k&35f9`Q@Us|NPetVqe8=dX*VxJdn ze`q7b=Dn(UA(2sf&g)cOmQFhNJ#<-aMELJZbA#@to>25@kbW<)&!X01 z%NMJt>1ST)tyX)h@?`DxhbgCHr>S4wv}WC&Nw-!{+Z7$2D}74QAcXTvip=M0%Tp_N zor=k`)t|ra^ySr-+(|R9mB(E=`MX#y(wSw)$!iymzB;^c*>%&^*7HxTnRga=soSZT zdDl+9s;r!v8hk6POtzBaig4pRp7eWF(<8gufvNHPu6xs-=e{;mnHzJyGKE+8L0j}; z@%8-e^UCL5HhMiR>sD3Rve&yVZ#{Q1*CO8c+qSr^Z#CN;)(X5>tGG5yUw3<+CfhaL z%bP;hZ?jvgJU67BWyiy74_)6r)_nSxttxn0`0?HE^5(uydHVgP+HE$V?Lv)Leti43 zWA|;f-RqX``95>)^P-fw!Vi{3KNsII-*5f){gdxqd%gVdB1sOBNe=nEW%;i~g_P8J w!5uhoe-Jcg1nPN%MiEAtgE$;km@@t6ukO)1^!cY^83Pb_y85}Sb4q9e0FIsP9{>OV literal 0 HcmV?d00001 diff --git a/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/forui/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/forui/example/macos/Runner/Configs/AppInfo.xcconfig b/forui/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..b08c22631 --- /dev/null +++ b/forui/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.foruslabs.forui.samples.example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.foruslabs.forui.samples. All rights reserved. diff --git a/forui/example/macos/Runner/Configs/Debug.xcconfig b/forui/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/forui/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/forui/example/macos/Runner/Configs/Release.xcconfig b/forui/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/forui/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/forui/example/macos/Runner/Configs/Warnings.xcconfig b/forui/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/forui/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/forui/example/macos/Runner/DebugProfile.entitlements b/forui/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/forui/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/forui/example/macos/Runner/Info.plist b/forui/example/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/forui/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/forui/example/macos/Runner/MainFlutterWindow.swift b/forui/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..3cc05eb23 --- /dev/null +++ b/forui/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/forui/example/macos/Runner/Release.entitlements b/forui/example/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/forui/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/forui/example/macos/RunnerTests/RunnerTests.swift b/forui/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..61f3bd1fc --- /dev/null +++ b/forui/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 43f3f001c..df34558fd 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -18,12 +18,14 @@ final class FCalendarStyle with Diagnosticable { final FCalendarDayPickerStyle dayPickerStyle; final BoxDecoration decoration; final EdgeInsets padding; + final Duration animationDuration; FCalendarStyle({ required this.headerStyle, required this.dayPickerStyle, required this.decoration, this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + this.animationDuration = const Duration(milliseconds: 200), }); FCalendarStyle.inherit({ diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 3e97eb34f..aa7998395 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -2,7 +2,7 @@ part of '../calendar.dart'; /// The maximum number of rows in a month. In this case, a 31 day month that starts on Saturday. @internal -const maxMonthRows = 6; +const maxGridRows = 7; /// The height & width of a day in a [DayPicker]. @internal @@ -55,7 +55,31 @@ class _DayPickerState extends State { @override void initState() { super.initState(); - _updateMonth(); + + final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization + final firstDayOfMonth = widget.month.firstDayOfMonth; + var difference = firstDayOfMonth.weekday - firstDayOfWeek; + if (difference < 0) { + difference += 7; + } + + final first = firstDayOfMonth.minus(days: difference); + + final lastDayOfWeek = firstDayOfWeek == DateTime.monday ? DateTime.sunday : firstDayOfWeek - 1; + final lastDayOfMonth = widget.month.lastDayOfMonth; + difference = lastDayOfWeek - lastDayOfMonth.weekday; + if (difference < 0) { + difference += 7; + } + + final last = lastDayOfMonth.plus(days: difference); + for (var date = first; date <= last; date = date.tomorrow) { + _days[date] = FocusNode(skipTraversal: true, debugLabel: '$date'); + } + + if (_days[widget.focused] case final focusNode?) { + focusNode.requestFocus(); + } } @override @@ -102,40 +126,13 @@ class _DayPickerState extends State { @override void didUpdateWidget(DayPicker old) { super.didUpdateWidget(old); - if (old.month != widget.month) { - _updateMonth(); - } + assert(old.month == widget.month, 'We assumed that a new DayPicker is created each time we navigate to a new month.'); if (_days[widget.focused] case final focusNode? when old.focused != widget.focused) { focusNode.requestFocus(); } } - void _updateMonth() { - final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization - final firstDayOfMonth = widget.month.firstDayOfMonth; - var difference = firstDayOfMonth.weekday - firstDayOfWeek; - if (difference < 0) { - difference += 7; - } - - final first = firstDayOfMonth.minus(days: difference); - - final lastDayOfWeek = firstDayOfWeek == DateTime.monday ? DateTime.sunday : firstDayOfWeek - 1; - final lastDayOfMonth = widget.month.lastDayOfMonth; - difference = lastDayOfWeek - lastDayOfMonth.weekday; - if (difference < 0) { - difference += 7; - } - - final last = lastDayOfMonth.plus(days: difference); - - _days.clear(); - for (var date = first; date <= last; date = date.tomorrow) { - _days[date] = FocusNode(skipTraversal: true, debugLabel: '$date'); - } - } - @override void dispose() { for (final node in _days.values) { diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 62aa75497..2699ad4c4 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,7 +1,5 @@ part of '../calendar.dart'; -const Duration _monthScrollDuration = Duration(milliseconds: 200); - @internal class PagedDayPicker extends StatefulWidget { final FCalendarStyle style; @@ -105,7 +103,7 @@ class _PageDayPickerState extends State { onNext: _last ? null : _handleNextMonth, ), SizedBox( - height: dayDimension * maxMonthRows, + height: dayDimension * maxGridRows, child: FocusableActionDetector( shortcuts: _shortcuts, actions: _actions, @@ -115,22 +113,22 @@ class _PageDayPickerState extends State { key: _pageViewKey, controller: _controller, itemBuilder: (context, index) => DayPicker( - focused: _focusedDay, - style: widget.style.dayPickerStyle, - month: _currentMonth, - today: widget.today, - enabledPredicate: (date) => - widget.start <= date && date <= widget.end && widget.enabledPredicate(date), - selectedPredicate: widget.selectedPredicate, - onPress: (date) { - setState(() => _focusedDay = date); - widget.onPress(date); - }, - onLongPress: (date) { - setState(() => _focusedDay = date); - widget.onLongPress(date); - }, - ), + focused: _focusedDay, + style: widget.style.dayPickerStyle, + month: widget.start.truncate(to: DateUnit.months).plus(months: index), + today: widget.today, + enabledPredicate: (date) => + widget.start <= date && date <= widget.end && widget.enabledPredicate(date), + selectedPredicate: widget.selectedPredicate, + onPress: (date) { + setState(() => _focusedDay = date); + widget.onPress(date); + }, + onLongPress: (date) { + setState(() => _focusedDay = date); + widget.onLongPress(date); + }, + ), itemCount: delta(widget.start, widget.end), onPageChanged: _handleMonthPageChanged, ), @@ -159,7 +157,7 @@ class _PageDayPickerState extends State { void _handleNextMonth() { if (!_last) { _controller.nextPage( - duration: _monthScrollDuration, + duration: widget.style.animationDuration, curve: Curves.ease, ); } @@ -169,7 +167,7 @@ class _PageDayPickerState extends State { void _handlePreviousMonth() { if (!_first) { _controller.previousPage( - duration: _monthScrollDuration, + duration: widget.style.animationDuration, curve: Curves.ease, ); } @@ -189,7 +187,7 @@ class _PageDayPickerState extends State { } else { _controller.animateToPage( page, - duration: _monthScrollDuration, + duration: widget.style.animationDuration, curve: Curves.ease, ); } From 51a4bb57d6a511a68055725892f266cc68e21ff1 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 11:37:58 +0800 Subject: [PATCH 14/35] Make consecutive dates connect smoothly --- forui/lib/src/widgets/calendar/calendar.dart | 1 + forui/lib/src/widgets/calendar/day/day.dart | 82 ++++++++++--------- .../src/widgets/calendar/day/day_picker.dart | 20 +++-- .../calendar/day/paged_day_picker.dart | 7 +- 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index df34558fd..0bc1847d4 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -40,6 +40,7 @@ final class FCalendarStyle with Diagnosticable { border: Border.all( color: colorScheme.border, ), + color: colorScheme.background, ), ); } diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/calendar/day/day.dart index 2082b7a5f..d9bfda718 100644 --- a/forui/lib/src/widgets/calendar/day/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -6,6 +6,7 @@ Widget day( FCalendarDayPickerStyle monthStyle, LocalDate date, FocusNode focusNode, + bool Function(LocalDate day) selectedPredicate, ValueChanged onPress, ValueChanged onLongPress, { required bool enabled, @@ -26,13 +27,14 @@ Widget day( style: style, date: date, focusNode: focusNode, + selectedPredicate: selectedPredicate, onPress: onPress, onLongPress: onLongPress, today: today, selected: selected, ); } else { - return DisabledDay(style: style, date: date); + return DisabledDay(style: style, date: date, selectedPredicate: selectedPredicate); } } @@ -41,6 +43,7 @@ class EnabledDay extends StatefulWidget { final FCalendarDayStateStyle style; final LocalDate date; final FocusNode focusNode; + final bool Function(LocalDate day) selectedPredicate; final ValueChanged onPress; final ValueChanged onLongPress; final bool today; @@ -50,6 +53,7 @@ class EnabledDay extends StatefulWidget { required this.style, required this.date, required this.focusNode, + required this.selectedPredicate, required this.onPress, required this.onLongPress, required this.today, @@ -67,6 +71,7 @@ class EnabledDay extends StatefulWidget { ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onLongPress', onLongPress, level: DiagnosticLevel.debug)) ..add(FlagProperty('today', value: today, ifTrue: 'today', level: DiagnosticLevel.debug)) @@ -78,7 +83,6 @@ class _EnabledDayState extends State { bool _focused = false; bool _hovered = false; - @override void initState() { super.initState(); @@ -91,7 +95,7 @@ class _EnabledDayState extends State { old.focusNode.removeListener(_updateFocused); widget.focusNode.addListener(_updateFocused); } - + @override Widget build(BuildContext context) => Focus( focusNode: widget.focusNode, @@ -108,7 +112,13 @@ class _EnabledDayState extends State { onTap: () => widget.onPress(widget.date), onLongPress: () => widget.onLongPress(widget.date), child: DecoratedBox( - decoration: _focused || _hovered ? widget.style.focusedDecoration : widget.style.decoration, + decoration: BoxDecoration( + borderRadius: BorderRadius.horizontal( + left: widget.selectedPredicate(widget.date.yesterday) ? Radius.zero : const Radius.circular(4), + right: widget.selectedPredicate(widget.date.tomorrow) ? Radius.zero : const Radius.circular(4), + ), + color: _focused || _hovered ? widget.style.focusedBackgroundColor : widget.style.backgroundColor, + ), child: Center( child: Text( '${widget.date.day}', // TODO: localization @@ -141,17 +151,22 @@ class _EnabledDayState extends State { class DisabledDay extends StatelessWidget { final FCalendarDayStateStyle style; final LocalDate date; + final bool Function(LocalDate day) selectedPredicate; const DisabledDay({ required this.style, required this.date, + required this.selectedPredicate, super.key, }); @override Widget build(BuildContext context) => ExcludeSemantics( child: DecoratedBox( - decoration: style.decoration, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: style.backgroundColor, + ), child: Center( child: Text('${date.day}', style: style.textStyle), // TODO: localization ), @@ -163,7 +178,8 @@ class DisabledDay extends StatelessWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)); + ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)); } } @@ -242,47 +258,37 @@ final class FCalendarDayStyle with Diagnosticable { /// A calendar day state's style. final class FCalendarDayStateStyle with Diagnosticable { - /// The unfocused day's decoration. - final BoxDecoration decoration; + /// The unfocused day's background color. + final Color backgroundColor; /// The unfocused day's text style. final TextStyle textStyle; - /// The focused day's decoration. Defaults to [decoration]. - final BoxDecoration focusedDecoration; + /// The focused day's background color. Defaults to [backgroundColor]. + final Color focusedBackgroundColor; /// The focused day's text style. Defaults to [textStyle]. final TextStyle focusedTextStyle; /// Creates a [FCalendarDayStateStyle]. FCalendarDayStateStyle({ - required this.decoration, + required this.backgroundColor, required this.textStyle, - BoxDecoration? focusedDecoration, + Color? focusedBackgroundColor, TextStyle? focusedTextStyle, - }) : focusedDecoration = focusedDecoration ?? decoration, + }) : focusedBackgroundColor = focusedBackgroundColor ?? backgroundColor, focusedTextStyle = focusedTextStyle ?? textStyle; /// Creates a [FCalendarDayStateStyle] that inherits the given colors. FCalendarDayStateStyle.inherit({ + required Color backgroundColor, required TextStyle textStyle, - Color? color, - Color? focusedColor, + Color? focusedBackgroundColor, TextStyle? focusedTextStyle, }) : this( - decoration: color == null - ? const BoxDecoration() - : BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: color, - ), + backgroundColor: backgroundColor, textStyle: textStyle, - focusedDecoration: (focusedColor ?? color) == null - ? const BoxDecoration() - : BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: focusedColor ?? color, - ), + focusedBackgroundColor: focusedBackgroundColor ?? backgroundColor, focusedTextStyle: focusedTextStyle ?? textStyle, ); @@ -290,7 +296,7 @@ final class FCalendarDayStateStyle with Diagnosticable { /// /// ```dart /// final style = FDayStateStyle( - /// decoration: ..., + /// backgroundColor: ..., /// textStyle: ..., /// ); /// @@ -298,19 +304,19 @@ final class FCalendarDayStateStyle with Diagnosticable { /// textStyle: ..., /// ); /// - /// print(style.decoration == copy.decoration); // true + /// print(style.backgroundColor == copy.backgroundColor); // true /// print(style.textStyle == copy.textStyle); // false /// ``` FCalendarDayStateStyle copyWith({ - BoxDecoration? decoration, + Color? backgroundColor, TextStyle? textStyle, - BoxDecoration? focusedDecoration, + Color? focusedBackgroundColor, TextStyle? focusedTextStyle, }) => FCalendarDayStateStyle( - decoration: decoration ?? this.decoration, + backgroundColor: backgroundColor ?? this.backgroundColor, textStyle: textStyle ?? this.textStyle, - focusedDecoration: focusedDecoration ?? this.focusedDecoration, + focusedBackgroundColor: focusedBackgroundColor ?? this.focusedBackgroundColor, focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, ); @@ -318,9 +324,9 @@ final class FCalendarDayStateStyle with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('decoration', decoration)) + ..add(DiagnosticsProperty('backgroundColor', backgroundColor)) ..add(DiagnosticsProperty('textStyle', textStyle)) - ..add(DiagnosticsProperty('focusedDecoration', focusedDecoration)) + ..add(DiagnosticsProperty('focusedBackgroundColor', focusedBackgroundColor)) ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)); } @@ -329,11 +335,11 @@ final class FCalendarDayStateStyle with Diagnosticable { identical(this, other) || other is FCalendarDayStateStyle && runtimeType == other.runtimeType && - decoration == other.decoration && + backgroundColor == other.backgroundColor && textStyle == other.textStyle && - focusedDecoration == other.focusedDecoration && + focusedBackgroundColor == other.focusedBackgroundColor && focusedTextStyle == other.focusedTextStyle; @override - int get hashCode => decoration.hashCode ^ textStyle.hashCode ^ focusedDecoration.hashCode ^ focusedTextStyle.hashCode; + int get hashCode => backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; } diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index aa7998395..f65350463 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -98,6 +98,7 @@ class _DayPickerState extends State { widget.style, date, focusNode, + widget.selectedPredicate, widget.onPress, widget.onLongPress, enabled: widget.enabledPredicate(date), @@ -200,14 +201,15 @@ final class FCalendarDayPickerStyle with Diagnosticable { final disabled = FCalendarDayStyle( todayStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.primaryForeground, + backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), unselectedStyle: FCalendarDayStateStyle.inherit( + backgroundColor: colorScheme.background, textStyle: mutedTextStyle, ), selectedStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.primaryForeground, + backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), ); @@ -217,29 +219,31 @@ final class FCalendarDayPickerStyle with Diagnosticable { enabled: ( current: FCalendarDayStyle( todayStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.secondary, + backgroundColor: colorScheme.secondary, textStyle: textStyle, ), unselectedStyle: FCalendarDayStateStyle.inherit( + backgroundColor: colorScheme.background, textStyle: textStyle, - focusedColor: colorScheme.secondary, + focusedBackgroundColor: colorScheme.secondary, ), selectedStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.foreground, + backgroundColor: colorScheme.foreground, textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), ), ), enclosing: FCalendarDayStyle( todayStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.primaryForeground, + backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), unselectedStyle: FCalendarDayStateStyle.inherit( + backgroundColor: colorScheme.background, textStyle: mutedTextStyle, - focusedColor: colorScheme.primaryForeground, + focusedBackgroundColor: colorScheme.primaryForeground, ), selectedStyle: FCalendarDayStateStyle.inherit( - color: colorScheme.primaryForeground, + backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), ), diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 2699ad4c4..6754c1d56 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -244,11 +244,8 @@ class _PageDayPickerState extends State { void _handleGridFocusChange(bool focused) { setState(() { if (focused && _focusedDay == null) { - if (widget.today.truncate(to: DateUnit.months) == _currentMonth) { - _focusedDay = _focusableDayForMonth(_currentMonth, widget.today.day); - } else { - _focusedDay = _focusableDayForMonth(_currentMonth, 1); - } + final preferred = widget.today.truncate(to: DateUnit.months) == _currentMonth ? widget.today.day : 1; + _focusedDay = _focusableDayForMonth(_currentMonth, preferred); } }); } From 9fe7a236848392f3807c170fc756f6e33c6cd8bc Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 15:04:11 +0800 Subject: [PATCH 15/35] Underline today --- forui/lib/src/widgets/calendar/day/day.dart | 74 +++++++++---------- .../src/widgets/calendar/day/day_picker.dart | 22 ++---- 2 files changed, 41 insertions(+), 55 deletions(-) diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/calendar/day/day.dart index d9bfda718..4af5109f5 100644 --- a/forui/lib/src/widgets/calendar/day/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -16,11 +16,7 @@ Widget day( }) { final styles = enabled ? monthStyle.enabled : monthStyle.disabled; final dayStyle = current ? styles.current : styles.enclosing; - final style = switch ((today, selected)) { - (_, true) => dayStyle.selectedStyle, - (false, _) => dayStyle.unselectedStyle, - (true, _) => dayStyle.todayStyle, - }; + final style = selected ? dayStyle.selectedStyle : dayStyle.unselectedStyle; if (enabled) { return EnabledDay( @@ -34,7 +30,7 @@ Widget day( selected: selected, ); } else { - return DisabledDay(style: style, date: date, selectedPredicate: selectedPredicate); + return DisabledDay(style: style, date: date, today: today, selectedPredicate: selectedPredicate); } } @@ -97,7 +93,13 @@ class _EnabledDayState extends State { } @override - Widget build(BuildContext context) => Focus( + Widget build(BuildContext context) { + var textStyle = _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; + if (widget.today) { + textStyle = textStyle.copyWith(decoration: TextDecoration.underline); + } + + return Focus( focusNode: widget.focusNode, child: MouseRegion( cursor: SystemMouseCursors.click, @@ -120,16 +122,14 @@ class _EnabledDayState extends State { color: _focused || _hovered ? widget.style.focusedBackgroundColor : widget.style.backgroundColor, ), child: Center( - child: Text( - '${widget.date.day}', // TODO: localization - style: _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle, - ), + child: Text('${widget.date.day}', style: textStyle), // TODO: localization ), ), ), ), ), ); + } @override @@ -151,27 +151,39 @@ class _EnabledDayState extends State { class DisabledDay extends StatelessWidget { final FCalendarDayStateStyle style; final LocalDate date; + final bool today; final bool Function(LocalDate day) selectedPredicate; const DisabledDay({ required this.style, required this.date, + required this.today, required this.selectedPredicate, super.key, }); @override - Widget build(BuildContext context) => ExcludeSemantics( + Widget build(BuildContext context) { + var textStyle = style.textStyle; + if (today) { + textStyle = textStyle.copyWith(decoration: TextDecoration.underline); + } + + return ExcludeSemantics( child: DecoratedBox( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.horizontal( + left: selectedPredicate(date.yesterday) ? Radius.zero : const Radius.circular(4), + right: selectedPredicate(date.tomorrow) ? Radius.zero : const Radius.circular(4), + ), color: style.backgroundColor, ), child: Center( - child: Text('${date.day}', style: style.textStyle), // TODO: localization + child: Text('${date.day}', style: textStyle), // TODO: localization ), ), ); + } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -179,30 +191,20 @@ class DisabledDay extends StatelessWidget { properties ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('today', today)) ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)); } } /// A calender day's style. -/// -/// [selectedStyle] takes precedence over [unselectedStyle] and [todayStyle]. For example, if the current date is -/// selected, [selectedStyle] will be applied. final class FCalendarDayStyle with Diagnosticable { - /// The current date's style. - final FCalendarDayStateStyle todayStyle; - - /// The unselected dates' style. - final FCalendarDayStateStyle unselectedStyle; - /// The selected dates' style. - /// - /// This style takes precedence over [unselectedStyle] and [todayStyle]. For example, if the current date is - /// selected, [todayStyle] will be applied. final FCalendarDayStateStyle selectedStyle; + /// The unselected dates' style. + final FCalendarDayStateStyle unselectedStyle; /// Creates a [FCalendarDayStyle]. const FCalendarDayStyle({ - required this.todayStyle, required this.unselectedStyle, required this.selectedStyle, }); @@ -211,7 +213,7 @@ final class FCalendarDayStyle with Diagnosticable { /// /// ```dart /// final style = FDayStyle( - /// todayStyle: ..., + /// selectedStyle: ..., /// unselectedStyle: ..., /// // Other arguments omitted for brevity /// ); @@ -220,27 +222,24 @@ final class FCalendarDayStyle with Diagnosticable { /// unselectedStyle: ..., /// ); /// - /// print(style.todayStyle == copy.todayStyle); // true + /// print(style.selectedStyle == copy.selectedStyle); // true /// print(style.unselectedStyle == copy.unselectedStyle); // false /// ``` FCalendarDayStyle copyWith({ - FCalendarDayStateStyle? todayStyle, - FCalendarDayStateStyle? unselectedStyle, FCalendarDayStateStyle? selectedStyle, + FCalendarDayStateStyle? unselectedStyle, }) => FCalendarDayStyle( - todayStyle: todayStyle ?? this.todayStyle, - unselectedStyle: unselectedStyle ?? this.unselectedStyle, selectedStyle: selectedStyle ?? this.selectedStyle, + unselectedStyle: unselectedStyle ?? this.unselectedStyle, ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('todayStyle', todayStyle)) - ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)) - ..add(DiagnosticsProperty('selectedStyle', selectedStyle)); + ..add(DiagnosticsProperty('selectedStyle', selectedStyle)) + ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)); } @override @@ -248,12 +247,11 @@ final class FCalendarDayStyle with Diagnosticable { identical(this, other) || other is FCalendarDayStyle && runtimeType == other.runtimeType && - todayStyle == other.todayStyle && unselectedStyle == other.unselectedStyle && selectedStyle == other.selectedStyle; @override - int get hashCode => todayStyle.hashCode ^ unselectedStyle.hashCode ^ selectedStyle.hashCode; + int get hashCode => unselectedStyle.hashCode ^ selectedStyle.hashCode; } /// A calendar day state's style. diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index f65350463..8e2ac42ab 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -200,7 +200,7 @@ final class FCalendarDayPickerStyle with Diagnosticable { typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); final disabled = FCalendarDayStyle( - todayStyle: FCalendarDayStateStyle.inherit( + selectedStyle: FCalendarDayStateStyle.inherit( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), @@ -208,32 +208,24 @@ final class FCalendarDayPickerStyle with Diagnosticable { backgroundColor: colorScheme.background, textStyle: mutedTextStyle, ), - selectedStyle: FCalendarDayStateStyle.inherit( - backgroundColor: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - ), ); return FCalendarDayPickerStyle( headerTextStyle: typography.xs.copyWith(color: colorScheme.mutedForeground), enabled: ( current: FCalendarDayStyle( - todayStyle: FCalendarDayStateStyle.inherit( - backgroundColor: colorScheme.secondary, - textStyle: textStyle, + selectedStyle: FCalendarDayStateStyle.inherit( + backgroundColor: colorScheme.foreground, + textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), ), unselectedStyle: FCalendarDayStateStyle.inherit( backgroundColor: colorScheme.background, textStyle: textStyle, focusedBackgroundColor: colorScheme.secondary, ), - selectedStyle: FCalendarDayStateStyle.inherit( - backgroundColor: colorScheme.foreground, - textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), - ), ), enclosing: FCalendarDayStyle( - todayStyle: FCalendarDayStateStyle.inherit( + selectedStyle: FCalendarDayStateStyle.inherit( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), @@ -242,10 +234,6 @@ final class FCalendarDayPickerStyle with Diagnosticable { textStyle: mutedTextStyle, focusedBackgroundColor: colorScheme.primaryForeground, ), - selectedStyle: FCalendarDayStateStyle.inherit( - backgroundColor: colorScheme.primaryForeground, - textStyle: mutedTextStyle, - ), ), ), disabled: ( From c21e85b531039e9ac9e9fe5d8358a4e75d9eea00 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 19:35:25 +0800 Subject: [PATCH 16/35] WIP year_picker --- forui/example/lib/main.dart | 13 +- forui/lib/src/widgets/calendar/calendar.dart | 104 ++++++++++- .../{day/header.dart => controls.dart} | 78 ++++---- forui/lib/src/widgets/calendar/day/day.dart | 4 +- .../src/widgets/calendar/day/day_picker.dart | 38 ++-- .../calendar/day/paged_day_picker.dart | 97 +++++----- forui/lib/src/widgets/calendar/toggle.dart | 33 ++++ .../calendar/year_month/year_month.dart | 176 ++++++++++++++++++ .../calendar/year_month/year_picker.dart | 108 +++++++++++ samples/lib/main.dart | 15 +- 10 files changed, 530 insertions(+), 136 deletions(-) rename forui/lib/src/widgets/calendar/{day/header.dart => controls.dart} (67%) create mode 100644 forui/lib/src/widgets/calendar/toggle.dart create mode 100644 forui/lib/src/widgets/calendar/year_month/year_month.dart create mode 100644 forui/lib/src/widgets/calendar/year_month/year_picker.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index d752d6cdd..96871a7af 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -43,22 +43,23 @@ class Application extends StatelessWidget { } class Testing extends StatelessWidget { + + static final _selected = { LocalDate(2024, 7, 16), LocalDate(2024, 7, 17), LocalDate(2024, 7, 18), LocalDate(2024, 7, 29)}; + const Testing({super.key}); @override - Widget build(BuildContext context) { - return PagedDayPicker( + Widget build(BuildContext context) => Calendar( style: FCalendarStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography, style: context.theme.style), - start: LocalDate(2023, 1, 8), - end: LocalDate(2025, 7, 10), + start: LocalDate(1900, 1, 8), + end: LocalDate(2024, 7, 10), today: LocalDate.now(), initialMonth: LocalDate(2024, 7), enabledPredicate: (_) => true, - selectedPredicate: (a) => a == LocalDate(2024, 7, 11), + selectedPredicate: _selected.contains, onMonthChange: print, onPress: print, onLongPress: print, ); - } } diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 0bc1847d4..ddfaf6ff3 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -7,25 +7,122 @@ import 'package:flutter/services.dart'; import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:sugar/time.dart'; part 'day/day.dart'; part 'day/day_picker.dart'; -part 'day/header.dart'; +part 'controls.dart'; part 'day/paged_day_picker.dart'; +part 'year_month/year_month.dart'; +part 'year_month/year_picker.dart'; + +part 'toggle.dart'; + +enum FCalendarPickerMode { + day, + yearMonth, +} + +@internal +class Calendar extends StatefulWidget { + final FCalendarStyle style; // TODO: Make this nullable. + final FCalendarPickerMode initialMode; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final LocalDate initialMonth; + final bool Function(LocalDate day) enabledPredicate; + final bool Function(LocalDate day) selectedPredicate; + final ValueChanged? onMonthChange; + final ValueChanged onPress; + final ValueChanged onLongPress; + + const Calendar({ + required this.style, + required this.start, + required this.end, + required this.today, + required this.initialMonth, + required this.enabledPredicate, + required this.selectedPredicate, + this.onMonthChange, + required this.onPress, + required this.onLongPress, + this.initialMode = FCalendarPickerMode.day, + super.key, + }); + + @override + State createState() => _CalendarState(); +} + +class _CalendarState extends State { + late FCalendarPickerMode mode; + late LocalDate month; + + @override + void initState() { + super.initState(); + mode = FCalendarPickerMode.day; // TODO: + month = widget.initialMonth; + } + + @override + Widget build(BuildContext context) => DecoratedBox( + decoration: widget.style.decoration, + child: Padding( + padding: widget.style.padding, + child: SizedBox( + height: dayDimension * maxGridRows, + width: dayDimension * DateTime.daysPerWeek, + child: Stack( + alignment: Alignment.topCenter, + children: [ + switch (mode) { + FCalendarPickerMode.day => PagedDayPicker( + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initialMonth: widget.initialMonth, + enabledPredicate: widget.enabledPredicate, + selectedPredicate: widget.selectedPredicate, + onMonthChange: widget.onMonthChange, + onPress: widget.onPress, + onLongPress: widget.onLongPress, + ), + FCalendarPickerMode.year => YearPicker( + style: widget.style, + start: widget.start, + end: widget.end, + current: widget.today, + onPress: print, + ), + }, + Toggle(style: widget.style, month: month), + ], + ), + ), + ), + ); +} + final class FCalendarStyle with Diagnosticable { final FCalendarHeaderStyle headerStyle; final FCalendarDayPickerStyle dayPickerStyle; + final FCalendarYearMonthPickerStyle yearMonthPickerStyle; final BoxDecoration decoration; final EdgeInsets padding; - final Duration animationDuration; + final Duration pageAnimationDuration; FCalendarStyle({ required this.headerStyle, required this.dayPickerStyle, + required this.yearMonthPickerStyle, required this.decoration, this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 16), - this.animationDuration = const Duration(milliseconds: 200), + this.pageAnimationDuration = const Duration(milliseconds: 200), }); FCalendarStyle.inherit({ @@ -35,6 +132,7 @@ final class FCalendarStyle with Diagnosticable { }) : this( headerStyle: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), dayPickerStyle: FCalendarDayPickerStyle.inherit(colorScheme: colorScheme, typography: typography), + yearMonthPickerStyle: FCalendarYearMonthPickerStyle.inherit(colorScheme: colorScheme, typography: typography), decoration: BoxDecoration( borderRadius: style.borderRadius, border: Border.all( diff --git a/forui/lib/src/widgets/calendar/day/header.dart b/forui/lib/src/widgets/calendar/controls.dart similarity index 67% rename from forui/lib/src/widgets/calendar/day/header.dart rename to forui/lib/src/widgets/calendar/controls.dart index d23182db3..231d45287 100644 --- a/forui/lib/src/widgets/calendar/day/header.dart +++ b/forui/lib/src/widgets/calendar/controls.dart @@ -1,15 +1,13 @@ -part of '../calendar.dart'; +part of 'calendar.dart'; @internal -class Header extends StatelessWidget { +class Controls extends StatelessWidget { final FCalendarHeaderStyle style; - final LocalDate month; final VoidCallback? onPrevious; final VoidCallback? onNext; - const Header({ + const Controls({ required this.style, - required this.month, required this.onPrevious, required this.onNext, super.key, @@ -25,47 +23,50 @@ class Header extends StatelessWidget { return Padding( padding: const EdgeInsets.only(bottom: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 7), - child: FButton.raw( - // TODO: Replace with FButton.icon. - style: effectiveButtonStyle, - onPress: onPrevious, - child: Padding( - padding: const EdgeInsets.all(7), - child: FAssets.icons.chevronLeft( - height: 17, - colorFilter: ColorFilter.mode( - style.iconColor, - BlendMode.srcIn, + child: SizedBox( + height: toggleHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 7), + child: FButton.raw( + // TODO: Replace with FButton.icon. + style: effectiveButtonStyle, + onPress: onPrevious, + child: Padding( + padding: const EdgeInsets.all(7), + child: FAssets.icons.chevronLeft( + height: 17, + colorFilter: ColorFilter.mode( + style.iconColor, + BlendMode.srcIn, + ), ), ), ), ), - ), - Text('${month.month} ${month.year}', style: style.headerTextStyle), // TODO: Localization - Padding( - padding: const EdgeInsets.only(right: 7), - child: FButton.raw( - // TODO: Replace with FButton.icon. - style: effectiveButtonStyle, - onPress: onNext, - child: Padding( - padding: const EdgeInsets.all(7), - child: FAssets.icons.chevronRight( - height: 17, - colorFilter: ColorFilter.mode( - style.iconColor, - BlendMode.srcIn, + const Expanded(child: SizedBox()), + Padding( + padding: const EdgeInsets.only(right: 7), + child: FButton.raw( + // TODO: Replace with FButton.icon. + style: effectiveButtonStyle, + onPress: onNext, + child: Padding( + padding: const EdgeInsets.all(7), + child: FAssets.icons.chevronRight( + height: 17, + colorFilter: ColorFilter.mode( + style.iconColor, + BlendMode.srcIn, + ), ), ), ), ), - ), - ], + ], + ), ), ); } @@ -75,7 +76,6 @@ class Header extends StatelessWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style)) - ..add(DiagnosticsProperty('month', month)) ..add(DiagnosticsProperty('onPrevious', onPrevious)) ..add(DiagnosticsProperty('onNext', onNext)); } diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/calendar/day/day.dart index 4af5109f5..25955f4e2 100644 --- a/forui/lib/src/widgets/calendar/day/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -3,7 +3,7 @@ part of '../calendar.dart'; /// Returns the [date]. @internal Widget day( - FCalendarDayPickerStyle monthStyle, + FCalendarDayPickerStyle pickerStyle, LocalDate date, FocusNode focusNode, bool Function(LocalDate day) selectedPredicate, @@ -14,7 +14,7 @@ Widget day( required bool today, required bool selected, }) { - final styles = enabled ? monthStyle.enabled : monthStyle.disabled; + final styles = enabled ? pickerStyle.enabledStyles : pickerStyle.disabledStyles; final dayStyle = current ? styles.current : styles.enclosing; final style = selected ? dayStyle.selectedStyle : dayStyle.unselectedStyle; diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 8e2ac42ab..98190380e 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -167,10 +167,10 @@ final class FCalendarDayPickerStyle with Diagnosticable { final TextStyle headerTextStyle; /// The styles of the current month on display and the enclosing months, when enabled. - final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) enabled; + final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) enabledStyles; /// The styles of the current month on display and the enclosing months, when disabled. - final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) disabled; + final ({FCalendarDayStyle current, FCalendarDayStyle enclosing}) disabledStyles; /// The starting day of the week. Defaults to the current locale's preferred starting day of the week if null. /// @@ -185,8 +185,8 @@ final class FCalendarDayPickerStyle with Diagnosticable { /// Creates a [FCalendarDayPickerStyle]. const FCalendarDayPickerStyle({ required this.headerTextStyle, - required this.enabled, - required this.disabled, + required this.enabledStyles, + required this.disabledStyles, this.startDayOfWeek, }) : assert( startDayOfWeek == null || (DateTime.monday <= startDayOfWeek && startDayOfWeek <= DateTime.sunday), @@ -212,7 +212,7 @@ final class FCalendarDayPickerStyle with Diagnosticable { return FCalendarDayPickerStyle( headerTextStyle: typography.xs.copyWith(color: colorScheme.mutedForeground), - enabled: ( + enabledStyles: ( current: FCalendarDayStyle( selectedStyle: FCalendarDayStateStyle.inherit( backgroundColor: colorScheme.foreground, @@ -236,7 +236,7 @@ final class FCalendarDayPickerStyle with Diagnosticable { ), ), ), - disabled: ( + disabledStyles: ( current: disabled, enclosing: disabled, ), @@ -269,13 +269,13 @@ final class FCalendarDayPickerStyle with Diagnosticable { }) => FCalendarDayPickerStyle( headerTextStyle: headerTextStyle ?? this.headerTextStyle, - enabled: ( - current: enabledCurrent ?? enabled.current, - enclosing: enabledEnclosing ?? enabled.enclosing, + enabledStyles: ( + current: enabledCurrent ?? enabledStyles.current, + enclosing: enabledEnclosing ?? enabledStyles.enclosing, ), - disabled: ( - current: disabledCurrent ?? disabled.current, - enclosing: disabledEnclosing ?? disabled.enclosing, + disabledStyles: ( + current: disabledCurrent ?? disabledStyles.current, + enclosing: disabledEnclosing ?? disabledStyles.enclosing, ), startDayOfWeek: startDayOfWeek ?? this.startDayOfWeek, ); @@ -285,10 +285,10 @@ final class FCalendarDayPickerStyle with Diagnosticable { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('headerTextStyle', headerTextStyle)) - ..add(DiagnosticsProperty('enabled.current', enabled.current)) - ..add(DiagnosticsProperty('enabled.enclosing', enabled.enclosing)) - ..add(DiagnosticsProperty('disabled.current', disabled.current)) - ..add(DiagnosticsProperty('disabled.enclosing', disabled.enclosing)) + ..add(DiagnosticsProperty('enabled.current', enabledStyles.current)) + ..add(DiagnosticsProperty('enabled.enclosing', enabledStyles.enclosing)) + ..add(DiagnosticsProperty('disabled.current', disabledStyles.current)) + ..add(DiagnosticsProperty('disabled.enclosing', disabledStyles.enclosing)) ..add(IntProperty('startDayOfWeek', startDayOfWeek)); } @@ -298,10 +298,10 @@ final class FCalendarDayPickerStyle with Diagnosticable { other is FCalendarDayPickerStyle && runtimeType == other.runtimeType && headerTextStyle == other.headerTextStyle && - enabled == other.enabled && - disabled == other.disabled && + enabledStyles == other.enabledStyles && + disabledStyles == other.disabledStyles && startDayOfWeek == other.startDayOfWeek; @override - int get hashCode => headerTextStyle.hashCode ^ enabled.hashCode ^ disabled.hashCode ^ startDayOfWeek.hashCode; + int get hashCode => headerTextStyle.hashCode ^ enabledStyles.hashCode ^ disabledStyles.hashCode ^ startDayOfWeek.hashCode; } diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 6754c1d56..9705e7ca1 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -2,7 +2,7 @@ part of '../calendar.dart'; @internal class PagedDayPicker extends StatefulWidget { - final FCalendarStyle style; + final FCalendarStyle style; // TODO: retrieve via context final LocalDate start; final LocalDate end; final LocalDate today; @@ -87,58 +87,47 @@ class _PageDayPickerState extends State { } @override - Widget build(BuildContext context) => DecoratedBox( - decoration: widget.style.decoration, - child: Padding( - padding: widget.style.padding, - child: SizedBox( - width: dayDimension * DateTime.daysPerWeek, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Header( - style: widget.style.headerStyle, - month: _currentMonth, - onPrevious: _first ? null : _handlePreviousMonth, - onNext: _last ? null : _handleNextMonth, - ), - SizedBox( - height: dayDimension * maxGridRows, - child: FocusableActionDetector( - shortcuts: _shortcuts, - actions: _actions, - focusNode: _dayGridFocus, - onFocusChange: _handleGridFocusChange, - child: PageView.builder( - key: _pageViewKey, - controller: _controller, - itemBuilder: (context, index) => DayPicker( - focused: _focusedDay, - style: widget.style.dayPickerStyle, - month: widget.start.truncate(to: DateUnit.months).plus(months: index), - today: widget.today, - enabledPredicate: (date) => - widget.start <= date && date <= widget.end && widget.enabledPredicate(date), - selectedPredicate: widget.selectedPredicate, - onPress: (date) { - setState(() => _focusedDay = date); - widget.onPress(date); - }, - onLongPress: (date) { - setState(() => _focusedDay = date); - widget.onLongPress(date); - }, - ), - itemCount: delta(widget.start, widget.end), - onPageChanged: _handleMonthPageChanged, - ), - ), - ), - ], - ), + Widget build(BuildContext context) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Controls( + style: widget.style.headerStyle, + onPrevious: _first ? null : _handlePreviousMonth, + onNext: _last ? null : _handleNextMonth, + ), + Expanded( + child: FocusableActionDetector( + shortcuts: _shortcuts, + actions: _actions, + focusNode: _dayGridFocus, + onFocusChange: _handleGridFocusChange, + child: PageView.builder( + key: _pageViewKey, + controller: _controller, + itemBuilder: (context, index) => DayPicker( + focused: _focusedDay, + style: widget.style.dayPickerStyle, + month: widget.start.truncate(to: DateUnit.months).plus(months: index), + today: widget.today, + enabledPredicate: (date) => + widget.start <= date && date <= widget.end && widget.enabledPredicate(date), + selectedPredicate: widget.selectedPredicate, + onPress: (date) { + setState(() => _focusedDay = date); + widget.onPress(date); + }, + onLongPress: (date) { + setState(() => _focusedDay = date); + widget.onLongPress(date); + }, + ), + itemCount: delta(widget.start, widget.end), + onPageChanged: _handleMonthPageChanged, ), ), - ); + ), + ], + ); @override void didChangeDependencies() { @@ -157,7 +146,7 @@ class _PageDayPickerState extends State { void _handleNextMonth() { if (!_last) { _controller.nextPage( - duration: widget.style.animationDuration, + duration: widget.style.pageAnimationDuration, curve: Curves.ease, ); } @@ -167,7 +156,7 @@ class _PageDayPickerState extends State { void _handlePreviousMonth() { if (!_first) { _controller.previousPage( - duration: widget.style.animationDuration, + duration: widget.style.pageAnimationDuration, curve: Curves.ease, ); } @@ -187,7 +176,7 @@ class _PageDayPickerState extends State { } else { _controller.animateToPage( page, - duration: widget.style.animationDuration, + duration: widget.style.pageAnimationDuration, curve: Curves.ease, ); } diff --git a/forui/lib/src/widgets/calendar/toggle.dart b/forui/lib/src/widgets/calendar/toggle.dart new file mode 100644 index 000000000..dae2bf047 --- /dev/null +++ b/forui/lib/src/widgets/calendar/toggle.dart @@ -0,0 +1,33 @@ +part of 'calendar.dart'; + +/// The toggle's height. This is a workaround to the pickers being in a stack alongside the toggle. +@internal +const toggleHeight = 31.0; + +class Toggle extends StatefulWidget { + final FCalendarStyle style; + final LocalDate month; + + const Toggle({ + super.key, + required this.style, + required this.month, + }); + + @override + State createState() => _ToggleState(); +} + +class _ToggleState extends State { + @override + Widget build(BuildContext context) => + SizedBox( + height: toggleHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${widget.month.month} ${widget.month.year}', style: widget.style.headerStyle.headerTextStyle), + ], + ), + ); // TODO: Localization +} diff --git a/forui/lib/src/widgets/calendar/year_month/year_month.dart b/forui/lib/src/widgets/calendar/year_month/year_month.dart new file mode 100644 index 000000000..88ac41e44 --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/year_month.dart @@ -0,0 +1,176 @@ +part of '../calendar.dart'; + +/// Returns the current year/month. +@internal +Widget yearMonth( + FCalendarYearMonthPickerStyle pickerStyle, + LocalDate date, + ValueChanged onPress, + String Function(LocalDate) localize, { + required bool enabled, + required bool current, +}) { + final style = enabled ? pickerStyle.enabledStyle : pickerStyle.disabledStyle; + if (enabled) { + return EnabledYearMonth( + style: style, + date: date, + onPress: onPress, + localize: localize, + current: current, + ); + } else { + return DisabledYearMonth( + style: style, + date: date, + localize: localize, + current: current, + ); + } +} + +@internal +class EnabledYearMonth extends StatefulWidget { + final FCalendarYearMonthPickerStateStyle style; + final LocalDate date; + final bool current; + final ValueChanged onPress; + final String Function(LocalDate) localize; + + const EnabledYearMonth({ + required this.style, + required this.date, + required this.current, + required this.onPress, + required this.localize, + super.key, + }); + + @override + State createState() => _EnabledYearMonthState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(FlagProperty('current', value: current, ifTrue: 'current', level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('localize', localize, level: DiagnosticLevel.debug)); + } +} + +class _EnabledYearMonthState extends State { + bool _hovered = false; + + @override + Widget build(BuildContext context) { + var textStyle = _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; + if (widget.current) { + textStyle = textStyle.copyWith(decoration: TextDecoration.underline); + } + + return MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), + child: Semantics( + label: widget.localize(widget.date), + button: true, + excludeSemantics: true, + child: GestureDetector( + onTap: () => widget.onPress(widget.date), + child: DecoratedBox( + decoration: _hovered ? widget.style.focusedDecoration : widget.style.decoration, + child: Center( + child: Text(widget.localize(widget.date), style: textStyle), + ), + ), + ), + ), + ); + } +} + +@internal +class DisabledYearMonth extends StatelessWidget { + final FCalendarYearMonthPickerStateStyle style; + final LocalDate date; + final bool current; + final String Function(LocalDate) localize; + + const DisabledYearMonth({ + required this.style, + required this.date, + required this.current, + required this.localize, + super.key, + }); + + @override + Widget build(BuildContext context) { + var textStyle = style.textStyle; + if (current) { + textStyle = textStyle.copyWith(decoration: TextDecoration.underline); + } + + return ExcludeSemantics( + child: DecoratedBox( + decoration: style.decoration, + child: Center( + child: Text(localize(date), style: textStyle), + ), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('current', current)) + ..add(DiagnosticsProperty('localize', localize)); + } +} + +final class FCalendarYearMonthPickerStyle with Diagnosticable { + final FCalendarYearMonthPickerStateStyle enabledStyle; + final FCalendarYearMonthPickerStateStyle disabledStyle; + + FCalendarYearMonthPickerStyle({required this.enabledStyle, required this.disabledStyle}); + + FCalendarYearMonthPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : this( + enabledStyle: FCalendarYearMonthPickerStateStyle( + decoration: const BoxDecoration(), + textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), + focusedDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: colorScheme.secondary, + ), + ), + disabledStyle: FCalendarYearMonthPickerStateStyle( + decoration: const BoxDecoration(), + textStyle: typography.sm + .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), + ), + ); +} + +final class FCalendarYearMonthPickerStateStyle with Diagnosticable { + final BoxDecoration decoration; + final TextStyle textStyle; + final BoxDecoration focusedDecoration; + final TextStyle focusedTextStyle; + + FCalendarYearMonthPickerStateStyle({ + required this.decoration, + required this.textStyle, + BoxDecoration? focusedDecoration, + TextStyle? focusedTextStyle, + }) : focusedDecoration = focusedDecoration ?? decoration, + focusedTextStyle = focusedTextStyle ?? textStyle; +} diff --git a/forui/lib/src/widgets/calendar/year_month/year_picker.dart b/forui/lib/src/widgets/calendar/year_month/year_picker.dart new file mode 100644 index 000000000..6f7b28cbe --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/year_picker.dart @@ -0,0 +1,108 @@ +part of '../calendar.dart'; + +@internal +class YearPicker extends StatefulWidget { + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; + final LocalDate current; + final ValueChanged onPress; + + const YearPicker({ + required this.style, + required this.start, + required this.end, + required this.current, + required this.onPress, + super.key, + }); + + @override + State createState() => _YearPickerState(); +} + +class _YearPickerState extends State { + static const _columns = 3; + + static int delta(LocalDate start, LocalDate end) => ((end.year - start.year + 1) / 12).ceil(); + + final GlobalKey key = GlobalKey(); + late LocalDate _current; + late PageController _controller; + + @override + void initState() { + super.initState(); + _current = widget.current.truncate(to: DateUnit.years); + _controller = PageController(initialPage: delta(widget.start, widget.end)); + } + + @override + Widget build(BuildContext context) { + final initial = widget.start.truncate(to: DateUnit.years); + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Controls( + style: widget.style.headerStyle, + onPrevious: _first ? null : _handlePrevious, + onNext: _last ? null : _handleNext, + ), + ), + Expanded( + child: PageView.builder( + key: key, + controller: _controller, + itemBuilder: (context, index) => GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + childAspectRatio: 1.618, + ), + children: [ + for (var year = initial.plus(years: index * 12), i = 0; i < 12; year = year.plus(years: 1), i++) + yearMonth( + widget.style.yearMonthPickerStyle, + year, + widget.onPress, + (date) => '${date.year}', // TODO: localize + enabled: widget.start <= year && year <= widget.end, + current: widget.current.year == year.year, + ) + ], + ), + itemCount: delta(widget.start, widget.end), + ), + ), + ], + ); + } + + /// Navigate to the next month. + void _handleNext() { + if (!_last) { + _controller.nextPage( + duration: widget.style.pageAnimationDuration, + curve: Curves.ease, + ); + } + } + + /// Navigate to the previous month. + void _handlePrevious() { + if (!_first) { + _controller.previousPage( + duration: widget.style.pageAnimationDuration, + curve: Curves.ease, + ); + } + } + + /// True if the earliest allowable years are displayed. + bool get _first => delta(widget.start, _current) == 0; + + /// True if the latest allowable years are displayed. + bool get _last { + return delta(widget.start, _current) == delta(widget.start, widget.end); + } +} diff --git a/samples/lib/main.dart b/samples/lib/main.dart index fcb2bc76e..3b5b40075 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -1,12 +1,8 @@ -import 'package:flutter/material.dart' hide DialogRoute; - import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart' hide DialogRoute; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; -import 'package:forui/forui.dart'; - import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; -import 'package:sugar/sugar.dart'; void main() { usePathUrlStrategy(); @@ -30,14 +26,7 @@ class ForuiSamples extends StatelessWidget { @RoutePage() class EmptyPage extends SampleScaffold { @override - Widget child(BuildContext context) => const Testing(); -} - -class Testing extends StatelessWidget { - const Testing({super.key}); - - @override - Widget build(BuildContext context) => PagedMonth(initialDate: DateTime(2024, 7, 8)); + Widget child(BuildContext context) => const Placeholder(); } @AutoRouterConfig() From a24282e2988e5a176298e568afefd4c54c935d96 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 20:29:40 +0800 Subject: [PATCH 17/35] abstract paging logic --- forui/lib/src/widgets/calendar/calendar.dart | 1 + .../calendar/day/paged_day_picker.dart | 596 +++++++++--------- .../src/widgets/calendar/paged_picker.dart | 207 ++++++ 3 files changed, 506 insertions(+), 298 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/paged_picker.dart diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index ddfaf6ff3..ad41ffa72 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -17,6 +17,7 @@ part 'day/paged_day_picker.dart'; part 'year_month/year_month.dart'; part 'year_month/year_picker.dart'; +part 'paged_picker.dart'; part 'toggle.dart'; enum FCalendarPickerMode { diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 9705e7ca1..a5666b44c 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,300 +1,300 @@ part of '../calendar.dart'; -@internal -class PagedDayPicker extends StatefulWidget { - final FCalendarStyle style; // TODO: retrieve via context - final LocalDate start; - final LocalDate end; - final LocalDate today; - final LocalDate initialMonth; - final bool Function(LocalDate day) enabledPredicate; - final bool Function(LocalDate day) selectedPredicate; - final ValueChanged? onMonthChange; - final ValueChanged onPress; - final ValueChanged onLongPress; - - const PagedDayPicker({ - required this.style, - required this.start, - required this.end, - required this.today, - required this.initialMonth, - required this.enabledPredicate, - required this.selectedPredicate, - required this.onMonthChange, - required this.onPress, - required this.onLongPress, - super.key, - }); - - @override - State createState() => _PageDayPickerState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style)) - ..add(DiagnosticsProperty('start', start)) - ..add(DiagnosticsProperty('end', end)) - ..add(DiagnosticsProperty('today', today)) - ..add(DiagnosticsProperty('initialMonth', initialMonth)) - ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)) - ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) - ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) - ..add(DiagnosticsProperty('onPress', onPress)) - ..add(DiagnosticsProperty('onLongPress', onLongPress)); - } -} - -// Most of the traversal logic is copied from Material's _MonthPickerState. -class _PageDayPickerState extends State { - static int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; - - static const _shortcuts = { - SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), - SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), - SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), - SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), - }; - - static const _directionOffset = { - TraversalDirection.up: -DateTime.daysPerWeek, - TraversalDirection.right: 1, - TraversalDirection.down: DateTime.daysPerWeek, - TraversalDirection.left: -1, - }; - - final GlobalKey _pageViewKey = GlobalKey(); - late LocalDate _currentMonth; - late PageController _controller; - late TextDirection _textDirection; - late Map> _actions; - late FocusNode _dayGridFocus; - LocalDate? _focusedDay; - - @override - void initState() { - super.initState(); - _currentMonth = widget.initialMonth; - _controller = PageController(initialPage: delta(widget.start, widget.initialMonth)); - _actions = { - NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), - PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), - DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), - }; - _dayGridFocus = FocusNode(debugLabel: 'Day Grid'); - } - - @override - Widget build(BuildContext context) => Column( - mainAxisSize: MainAxisSize.min, - children: [ - Controls( - style: widget.style.headerStyle, - onPrevious: _first ? null : _handlePreviousMonth, - onNext: _last ? null : _handleNextMonth, - ), - Expanded( - child: FocusableActionDetector( - shortcuts: _shortcuts, - actions: _actions, - focusNode: _dayGridFocus, - onFocusChange: _handleGridFocusChange, - child: PageView.builder( - key: _pageViewKey, - controller: _controller, - itemBuilder: (context, index) => DayPicker( - focused: _focusedDay, - style: widget.style.dayPickerStyle, - month: widget.start.truncate(to: DateUnit.months).plus(months: index), - today: widget.today, - enabledPredicate: (date) => - widget.start <= date && date <= widget.end && widget.enabledPredicate(date), - selectedPredicate: widget.selectedPredicate, - onPress: (date) { - setState(() => _focusedDay = date); - widget.onPress(date); - }, - onLongPress: (date) { - setState(() => _focusedDay = date); - widget.onLongPress(date); - }, - ), - itemCount: delta(widget.start, widget.end), - onPageChanged: _handleMonthPageChanged, - ), - ), - ), - ], - ); - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _textDirection = Directionality.of(context); - } - - @override - void dispose() { - _controller.dispose(); - _dayGridFocus.dispose(); - super.dispose(); - } - - /// Navigate to the next month. - void _handleNextMonth() { - if (!_last) { - _controller.nextPage( - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); - } - } - - /// Navigate to the previous month. - void _handlePreviousMonth() { - if (!_first) { - _controller.previousPage( - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); - } - } - - /// True if the earliest allowable month is displayed. - bool get _first => widget.start.truncate(to: DateUnit.months) == _currentMonth; - - /// True if the latest allowable month is displayed. - bool get _last => widget.end.truncate(to: DateUnit.months) == _currentMonth; - - /// Navigate to the given month. - void _showMonth(LocalDate month, {bool jump = false}) { - final page = delta(widget.start, month); - if (jump) { - _controller.jumpToPage(page); - } else { - _controller.animateToPage( - page, - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); - } - } - - void _handleMonthPageChanged(int page) { - setState(() { - final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); - if (_currentMonth == changed) { - return; - } - - _currentMonth = changed; - widget.onMonthChange?.call(_currentMonth.toNative()); - if (_focusedDay case final focused? when focused.truncate(to: DateUnit.months) == _currentMonth) { - // We have navigated to a new month with the grid focused, but the - // focused day is not in this month. Choose a new one trying to keep - // the same day of the month. - _focusedDay = _focusableDayForMonth(_currentMonth, _focusedDay!.day); - } - - SemanticsService.announce( - _currentMonth.toString(), // TODO: localization - _textDirection, - ); - }); - } - - /// Returns a focusable date for the given month. - /// - /// If the preferredDay is available in the month it will be returned, - /// otherwise the first selectable day in the month will be returned. If - /// no dates are selectable in the month, then it will return null. - LocalDate? _focusableDayForMonth(LocalDate month, int preferredDay) { - // Can we use the preferred day in this month? - if (preferredDay <= month.daysInMonth) { - final newFocus = month.copyWith(day: preferredDay); - if (widget.enabledPredicate(newFocus)) { - return newFocus; - } - } - - // Start at the 1st and take the first enabled date. - for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { - if (widget.enabledPredicate(newFocus)) { - return newFocus; - } - } - - return null; - } - - /// Handler for when the overall day grid obtains or loses focus. - void _handleGridFocusChange(bool focused) { - setState(() { - if (focused && _focusedDay == null) { - final preferred = widget.today.truncate(to: DateUnit.months) == _currentMonth ? widget.today.day : 1; - _focusedDay = _focusableDayForMonth(_currentMonth, preferred); - } - }); - } - - /// Move focus to the next element after the day grid. - void _handleGridNextFocus(NextFocusIntent intent) { - _dayGridFocus - ..requestFocus() - ..nextFocus(); - } - - /// Move focus to the previous element before the day grid. - void _handleGridPreviousFocus(PreviousFocusIntent intent) { - _dayGridFocus - ..requestFocus() - ..previousFocus(); - } - - /// Move the internal focus date in the direction of the given intent. - /// - /// This will attempt to move the focused day to the next selectable day in - /// the given direction. If the new date is not in the current month, then - /// the page view will be scrolled to show the new date's month. - /// - /// For horizontal directions, it will move forward or backward a day (depending - /// on the current [TextDirection]). For vertical directions it will move up and - /// down a week at a time. - void _handleDirectionFocus(DirectionalFocusIntent intent) { - assert(_focusedDay != null, 'Cannot move focus without a focused day.'); - setState(() { - final nextDate = _nextDateInDirection(_focusedDay!, intent.direction); - if (nextDate != null) { - _focusedDay = nextDate; - if (_focusedDay?.truncate(to: DateUnit.months) != _currentMonth) { - _showMonth(_focusedDay!); - } - } - }); - } - - // Swap left and right if the text direction if RTL - int _dayDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => - _directionOffset[switch ((traversalDirection, textDirection)) { - (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, - (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, - _ => traversalDirection, - }]!; - - LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { - final textDirection = Directionality.of(context); - - var next = date.plus(days: _dayDirectionOffset(direction, textDirection)); - while (widget.start <= next && next <= widget.end) { - if (widget.enabledPredicate(next)) { - return next; - } - - next = date.plus(days: _dayDirectionOffset(direction, textDirection)); - } - - return null; - } -} +// @internal +// class PagedDayPicker extends StatefulWidget { +// final FCalendarStyle style; +// final LocalDate start; +// final LocalDate end; +// final LocalDate today; +// final LocalDate initialMonth; +// final bool Function(LocalDate day) enabledPredicate; +// final bool Function(LocalDate day) selectedPredicate; +// final ValueChanged? onMonthChange; +// final ValueChanged onPress; +// final ValueChanged onLongPress; +// +// const PagedDayPicker({ +// required this.style, +// required this.start, +// required this.end, +// required this.today, +// required this.initialMonth, +// required this.enabledPredicate, +// required this.selectedPredicate, +// required this.onMonthChange, +// required this.onPress, +// required this.onLongPress, +// super.key, +// }); +// +// @override +// State createState() => _PageDayPickerState(); +// +// @override +// void debugFillProperties(DiagnosticPropertiesBuilder properties) { +// super.debugFillProperties(properties); +// properties +// ..add(DiagnosticsProperty('style', style)) +// ..add(DiagnosticsProperty('start', start)) +// ..add(DiagnosticsProperty('end', end)) +// ..add(DiagnosticsProperty('today', today)) +// ..add(DiagnosticsProperty('initialMonth', initialMonth)) +// ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)) +// ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) +// ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) +// ..add(DiagnosticsProperty('onPress', onPress)) +// ..add(DiagnosticsProperty('onLongPress', onLongPress)); +// } +// } +// +// // Most of the traversal logic is copied from Material's _MonthPickerState. +// class _PageDayPickerState extends State { +// static int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; +// +// static const _shortcuts = { +// SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), +// SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), +// SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), +// SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), +// }; +// +// static const _directionOffset = { +// TraversalDirection.up: -DateTime.daysPerWeek, +// TraversalDirection.right: 1, +// TraversalDirection.down: DateTime.daysPerWeek, +// TraversalDirection.left: -1, +// }; +// +// final GlobalKey _pageViewKey = GlobalKey(); +// late LocalDate _currentMonth; +// late PageController _controller; +// late TextDirection _textDirection; +// late Map> _actions; +// late FocusNode _dayGridFocus; +// LocalDate? _focusedDay; +// +// @override +// void initState() { +// super.initState(); +// _currentMonth = widget.initialMonth; +// _controller = PageController(initialPage: delta(widget.start, widget.initialMonth)); +// _actions = { +// NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), +// PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), +// DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), +// }; +// _dayGridFocus = FocusNode(debugLabel: 'Day Grid'); +// } +// +// @override +// Widget build(BuildContext context) => Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// Controls( +// style: widget.style.headerStyle, +// onPrevious: _first ? null : _handlePreviousMonth, +// onNext: _last ? null : _handleNextMonth, +// ), +// Expanded( +// child: FocusableActionDetector( +// shortcuts: _shortcuts, +// actions: _actions, +// focusNode: _dayGridFocus, +// onFocusChange: _handleGridFocusChange, +// child: PageView.builder( +// key: _pageViewKey, +// controller: _controller, +// itemBuilder: (context, index) => DayPicker( +// focused: _focusedDay, +// style: widget.style.dayPickerStyle, +// month: widget.start.truncate(to: DateUnit.months).plus(months: index), +// today: widget.today, +// enabledPredicate: (date) => +// widget.start <= date && date <= widget.end && widget.enabledPredicate(date), +// selectedPredicate: widget.selectedPredicate, +// onPress: (date) { +// setState(() => _focusedDay = date); +// widget.onPress(date); +// }, +// onLongPress: (date) { +// setState(() => _focusedDay = date); +// widget.onLongPress(date); +// }, +// ), +// itemCount: delta(widget.start, widget.end), +// onPageChanged: _handleMonthPageChanged, +// ), +// ), +// ), +// ], +// ); +// +// @override +// void didChangeDependencies() { +// super.didChangeDependencies(); +// _textDirection = Directionality.of(context); +// } +// +// @override +// void dispose() { +// _controller.dispose(); +// _dayGridFocus.dispose(); +// super.dispose(); +// } +// +// /// Navigate to the next month. +// void _handleNextMonth() { +// if (!_last) { +// _controller.nextPage( +// duration: widget.style.pageAnimationDuration, +// curve: Curves.ease, +// ); +// } +// } +// +// /// Navigate to the previous month. +// void _handlePreviousMonth() { +// if (!_first) { +// _controller.previousPage( +// duration: widget.style.pageAnimationDuration, +// curve: Curves.ease, +// ); +// } +// } +// +// /// True if the earliest allowable month is displayed. +// bool get _first => widget.start.truncate(to: DateUnit.months) == _currentMonth; +// +// /// True if the latest allowable month is displayed. +// bool get _last => widget.end.truncate(to: DateUnit.months) == _currentMonth; +// +// /// Navigate to the given month. +// void _showMonth(LocalDate month, {bool jump = false}) { +// final page = delta(widget.start, month); +// if (jump) { +// _controller.jumpToPage(page); +// } else { +// _controller.animateToPage( +// page, +// duration: widget.style.pageAnimationDuration, +// curve: Curves.ease, +// ); +// } +// } +// +// void _handleMonthPageChanged(int page) { +// setState(() { +// final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); +// if (_currentMonth == changed) { +// return; +// } +// +// _currentMonth = changed; +// widget.onMonthChange?.call(_currentMonth.toNative()); +// if (_focusedDay case final focused? when focused.truncate(to: DateUnit.months) == _currentMonth) { +// // We have navigated to a new month with the grid focused, but the +// // focused day is not in this month. Choose a new one trying to keep +// // the same day of the month. +// _focusedDay = _focusableDayForMonth(_currentMonth, _focusedDay!.day); +// } +// +// SemanticsService.announce( +// _currentMonth.toString(), // TODO: localization +// _textDirection, +// ); +// }); +// } +// +// /// Returns a focusable date for the given month. +// /// +// /// If the preferredDay is available in the month it will be returned, +// /// otherwise the first selectable day in the month will be returned. If +// /// no dates are selectable in the month, then it will return null. +// LocalDate? _focusableDayForMonth(LocalDate month, int preferredDay) { +// // Can we use the preferred day in this month? +// if (preferredDay <= month.daysInMonth) { +// final newFocus = month.copyWith(day: preferredDay); +// if (widget.enabledPredicate(newFocus)) { +// return newFocus; +// } +// } +// +// // Start at the 1st and take the first enabled date. +// for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { +// if (widget.enabledPredicate(newFocus)) { +// return newFocus; +// } +// } +// +// return null; +// } +// +// /// Handler for when the overall day grid obtains or loses focus. +// void _handleGridFocusChange(bool focused) { +// setState(() { +// if (focused && _focusedDay == null) { +// final preferred = widget.today.truncate(to: DateUnit.months) == _currentMonth ? widget.today.day : 1; +// _focusedDay = _focusableDayForMonth(_currentMonth, preferred); +// } +// }); +// } +// +// /// Move focus to the next element after the day grid. +// void _handleGridNextFocus(NextFocusIntent intent) { +// _dayGridFocus +// ..requestFocus() +// ..nextFocus(); +// } +// +// /// Move focus to the previous element before the day grid. +// void _handleGridPreviousFocus(PreviousFocusIntent intent) { +// _dayGridFocus +// ..requestFocus() +// ..previousFocus(); +// } +// +// /// Move the internal focus date in the direction of the given intent. +// /// +// /// This will attempt to move the focused day to the next selectable day in +// /// the given direction. If the new date is not in the current month, then +// /// the page view will be scrolled to show the new date's month. +// /// +// /// For horizontal directions, it will move forward or backward a day (depending +// /// on the current [TextDirection]). For vertical directions it will move up and +// /// down a week at a time. +// void _handleDirectionFocus(DirectionalFocusIntent intent) { +// assert(_focusedDay != null, 'Cannot move focus without a focused day.'); +// setState(() { +// final nextDate = _nextDateInDirection(_focusedDay!, intent.direction); +// if (nextDate != null) { +// _focusedDay = nextDate; +// if (_focusedDay?.truncate(to: DateUnit.months) != _currentMonth) { +// _showMonth(_focusedDay!); +// } +// } +// }); +// } +// +// // Swap left and right if the text direction if RTL +// int _dayDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => +// _directionOffset[switch ((traversalDirection, textDirection)) { +// (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, +// (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, +// _ => traversalDirection, +// }]!; +// +// LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { +// final textDirection = Directionality.of(context); +// +// var next = date.plus(days: _dayDirectionOffset(direction, textDirection)); +// while (widget.start <= next && next <= widget.end) { +// if (widget.enabledPredicate(next)) { +// return next; +// } +// +// next = date.plus(days: _dayDirectionOffset(direction, textDirection)); +// } +// +// return null; +// } +// } diff --git a/forui/lib/src/widgets/calendar/paged_picker.dart b/forui/lib/src/widgets/calendar/paged_picker.dart new file mode 100644 index 000000000..52cfdfbda --- /dev/null +++ b/forui/lib/src/widgets/calendar/paged_picker.dart @@ -0,0 +1,207 @@ +part of 'calendar.dart'; + +@internal +abstract class PagedPicker extends StatefulWidget { + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final LocalDate initial; + final bool Function(LocalDate day) enabledPredicate; + + const PagedPicker({ + required this.style, + required this.start, + required this.end, + required this.today, + required this.initial, + required this.enabledPredicate, + super.key, + }); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('start', start)) + ..add(DiagnosticsProperty('end', end)) + ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('initial', initial)); + } +} + +// Most of the traversal logic is copied from Material's _MonthPickerState. +abstract class _PagedPickerState extends State { + + static const _shortcuts = { + SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), + SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), + SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), + SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), + }; + + final GlobalKey _pageViewKey = GlobalKey(); + late LocalDate _current; + late PageController _controller; + late TextDirection _textDirection; + late Map> _actions; + late FocusNode _gridFocusNode; + LocalDate? _focused; + + @override + void initState() { + super.initState(); + _current = widget.initial; + _controller = PageController(initialPage: _delta(widget.start, widget.initial)); + _actions = { + NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), + PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), + DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), + }; + _gridFocusNode = FocusNode(debugLabel: 'Grid'); + } + + @override + Widget build(BuildContext context) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Controls( + style: widget.style.headerStyle, + onPrevious: _first ? null : _handlePrevious, + onNext: _last ? null : _handleNext, + ), + Expanded( + child: FocusableActionDetector( + shortcuts: _shortcuts, + actions: _actions, + focusNode: _gridFocusNode, + onFocusChange: _handleGridFocusChange, + child: PageView.builder( + key: _pageViewKey, + controller: _controller, + itemBuilder: _item, + itemCount: _delta(widget.start, widget.end), + onPageChanged: _handlePageChange, + ), + ), + ), + ], + ); + + Widget _item(BuildContext context, int index); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _textDirection = Directionality.of(context); + } + + @override + void dispose() { + _controller.dispose(); + _gridFocusNode.dispose(); + super.dispose(); + } + + + void _handleNext() { + if (!_last) { + _controller.nextPage(duration: widget.style.pageAnimationDuration, curve: Curves.ease); + } + } + + void _handlePrevious() { + if (!_first) { + _controller.previousPage(duration: widget.style.pageAnimationDuration, curve: Curves.ease); + } + } + + bool get _first; + + bool get _last; + + /// Navigate to the given month. + void _showPage(LocalDate date, {bool jump = false}) { + final page = _delta(widget.start, date); + if (jump) { + _controller.jumpToPage(page); + } else { + _controller.animateToPage( + page, + duration: widget.style.pageAnimationDuration, + curve: Curves.ease, + ); + } + } + + void _handlePageChange(int page); + + void _handleGridFocusChange(bool focused); + + + /// Move focus to the next element after the day grid. + void _handleGridNextFocus(NextFocusIntent intent) { + _gridFocusNode + ..requestFocus() + ..nextFocus(); + } + + /// Move focus to the previous element before the day grid. + void _handleGridPreviousFocus(PreviousFocusIntent intent) { + _gridFocusNode + ..requestFocus() + ..previousFocus(); + } + + + /// Move the internal focus date in the direction of the given intent. + /// + /// This will attempt to move the focused day to the next selectable day in + /// the given direction. If the new date is not in the current month, then + /// the page view will be scrolled to show the new date's month. + /// + /// For horizontal directions, it will move forward or backward a day (depending + /// on the current [TextDirection]). For vertical directions it will move up and + /// down a week at a time. + void _handleDirectionFocus(DirectionalFocusIntent intent) { + assert(_focused != null, 'Cannot move focus without a focused day.'); + setState(() { + final nextDate = _nextDateInDirection(_focused!, intent.direction); + if (nextDate != null) { + _focused = nextDate; + if (_delta(widget.start, _focused!) != _delta(widget.start, _current)) { + _showPage(_focused!); + } + } + }); + } + + // Swap left and right if the text direction if RTL + Period _adjustDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => + _directionOffset[switch ((traversalDirection, textDirection)) { + (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, + (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, + _ => traversalDirection, + }]!; + + LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { + final textDirection = Directionality.of(context); + + var next = date + _adjustDirectionOffset(direction, textDirection); + while (widget.start <= next && next <= widget.end) { + if (widget.enabledPredicate(next)) { + return next; + } + + next = date + _adjustDirectionOffset(direction, textDirection); + } + + return null; + } + + + int _delta(LocalDate start, LocalDate end); + + Map get _directionOffset; +} From 0f22222ded6e751ebaaefd7adbd016d7f9c684b9 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 20:52:10 +0800 Subject: [PATCH 18/35] Refactor paged_day_picker --- .../calendar/day/paged_day_picker.dart | 430 ++++++------------ .../src/widgets/calendar/paged_picker.dart | 45 +- 2 files changed, 151 insertions(+), 324 deletions(-) diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index a5666b44c..0080a652b 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,300 +1,134 @@ part of '../calendar.dart'; -// @internal -// class PagedDayPicker extends StatefulWidget { -// final FCalendarStyle style; -// final LocalDate start; -// final LocalDate end; -// final LocalDate today; -// final LocalDate initialMonth; -// final bool Function(LocalDate day) enabledPredicate; -// final bool Function(LocalDate day) selectedPredicate; -// final ValueChanged? onMonthChange; -// final ValueChanged onPress; -// final ValueChanged onLongPress; -// -// const PagedDayPicker({ -// required this.style, -// required this.start, -// required this.end, -// required this.today, -// required this.initialMonth, -// required this.enabledPredicate, -// required this.selectedPredicate, -// required this.onMonthChange, -// required this.onPress, -// required this.onLongPress, -// super.key, -// }); -// -// @override -// State createState() => _PageDayPickerState(); -// -// @override -// void debugFillProperties(DiagnosticPropertiesBuilder properties) { -// super.debugFillProperties(properties); -// properties -// ..add(DiagnosticsProperty('style', style)) -// ..add(DiagnosticsProperty('start', start)) -// ..add(DiagnosticsProperty('end', end)) -// ..add(DiagnosticsProperty('today', today)) -// ..add(DiagnosticsProperty('initialMonth', initialMonth)) -// ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)) -// ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) -// ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) -// ..add(DiagnosticsProperty('onPress', onPress)) -// ..add(DiagnosticsProperty('onLongPress', onLongPress)); -// } -// } -// -// // Most of the traversal logic is copied from Material's _MonthPickerState. -// class _PageDayPickerState extends State { -// static int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; -// -// static const _shortcuts = { -// SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), -// SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), -// SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), -// SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), -// }; -// -// static const _directionOffset = { -// TraversalDirection.up: -DateTime.daysPerWeek, -// TraversalDirection.right: 1, -// TraversalDirection.down: DateTime.daysPerWeek, -// TraversalDirection.left: -1, -// }; -// -// final GlobalKey _pageViewKey = GlobalKey(); -// late LocalDate _currentMonth; -// late PageController _controller; -// late TextDirection _textDirection; -// late Map> _actions; -// late FocusNode _dayGridFocus; -// LocalDate? _focusedDay; -// -// @override -// void initState() { -// super.initState(); -// _currentMonth = widget.initialMonth; -// _controller = PageController(initialPage: delta(widget.start, widget.initialMonth)); -// _actions = { -// NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), -// PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), -// DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), -// }; -// _dayGridFocus = FocusNode(debugLabel: 'Day Grid'); -// } -// -// @override -// Widget build(BuildContext context) => Column( -// mainAxisSize: MainAxisSize.min, -// children: [ -// Controls( -// style: widget.style.headerStyle, -// onPrevious: _first ? null : _handlePreviousMonth, -// onNext: _last ? null : _handleNextMonth, -// ), -// Expanded( -// child: FocusableActionDetector( -// shortcuts: _shortcuts, -// actions: _actions, -// focusNode: _dayGridFocus, -// onFocusChange: _handleGridFocusChange, -// child: PageView.builder( -// key: _pageViewKey, -// controller: _controller, -// itemBuilder: (context, index) => DayPicker( -// focused: _focusedDay, -// style: widget.style.dayPickerStyle, -// month: widget.start.truncate(to: DateUnit.months).plus(months: index), -// today: widget.today, -// enabledPredicate: (date) => -// widget.start <= date && date <= widget.end && widget.enabledPredicate(date), -// selectedPredicate: widget.selectedPredicate, -// onPress: (date) { -// setState(() => _focusedDay = date); -// widget.onPress(date); -// }, -// onLongPress: (date) { -// setState(() => _focusedDay = date); -// widget.onLongPress(date); -// }, -// ), -// itemCount: delta(widget.start, widget.end), -// onPageChanged: _handleMonthPageChanged, -// ), -// ), -// ), -// ], -// ); -// -// @override -// void didChangeDependencies() { -// super.didChangeDependencies(); -// _textDirection = Directionality.of(context); -// } -// -// @override -// void dispose() { -// _controller.dispose(); -// _dayGridFocus.dispose(); -// super.dispose(); -// } -// -// /// Navigate to the next month. -// void _handleNextMonth() { -// if (!_last) { -// _controller.nextPage( -// duration: widget.style.pageAnimationDuration, -// curve: Curves.ease, -// ); -// } -// } -// -// /// Navigate to the previous month. -// void _handlePreviousMonth() { -// if (!_first) { -// _controller.previousPage( -// duration: widget.style.pageAnimationDuration, -// curve: Curves.ease, -// ); -// } -// } -// -// /// True if the earliest allowable month is displayed. -// bool get _first => widget.start.truncate(to: DateUnit.months) == _currentMonth; -// -// /// True if the latest allowable month is displayed. -// bool get _last => widget.end.truncate(to: DateUnit.months) == _currentMonth; -// -// /// Navigate to the given month. -// void _showMonth(LocalDate month, {bool jump = false}) { -// final page = delta(widget.start, month); -// if (jump) { -// _controller.jumpToPage(page); -// } else { -// _controller.animateToPage( -// page, -// duration: widget.style.pageAnimationDuration, -// curve: Curves.ease, -// ); -// } -// } -// -// void _handleMonthPageChanged(int page) { -// setState(() { -// final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); -// if (_currentMonth == changed) { -// return; -// } -// -// _currentMonth = changed; -// widget.onMonthChange?.call(_currentMonth.toNative()); -// if (_focusedDay case final focused? when focused.truncate(to: DateUnit.months) == _currentMonth) { -// // We have navigated to a new month with the grid focused, but the -// // focused day is not in this month. Choose a new one trying to keep -// // the same day of the month. -// _focusedDay = _focusableDayForMonth(_currentMonth, _focusedDay!.day); -// } -// -// SemanticsService.announce( -// _currentMonth.toString(), // TODO: localization -// _textDirection, -// ); -// }); -// } -// -// /// Returns a focusable date for the given month. -// /// -// /// If the preferredDay is available in the month it will be returned, -// /// otherwise the first selectable day in the month will be returned. If -// /// no dates are selectable in the month, then it will return null. -// LocalDate? _focusableDayForMonth(LocalDate month, int preferredDay) { -// // Can we use the preferred day in this month? -// if (preferredDay <= month.daysInMonth) { -// final newFocus = month.copyWith(day: preferredDay); -// if (widget.enabledPredicate(newFocus)) { -// return newFocus; -// } -// } -// -// // Start at the 1st and take the first enabled date. -// for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { -// if (widget.enabledPredicate(newFocus)) { -// return newFocus; -// } -// } -// -// return null; -// } -// -// /// Handler for when the overall day grid obtains or loses focus. -// void _handleGridFocusChange(bool focused) { -// setState(() { -// if (focused && _focusedDay == null) { -// final preferred = widget.today.truncate(to: DateUnit.months) == _currentMonth ? widget.today.day : 1; -// _focusedDay = _focusableDayForMonth(_currentMonth, preferred); -// } -// }); -// } -// -// /// Move focus to the next element after the day grid. -// void _handleGridNextFocus(NextFocusIntent intent) { -// _dayGridFocus -// ..requestFocus() -// ..nextFocus(); -// } -// -// /// Move focus to the previous element before the day grid. -// void _handleGridPreviousFocus(PreviousFocusIntent intent) { -// _dayGridFocus -// ..requestFocus() -// ..previousFocus(); -// } -// -// /// Move the internal focus date in the direction of the given intent. -// /// -// /// This will attempt to move the focused day to the next selectable day in -// /// the given direction. If the new date is not in the current month, then -// /// the page view will be scrolled to show the new date's month. -// /// -// /// For horizontal directions, it will move forward or backward a day (depending -// /// on the current [TextDirection]). For vertical directions it will move up and -// /// down a week at a time. -// void _handleDirectionFocus(DirectionalFocusIntent intent) { -// assert(_focusedDay != null, 'Cannot move focus without a focused day.'); -// setState(() { -// final nextDate = _nextDateInDirection(_focusedDay!, intent.direction); -// if (nextDate != null) { -// _focusedDay = nextDate; -// if (_focusedDay?.truncate(to: DateUnit.months) != _currentMonth) { -// _showMonth(_focusedDay!); -// } -// } -// }); -// } -// -// // Swap left and right if the text direction if RTL -// int _dayDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => -// _directionOffset[switch ((traversalDirection, textDirection)) { -// (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, -// (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, -// _ => traversalDirection, -// }]!; -// -// LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { -// final textDirection = Directionality.of(context); -// -// var next = date.plus(days: _dayDirectionOffset(direction, textDirection)); -// while (widget.start <= next && next <= widget.end) { -// if (widget.enabledPredicate(next)) { -// return next; -// } -// -// next = date.plus(days: _dayDirectionOffset(direction, textDirection)); -// } -// -// return null; -// } -// } +@internal +class PagedDayPicker extends PagedPicker { + final bool Function(LocalDate day) selectedPredicate; + final ValueChanged? onMonthChange; + final ValueChanged onPress; + final ValueChanged onLongPress; + + const PagedDayPicker({ + required this.selectedPredicate, + required this.onMonthChange, + required this.onPress, + required this.onLongPress, + required super.style, + required super.start, + required super.end, + required super.today, + required super.initial, + required super.enabledPredicate, + super.key, + }); + + @override + State createState() => _PageDayPickerState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) + ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) + ..add(DiagnosticsProperty('onPress', onPress)) + ..add(DiagnosticsProperty('onLongPress', onLongPress)); + } +} + +class _PageDayPickerState extends PagedPickerState { + late TextDirection _textDirection; + + @override + Widget buildItem(BuildContext context, int index) => DayPicker( + focused: _focused, + style: widget.style.dayPickerStyle, + month: widget.start.truncate(to: DateUnit.months).plus(months: index), + today: widget.today, + enabledPredicate: (date) => widget.start <= date && date <= widget.end && widget.enabledPredicate(date), + selectedPredicate: widget.selectedPredicate, + onPress: (date) { + setState(() => _focused = date); + widget.onPress(date); + }, + onLongPress: (date) { + setState(() => _focused = date); + widget.onLongPress(date); + }, + ); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _textDirection = Directionality.of(context); + } + + /// Handler for when the overall day grid obtains or loses focus. + @override + void handleGridFocusChange(bool focused) { + setState(() { + if (focused && _focused == null) { + final preferred = widget.today.truncate(to: DateUnit.months) == current ? widget.today.day : 1; + _focused = _focusableDayForMonth(current, preferred); + } + }); + } + + /// Returns a focusable date for the given month. + /// + /// If the preferredDay is available in the month it will be returned, + /// otherwise the first selectable day in the month will be returned. If + /// no dates are selectable in the month, then it will return null. + LocalDate? _focusableDayForMonth(LocalDate month, int preferredDay) { + // Can we use the preferred day in this month? + if (preferredDay <= month.daysInMonth) { + final newFocus = month.copyWith(day: preferredDay); + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + // Start at the 1st and take the first enabled date. + for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + return null; + } + + @override + void handlePageChange(int page) { + setState(() { + final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); + if (current == changed) { + return; + } + + current = changed; + widget.onMonthChange?.call(current.toNative()); + if (_focused case final focused? when focused.truncate(to: DateUnit.months) == current) { + // We have navigated to a new month with the grid focused, but the + // focused day is not in this month. Choose a new one trying to keep + // the same day of the month. + _focused = _focusableDayForMonth(current, _focused!.day); + } + + SemanticsService.announce( + current.toString(), // TODO: localization + _textDirection, + ); + }); + } + + @override + int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; + + @override + Map get directionOffset => const { + TraversalDirection.up: Period(days: -DateTime.daysPerWeek), + TraversalDirection.right: Period(days: 1), + TraversalDirection.down: Period(days: DateTime.daysPerWeek), + TraversalDirection.left: Period(days: -1), + }; +} diff --git a/forui/lib/src/widgets/calendar/paged_picker.dart b/forui/lib/src/widgets/calendar/paged_picker.dart index 52cfdfbda..6f4aa0427 100644 --- a/forui/lib/src/widgets/calendar/paged_picker.dart +++ b/forui/lib/src/widgets/calendar/paged_picker.dart @@ -32,7 +32,8 @@ abstract class PagedPicker extends StatefulWidget { } // Most of the traversal logic is copied from Material's _MonthPickerState. -abstract class _PagedPickerState extends State { +@internal +abstract class PagedPickerState extends State { static const _shortcuts = { SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), @@ -42,9 +43,8 @@ abstract class _PagedPickerState extends State { }; final GlobalKey _pageViewKey = GlobalKey(); - late LocalDate _current; + late LocalDate current; late PageController _controller; - late TextDirection _textDirection; late Map> _actions; late FocusNode _gridFocusNode; LocalDate? _focused; @@ -52,8 +52,8 @@ abstract class _PagedPickerState extends State { @override void initState() { super.initState(); - _current = widget.initial; - _controller = PageController(initialPage: _delta(widget.start, widget.initial)); + current = widget.initial; + _controller = PageController(initialPage: delta(widget.start, widget.initial)); _actions = { NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), @@ -64,7 +64,6 @@ abstract class _PagedPickerState extends State { @override Widget build(BuildContext context) => Column( - mainAxisSize: MainAxisSize.min, children: [ Controls( style: widget.style.headerStyle, @@ -76,26 +75,20 @@ abstract class _PagedPickerState extends State { shortcuts: _shortcuts, actions: _actions, focusNode: _gridFocusNode, - onFocusChange: _handleGridFocusChange, + onFocusChange: handleGridFocusChange, child: PageView.builder( key: _pageViewKey, controller: _controller, - itemBuilder: _item, - itemCount: _delta(widget.start, widget.end), - onPageChanged: _handlePageChange, + itemBuilder: buildItem, + itemCount: delta(widget.start, widget.end), + onPageChanged: handlePageChange, ), ), ), ], ); - Widget _item(BuildContext context, int index); - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _textDirection = Directionality.of(context); - } + Widget buildItem(BuildContext context, int index); @override void dispose() { @@ -117,13 +110,13 @@ abstract class _PagedPickerState extends State { } } - bool get _first; + bool get _first => delta(widget.start, current) == 0; - bool get _last; + bool get _last => delta(widget.start, current) == delta(widget.start, widget.end); /// Navigate to the given month. void _showPage(LocalDate date, {bool jump = false}) { - final page = _delta(widget.start, date); + final page = delta(widget.start, date); if (jump) { _controller.jumpToPage(page); } else { @@ -135,9 +128,9 @@ abstract class _PagedPickerState extends State { } } - void _handlePageChange(int page); + void handlePageChange(int page); - void _handleGridFocusChange(bool focused); + void handleGridFocusChange(bool focused); /// Move focus to the next element after the day grid. @@ -170,7 +163,7 @@ abstract class _PagedPickerState extends State { final nextDate = _nextDateInDirection(_focused!, intent.direction); if (nextDate != null) { _focused = nextDate; - if (_delta(widget.start, _focused!) != _delta(widget.start, _current)) { + if (delta(widget.start, _focused!) != delta(widget.start, current)) { _showPage(_focused!); } } @@ -179,7 +172,7 @@ abstract class _PagedPickerState extends State { // Swap left and right if the text direction if RTL Period _adjustDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => - _directionOffset[switch ((traversalDirection, textDirection)) { + directionOffset[switch ((traversalDirection, textDirection)) { (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, _ => traversalDirection, @@ -201,7 +194,7 @@ abstract class _PagedPickerState extends State { } - int _delta(LocalDate start, LocalDate end); + int delta(LocalDate start, LocalDate end); - Map get _directionOffset; + Map get directionOffset; } From 9ba192774480355b28a41e24450111ee1ec9f6be Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 10 Jul 2024 22:56:17 +0800 Subject: [PATCH 19/35] Add PagedYearPicker --- forui/example/lib/main.dart | 1 - forui/lib/src/widgets/calendar/calendar.dart | 16 ++- forui/lib/src/widgets/calendar/day/day.dart | 83 +++++------ .../src/widgets/calendar/day/day_picker.dart | 14 +- .../calendar/day/paged_day_picker.dart | 72 +++++----- .../src/widgets/calendar/paged_picker.dart | 76 +++++----- .../year_month/paged_year_picker.dart | 101 +++++++++++++ .../calendar/year_month/year_month.dart | 62 +++++--- .../calendar/year_month/year_picker.dart | 133 +++++++++--------- 9 files changed, 344 insertions(+), 214 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 96871a7af..9f104fd01 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -62,4 +62,3 @@ class Testing extends StatelessWidget { onLongPress: print, ); } - diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index ad41ffa72..52f410cce 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -11,12 +11,13 @@ import 'package:sugar/time.dart'; part 'day/day.dart'; part 'day/day_picker.dart'; -part 'controls.dart'; part 'day/paged_day_picker.dart'; +part 'year_month/paged_year_picker.dart'; part 'year_month/year_month.dart'; part 'year_month/year_picker.dart'; +part 'controls.dart'; part 'paged_picker.dart'; part 'toggle.dart'; @@ -65,7 +66,7 @@ class _CalendarState extends State { @override void initState() { super.initState(); - mode = FCalendarPickerMode.day; // TODO: + mode = FCalendarPickerMode.yearMonth; // TODO: month = widget.initialMonth; } @@ -75,8 +76,8 @@ class _CalendarState extends State { child: Padding( padding: widget.style.padding, child: SizedBox( - height: dayDimension * maxGridRows, - width: dayDimension * DateTime.daysPerWeek, + height: (maxDayPickerTileDimension * maxDayPickerGridRows) + toggleHeight + 5, + width: maxDayPickerTileDimension * DateTime.daysPerWeek, child: Stack( alignment: Alignment.topCenter, children: [ @@ -86,18 +87,19 @@ class _CalendarState extends State { start: widget.start, end: widget.end, today: widget.today, - initialMonth: widget.initialMonth, + initial: widget.initialMonth.truncate(to: DateUnit.months), enabledPredicate: widget.enabledPredicate, selectedPredicate: widget.selectedPredicate, onMonthChange: widget.onMonthChange, onPress: widget.onPress, onLongPress: widget.onLongPress, ), - FCalendarPickerMode.year => YearPicker( + FCalendarPickerMode.yearMonth => PagedYearPicker( style: widget.style, start: widget.start, end: widget.end, - current: widget.today, + today: widget.today, + initial: widget.initialMonth.truncate(to: DateUnit.years), onPress: print, ), }, diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/calendar/day/day.dart index 25955f4e2..e0eb5cada 100644 --- a/forui/lib/src/widgets/calendar/day/day.dart +++ b/forui/lib/src/widgets/calendar/day/day.dart @@ -91,7 +91,7 @@ class _EnabledDayState extends State { old.focusNode.removeListener(_updateFocused); widget.focusNode.addListener(_updateFocused); } - + @override Widget build(BuildContext context) { var textStyle = _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; @@ -100,38 +100,37 @@ class _EnabledDayState extends State { } return Focus( - focusNode: widget.focusNode, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => _hovered = true), - onExit: (_) => setState(() => _hovered = false), - child: Semantics( - label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization - button: true, - selected: widget.selected, - excludeSemantics: true, - child: GestureDetector( - onTap: () => widget.onPress(widget.date), - onLongPress: () => widget.onLongPress(widget.date), - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.horizontal( - left: widget.selectedPredicate(widget.date.yesterday) ? Radius.zero : const Radius.circular(4), - right: widget.selectedPredicate(widget.date.tomorrow) ? Radius.zero : const Radius.circular(4), - ), - color: _focused || _hovered ? widget.style.focusedBackgroundColor : widget.style.backgroundColor, - ), - child: Center( - child: Text('${widget.date.day}', style: textStyle), // TODO: localization + focusNode: widget.focusNode, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), + child: Semantics( + label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization + button: true, + selected: widget.selected, + excludeSemantics: true, + child: GestureDetector( + onTap: () => widget.onPress(widget.date), + onLongPress: () => widget.onLongPress(widget.date), + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.horizontal( + left: widget.selectedPredicate(widget.date.yesterday) ? Radius.zero : const Radius.circular(4), + right: widget.selectedPredicate(widget.date.tomorrow) ? Radius.zero : const Radius.circular(4), ), + color: _focused || _hovered ? widget.style.focusedBackgroundColor : widget.style.backgroundColor, + ), + child: Center( + child: Text('${widget.date.day}', style: textStyle), // TODO: localization ), ), ), ), - ); + ), + ); } - @override void dispose() { widget.focusNode.removeListener(_updateFocused); @@ -139,12 +138,6 @@ class _EnabledDayState extends State { } void _updateFocused() => setState(() => _focused = widget.focusNode.hasFocus); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(FlagProperty('focused', value: _hovered, ifTrue: 'focused')); - } } @internal @@ -170,19 +163,19 @@ class DisabledDay extends StatelessWidget { } return ExcludeSemantics( - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.horizontal( - left: selectedPredicate(date.yesterday) ? Radius.zero : const Radius.circular(4), - right: selectedPredicate(date.tomorrow) ? Radius.zero : const Radius.circular(4), - ), - color: style.backgroundColor, - ), - child: Center( - child: Text('${date.day}', style: textStyle), // TODO: localization + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.horizontal( + left: selectedPredicate(date.yesterday) ? Radius.zero : const Radius.circular(4), + right: selectedPredicate(date.tomorrow) ? Radius.zero : const Radius.circular(4), ), + color: style.backgroundColor, ), - ); + child: Center( + child: Text('${date.day}', style: textStyle), // TODO: localization + ), + ), + ); } @override @@ -200,6 +193,7 @@ class DisabledDay extends StatelessWidget { final class FCalendarDayStyle with Diagnosticable { /// The selected dates' style. final FCalendarDayStateStyle selectedStyle; + /// The unselected dates' style. final FCalendarDayStateStyle unselectedStyle; @@ -339,5 +333,6 @@ final class FCalendarDayStateStyle with Diagnosticable { focusedTextStyle == other.focusedTextStyle; @override - int get hashCode => backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; + int get hashCode => + backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; } diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 98190380e..008afc05a 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -2,11 +2,11 @@ part of '../calendar.dart'; /// The maximum number of rows in a month. In this case, a 31 day month that starts on Saturday. @internal -const maxGridRows = 7; +const maxDayPickerGridRows = 7; /// The height & width of a day in a [DayPicker]. @internal -const dayDimension = 42.0; +const maxDayPickerTileDimension = 42.0; @internal class DayPicker extends StatefulWidget { @@ -84,7 +84,7 @@ class _DayPickerState extends State { @override Widget build(BuildContext context) => SizedBox( - width: DateTime.daysPerWeek * dayDimension, + width: DateTime.daysPerWeek * maxDayPickerTileDimension, child: GridView.custom( padding: EdgeInsets.zero, shrinkWrap: true, @@ -149,11 +149,11 @@ class _GridDelegate extends SliverGridDelegate { @override SliverGridLayout getLayout(SliverConstraints constraints) => SliverGridRegularTileLayout( - childCrossAxisExtent: dayDimension, - childMainAxisExtent: dayDimension, + childCrossAxisExtent: maxDayPickerTileDimension, + childMainAxisExtent: maxDayPickerTileDimension, crossAxisCount: DateTime.daysPerWeek, - crossAxisStride: dayDimension, - mainAxisStride: dayDimension, + crossAxisStride: maxDayPickerTileDimension, + mainAxisStride: maxDayPickerTileDimension, reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), ); diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 0080a652b..c5e552f72 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -7,7 +7,7 @@ class PagedDayPicker extends PagedPicker { final ValueChanged onPress; final ValueChanged onLongPress; - const PagedDayPicker({ + PagedDayPicker({ required this.selectedPredicate, required this.onMonthChange, required this.onPress, @@ -17,9 +17,11 @@ class PagedDayPicker extends PagedPicker { required super.end, required super.today, required super.initial, - required super.enabledPredicate, + required bool Function(LocalDate) enabledPredicate, super.key, - }); + }) : super( + enabledPredicate: (date) => start <= date && date <= end && enabledPredicate(date), + ); @override State createState() => _PageDayPickerState(); @@ -39,19 +41,19 @@ class _PageDayPickerState extends PagedPickerState { late TextDirection _textDirection; @override - Widget buildItem(BuildContext context, int index) => DayPicker( - focused: _focused, + Widget buildItem(BuildContext context, int page) => DayPicker( + focused: focusedDate, style: widget.style.dayPickerStyle, - month: widget.start.truncate(to: DateUnit.months).plus(months: index), + month: widget.start.truncate(to: DateUnit.months).plus(months: page), today: widget.today, - enabledPredicate: (date) => widget.start <= date && date <= widget.end && widget.enabledPredicate(date), + enabledPredicate: widget.enabledPredicate, selectedPredicate: widget.selectedPredicate, onPress: (date) { - setState(() => _focused = date); + setState(() => focusedDate = date); widget.onPress(date); }, onLongPress: (date) { - setState(() => _focused = date); + setState(() => focusedDate = date); widget.onLongPress(date); }, ); @@ -66,13 +68,37 @@ class _PageDayPickerState extends PagedPickerState { @override void handleGridFocusChange(bool focused) { setState(() { - if (focused && _focused == null) { + if (focused && focusedDate == null) { final preferred = widget.today.truncate(to: DateUnit.months) == current ? widget.today.day : 1; - _focused = _focusableDayForMonth(current, preferred); + focusedDate = _focusableDayForMonth(current, preferred); } }); } + @override + void handlePageChange(int page) { + setState(() { + final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); + if (current == changed) { + return; + } + + current = changed; + widget.onMonthChange?.call(current.toNative()); + if (focusedDate case final focused? when focused.truncate(to: DateUnit.months) == current) { + // We have navigated to a new month with the grid focused, but the + // focused day is not in this month. Choose a new one trying to keep + // the same day of the month. + focusedDate = _focusableDayForMonth(current, focusedDate!.day); + } + + SemanticsService.announce( + current.toString(), // TODO: localization + _textDirection, + ); + }); + } + /// Returns a focusable date for the given month. /// /// If the preferredDay is available in the month it will be returned, @@ -97,30 +123,6 @@ class _PageDayPickerState extends PagedPickerState { return null; } - @override - void handlePageChange(int page) { - setState(() { - final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); - if (current == changed) { - return; - } - - current = changed; - widget.onMonthChange?.call(current.toNative()); - if (_focused case final focused? when focused.truncate(to: DateUnit.months) == current) { - // We have navigated to a new month with the grid focused, but the - // focused day is not in this month. Choose a new one trying to keep - // the same day of the month. - _focused = _focusableDayForMonth(current, _focused!.day); - } - - SemanticsService.announce( - current.toString(), // TODO: localization - _textDirection, - ); - }); - } - @override int delta(LocalDate start, LocalDate end) => (end.year - start.year) * 12 + end.month - start.month; diff --git a/forui/lib/src/widgets/calendar/paged_picker.dart b/forui/lib/src/widgets/calendar/paged_picker.dart index 6f4aa0427..88848f1be 100644 --- a/forui/lib/src/widgets/calendar/paged_picker.dart +++ b/forui/lib/src/widgets/calendar/paged_picker.dart @@ -27,14 +27,14 @@ abstract class PagedPicker extends StatefulWidget { ..add(DiagnosticsProperty('start', start)) ..add(DiagnosticsProperty('end', end)) ..add(DiagnosticsProperty('today', today)) - ..add(DiagnosticsProperty('initial', initial)); + ..add(DiagnosticsProperty('initial', initial)) + ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)); } } // Most of the traversal logic is copied from Material's _MonthPickerState. @internal abstract class PagedPickerState extends State { - static const _shortcuts = { SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), @@ -42,12 +42,12 @@ abstract class PagedPickerState extends State { SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), }; - final GlobalKey _pageViewKey = GlobalKey(); late LocalDate current; + LocalDate? focusedDate; + final GlobalKey _pageViewKey = GlobalKey(); late PageController _controller; late Map> _actions; late FocusNode _gridFocusNode; - LocalDate? _focused; @override void initState() { @@ -64,31 +64,31 @@ abstract class PagedPickerState extends State { @override Widget build(BuildContext context) => Column( - children: [ - Controls( - style: widget.style.headerStyle, - onPrevious: _first ? null : _handlePrevious, - onNext: _last ? null : _handleNext, - ), - Expanded( - child: FocusableActionDetector( - shortcuts: _shortcuts, - actions: _actions, - focusNode: _gridFocusNode, - onFocusChange: handleGridFocusChange, - child: PageView.builder( - key: _pageViewKey, - controller: _controller, - itemBuilder: buildItem, - itemCount: delta(widget.start, widget.end), - onPageChanged: handlePageChange, + children: [ + Controls( + style: widget.style.headerStyle, + onPrevious: _first ? null : _handlePrevious, + onNext: _last ? null : _handleNext, + ), + Expanded( + child: FocusableActionDetector( + shortcuts: _shortcuts, + actions: _actions, + focusNode: _gridFocusNode, + onFocusChange: handleGridFocusChange, + child: PageView.builder( + key: _pageViewKey, + controller: _controller, + itemBuilder: buildItem, + itemCount: delta(widget.start, widget.end) + 1, + onPageChanged: handlePageChange, + ), + ), ), - ), - ), - ], - ); + ], + ); - Widget buildItem(BuildContext context, int index); + Widget buildItem(BuildContext context, int page); @override void dispose() { @@ -97,6 +97,14 @@ abstract class PagedPickerState extends State { super.dispose(); } + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('current', current)) + ..add(DiagnosticsProperty('focusedDate', focusedDate)) + ..add(DiagnosticsProperty('directionOffset', directionOffset)); + } void _handleNext() { if (!_last) { @@ -132,7 +140,6 @@ abstract class PagedPickerState extends State { void handleGridFocusChange(bool focused); - /// Move focus to the next element after the day grid. void _handleGridNextFocus(NextFocusIntent intent) { _gridFocusNode @@ -147,7 +154,6 @@ abstract class PagedPickerState extends State { ..previousFocus(); } - /// Move the internal focus date in the direction of the given intent. /// /// This will attempt to move the focused day to the next selectable day in @@ -158,13 +164,14 @@ abstract class PagedPickerState extends State { /// on the current [TextDirection]). For vertical directions it will move up and /// down a week at a time. void _handleDirectionFocus(DirectionalFocusIntent intent) { - assert(_focused != null, 'Cannot move focus without a focused day.'); + assert(focusedDate != null, 'Cannot move focus without a focused day.'); setState(() { - final nextDate = _nextDateInDirection(_focused!, intent.direction); + final nextDate = _nextDateInDirection(focusedDate!, intent.direction); if (nextDate != null) { - _focused = nextDate; - if (delta(widget.start, _focused!) != delta(widget.start, current)) { - _showPage(_focused!); + focusedDate = nextDate; + print(focusedDate); + if (delta(widget.start, focusedDate!) != delta(widget.start, current)) { + _showPage(focusedDate!); } } }); @@ -193,7 +200,6 @@ abstract class PagedPickerState extends State { return null; } - int delta(LocalDate start, LocalDate end); Map get directionOffset; diff --git a/forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart b/forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart new file mode 100644 index 000000000..02c440163 --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart @@ -0,0 +1,101 @@ +part of '../calendar.dart'; + +@internal +class PagedYearPicker extends PagedPicker { + final ValueChanged onPress; + + PagedYearPicker({ + required this.onPress, + required super.style, + required super.start, + required super.end, + required super.today, + required super.initial, + super.key, + }) : super(enabledPredicate: (date) => start <= date && date <= end); + + @override + State createState() => _PagedYearPickerState(); +} + +class _PagedYearPickerState extends PagedPickerState { + late TextDirection _textDirection; + + @override + Widget buildItem(BuildContext context, int page) => YearPicker( + style: widget.style.yearMonthPickerStyle, + startYear: widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems), + start: widget.start, + end: widget.end, + today: widget.today, + focused: focusedDate, + onPress: widget.onPress, + ); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _textDirection = Directionality.of(context); + } + + @override + void handleGridFocusChange(bool focused) { + setState(() { + if (focused && focusedDate == null) { + final currentYear = widget.today.truncate(to: DateUnit.years); + focusedDate = _focusableYear(current, currentYear == current ? currentYear : current); + } + }); + } + + @override + void handlePageChange(int page) { + setState(() { + print('handled'); + + final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems); + if (current == changed) { + return; + } + + current = changed; + if (focusedDate case final focused? when focused.truncate(to: DateUnit.years) == current) { + // We have navigated to a new page with the grid focused, but the + // focused year is not in this page. Choose a new one. + focusedDate = _focusableYear(current, focusedDate!); + } + + SemanticsService.announce( + current.toString(), // TODO: localization + _textDirection, + ); + }); + } + + LocalDate? _focusableYear(LocalDate startYear, LocalDate preferredYear) { + final endYear = startYear.plus(years: yearMonthPickerItems); + if (startYear <= preferredYear && preferredYear < endYear) { + return preferredYear; + } + + // Start at the 1st and take the first enabled date. + for (var newFocus = startYear; newFocus < endYear; newFocus = newFocus.plus(years: 1)) { + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + return null; + } + + @override + int delta(LocalDate start, LocalDate end) => ((end.year - start.year) / yearMonthPickerItems).floor(); + + @override + Map get directionOffset => const { + TraversalDirection.up: Period(years: -yearMonthPickerColumns), + TraversalDirection.right: Period(years: 1), + TraversalDirection.down: Period(years: yearMonthPickerColumns), + TraversalDirection.left: Period(years: -1), + }; +} diff --git a/forui/lib/src/widgets/calendar/year_month/year_month.dart b/forui/lib/src/widgets/calendar/year_month/year_month.dart index 88ac41e44..eecd33ac0 100644 --- a/forui/lib/src/widgets/calendar/year_month/year_month.dart +++ b/forui/lib/src/widgets/calendar/year_month/year_month.dart @@ -5,6 +5,7 @@ part of '../calendar.dart'; Widget yearMonth( FCalendarYearMonthPickerStyle pickerStyle, LocalDate date, + FocusNode focusNode, ValueChanged onPress, String Function(LocalDate) localize, { required bool enabled, @@ -15,6 +16,7 @@ Widget yearMonth( return EnabledYearMonth( style: style, date: date, + focusNode: focusNode, onPress: onPress, localize: localize, current: current, @@ -33,6 +35,7 @@ Widget yearMonth( class EnabledYearMonth extends StatefulWidget { final FCalendarYearMonthPickerStateStyle style; final LocalDate date; + final FocusNode focusNode; final bool current; final ValueChanged onPress; final String Function(LocalDate) localize; @@ -40,6 +43,7 @@ class EnabledYearMonth extends StatefulWidget { const EnabledYearMonth({ required this.style, required this.date, + required this.focusNode, required this.current, required this.onPress, required this.localize, @@ -55,6 +59,7 @@ class EnabledYearMonth extends StatefulWidget { properties ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) ..add(FlagProperty('current', value: current, ifTrue: 'current', level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('localize', localize, level: DiagnosticLevel.debug)); @@ -62,35 +67,60 @@ class EnabledYearMonth extends StatefulWidget { } class _EnabledYearMonthState extends State { + bool _focused = false; bool _hovered = false; + @override + void initState() { + super.initState(); + widget.focusNode.addListener(_updateFocused); + } + + @override + void didUpdateWidget(EnabledYearMonth old) { + super.didUpdateWidget(old); + old.focusNode.removeListener(_updateFocused); + widget.focusNode.addListener(_updateFocused); + } + @override Widget build(BuildContext context) { - var textStyle = _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; + var textStyle = _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; if (widget.current) { textStyle = textStyle.copyWith(decoration: TextDecoration.underline); } - return MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => _hovered = true), - onExit: (_) => setState(() => _hovered = false), - child: Semantics( - label: widget.localize(widget.date), - button: true, - excludeSemantics: true, - child: GestureDetector( - onTap: () => widget.onPress(widget.date), - child: DecoratedBox( - decoration: _hovered ? widget.style.focusedDecoration : widget.style.decoration, - child: Center( - child: Text(widget.localize(widget.date), style: textStyle), + return Focus( + focusNode: widget.focusNode, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), + child: Semantics( + label: widget.localize(widget.date), + button: true, + excludeSemantics: true, + child: GestureDetector( + onTap: () => widget.onPress(widget.date), + child: DecoratedBox( + decoration: _focused || _hovered ? widget.style.focusedDecoration : widget.style.decoration, + child: Center( + child: Text(widget.localize(widget.date), style: textStyle), + ), ), ), ), ), ); } + + @override + void dispose() { + widget.focusNode.removeListener(_updateFocused); + super.dispose(); + } + + void _updateFocused() => setState(() => _focused = widget.focusNode.hasFocus); } @internal @@ -148,7 +178,7 @@ final class FCalendarYearMonthPickerStyle with Diagnosticable { decoration: const BoxDecoration(), textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), focusedDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), + borderRadius: BorderRadius.circular(8), color: colorScheme.secondary, ), ), diff --git a/forui/lib/src/widgets/calendar/year_month/year_picker.dart b/forui/lib/src/widgets/calendar/year_month/year_picker.dart index 6f7b28cbe..204a75ef2 100644 --- a/forui/lib/src/widgets/calendar/year_month/year_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month/year_picker.dart @@ -1,18 +1,34 @@ part of '../calendar.dart'; +/// The number of columns in a year & month picker. +@internal +const yearMonthPickerColumns = 3; + +/// The number of rows in a year & month picker. +@internal +const yearMonthPickerRows = 4; + +/// The total number of items in a year & month picker. +@internal +const yearMonthPickerItems = yearMonthPickerColumns * yearMonthPickerRows; + @internal class YearPicker extends StatefulWidget { - final FCalendarStyle style; + final FCalendarYearMonthPickerStyle style; + final LocalDate startYear; final LocalDate start; final LocalDate end; - final LocalDate current; + final LocalDate today; + final LocalDate? focused; final ValueChanged onPress; const YearPicker({ required this.style, + required this.startYear, required this.start, required this.end, - required this.current, + required this.today, + required this.focused, required this.onPress, super.key, }); @@ -22,87 +38,66 @@ class YearPicker extends StatefulWidget { } class _YearPickerState extends State { - static const _columns = 3; - - static int delta(LocalDate start, LocalDate end) => ((end.year - start.year + 1) / 12).ceil(); - - final GlobalKey key = GlobalKey(); - late LocalDate _current; - late PageController _controller; + late List _years; @override void initState() { super.initState(); - _current = widget.current.truncate(to: DateUnit.years); - _controller = PageController(initialPage: delta(widget.start, widget.end)); + _years = List.generate(yearMonthPickerItems, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); + + final focused = widget.focused; + + + if (focused == null || focused < widget.startYear || widget.startYear.plus(years: yearMonthPickerItems) <= focused) { + return; + } + + _years[focused.year - widget.startYear.year].requestFocus(); } @override - Widget build(BuildContext context) { - final initial = widget.start.truncate(to: DateUnit.years); - return Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Controls( - style: widget.style.headerStyle, - onPrevious: _first ? null : _handlePrevious, - onNext: _last ? null : _handleNext, - ), + Widget build(BuildContext context) => GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: yearMonthPickerColumns, + childAspectRatio: 1.618, ), - Expanded( - child: PageView.builder( - key: key, - controller: _controller, - itemBuilder: (context, index) => GridView( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - childAspectRatio: 1.618, - ), - children: [ - for (var year = initial.plus(years: index * 12), i = 0; i < 12; year = year.plus(years: 1), i++) - yearMonth( - widget.style.yearMonthPickerStyle, - year, - widget.onPress, - (date) => '${date.year}', // TODO: localize - enabled: widget.start <= year && year <= widget.end, - current: widget.current.year == year.year, - ) - ], + children: [ + for (var year = widget.startYear, i = 0; i < yearMonthPickerItems; year = year.plus(years: 1), i++) + yearMonth( + widget.style, + year, + _years[i], + widget.onPress, + (date) => '${date.year}', // TODO: localize + enabled: widget.start <= year && year <= widget.end, + current: widget.today.year == year.year, ), - itemCount: delta(widget.start, widget.end), - ), - ), - ], + ], + ); + + @override + void didUpdateWidget(YearPicker old) { + super.didUpdateWidget(old); + assert( + old.startYear == widget.startYear, + 'We assumed that a new YearPicker is created each time we navigate to a years page.', ); - } - /// Navigate to the next month. - void _handleNext() { - if (!_last) { - _controller.nextPage( - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); + final focused = widget.focused; + if (focused == null || focused < widget.startYear || widget.startYear.plus(years: yearMonthPickerItems) <= focused) { + return; } - } - /// Navigate to the previous month. - void _handlePrevious() { - if (!_first) { - _controller.previousPage( - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); + if (_years[focused.year - widget.startYear.year] case final focusNode when old.focused != widget.focused) { + focusNode.requestFocus(); } } - /// True if the earliest allowable years are displayed. - bool get _first => delta(widget.start, _current) == 0; - - /// True if the latest allowable years are displayed. - bool get _last { - return delta(widget.start, _current) == delta(widget.start, widget.end); + @override + void dispose() { + for (final node in _years) { + node.dispose(); + } + super.dispose(); } } From e54302be56b1b429090b96ff6a79314756407e78 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 11 Jul 2024 15:30:12 +0800 Subject: [PATCH 20/35] First fully working prototype --- forui/example/lib/main.dart | 2 +- forui/lib/src/widgets/calendar/calendar.dart | 72 +++++++++----- forui/lib/src/widgets/calendar/toggle.dart | 63 ++++++++++-- .../year_month/month/month_picker.dart | 99 +++++++++++++++++++ .../year_month/month/paged_month_picker.dart | 99 +++++++++++++++++++ .../{ => year}/paged_year_picker.dart | 4 +- .../year_month/{ => year}/year_picker.dart | 28 +++--- .../calendar/year_month/year_month.dart | 24 ----- .../year_month/year_month_picker.dart | 91 +++++++++++++++++ 9 files changed, 407 insertions(+), 75 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/year_month/month/month_picker.dart create mode 100644 forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart rename forui/lib/src/widgets/calendar/year_month/{ => year}/paged_year_picker.dart (98%) rename forui/lib/src/widgets/calendar/year_month/{ => year}/year_picker.dart (76%) create mode 100644 forui/lib/src/widgets/calendar/year_month/year_month_picker.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 9f104fd01..964568f6b 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -54,7 +54,7 @@ class Testing extends StatelessWidget { start: LocalDate(1900, 1, 8), end: LocalDate(2024, 7, 10), today: LocalDate.now(), - initialMonth: LocalDate(2024, 7), + initialMonth: LocalDate(2023, 7), enabledPredicate: (_) => true, selectedPredicate: _selected.contains, onMonthChange: print, diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 52f410cce..cd5439302 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,4 +1,6 @@ import 'dart:collection'; +import 'dart:ffi'; +import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -6,16 +8,18 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; -import 'package:sugar/sugar.dart'; -import 'package:sugar/time.dart'; +import 'package:sugar/sugar.dart' hide Offset; part 'day/day.dart'; part 'day/day_picker.dart'; part 'day/paged_day_picker.dart'; -part 'year_month/paged_year_picker.dart'; part 'year_month/year_month.dart'; -part 'year_month/year_picker.dart'; +part 'year_month/year_month_picker.dart'; +part 'year_month/month/month_picker.dart'; +part 'year_month/month/paged_month_picker.dart'; +part 'year_month/year/paged_year_picker.dart'; +part 'year_month/year/year_picker.dart'; part 'controls.dart'; part 'paged_picker.dart'; @@ -59,15 +63,17 @@ class Calendar extends StatefulWidget { State createState() => _CalendarState(); } -class _CalendarState extends State { - late FCalendarPickerMode mode; +class _CalendarState extends State with TickerProviderStateMixin { + late ValueNotifier mode; late LocalDate month; + late AnimationController _yearMonthPickerController; @override void initState() { super.initState(); - mode = FCalendarPickerMode.yearMonth; // TODO: + mode = ValueNotifier(widget.initialMode); month = widget.initialMonth; + _yearMonthPickerController = AnimationController(vsync: this, duration: const Duration(milliseconds: 200)); } @override @@ -81,29 +87,45 @@ class _CalendarState extends State { child: Stack( alignment: Alignment.topCenter, children: [ - switch (mode) { - FCalendarPickerMode.day => PagedDayPicker( + ValueListenableBuilder( + valueListenable: mode, + builder: (context, value, child) => switch (value) { + FCalendarPickerMode.day => PagedDayPicker( + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initial: month.truncate(to: DateUnit.months), + enabledPredicate: widget.enabledPredicate, + selectedPredicate: widget.selectedPredicate, + onMonthChange: (month) { + print('called'); + setState(() { + this.month = month.toLocalDate(); + }); + widget.onMonthChange?.call(month); + }, + onPress: widget.onPress, + onLongPress: widget.onLongPress, + ), + FCalendarPickerMode.yearMonth => YearMonthPicker( style: widget.style, start: widget.start, end: widget.end, today: widget.today, - initial: widget.initialMonth.truncate(to: DateUnit.months), - enabledPredicate: widget.enabledPredicate, - selectedPredicate: widget.selectedPredicate, - onMonthChange: widget.onMonthChange, - onPress: widget.onPress, - onLongPress: widget.onLongPress, + onMonthChange: (date) => setState(() { + mode.value = FCalendarPickerMode.day; + month = date; + }), ), - FCalendarPickerMode.yearMonth => PagedYearPicker( - style: widget.style, - start: widget.start, - end: widget.end, - today: widget.today, - initial: widget.initialMonth.truncate(to: DateUnit.years), - onPress: print, - ), - }, - Toggle(style: widget.style, month: month), + }, + ), + Toggle( + style: widget.style, + month: month, + mode: mode, + yearMonthPickerController: _yearMonthPickerController, + ), ], ), ), diff --git a/forui/lib/src/widgets/calendar/toggle.dart b/forui/lib/src/widgets/calendar/toggle.dart index dae2bf047..4295b45af 100644 --- a/forui/lib/src/widgets/calendar/toggle.dart +++ b/forui/lib/src/widgets/calendar/toggle.dart @@ -7,27 +7,76 @@ const toggleHeight = 31.0; class Toggle extends StatefulWidget { final FCalendarStyle style; final LocalDate month; + final ValueNotifier mode; + final AnimationController yearMonthPickerController; const Toggle({ super.key, required this.style, required this.month, + required this.mode, + required this.yearMonthPickerController, }); @override State createState() => _ToggleState(); } -class _ToggleState extends State { +class _ToggleState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 100)); + widget.mode.addListener(() { + if (_controller.isCompleted) { + _controller.reverse(); + } else { + widget.yearMonthPickerController.forward(); + _controller.forward(); + } + }); + } + @override Widget build(BuildContext context) => SizedBox( height: toggleHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('${widget.month.month} ${widget.month.year}', style: widget.style.headerStyle.headerTextStyle), - ], + child: GestureDetector( + onTap: () { + final value = widget.mode.value; + if (value == FCalendarPickerMode.day) { + widget.mode.value = FCalendarPickerMode.yearMonth; + } else { + widget.mode.value = FCalendarPickerMode.day; + } + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${widget.month.month} ${widget.month.year}', style: widget.style.headerStyle.headerTextStyle), // TODO: Localization + RotationTransition( + turns: Tween(begin: 0.0, end: 0.25).animate(_controller), + child: Padding( + padding: const EdgeInsets.all(2.0), + child: FAssets.icons.chevronRight( + height: 15, + colorFilter: ColorFilter.mode( + context.theme.colorScheme.primary, + BlendMode.srcIn, + ), + ), + ), + ), + ], + ), ), - ); // TODO: Localization + ); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } } diff --git a/forui/lib/src/widgets/calendar/year_month/month/month_picker.dart b/forui/lib/src/widgets/calendar/year_month/month/month_picker.dart new file mode 100644 index 000000000..346b0a97e --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/month/month_picker.dart @@ -0,0 +1,99 @@ +part of '../../calendar.dart'; + +@internal +class MonthPicker extends StatefulWidget { + final FCalendarYearMonthPickerStyle style; + final LocalDate currentYear; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final LocalDate? focused; + final ValueChanged onPress; + + const MonthPicker({ + required this.style, + required this.currentYear, + required this.start, + required this.end, + required this.today, + required this.focused, + required this.onPress, + super.key, + }); + + @override + State createState() => _MonthPickerState(); + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('currentYear', currentYear, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('start', start, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('end', end, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('today', today, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('focused', focused, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)); + } +} + +class _MonthPickerState extends State { + late List _months; + + @override + void initState() { + super.initState(); + _months = List.generate(12, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); + + final focused = widget.focused; + if (focused != null) { + _months[focused.month - 1].requestFocus(); + } + } + + @override + Widget build(BuildContext context) => GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: yearMonthPickerColumns, + childAspectRatio: 1.618, + ), + children: [ + for (var month = widget.currentYear, i = 0; i < 12; month = month.plus(months: 1), i++) + yearMonth( + widget.style, + month, + _months[i], + widget.onPress, + (date) => '${date.month}', // TODO: localize + enabled: widget.start <= month && month <= widget.end, + current: widget.today.truncate(to: DateUnit.months) == month, + ), + ], + ); + + @override + void didUpdateWidget(MonthPicker old) { + super.didUpdateWidget(old); + assert( + old.currentYear == widget.currentYear, + 'We assumed that a new YearPicker is created each time we navigate to a years page.', + ); + + final focused = widget.focused; + if (focused == null || focused < widget.currentYear || widget.currentYear.plus(years: 1) <= focused) { + return; + } + + if (_months[focused.month - 1] case final focusNode when old.focused != widget.focused) { + focusNode.requestFocus(); + } + } + + @override + void dispose() { + for (final node in _months) { + node.dispose(); + } + super.dispose(); + } +} diff --git a/forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart b/forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart new file mode 100644 index 000000000..7a451ec25 --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart @@ -0,0 +1,99 @@ +part of '../../calendar.dart'; + +@internal +class PagedMonthPicker extends PagedPicker { + final ValueChanged onPress; + + PagedMonthPicker({ + required this.onPress, + required super.style, + required super.start, + required super.end, + required super.today, + required super.initial, + super.key, + }) : super(enabledPredicate: (date) => start <= date && date <= end); + + @override + State createState() => _PagedMonthPickerState(); +} + +class _PagedMonthPickerState extends PagedPickerState { + late TextDirection _textDirection; + + @override + Widget buildItem(BuildContext context, int page) => MonthPicker( + style: widget.style.yearMonthPickerStyle, + currentYear: widget.initial, + start: widget.start, + end: widget.end, + today: widget.today, + focused: focusedDate, + onPress: widget.onPress, + ); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _textDirection = Directionality.of(context); + } + + @override + void handleGridFocusChange(bool focused) { + setState(() { + if (focused && focusedDate == null) { + final currentMonth = widget.today.truncate(to: DateUnit.months); + focusedDate = _focusableMonth(widget.initial.year == widget.today.year ? currentMonth : current); + } + }); + } + + @override + void handlePageChange(int page) { + setState(() { + print('handlePageChange'); + // final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems); + // if (current == changed) { + // return; + // } + // + // current = changed; + // if (focusedDate case final focused? when focused.truncate(to: DateUnit.years) == current) { + // // We have navigated to a new page with the grid focused, but the + // // focused year is not in this page. Choose a new one. + // focusedDate = _focusableMonth(current, focusedDate!); + // } + + SemanticsService.announce( + current.toString(), // TODO: localization + _textDirection, + ); + }); + } + + LocalDate? _focusableMonth(LocalDate preferredMonth) { + final end = widget.initial.plus(years: 1); + if (widget.initial <= preferredMonth && preferredMonth < end) { + return preferredMonth; + } + + for (var newFocus = widget.initial; newFocus < end; newFocus = newFocus.plus(months: 1)) { + if (widget.enabledPredicate(newFocus)) { + return newFocus; + } + } + + return null; + } + + @override + int delta(LocalDate start, LocalDate end) => 0; + + @override + Map get directionOffset => const { + TraversalDirection.up: Period(months: -yearMonthPickerColumns), + TraversalDirection.right: Period(months: 1), + TraversalDirection.down: Period(months: yearMonthPickerColumns), + TraversalDirection.left: Period(months: -1), + }; +} \ No newline at end of file diff --git a/forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart b/forui/lib/src/widgets/calendar/year_month/year/paged_year_picker.dart similarity index 98% rename from forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart rename to forui/lib/src/widgets/calendar/year_month/year/paged_year_picker.dart index 02c440163..54a29b202 100644 --- a/forui/lib/src/widgets/calendar/year_month/paged_year_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month/year/paged_year_picker.dart @@ -1,4 +1,4 @@ -part of '../calendar.dart'; +part of '../../calendar.dart'; @internal class PagedYearPicker extends PagedPicker { @@ -51,8 +51,6 @@ class _PagedYearPickerState extends PagedPickerState { @override void handlePageChange(int page) { setState(() { - print('handled'); - final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems); if (current == changed) { return; diff --git a/forui/lib/src/widgets/calendar/year_month/year_picker.dart b/forui/lib/src/widgets/calendar/year_month/year/year_picker.dart similarity index 76% rename from forui/lib/src/widgets/calendar/year_month/year_picker.dart rename to forui/lib/src/widgets/calendar/year_month/year/year_picker.dart index 204a75ef2..786037591 100644 --- a/forui/lib/src/widgets/calendar/year_month/year_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month/year/year_picker.dart @@ -1,16 +1,4 @@ -part of '../calendar.dart'; - -/// The number of columns in a year & month picker. -@internal -const yearMonthPickerColumns = 3; - -/// The number of rows in a year & month picker. -@internal -const yearMonthPickerRows = 4; - -/// The total number of items in a year & month picker. -@internal -const yearMonthPickerItems = yearMonthPickerColumns * yearMonthPickerRows; +part of '../../calendar.dart'; @internal class YearPicker extends StatefulWidget { @@ -35,6 +23,18 @@ class YearPicker extends StatefulWidget { @override State createState() => _YearPickerState(); + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('startYear', startYear, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('start', start, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('end', end, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('today', today, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('focused', focused, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)); + } } class _YearPickerState extends State { @@ -46,8 +46,6 @@ class _YearPickerState extends State { _years = List.generate(yearMonthPickerItems, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); final focused = widget.focused; - - if (focused == null || focused < widget.startYear || widget.startYear.plus(years: yearMonthPickerItems) <= focused) { return; } diff --git a/forui/lib/src/widgets/calendar/year_month/year_month.dart b/forui/lib/src/widgets/calendar/year_month/year_month.dart index eecd33ac0..9873ed116 100644 --- a/forui/lib/src/widgets/calendar/year_month/year_month.dart +++ b/forui/lib/src/widgets/calendar/year_month/year_month.dart @@ -166,30 +166,6 @@ class DisabledYearMonth extends StatelessWidget { } } -final class FCalendarYearMonthPickerStyle with Diagnosticable { - final FCalendarYearMonthPickerStateStyle enabledStyle; - final FCalendarYearMonthPickerStateStyle disabledStyle; - - FCalendarYearMonthPickerStyle({required this.enabledStyle, required this.disabledStyle}); - - FCalendarYearMonthPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) - : this( - enabledStyle: FCalendarYearMonthPickerStateStyle( - decoration: const BoxDecoration(), - textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), - focusedDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: colorScheme.secondary, - ), - ), - disabledStyle: FCalendarYearMonthPickerStateStyle( - decoration: const BoxDecoration(), - textStyle: typography.sm - .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), - ), - ); -} - final class FCalendarYearMonthPickerStateStyle with Diagnosticable { final BoxDecoration decoration; final TextStyle textStyle; diff --git a/forui/lib/src/widgets/calendar/year_month/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month/year_month_picker.dart new file mode 100644 index 000000000..d30be3ca4 --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month/year_month_picker.dart @@ -0,0 +1,91 @@ +part of '../calendar.dart'; + +/// The number of columns in a year & month picker. +@internal +const yearMonthPickerColumns = 3; + +/// The number of rows in a year & month picker. +@internal +const yearMonthPickerRows = 4; + +/// The total number of items in a year & month picker. +@internal +const yearMonthPickerItems = yearMonthPickerColumns * yearMonthPickerRows; + +class YearMonthPicker extends StatefulWidget { + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final ValueChanged onMonthChange; + + const YearMonthPicker({ + required this.style, + required this.start, + required this.end, + required this.today, + required this.onMonthChange, + super.key, + }); + + @override + State createState() => _YearMonthPickerState(); +} + +class _YearMonthPickerState extends State { + LocalDate? _date; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + if (_date == null) { + return PagedYearPicker( + onPress: (year) => setState(() { + _date = year; + }), + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initial: widget.today.truncate(to: DateUnit.years), + ); + } else { + return PagedMonthPicker( + onPress: widget.onMonthChange, + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initial: _date!, + ); + } + } +} + +final class FCalendarYearMonthPickerStyle with Diagnosticable { + final FCalendarYearMonthPickerStateStyle enabledStyle; + final FCalendarYearMonthPickerStateStyle disabledStyle; + + FCalendarYearMonthPickerStyle({required this.enabledStyle, required this.disabledStyle}); + + FCalendarYearMonthPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : this( + enabledStyle: FCalendarYearMonthPickerStateStyle( + decoration: const BoxDecoration(), + textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), + focusedDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: colorScheme.secondary, + ), + ), + disabledStyle: FCalendarYearMonthPickerStateStyle( + decoration: const BoxDecoration(), + textStyle: typography.sm + .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), + ), + ); +} From 19667d7c4109f7b6076fdf06b16904fe3199cc86 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 11 Jul 2024 16:43:55 +0800 Subject: [PATCH 21/35] WIP refactor --- forui/example/pubspec.lock | 16 +--- forui/lib/src/foundation/inkwell.dart | 88 +++++++++++++++++++ .../{calendar => old_calendar}/calendar.dart | 0 .../{calendar => old_calendar}/controls.dart | 0 .../{calendar => old_calendar}/day/day.dart | 0 .../day/day_picker.dart | 0 .../day/paged_day_picker.dart | 0 .../paged_picker.dart | 0 .../{calendar => old_calendar}/toggle.dart | 0 .../year_month/month/month_picker.dart | 0 .../year_month/month/paged_month_picker.dart | 0 .../year_month/year/paged_year_picker.dart | 0 .../year_month/year/year_picker.dart | 0 .../year_month/year_month.dart | 0 .../year_month/year_month_picker.dart | 0 forui/lib/widgets.dart | 1 - 16 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 forui/lib/src/foundation/inkwell.dart rename forui/lib/src/widgets/{calendar => old_calendar}/calendar.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/controls.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/day/day.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/day/day_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/day/paged_day_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/paged_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/toggle.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/month/month_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/month/paged_month_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/year/paged_year_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/year/year_picker.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/year_month.dart (100%) rename forui/lib/src/widgets/{calendar => old_calendar}/year_month/year_month_picker.dart (100%) diff --git a/forui/example/pubspec.lock b/forui/example/pubspec.lock index 26fa81a28..a6a869abf 100644 --- a/forui/example/pubspec.lock +++ b/forui/example/pubspec.lock @@ -458,10 +458,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.6" + version: "2.2.7" path_provider_foundation: dependency: transitive description: @@ -490,10 +490,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -723,14 +723,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" - win32: - dependency: transitive - description: - name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 - url: "https://pub.dev" - source: hosted - version: "5.5.1" xdg_directories: dependency: transitive description: diff --git a/forui/lib/src/foundation/inkwell.dart b/forui/lib/src/foundation/inkwell.dart new file mode 100644 index 000000000..d82599f12 --- /dev/null +++ b/forui/lib/src/foundation/inkwell.dart @@ -0,0 +1,88 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:meta/meta.dart'; + +@internal +class FInkWell extends StatefulWidget { + final FocusNode? focusNode; + final String semanticLabel; + final bool selected; + final VoidCallback? onPress; + final VoidCallback? onLongPress; + final ValueWidgetBuilder builder; + final Widget? child; + + const FInkWell({ + required this.semanticLabel, + required this.builder, + this.focusNode, + this.selected = false, + this.onPress, + this.onLongPress, + this.child, + super.key, + }); + + @override + State createState() => _FInkWellState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('semanticLabel', semanticLabel, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) + ..add(FlagProperty('selected', value: selected, ifTrue: 'selected', level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('onLongPress', onLongPress, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('builder', builder, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('child', child, level: DiagnosticLevel.debug)); + } +} + +class _FInkWellState extends State { + bool _focused = false; + bool _hovered = false; + + @override + void initState() { + super.initState(); + widget.focusNode?.addListener(_updateFocused); + } + + @override + void didUpdateWidget(FInkWell old) { + super.didUpdateWidget(old); + widget.focusNode?.addListener(_updateFocused); + old.focusNode?.removeListener(_updateFocused); + } + + @override + Widget build(BuildContext context) => Focus( + focusNode: widget.focusNode, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => setState(() => _hovered = true), + onExit: (_) => setState(() => _hovered = false), + child: Semantics( + label: widget.semanticLabel, + button: true, + selected: widget.selected, + excludeSemantics: true, + child: GestureDetector( + onTap: widget.onPress, + onLongPress: widget.onLongPress, + child: widget.builder(context, _focused || _hovered, widget.child), + ), + ), + ), + ); + + @override + void dispose() { + widget.focusNode?.removeListener(_updateFocused); + super.dispose(); + } + + void _updateFocused() => setState(() => _focused = widget.focusNode?.hasFocus ?? false); +} diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/old_calendar/calendar.dart similarity index 100% rename from forui/lib/src/widgets/calendar/calendar.dart rename to forui/lib/src/widgets/old_calendar/calendar.dart diff --git a/forui/lib/src/widgets/calendar/controls.dart b/forui/lib/src/widgets/old_calendar/controls.dart similarity index 100% rename from forui/lib/src/widgets/calendar/controls.dart rename to forui/lib/src/widgets/old_calendar/controls.dart diff --git a/forui/lib/src/widgets/calendar/day/day.dart b/forui/lib/src/widgets/old_calendar/day/day.dart similarity index 100% rename from forui/lib/src/widgets/calendar/day/day.dart rename to forui/lib/src/widgets/old_calendar/day/day.dart diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/old_calendar/day/day_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/day/day_picker.dart rename to forui/lib/src/widgets/old_calendar/day/day_picker.dart diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/old_calendar/day/paged_day_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/day/paged_day_picker.dart rename to forui/lib/src/widgets/old_calendar/day/paged_day_picker.dart diff --git a/forui/lib/src/widgets/calendar/paged_picker.dart b/forui/lib/src/widgets/old_calendar/paged_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/paged_picker.dart rename to forui/lib/src/widgets/old_calendar/paged_picker.dart diff --git a/forui/lib/src/widgets/calendar/toggle.dart b/forui/lib/src/widgets/old_calendar/toggle.dart similarity index 100% rename from forui/lib/src/widgets/calendar/toggle.dart rename to forui/lib/src/widgets/old_calendar/toggle.dart diff --git a/forui/lib/src/widgets/calendar/year_month/month/month_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/month/month_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/month/month_picker.dart rename to forui/lib/src/widgets/old_calendar/year_month/month/month_picker.dart diff --git a/forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/month/paged_month_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/month/paged_month_picker.dart rename to forui/lib/src/widgets/old_calendar/year_month/month/paged_month_picker.dart diff --git a/forui/lib/src/widgets/calendar/year_month/year/paged_year_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/year/paged_year_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/year/paged_year_picker.dart rename to forui/lib/src/widgets/old_calendar/year_month/year/paged_year_picker.dart diff --git a/forui/lib/src/widgets/calendar/year_month/year/year_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/year/year_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/year/year_picker.dart rename to forui/lib/src/widgets/old_calendar/year_month/year/year_picker.dart diff --git a/forui/lib/src/widgets/calendar/year_month/year_month.dart b/forui/lib/src/widgets/old_calendar/year_month/year_month.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/year_month.dart rename to forui/lib/src/widgets/old_calendar/year_month/year_month.dart diff --git a/forui/lib/src/widgets/calendar/year_month/year_month_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart similarity index 100% rename from forui/lib/src/widgets/calendar/year_month/year_month_picker.dart rename to forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart diff --git a/forui/lib/widgets.dart b/forui/lib/widgets.dart index 20d18c64a..25e657a06 100644 --- a/forui/lib/widgets.dart +++ b/forui/lib/widgets.dart @@ -4,7 +4,6 @@ library forui.widgets; export 'src/widgets/badge/badge.dart' hide Variant; export 'src/widgets/button/button.dart' hide Variant; export 'src/widgets/card/card.dart'; -export 'src/widgets/calendar/calendar.dart'; export 'src/widgets/checkbox.dart'; export 'src/widgets/dialog/dialog.dart'; export 'src/widgets/header/header.dart'; From 23616317910206bf7315e20344a04bd8b56d217d Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 11 Jul 2024 22:37:12 +0800 Subject: [PATCH 22/35] Add tests for inkwell --- forui/lib/src/foundation/inkwell.dart | 4 +- forui/test/src/foundation/inkwell_test.dart | 83 +++++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 forui/test/src/foundation/inkwell_test.dart diff --git a/forui/lib/src/foundation/inkwell.dart b/forui/lib/src/foundation/inkwell.dart index d82599f12..31f45e7fe 100644 --- a/forui/lib/src/foundation/inkwell.dart +++ b/forui/lib/src/foundation/inkwell.dart @@ -5,7 +5,7 @@ import 'package:meta/meta.dart'; @internal class FInkWell extends StatefulWidget { final FocusNode? focusNode; - final String semanticLabel; + final String? semanticLabel; final bool selected; final VoidCallback? onPress; final VoidCallback? onLongPress; @@ -13,9 +13,9 @@ class FInkWell extends StatefulWidget { final Widget? child; const FInkWell({ - required this.semanticLabel, required this.builder, this.focusNode, + this.semanticLabel, this.selected = false, this.onPress, this.onLongPress, diff --git a/forui/test/src/foundation/inkwell_test.dart b/forui/test/src/foundation/inkwell_test.dart new file mode 100644 index 000000000..59e045b4c --- /dev/null +++ b/forui/test/src/foundation/inkwell_test.dart @@ -0,0 +1,83 @@ +import 'dart:math'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/foundation/inkwell.dart'; + +import '../test_scaffold.dart'; + +void main() { + group('FInkWell', () { + testWidgets('focused', (tester) async { + final focusNode = FocusNode(); + + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FInkWell( + focusNode: focusNode, + builder: (_, value, __) => Text('$value'), + ), + ), + ); + expect(find.text('false'), findsOneWidget); + + focusNode.requestFocus(); + await tester.pumpAndSettle(); + expect(find.text('true'), findsOneWidget); + }); + + testWidgets('hovered', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FInkWell( + builder: (_, value, __) => Text('$value'), + ), + ), + ); + expect(find.text('false'), findsOneWidget); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(tester.getCenter(find.byType(FInkWell))); + await tester.pumpAndSettle(); + + expect(find.text('true'), findsOneWidget); + + await gesture.moveTo(Offset.zero); + await tester.pumpAndSettle(); + + expect(find.text('false'), findsOneWidget); + }); + + testWidgets('semantics', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FInkWell( + semanticLabel: 'My Label', + selected: true, + builder: (_, value, __) => Text('$value'), + ), + ), + ); + + final semantics = tester.getSemantics(find.byType(FInkWell)); + expect( + semantics, + matchesSemantics( + label: 'My Label', + isButton: true, + isSelected: true, + isFocusable: true, + ), + ); + }); + }); +} From d5a066cbfcb6420f93461af95b08927dace65faf Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Fri, 12 Jul 2024 23:12:56 +0800 Subject: [PATCH 23/35] Refactor calendar --- forui/example/lib/main.dart | 8 +- forui/lib/src/widgets/calendar/calendar.dart | 229 ++++++++++++ .../day/day_picker.dart | 201 +++++++---- .../day/paged_day_picker.dart | 74 ++-- .../month/month_picker.dart | 42 ++- .../month/paged_month_picker.dart | 55 +-- .../src/widgets/calendar/shared/entry.dart | 283 +++++++++++++++ .../src/widgets/calendar/shared/header.dart | 256 +++++++++++++ .../shared}/paged_picker.dart | 118 +++--- .../year/paged_year_picker.dart | 47 ++- .../year/year_picker.dart | 41 ++- .../widgets/calendar/year_month_picker.dart | 138 +++++++ .../src/widgets/old_calendar/calendar.dart | 169 --------- .../src/widgets/old_calendar/controls.dart | 143 -------- .../lib/src/widgets/old_calendar/day/day.dart | 338 ------------------ .../lib/src/widgets/old_calendar/toggle.dart | 82 ----- .../old_calendar/year_month/year_month.dart | 182 ---------- .../year_month/year_month_picker.dart | 91 ----- forui/pubspec.yaml | 1 + forui/test/src/foundation/inkwell_test.dart | 2 - 20 files changed, 1230 insertions(+), 1270 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/calendar.dart rename forui/lib/src/widgets/{old_calendar => calendar}/day/day_picker.dart (65%) rename forui/lib/src/widgets/{old_calendar => calendar}/day/paged_day_picker.dart (72%) rename forui/lib/src/widgets/{old_calendar/year_month => calendar}/month/month_picker.dart (71%) rename forui/lib/src/widgets/{old_calendar/year_month => calendar}/month/paged_month_picker.dart (57%) create mode 100644 forui/lib/src/widgets/calendar/shared/entry.dart create mode 100644 forui/lib/src/widgets/calendar/shared/header.dart rename forui/lib/src/widgets/{old_calendar => calendar/shared}/paged_picker.dart (66%) rename forui/lib/src/widgets/{old_calendar/year_month => calendar}/year/paged_year_picker.dart (69%) rename forui/lib/src/widgets/{old_calendar/year_month => calendar}/year/year_picker.dart (69%) create mode 100644 forui/lib/src/widgets/calendar/year_month_picker.dart delete mode 100644 forui/lib/src/widgets/old_calendar/calendar.dart delete mode 100644 forui/lib/src/widgets/old_calendar/controls.dart delete mode 100644 forui/lib/src/widgets/old_calendar/day/day.dart delete mode 100644 forui/lib/src/widgets/old_calendar/toggle.dart delete mode 100644 forui/lib/src/widgets/old_calendar/year_month/year_month.dart delete mode 100644 forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 964568f6b..d664140ce 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -53,11 +53,11 @@ class Testing extends StatelessWidget { style: FCalendarStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography, style: context.theme.style), start: LocalDate(1900, 1, 8), end: LocalDate(2024, 7, 10), - today: LocalDate.now(), + current: LocalDate.now(), initialMonth: LocalDate(2023, 7), - enabledPredicate: (_) => true, - selectedPredicate: _selected.contains, - onMonthChange: print, + enabled: (_) => true, + selected: _selected.contains, + date: print, onPress: print, onLongPress: print, ); diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart new file mode 100644 index 000000000..ed929410f --- /dev/null +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -0,0 +1,229 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/calendar/day/day_picker.dart'; +import 'package:forui/src/widgets/calendar/day/paged_day_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/header.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; +import 'package:sugar/sugar.dart'; + +class FCalendar extends StatelessWidget { + + @override + Widget build(BuildContext context) { + // TODO: implement build + throw UnimplementedError(); + } + +} + +class _Calendar extends StatelessWidget { + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final ValueNotifier type; + final ValueNotifier month; + final Predicate enabled; + final Predicate selected; + final ValueChanged onMonthChange; + final ValueChanged onPress; + final ValueChanged onLongPress; + + const _Calendar({ + required this.style, + required this.start, + required this.end, + required this.today, + required this.type, + required this.month, + required this.enabled, + required this.selected, + required this.onMonthChange, + required this.onPress, + required this.onLongPress, + }); + + @override + Widget build(BuildContext context) => DecoratedBox( + decoration: style.decoration, + child: Padding( + padding: style.padding, + child: SizedBox( + height: (DayPicker.maxRows * DayPicker.tileDimension) + Header.height + 5, + width: DateTime.daysPerWeek * DayPicker.tileDimension, + child: Stack( + alignment: Alignment.topCenter, + children: [ + ValueListenableBuilder( + valueListenable: month, + builder: (context, month, child) => Header( + style: style.headerStyle, + type: type, + month: month, + ), + ), + ValueListenableBuilder( + valueListenable: type, + builder: (context, value, child) => switch (value) { + FCalendarPickerType.day => PagedDayPicker( + style: style, + start: start, + end: end, + today: today, + initial: month.value.truncate(to: DateUnit.months), + enabled: enabled, + selected: selected, + onMonthChange: (date) { + month.value = date; + onMonthChange(date); + }, + onPress: onPress, + onLongPress: onLongPress, + ), + FCalendarPickerType.yearMonth => YearMonthPicker( + style: style, + start: start, + end: end, + today: today, + onChange: (date) { + month.value = date; + type.value = FCalendarPickerType.day; + }, + ), + }, + ), + ], + ), + ), + ), + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('start', start)) + ..add(DiagnosticsProperty('end', end)) + ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('type', type)) + ..add(DiagnosticsProperty('month', month)) + ..add(DiagnosticsProperty('enabled', enabled)) + ..add(DiagnosticsProperty('selected', selected)) + ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) + ..add(DiagnosticsProperty('onPress', onPress)) + ..add(DiagnosticsProperty('onLongPress', onLongPress)); + } +} + +/// The calendar's style. +final class FCalendarStyle with Diagnosticable { + /// The header's style. + final FCalendarHeaderStyle headerStyle; + + /// The day picker's style. + final FCalendarDayPickerStyle dayPickerStyle; + + /// The year/month picker's style. + final FCalendarYearMonthPickerStyle yearMonthPickerStyle; + + /// The decoration surrounding the header & picker. + final BoxDecoration decoration; + + /// The padding surrounding the header & picker. Defaults to `const EdgeInsets.symmetric(horizontal: 12, vertical: 16)`. + final EdgeInsets padding; + + /// The duration of the page switch animation. Defaults to 200 milliseconds. + final Duration pageAnimationDuration; + + /// Creates a new [FCalendarStyle]. + FCalendarStyle({ + required this.headerStyle, + required this.dayPickerStyle, + required this.yearMonthPickerStyle, + required this.decoration, + this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + this.pageAnimationDuration = const Duration(milliseconds: 200), + }); + + /// Creates a [FCalendarStyle] that inherits the color scheme and typography. + FCalendarStyle.inherit({ + required FColorScheme colorScheme, + required FTypography typography, + required FStyle style, + }) : this( + headerStyle: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), + dayPickerStyle: FCalendarDayPickerStyle.inherit(colorScheme: colorScheme, typography: typography), + yearMonthPickerStyle: FCalendarYearMonthPickerStyle.inherit(colorScheme: colorScheme, typography: typography), + decoration: BoxDecoration( + borderRadius: style.borderRadius, + border: Border.all(color: colorScheme.border), + color: colorScheme.background, + ), + ); + + /// Returns a copy of this [FCalendarStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarStyle( + /// headerStyle: ..., + /// dayPickerStyle: ..., + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith(dayPickerStyle: ...); + /// + /// print(style.headerStyle == copy.headerStyle); // true + /// print(style.dayPickerStyle == copy.dayPickerStyle); // false + /// ``` + FCalendarStyle copyWith({ + FCalendarHeaderStyle? headerStyle, + FCalendarDayPickerStyle? dayPickerStyle, + FCalendarYearMonthPickerStyle? yearMonthPickerStyle, + BoxDecoration? decoration, + EdgeInsets? padding, + Duration? pageAnimationDuration, + }) => + FCalendarStyle( + headerStyle: headerStyle ?? this.headerStyle, + dayPickerStyle: dayPickerStyle ?? this.dayPickerStyle, + yearMonthPickerStyle: yearMonthPickerStyle ?? this.yearMonthPickerStyle, + decoration: decoration ?? this.decoration, + padding: padding ?? this.padding, + pageAnimationDuration: pageAnimationDuration ?? this.pageAnimationDuration, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('headerStyle', headerStyle)) + ..add(DiagnosticsProperty('dayPickerStyle', dayPickerStyle)) + ..add(DiagnosticsProperty('yearMonthPickerStyle', yearMonthPickerStyle)) + ..add(DiagnosticsProperty('decoration', decoration)) + ..add(DiagnosticsProperty('padding', padding)) + ..add(DiagnosticsProperty('pageAnimationDuration', pageAnimationDuration)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarStyle && + runtimeType == other.runtimeType && + headerStyle == other.headerStyle && + dayPickerStyle == other.dayPickerStyle && + yearMonthPickerStyle == other.yearMonthPickerStyle && + decoration == other.decoration && + padding == other.padding && + pageAnimationDuration == other.pageAnimationDuration; + + @override + int get hashCode => + headerStyle.hashCode ^ + dayPickerStyle.hashCode ^ + yearMonthPickerStyle.hashCode ^ + decoration.hashCode ^ + padding.hashCode ^ + pageAnimationDuration.hashCode; +} diff --git a/forui/lib/src/widgets/old_calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart similarity index 65% rename from forui/lib/src/widgets/old_calendar/day/day_picker.dart rename to forui/lib/src/widgets/calendar/day/day_picker.dart index 008afc05a..268734b0b 100644 --- a/forui/lib/src/widgets/old_calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -1,21 +1,24 @@ -part of '../calendar.dart'; +import 'dart:collection'; -/// The maximum number of rows in a month. In this case, a 31 day month that starts on Saturday. -@internal -const maxDayPickerGridRows = 7; - -/// The height & width of a day in a [DayPicker]. -@internal -const maxDayPickerTileDimension = 42.0; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal class DayPicker extends StatefulWidget { + static const maxRows = 7; + static const tileDimension = 42.0; + final FCalendarDayPickerStyle style; final LocalDate month; final LocalDate today; final LocalDate? focused; - final bool Function(LocalDate day) enabledPredicate; - final bool Function(LocalDate day) selectedPredicate; + final Predicate enabled; + final Predicate selected; final ValueChanged onPress; final ValueChanged onLongPress; @@ -24,8 +27,8 @@ class DayPicker extends StatefulWidget { required this.month, required this.today, required this.focused, - required this.enabledPredicate, - required this.selectedPredicate, + required this.enabled, + required this.selected, required this.onPress, required this.onLongPress, super.key, @@ -42,10 +45,10 @@ class DayPicker extends StatefulWidget { ..add(DiagnosticsProperty('month', month)) ..add(DiagnosticsProperty('today', today)) ..add(DiagnosticsProperty('focused', focused)) - ..add(ObjectFlagProperty('enabledPredicate', enabledPredicate, ifNull: 'null')) - ..add(ObjectFlagProperty('selectedPredicate', selectedPredicate, ifNull: 'null')) - ..add(ObjectFlagProperty('onPress', onPress, ifNull: 'null')) - ..add(ObjectFlagProperty('onLongPress', onLongPress, ifNull: 'null')); + ..add(DiagnosticsProperty('enabledPredicate', enabled, ifNull: 'all enabled')) + ..add(DiagnosticsProperty('selectedPredicate', selected, ifNull: 'none selected')) + ..add(DiagnosticsProperty('onPress', onPress)) + ..add(DiagnosticsProperty('onLongPress', onLongPress)); } } @@ -56,6 +59,17 @@ class _DayPickerState extends State { void initState() { super.initState(); + final (first, last) = _range; + for (var date = first; date <= last; date = date.tomorrow) { + _days[date] = FocusNode(skipTraversal: true, debugLabel: '$date'); + } + + if (_days[widget.focused] case final focusNode?) { + focusNode.requestFocus(); + } + } + + (LocalDate, LocalDate) get _range { final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization final firstDayOfMonth = widget.month.firstDayOfMonth; var difference = firstDayOfMonth.weekday - firstDayOfWeek; @@ -73,44 +87,39 @@ class _DayPickerState extends State { } final last = lastDayOfMonth.plus(days: difference); - for (var date = first; date <= last; date = date.tomorrow) { - _days[date] = FocusNode(skipTraversal: true, debugLabel: '$date'); - } - if (_days[widget.focused] case final focusNode?) { - focusNode.requestFocus(); - } + return (first, last); } + @override Widget build(BuildContext context) => SizedBox( - width: DateTime.daysPerWeek * maxDayPickerTileDimension, - child: GridView.custom( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const _GridDelegate(), - childrenDelegate: SliverChildListDelegate( - [ - ..._headers(context), - for (final MapEntry(key: date, value: focusNode) in _days.entries) - day( - widget.style, - date, - focusNode, - widget.selectedPredicate, - widget.onPress, - widget.onLongPress, - enabled: widget.enabledPredicate(date), - current: date.month == widget.month.month, - today: date == widget.today, - selected: widget.selectedPredicate(date), - ), - ], - addRepaintBoundaries: false, - ), + width: DateTime.daysPerWeek * DayPicker.tileDimension, + child: GridView.custom( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const _GridDelegate(), + childrenDelegate: SliverChildListDelegate( + addRepaintBoundaries: false, + [ + ..._headers(context), + for (final MapEntry(key: date, value: focusNode) in _days.entries) + Entry.day( + style: widget.style, + date: date, + focusNode: focusNode, + current: date.month == widget.month.month, + today: date == widget.today, + enabled: widget.enabled, + selected: widget.selected, + onPress: widget.onPress, + onLongPress: widget.onLongPress, + ), + ], ), - ); + ), + ); List _headers(BuildContext context) { final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization @@ -127,7 +136,7 @@ class _DayPickerState extends State { @override void didUpdateWidget(DayPicker old) { super.didUpdateWidget(old); - assert(old.month == widget.month, 'We assumed that a new DayPicker is created each time we navigate to a new month.'); + assert(old.month == widget.month, 'current month must not change.'); if (_days[widget.focused] case final focusNode? when old.focused != widget.focused) { focusNode.requestFocus(); @@ -149,18 +158,19 @@ class _GridDelegate extends SliverGridDelegate { @override SliverGridLayout getLayout(SliverConstraints constraints) => SliverGridRegularTileLayout( - childCrossAxisExtent: maxDayPickerTileDimension, - childMainAxisExtent: maxDayPickerTileDimension, - crossAxisCount: DateTime.daysPerWeek, - crossAxisStride: maxDayPickerTileDimension, - mainAxisStride: maxDayPickerTileDimension, - reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), - ); + childCrossAxisExtent: DayPicker.tileDimension, + childMainAxisExtent: DayPicker.tileDimension, + crossAxisCount: DateTime.daysPerWeek, + crossAxisStride: DayPicker.tileDimension, + mainAxisStride: DayPicker.tileDimension, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); @override bool shouldRelayout(_GridDelegate oldDelegate) => false; } + /// A day picker's style. final class FCalendarDayPickerStyle with Diagnosticable { /// The text style for the day of th week headers. @@ -200,11 +210,11 @@ final class FCalendarDayPickerStyle with Diagnosticable { typography.sm.copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500); final disabled = FCalendarDayStyle( - selectedStyle: FCalendarDayStateStyle.inherit( + selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), - unselectedStyle: FCalendarDayStateStyle.inherit( + unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: mutedTextStyle, ), @@ -214,32 +224,29 @@ final class FCalendarDayPickerStyle with Diagnosticable { headerTextStyle: typography.xs.copyWith(color: colorScheme.mutedForeground), enabledStyles: ( current: FCalendarDayStyle( - selectedStyle: FCalendarDayStateStyle.inherit( + selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.foreground, textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), ), - unselectedStyle: FCalendarDayStateStyle.inherit( + unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: textStyle, focusedBackgroundColor: colorScheme.secondary, ), ), enclosing: FCalendarDayStyle( - selectedStyle: FCalendarDayStateStyle.inherit( + selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, ), - unselectedStyle: FCalendarDayStateStyle.inherit( + unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: mutedTextStyle, focusedBackgroundColor: colorScheme.primaryForeground, ), ), ), - disabledStyles: ( - current: disabled, - enclosing: disabled, - ), + disabledStyles: (current: disabled, enclosing: disabled), ); } @@ -303,5 +310,65 @@ final class FCalendarDayPickerStyle with Diagnosticable { startDayOfWeek == other.startDayOfWeek; @override - int get hashCode => headerTextStyle.hashCode ^ enabledStyles.hashCode ^ disabledStyles.hashCode ^ startDayOfWeek.hashCode; + int get hashCode => + headerTextStyle.hashCode ^ enabledStyles.hashCode ^ disabledStyles.hashCode ^ startDayOfWeek.hashCode; +} + +/// A calender day's style. +final class FCalendarDayStyle with Diagnosticable { + /// The selected dates' style. + final FCalendarEntryStyle selectedStyle; + + /// The unselected dates' style. + final FCalendarEntryStyle unselectedStyle; + + /// Creates a [FCalendarDayStyle]. + const FCalendarDayStyle({ + required this.unselectedStyle, + required this.selectedStyle, + }); + + /// Returns a copy of this [FCalendarDayStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarDayStyle( + /// selectedStyle: ..., + /// unselectedStyle: ..., + /// // Other arguments omitted for brevity + /// ); + /// + /// final copy = style.copyWith( + /// unselectedStyle: ..., + /// ); + /// + /// print(style.selectedStyle == copy.selectedStyle); // true + /// print(style.unselectedStyle == copy.unselectedStyle); // false + /// ``` + FCalendarDayStyle copyWith({ + FCalendarEntryStyle? selectedStyle, + FCalendarEntryStyle? unselectedStyle, + }) => + FCalendarDayStyle( + selectedStyle: selectedStyle ?? this.selectedStyle, + unselectedStyle: unselectedStyle ?? this.unselectedStyle, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('selectedStyle', selectedStyle)) + ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarDayStyle && + runtimeType == other.runtimeType && + unselectedStyle == other.unselectedStyle && + selectedStyle == other.selectedStyle; + + @override + int get hashCode => unselectedStyle.hashCode ^ selectedStyle.hashCode; } diff --git a/forui/lib/src/widgets/old_calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart similarity index 72% rename from forui/lib/src/widgets/old_calendar/day/paged_day_picker.dart rename to forui/lib/src/widgets/calendar/day/paged_day_picker.dart index c5e552f72..9ec611d66 100644 --- a/forui/lib/src/widgets/old_calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,14 +1,20 @@ -part of '../calendar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/day/day_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal class PagedDayPicker extends PagedPicker { - final bool Function(LocalDate day) selectedPredicate; - final ValueChanged? onMonthChange; + final Predicate selected; + final ValueChanged? onMonthChange; final ValueChanged onPress; final ValueChanged onLongPress; PagedDayPicker({ - required this.selectedPredicate, + required this.selected, required this.onMonthChange, required this.onPress, required this.onLongPress, @@ -17,37 +23,33 @@ class PagedDayPicker extends PagedPicker { required super.end, required super.today, required super.initial, - required bool Function(LocalDate) enabledPredicate, + required super.enabled, super.key, - }) : super( - enabledPredicate: (date) => start <= date && date <= end && enabledPredicate(date), - ); + }); @override - State createState() => _PageDayPickerState(); + State createState() => _PagedDayPickerState(); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)) + ..add(DiagnosticsProperty('selectedPredicate', selected)) ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) ..add(DiagnosticsProperty('onPress', onPress)) ..add(DiagnosticsProperty('onLongPress', onLongPress)); } } -class _PageDayPickerState extends PagedPickerState { - late TextDirection _textDirection; - +class _PagedDayPickerState extends PagedPickerState { @override Widget buildItem(BuildContext context, int page) => DayPicker( - focused: focusedDate, style: widget.style.dayPickerStyle, month: widget.start.truncate(to: DateUnit.months).plus(months: page), today: widget.today, - enabledPredicate: widget.enabledPredicate, - selectedPredicate: widget.selectedPredicate, + focused: focusedDate, + enabled: widget.enabled, + selected: widget.selected, onPress: (date) { setState(() => focusedDate = date); widget.onPress(date); @@ -59,24 +61,7 @@ class _PageDayPickerState extends PagedPickerState { ); @override - void didChangeDependencies() { - super.didChangeDependencies(); - _textDirection = Directionality.of(context); - } - - /// Handler for when the overall day grid obtains or loses focus. - @override - void handleGridFocusChange(bool focused) { - setState(() { - if (focused && focusedDate == null) { - final preferred = widget.today.truncate(to: DateUnit.months) == current ? widget.today.day : 1; - focusedDate = _focusableDayForMonth(current, preferred); - } - }); - } - - @override - void handlePageChange(int page) { + void onPageChange(int page) { setState(() { final changed = widget.start.truncate(to: DateUnit.months).plus(months: page); if (current == changed) { @@ -84,7 +69,7 @@ class _PageDayPickerState extends PagedPickerState { } current = changed; - widget.onMonthChange?.call(current.toNative()); + widget.onMonthChange?.call(current); if (focusedDate case final focused? when focused.truncate(to: DateUnit.months) == current) { // We have navigated to a new month with the grid focused, but the // focused day is not in this month. Choose a new one trying to keep @@ -92,10 +77,17 @@ class _PageDayPickerState extends PagedPickerState { focusedDate = _focusableDayForMonth(current, focusedDate!.day); } - SemanticsService.announce( - current.toString(), // TODO: localization - _textDirection, - ); + SemanticsService.announce(current.toString(), textDirection); // TODO: localization + }); + } + + @override + void onGridFocusChange(bool focused) { + setState(() { + if (focused && focusedDate == null) { + final preferred = widget.today.truncate(to: DateUnit.months) == current ? widget.today.day : 1; + focusedDate = _focusableDayForMonth(current, preferred); + } }); } @@ -108,14 +100,14 @@ class _PageDayPickerState extends PagedPickerState { // Can we use the preferred day in this month? if (preferredDay <= month.daysInMonth) { final newFocus = month.copyWith(day: preferredDay); - if (widget.enabledPredicate(newFocus)) { + if (widget.enabled(newFocus)) { return newFocus; } } // Start at the 1st and take the first enabled date. for (var newFocus = month; newFocus.month == month.month; newFocus = newFocus.tomorrow) { - if (widget.enabledPredicate(newFocus)) { + if (widget.enabled(newFocus)) { return newFocus; } } diff --git a/forui/lib/src/widgets/old_calendar/year_month/month/month_picker.dart b/forui/lib/src/widgets/calendar/month/month_picker.dart similarity index 71% rename from forui/lib/src/widgets/old_calendar/year_month/month/month_picker.dart rename to forui/lib/src/widgets/calendar/month/month_picker.dart index 346b0a97e..cad228eb8 100644 --- a/forui/lib/src/widgets/old_calendar/year_month/month/month_picker.dart +++ b/forui/lib/src/widgets/calendar/month/month_picker.dart @@ -1,7 +1,17 @@ -part of '../../calendar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; + +final _yMMMM = DateFormat.yMMMM(); @internal class MonthPicker extends StatefulWidget { + static const columns = 3; + final FCalendarYearMonthPickerStyle style; final LocalDate currentYear; final LocalDate start; @@ -10,7 +20,7 @@ class MonthPicker extends StatefulWidget { final LocalDate? focused; final ValueChanged onPress; - const MonthPicker({ + MonthPicker({ required this.style, required this.currentYear, required this.start, @@ -19,7 +29,7 @@ class MonthPicker extends StatefulWidget { required this.focused, required this.onPress, super.key, - }); + }): assert(currentYear == currentYear.truncate(to: DateUnit.years), 'currentYear must be truncated to years'); @override State createState() => _MonthPickerState(); @@ -45,28 +55,27 @@ class _MonthPickerState extends State { super.initState(); _months = List.generate(12, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); - final focused = widget.focused; - if (focused != null) { - _months[focused.month - 1].requestFocus(); + if (widget.focused != null) { + _months[widget.focused!.month - 1].requestFocus(); } } @override Widget build(BuildContext context) => GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: yearMonthPickerColumns, + crossAxisCount: MonthPicker.columns, childAspectRatio: 1.618, ), children: [ for (var month = widget.currentYear, i = 0; i < 12; month = month.plus(months: 1), i++) - yearMonth( - widget.style, - month, - _months[i], - widget.onPress, - (date) => '${date.month}', // TODO: localize - enabled: widget.start <= month && month <= widget.end, + Entry.yearMonth( + style: widget.style, + date: month, + focusNode: _months[i], current: widget.today.truncate(to: DateUnit.months) == month, + enabled: widget.start <= month && month <= widget.end, + format: (date) => _yMMMM.format(date.toNative()), // TODO: localize + onPress: widget.onPress, ), ], ); @@ -74,10 +83,7 @@ class _MonthPickerState extends State { @override void didUpdateWidget(MonthPicker old) { super.didUpdateWidget(old); - assert( - old.currentYear == widget.currentYear, - 'We assumed that a new YearPicker is created each time we navigate to a years page.', - ); + assert(old.currentYear == widget.currentYear, 'currentYear must not change.'); final focused = widget.focused; if (focused == null || focused < widget.currentYear || widget.currentYear.plus(years: 1) <= focused) { diff --git a/forui/lib/src/widgets/old_calendar/year_month/month/paged_month_picker.dart b/forui/lib/src/widgets/calendar/month/paged_month_picker.dart similarity index 57% rename from forui/lib/src/widgets/old_calendar/year_month/month/paged_month_picker.dart rename to forui/lib/src/widgets/calendar/month/paged_month_picker.dart index 7a451ec25..118be0be2 100644 --- a/forui/lib/src/widgets/old_calendar/year_month/month/paged_month_picker.dart +++ b/forui/lib/src/widgets/calendar/month/paged_month_picker.dart @@ -1,4 +1,9 @@ -part of '../../calendar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/month/month_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal class PagedMonthPicker extends PagedPicker { @@ -12,15 +17,19 @@ class PagedMonthPicker extends PagedPicker { required super.today, required super.initial, super.key, - }) : super(enabledPredicate: (date) => start <= date && date <= end); + }); @override State createState() => _PagedMonthPickerState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('onPress', onPress)); + } } class _PagedMonthPickerState extends PagedPickerState { - late TextDirection _textDirection; - @override Widget buildItem(BuildContext context, int page) => MonthPicker( style: widget.style.yearMonthPickerStyle, @@ -33,13 +42,10 @@ class _PagedMonthPickerState extends PagedPickerState { ); @override - void didChangeDependencies() { - super.didChangeDependencies(); - _textDirection = Directionality.of(context); - } + void onPageChange(int page) {} // Months will only appear on a single page. @override - void handleGridFocusChange(bool focused) { + void onGridFocusChange(bool focused) { setState(() { if (focused && focusedDate == null) { final currentMonth = widget.today.truncate(to: DateUnit.months); @@ -48,29 +54,6 @@ class _PagedMonthPickerState extends PagedPickerState { }); } - @override - void handlePageChange(int page) { - setState(() { - print('handlePageChange'); - // final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems); - // if (current == changed) { - // return; - // } - // - // current = changed; - // if (focusedDate case final focused? when focused.truncate(to: DateUnit.years) == current) { - // // We have navigated to a new page with the grid focused, but the - // // focused year is not in this page. Choose a new one. - // focusedDate = _focusableMonth(current, focusedDate!); - // } - - SemanticsService.announce( - current.toString(), // TODO: localization - _textDirection, - ); - }); - } - LocalDate? _focusableMonth(LocalDate preferredMonth) { final end = widget.initial.plus(years: 1); if (widget.initial <= preferredMonth && preferredMonth < end) { @@ -78,7 +61,7 @@ class _PagedMonthPickerState extends PagedPickerState { } for (var newFocus = widget.initial; newFocus < end; newFocus = newFocus.plus(months: 1)) { - if (widget.enabledPredicate(newFocus)) { + if (widget.enabled(newFocus)) { return newFocus; } } @@ -91,9 +74,9 @@ class _PagedMonthPickerState extends PagedPickerState { @override Map get directionOffset => const { - TraversalDirection.up: Period(months: -yearMonthPickerColumns), + TraversalDirection.up: Period(months: -MonthPicker.columns), TraversalDirection.right: Period(months: 1), - TraversalDirection.down: Period(months: yearMonthPickerColumns), + TraversalDirection.down: Period(months: MonthPicker.columns), TraversalDirection.left: Period(months: -1), }; -} \ No newline at end of file +} diff --git a/forui/lib/src/widgets/calendar/shared/entry.dart b/forui/lib/src/widgets/calendar/shared/entry.dart new file mode 100644 index 000000000..708e5248a --- /dev/null +++ b/forui/lib/src/widgets/calendar/shared/entry.dart @@ -0,0 +1,283 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/foundation/inkwell.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; + +import 'package:forui/src/widgets/calendar/day/day_picker.dart'; + +final _yMMMMd = DateFormat.yMMMMd(); + +@internal +abstract class Entry extends StatelessWidget { + final FCalendarEntryStyle style; + final ValueWidgetBuilder builder; + + factory Entry.day({ + required FCalendarDayPickerStyle style, + required LocalDate date, + required FocusNode focusNode, + required bool current, + required bool today, + required Predicate enabled, + required Predicate selected, + required ValueChanged onPress, + required ValueChanged onLongPress, + }) { + final enable = enabled(date); + final select = selected(date); + + final styles = enable ? style.enabledStyles : style.disabledStyles; + final dayStyle = current ? styles.current : styles.enclosing; + final entryStyle = select ? dayStyle.selectedStyle : dayStyle.unselectedStyle; + + // ignore: avoid_positional_boolean_parameters + Widget builder(BuildContext context, bool focused, Widget? child) => _Content( + style: entryStyle, + borderRadius: BorderRadius.horizontal( + left: selected(date.yesterday) ? Radius.zero : const Radius.circular(4), + right: selected(date.tomorrow) ? Radius.zero : const Radius.circular(4), + ), + text: '${date.day}', // TODO: localization + focused: focused, + current: today, + ); + + if (enabled(date)) { + return _EnabledEntry( + focusNode: focusNode, + date: date, + semanticLabel: '${_yMMMMd.format(date.toNative())}${today ? ', Today' : ''}', + selected: selected(date), + onPress: onPress, + onLongPress: onLongPress, + style: entryStyle, + builder: builder, + ); + } else { + return _DisabledEntry(style: entryStyle, builder: builder); + } + } + + factory Entry.yearMonth({ + required FCalendarYearMonthPickerStyle style, + required LocalDate date, + required FocusNode focusNode, + required bool current, + required bool enabled, + required ValueChanged onPress, + required String Function(LocalDate) format, + }) { + final entryStyle = enabled ? style.enabledStyle : style.disabledStyle; + + // ignore: avoid_positional_boolean_parameters + Widget builder(BuildContext context, bool focused, Widget? child) => _Content( + style: entryStyle, + borderRadius: BorderRadius.circular(8), + text: format(date), + focused: focused, + current: current, + ); + + if (enabled) { + return _EnabledEntry( + focusNode: focusNode, + date: date, + semanticLabel: format(date), + onPress: onPress, + style: entryStyle, + builder: builder, + ); + } else { + return _DisabledEntry(style: entryStyle, builder: builder); + } + } + + const Entry._({ + required this.style, + required this.builder, + }); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('builder', builder)); + } +} + +class _EnabledEntry extends Entry { + final FocusNode focusNode; + final LocalDate date; + final String semanticLabel; + final bool selected; + final ValueChanged onPress; + final ValueChanged? onLongPress; + + const _EnabledEntry({ + required this.focusNode, + required this.date, + required this.semanticLabel, + required this.onPress, + required super.style, + required super.builder, + this.selected = false, + this.onLongPress, + }) : super._(); + + @override + Widget build(BuildContext context) => FInkWell( + focusNode: focusNode, + semanticLabel: semanticLabel, + selected: selected, + onPress: () => onPress(date), + onLongPress: () => onLongPress?.call(date), + builder: builder, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('focusNode', focusNode)) + ..add(DiagnosticsProperty('date', date)) + ..add(StringProperty('semanticLabel', semanticLabel)) + ..add(FlagProperty('selected', value: selected, ifTrue: 'selected')) + ..add(DiagnosticsProperty('onPress', onPress)) + ..add(DiagnosticsProperty('onLongPress', onLongPress)); + } +} + +class _DisabledEntry extends Entry { + const _DisabledEntry({ + required super.style, + required super.builder, + }) : super._(); + + @override + Widget build(BuildContext context) => ExcludeSemantics(child: builder(context, false, null)); +} + +class _Content extends StatelessWidget { + final FCalendarEntryStyle style; + final BorderRadius borderRadius; + final String text; + final bool focused; + final bool current; + + const _Content({ + required this.style, + required this.borderRadius, + required this.text, + required this.focused, + required this.current, + }); + + @override + Widget build(BuildContext context) { + var textStyle = focused ? style.focusedTextStyle : style.textStyle; + if (current) { + textStyle = textStyle.copyWith(decoration: TextDecoration.underline); + } + + return DecoratedBox( + decoration: BoxDecoration( + borderRadius: borderRadius, + color: focused ? style.focusedBackgroundColor : style.backgroundColor, + ), + child: Center( + child: Text(text, style: textStyle), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(StringProperty('text', text)) + ..add(FlagProperty('focused', value: focused, ifTrue: 'focused')) + ..add(FlagProperty('current', value: current, ifTrue: 'current')); + } +} + +/// A calendar entry's style. +final class FCalendarEntryStyle with Diagnosticable { + /// The unfocused day's background color. + final Color backgroundColor; + + /// The unfocused day's text style. + final TextStyle textStyle; + + /// The focused day's background color. Defaults to [backgroundColor]. + final Color focusedBackgroundColor; + + /// The focused day's text style. Defaults to [textStyle]. + final TextStyle focusedTextStyle; + + /// Creates a [FCalendarEntryStyle]. + FCalendarEntryStyle({ + required this.backgroundColor, + required this.textStyle, + Color? focusedBackgroundColor, + TextStyle? focusedTextStyle, + }) : focusedBackgroundColor = focusedBackgroundColor ?? backgroundColor, + focusedTextStyle = focusedTextStyle ?? textStyle; + + /// Returns a copy of this [FCalendarEntryStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarEntryStyle( + /// backgroundColor: ..., + /// textStyle: ..., + /// ); + /// + /// final copy = style.copyWith( + /// textStyle: ..., + /// ); + /// + /// print(style.backgroundColor == copy.backgroundColor); // true + /// print(style.textStyle == copy.textStyle); // false + /// ``` + FCalendarEntryStyle copyWith({ + Color? backgroundColor, + TextStyle? textStyle, + Color? focusedBackgroundColor, + TextStyle? focusedTextStyle, + }) => + FCalendarEntryStyle( + backgroundColor: backgroundColor ?? this.backgroundColor, + textStyle: textStyle ?? this.textStyle, + focusedBackgroundColor: focusedBackgroundColor ?? this.focusedBackgroundColor, + focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(DiagnosticsProperty('textStyle', textStyle)) + ..add(ColorProperty('focusedBackgroundColor', focusedBackgroundColor)) + ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarEntryStyle && + runtimeType == other.runtimeType && + backgroundColor == other.backgroundColor && + textStyle == other.textStyle && + focusedBackgroundColor == other.focusedBackgroundColor && + focusedTextStyle == other.focusedTextStyle; + + @override + int get hashCode => + backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; +} diff --git a/forui/lib/src/widgets/calendar/shared/header.dart b/forui/lib/src/widgets/calendar/shared/header.dart new file mode 100644 index 000000000..facb8e82a --- /dev/null +++ b/forui/lib/src/widgets/calendar/shared/header.dart @@ -0,0 +1,256 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/foundation/inkwell.dart'; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; + +/// The current picker type. +enum FCalendarPickerType { + /// The day picker. + day, + + /// The year-month picker. + yearMonth, +} + +final _yMMMM = DateFormat.yMMMM(); + +@internal +class Header extends StatefulWidget { + static const height = 31.0; + + final FCalendarHeaderStyle style; + final ValueNotifier type; + final LocalDate month; + + const Header({ + required this.style, + required this.type, + required this.month, + super.key, + }); + + @override + State
createState() => _HeaderState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('type', type)) + ..add(DiagnosticsProperty('month', month)); + } +} + +class _HeaderState extends State
with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.style.animationDuration); + widget.type.addListener(_animate); + } + + @override + Widget build(BuildContext context) => SizedBox( + height: Header.height, + child: FInkWell( + onPress: () => widget.type.value = switch (widget.type.value) { + FCalendarPickerType.day => FCalendarPickerType.day, + FCalendarPickerType.yearMonth => FCalendarPickerType.yearMonth, + }, + builder: (context, _, child) => child!, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(_yMMMM.format(widget.month.toNative()), style: widget.style.headerTextStyle), // TODO: Localization + RotationTransition( + turns: Tween(begin: 0.0, end: 0.25).animate(_controller), + child: Padding( + padding: const EdgeInsets.all(2.0), + child: FAssets.icons.chevronRight( + height: 15, + colorFilter: ColorFilter.mode(context.theme.colorScheme.primary, BlendMode.srcIn), + ), + ), + ), + ], + ), + ), + ); + + @override + void didUpdateWidget(Header old) { + super.didUpdateWidget(old); + old.type.removeListener(_animate); + widget.type.addListener(_animate); + } + + @override + void dispose() { + widget.type.removeListener(_animate); + _controller.dispose(); + super.dispose(); + } + + void _animate() { + if (_controller.isCompleted) { + _controller.reverse(); + } else { + _controller.forward(); + } + } +} + +@internal +class Navigation extends StatelessWidget { + final FCalendarHeaderStyle style; + final VoidCallback? onPrevious; + final VoidCallback? onNext; + + const Navigation({ + required this.style, + required this.onPrevious, + required this.onNext, + super.key, + }); + + @override + Widget build(BuildContext context) { + final buttonStyle = context.theme.buttonStyles.outline; + final effectiveButtonStyle = buttonStyle.copyWith( + enabledBoxDecoration: buttonStyle.enabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), + disabledBoxDecoration: buttonStyle.disabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), + ); + + return Padding( + padding: const EdgeInsets.only(bottom: 5), + child: SizedBox( + height: Header.height, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 7), + child: FButton.raw( + // TODO: Replace with FButton.icon. + style: effectiveButtonStyle, + onPress: onPrevious, + child: Padding( + padding: const EdgeInsets.all(7), + child: FAssets.icons.chevronLeft( + height: 17, + colorFilter: ColorFilter.mode(style.iconColor, BlendMode.srcIn), + ), + ), + ), + ), + const Expanded(child: SizedBox()), + Padding( + padding: const EdgeInsets.only(right: 7), + child: FButton.raw( + // TODO: Replace with FButton.icon. + style: effectiveButtonStyle, + onPress: onNext, + child: Padding( + padding: const EdgeInsets.all(7), + child: FAssets.icons.chevronRight( + height: 17, + colorFilter: ColorFilter.mode(style.iconColor, BlendMode.srcIn), + ), + ), + ), + ), + ], + ), + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('onPrevious', onPrevious)) + ..add(DiagnosticsProperty('onNext', onNext)); + } +} + +/// The calendar header's style. +final class FCalendarHeaderStyle with Diagnosticable { + /// The header's text style. + final TextStyle headerTextStyle; + + /// The header icons' color. + final Color iconColor; + + /// The arrow turn animation's duration. Defaults to `Duration(milliseconds: 200)`. + final Duration animationDuration; + + /// Creates a [FCalendarHeaderStyle]. + FCalendarHeaderStyle({ + required this.headerTextStyle, + required this.iconColor, + this.animationDuration = const Duration(milliseconds: 200), + }); + + /// Creates a [FCalendarHeaderStyle] that inherits its values from the given [colorScheme] and [typography]. + FCalendarHeaderStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : this( + headerTextStyle: typography.sm.copyWith(color: colorScheme.primary, fontWeight: FontWeight.w600), + iconColor: colorScheme.mutedForeground, + ); + + /// Creates a copy of this but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarHeaderStyle( + /// headerTextStyle: ..., + /// iconColor:..., + /// // Other arguments omitted for brevity. + /// ); + /// + /// final copy = style.copyWith( + /// iconColor: ..., + /// ); + /// + /// print(style.headerTextStyle == copy.headerTextStyle); // true + /// print(style.iconColor == copy.iconColor); // false + /// ``` + FCalendarHeaderStyle copyWith({ + TextStyle? headerTextStyle, + Color? iconColor, + Duration? animationDuration, + }) => + FCalendarHeaderStyle( + headerTextStyle: headerTextStyle ?? this.headerTextStyle, + iconColor: iconColor ?? this.iconColor, + animationDuration: animationDuration ?? this.animationDuration, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('headerTextStyle', headerTextStyle)) + ..add(ColorProperty('iconColor', iconColor)) + ..add(DiagnosticsProperty('animationDuration', animationDuration)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarHeaderStyle && + runtimeType == other.runtimeType && + headerTextStyle == other.headerTextStyle && + iconColor == other.iconColor && + animationDuration == other.animationDuration; + + @override + int get hashCode => headerTextStyle.hashCode ^ iconColor.hashCode ^ animationDuration.hashCode; +} diff --git a/forui/lib/src/widgets/old_calendar/paged_picker.dart b/forui/lib/src/widgets/calendar/shared/paged_picker.dart similarity index 66% rename from forui/lib/src/widgets/old_calendar/paged_picker.dart rename to forui/lib/src/widgets/calendar/shared/paged_picker.dart index 88848f1be..239ff8b64 100644 --- a/forui/lib/src/widgets/old_calendar/paged_picker.dart +++ b/forui/lib/src/widgets/calendar/shared/paged_picker.dart @@ -1,4 +1,10 @@ -part of 'calendar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/calendar.dart'; +import 'package:forui/src/widgets/calendar/shared/header.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal abstract class PagedPicker extends StatefulWidget { @@ -7,17 +13,18 @@ abstract class PagedPicker extends StatefulWidget { final LocalDate end; final LocalDate today; final LocalDate initial; - final bool Function(LocalDate day) enabledPredicate; + final Predicate enabled; - const PagedPicker({ + PagedPicker({ required this.style, required this.start, required this.end, required this.today, required this.initial, - required this.enabledPredicate, + Predicate? enabled, super.key, - }); + }): + enabled = ((date) => start <= date && date <= end && (enabled?.call(date) ?? true)); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -28,26 +35,27 @@ abstract class PagedPicker extends StatefulWidget { ..add(DiagnosticsProperty('end', end)) ..add(DiagnosticsProperty('today', today)) ..add(DiagnosticsProperty('initial', initial)) - ..add(DiagnosticsProperty('enabledPredicate', enabledPredicate)); + ..add(DiagnosticsProperty('enabledPredicate', enabled)); } } // Most of the traversal logic is copied from Material's _MonthPickerState. @internal abstract class PagedPickerState extends State { - static const _shortcuts = { + static const _shortcuts = { SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), SingleActivator(LogicalKeyboardKey.arrowDown): DirectionalFocusIntent(TraversalDirection.down), SingleActivator(LogicalKeyboardKey.arrowUp): DirectionalFocusIntent(TraversalDirection.up), }; - late LocalDate current; LocalDate? focusedDate; + late LocalDate current; + late TextDirection textDirection; final GlobalKey _pageViewKey = GlobalKey(); late PageController _controller; late Map> _actions; - late FocusNode _gridFocusNode; + late FocusNode _focusNode; @override void initState() { @@ -55,33 +63,33 @@ abstract class PagedPickerState extends State { current = widget.initial; _controller = PageController(initialPage: delta(widget.start, widget.initial)); _actions = { - NextFocusIntent: CallbackAction(onInvoke: _handleGridNextFocus), - PreviousFocusIntent: CallbackAction(onInvoke: _handleGridPreviousFocus), - DirectionalFocusIntent: CallbackAction(onInvoke: _handleDirectionFocus), + NextFocusIntent: CallbackAction(onInvoke: _onGridNextFocus), + PreviousFocusIntent: CallbackAction(onInvoke: _onGridPreviousFocus), + DirectionalFocusIntent: CallbackAction(onInvoke: _onDirectionFocus), }; - _gridFocusNode = FocusNode(debugLabel: 'Grid'); + _focusNode = FocusNode(); } @override Widget build(BuildContext context) => Column( children: [ - Controls( + Navigation( style: widget.style.headerStyle, - onPrevious: _first ? null : _handlePrevious, - onNext: _last ? null : _handleNext, + onPrevious: _first ? null : _onPrevious, + onNext: _last ? null : _onNext, ), Expanded( child: FocusableActionDetector( shortcuts: _shortcuts, actions: _actions, - focusNode: _gridFocusNode, - onFocusChange: handleGridFocusChange, + focusNode: _focusNode, + onFocusChange: onGridFocusChange, child: PageView.builder( key: _pageViewKey, controller: _controller, itemBuilder: buildItem, itemCount: delta(widget.start, widget.end) + 1, - onPageChanged: handlePageChange, + onPageChanged: onPageChange, ), ), ), @@ -90,10 +98,16 @@ abstract class PagedPickerState extends State { Widget buildItem(BuildContext context, int page); + @override + void didChangeDependencies() { + super.didChangeDependencies(); + textDirection = Directionality.of(context); + } + @override void dispose() { _controller.dispose(); - _gridFocusNode.dispose(); + _focusNode.dispose(); super.dispose(); } @@ -103,16 +117,17 @@ abstract class PagedPickerState extends State { properties ..add(DiagnosticsProperty('current', current)) ..add(DiagnosticsProperty('focusedDate', focusedDate)) + ..add(DiagnosticsProperty('textDirection', textDirection)) ..add(DiagnosticsProperty('directionOffset', directionOffset)); } - void _handleNext() { + void _onNext() { if (!_last) { _controller.nextPage(duration: widget.style.pageAnimationDuration, curve: Curves.ease); } } - void _handlePrevious() { + void _onPrevious() { if (!_first) { _controller.previousPage(duration: widget.style.pageAnimationDuration, curve: Curves.ease); } @@ -122,34 +137,30 @@ abstract class PagedPickerState extends State { bool get _last => delta(widget.start, current) == delta(widget.start, widget.end); - /// Navigate to the given month. - void _showPage(LocalDate date, {bool jump = false}) { + void _showPage(LocalDate date) { final page = delta(widget.start, date); - if (jump) { - _controller.jumpToPage(page); - } else { - _controller.animateToPage( - page, - duration: widget.style.pageAnimationDuration, - curve: Curves.ease, - ); - } + _controller.animateToPage( + page, + duration: widget.style.pageAnimationDuration, + curve: Curves.ease, + ); } - void handlePageChange(int page); + void onPageChange(int page); - void handleGridFocusChange(bool focused); + // ignore: avoid_positional_boolean_parameters + void onGridFocusChange(bool focused); /// Move focus to the next element after the day grid. - void _handleGridNextFocus(NextFocusIntent intent) { - _gridFocusNode + void _onGridNextFocus(NextFocusIntent intent) { + _focusNode ..requestFocus() ..nextFocus(); } /// Move focus to the previous element before the day grid. - void _handleGridPreviousFocus(PreviousFocusIntent intent) { - _gridFocusNode + void _onGridPreviousFocus(PreviousFocusIntent intent) { + _focusNode ..requestFocus() ..previousFocus(); } @@ -163,13 +174,11 @@ abstract class PagedPickerState extends State { /// For horizontal directions, it will move forward or backward a day (depending /// on the current [TextDirection]). For vertical directions it will move up and /// down a week at a time. - void _handleDirectionFocus(DirectionalFocusIntent intent) { + void _onDirectionFocus(DirectionalFocusIntent intent) { assert(focusedDate != null, 'Cannot move focus without a focused day.'); setState(() { - final nextDate = _nextDateInDirection(focusedDate!, intent.direction); - if (nextDate != null) { - focusedDate = nextDate; - print(focusedDate); + if (_nextDate(focusedDate!, intent.direction) case final next?) { + focusedDate = next; if (delta(widget.start, focusedDate!) != delta(widget.start, current)) { _showPage(focusedDate!); } @@ -177,24 +186,21 @@ abstract class PagedPickerState extends State { }); } - // Swap left and right if the text direction if RTL - Period _adjustDirectionOffset(TraversalDirection traversalDirection, TextDirection textDirection) => - directionOffset[switch ((traversalDirection, textDirection)) { - (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, - (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, - _ => traversalDirection, - }]!; - - LocalDate? _nextDateInDirection(LocalDate date, TraversalDirection direction) { + LocalDate? _nextDate(LocalDate date, TraversalDirection direction) { final textDirection = Directionality.of(context); + final offset = directionOffset[switch ((direction, textDirection)) { + (TraversalDirection.left, TextDirection.rtl) => TraversalDirection.right, + (TraversalDirection.right, TextDirection.rtl) => TraversalDirection.left, + _ => direction, + }]!; - var next = date + _adjustDirectionOffset(direction, textDirection); + var next = date + offset; while (widget.start <= next && next <= widget.end) { - if (widget.enabledPredicate(next)) { + if (widget.enabled(next)) { return next; } - next = date + _adjustDirectionOffset(direction, textDirection); + next = date + offset; } return null; diff --git a/forui/lib/src/widgets/old_calendar/year_month/year/paged_year_picker.dart b/forui/lib/src/widgets/calendar/year/paged_year_picker.dart similarity index 69% rename from forui/lib/src/widgets/old_calendar/year_month/year/paged_year_picker.dart rename to forui/lib/src/widgets/calendar/year/paged_year_picker.dart index 54a29b202..34773142e 100644 --- a/forui/lib/src/widgets/old_calendar/year_month/year/paged_year_picker.dart +++ b/forui/lib/src/widgets/calendar/year/paged_year_picker.dart @@ -1,4 +1,9 @@ -part of '../../calendar.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; +import 'package:forui/src/widgets/calendar/year/year_picker.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal class PagedYearPicker extends PagedPicker { @@ -12,19 +17,23 @@ class PagedYearPicker extends PagedPicker { required super.today, required super.initial, super.key, - }) : super(enabledPredicate: (date) => start <= date && date <= end); + }); @override State createState() => _PagedYearPickerState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('onPress', onPress)); + } } class _PagedYearPickerState extends PagedPickerState { - late TextDirection _textDirection; - @override Widget buildItem(BuildContext context, int page) => YearPicker( style: widget.style.yearMonthPickerStyle, - startYear: widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems), + startYear: widget.start.truncate(to: DateUnit.years).plus(years: page * YearPicker.items), start: widget.start, end: widget.end, today: widget.today, @@ -33,13 +42,7 @@ class _PagedYearPickerState extends PagedPickerState { ); @override - void didChangeDependencies() { - super.didChangeDependencies(); - _textDirection = Directionality.of(context); - } - - @override - void handleGridFocusChange(bool focused) { + void onGridFocusChange(bool focused) { setState(() { if (focused && focusedDate == null) { final currentYear = widget.today.truncate(to: DateUnit.years); @@ -49,9 +52,9 @@ class _PagedYearPickerState extends PagedPickerState { } @override - void handlePageChange(int page) { + void onPageChange(int page) { setState(() { - final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * yearMonthPickerItems); + final changed = widget.start.truncate(to: DateUnit.years).plus(years: page * YearPicker.items); if (current == changed) { return; } @@ -63,22 +66,18 @@ class _PagedYearPickerState extends PagedPickerState { focusedDate = _focusableYear(current, focusedDate!); } - SemanticsService.announce( - current.toString(), // TODO: localization - _textDirection, - ); + SemanticsService.announce(current.toString(), textDirection); }); } LocalDate? _focusableYear(LocalDate startYear, LocalDate preferredYear) { - final endYear = startYear.plus(years: yearMonthPickerItems); + final endYear = startYear.plus(years: YearPicker.items); if (startYear <= preferredYear && preferredYear < endYear) { return preferredYear; } - // Start at the 1st and take the first enabled date. for (var newFocus = startYear; newFocus < endYear; newFocus = newFocus.plus(years: 1)) { - if (widget.enabledPredicate(newFocus)) { + if (widget.enabled(newFocus)) { return newFocus; } } @@ -87,13 +86,13 @@ class _PagedYearPickerState extends PagedPickerState { } @override - int delta(LocalDate start, LocalDate end) => ((end.year - start.year) / yearMonthPickerItems).floor(); + int delta(LocalDate start, LocalDate end) => ((end.year - start.year) / YearPicker.items).floor(); @override Map get directionOffset => const { - TraversalDirection.up: Period(years: -yearMonthPickerColumns), + TraversalDirection.up: Period(years: -YearPicker.columns), TraversalDirection.right: Period(years: 1), - TraversalDirection.down: Period(years: yearMonthPickerColumns), + TraversalDirection.down: Period(years: YearPicker.columns), TraversalDirection.left: Period(years: -1), }; } diff --git a/forui/lib/src/widgets/old_calendar/year_month/year/year_picker.dart b/forui/lib/src/widgets/calendar/year/year_picker.dart similarity index 69% rename from forui/lib/src/widgets/old_calendar/year_month/year/year_picker.dart rename to forui/lib/src/widgets/calendar/year/year_picker.dart index 786037591..799f2aed9 100644 --- a/forui/lib/src/widgets/old_calendar/year_month/year/year_picker.dart +++ b/forui/lib/src/widgets/calendar/year/year_picker.dart @@ -1,7 +1,16 @@ -part of '../../calendar.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; @internal class YearPicker extends StatefulWidget { + static const columns = 3; + static const rows = 4; + static const items = columns * rows; + final FCalendarYearMonthPickerStyle style; final LocalDate startYear; final LocalDate start; @@ -23,6 +32,7 @@ class YearPicker extends StatefulWidget { @override State createState() => _YearPickerState(); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -43,10 +53,10 @@ class _YearPickerState extends State { @override void initState() { super.initState(); - _years = List.generate(yearMonthPickerItems, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); + _years = List.generate(YearPicker.items, (i) => FocusNode(skipTraversal: true, debugLabel: '$i')); final focused = widget.focused; - if (focused == null || focused < widget.startYear || widget.startYear.plus(years: yearMonthPickerItems) <= focused) { + if (focused == null || focused < widget.startYear || widget.startYear.plus(years: YearPicker.items) <= focused) { return; } @@ -56,19 +66,19 @@ class _YearPickerState extends State { @override Widget build(BuildContext context) => GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: yearMonthPickerColumns, + crossAxisCount: YearPicker.columns, childAspectRatio: 1.618, ), children: [ - for (var year = widget.startYear, i = 0; i < yearMonthPickerItems; year = year.plus(years: 1), i++) - yearMonth( - widget.style, - year, - _years[i], - widget.onPress, - (date) => '${date.year}', // TODO: localize - enabled: widget.start <= year && year <= widget.end, + for (var year = widget.startYear, i = 0; i < YearPicker.items; year = year.plus(years: 1), i++) + Entry.yearMonth( + style: widget.style, + date: year, + focusNode: _years[i], current: widget.today.year == year.year, + enabled: widget.start <= year && year <= widget.end, + format: (date) => '${date.year}', // TODO: localization + onPress: widget.onPress, ), ], ); @@ -76,13 +86,10 @@ class _YearPickerState extends State { @override void didUpdateWidget(YearPicker old) { super.didUpdateWidget(old); - assert( - old.startYear == widget.startYear, - 'We assumed that a new YearPicker is created each time we navigate to a years page.', - ); + assert(old.startYear == widget.startYear, 'startYear must noe change.'); final focused = widget.focused; - if (focused == null || focused < widget.startYear || widget.startYear.plus(years: yearMonthPickerItems) <= focused) { + if (focused == null || focused < widget.startYear || widget.startYear.plus(years: YearPicker.items) <= focused) { return; } diff --git a/forui/lib/src/widgets/calendar/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month_picker.dart new file mode 100644 index 000000000..33e8e8a93 --- /dev/null +++ b/forui/lib/src/widgets/calendar/year_month_picker.dart @@ -0,0 +1,138 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/calendar/calendar.dart'; +import 'package:forui/src/widgets/calendar/month/paged_month_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:forui/src/widgets/calendar/year/paged_year_picker.dart'; +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; + +@internal +class YearMonthPicker extends StatefulWidget { + final FCalendarStyle style; + final LocalDate start; + final LocalDate end; + final LocalDate today; + final ValueChanged onChange; + + const YearMonthPicker({ + required this.style, + required this.start, + required this.end, + required this.today, + required this.onChange, + super.key, + }); + + @override + State createState() => _YearMonthPickerState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('start', start)) + ..add(DiagnosticsProperty('end', end)) + ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('onChange', onChange)); + } +} + +class _YearMonthPickerState extends State { + LocalDate? _date; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + if (_date == null) { + return PagedYearPicker( + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initial: widget.today.truncate(to: DateUnit.years), + onPress: (year) => setState(() => _date = year), + ); + } else { + return PagedMonthPicker( + style: widget.style, + start: widget.start, + end: widget.end, + today: widget.today, + initial: _date!, + onPress: widget.onChange, + ); + } + } +} + + +/// The year/month picker's style. +final class FCalendarYearMonthPickerStyle with Diagnosticable { + /// The enabled years/months' styles. + final FCalendarEntryStyle enabledStyle; + /// The disabled years/months' styles. + final FCalendarEntryStyle disabledStyle; + + /// Creates a new year/month picker style. + FCalendarYearMonthPickerStyle({required this.enabledStyle, required this.disabledStyle}); + + /// Creates a new year/month picker style that inherits the color scheme and typography. + FCalendarYearMonthPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) + : this( + enabledStyle: FCalendarEntryStyle( + backgroundColor: colorScheme.background, + textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), + focusedBackgroundColor: colorScheme.secondary, + ), + disabledStyle: FCalendarEntryStyle( + backgroundColor: colorScheme.background, + textStyle: typography.sm + .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), + ), + ); + + /// Returns a copy of this [FCalendarYearMonthPickerStyle] but with the given fields replaced with the new values. + /// + /// ```dart + /// final style = FCalendarYearMonthPickerStyle( + /// enabledStyle: ..., + /// disabledStyle: ..., + /// ); + /// + /// final copy = style.copyWith(disabledStyle: ...); + /// + /// print(style.enabledStyle == copy.enabledStyle); // true + /// print(style.disabledStyle == copy.disabledStyle); // false + /// ``` + FCalendarYearMonthPickerStyle copyWith({ + FCalendarEntryStyle? enabledStyle, + FCalendarEntryStyle? disabledStyle, + }) => FCalendarYearMonthPickerStyle( + enabledStyle: enabledStyle ?? this.enabledStyle, + disabledStyle: disabledStyle ?? this.disabledStyle, + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('enabledStyle', enabledStyle)) + ..add(DiagnosticsProperty('disabledStyle', disabledStyle)); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FCalendarYearMonthPickerStyle && runtimeType == other.runtimeType && + enabledStyle == other.enabledStyle && disabledStyle == other.disabledStyle; + + @override + int get hashCode => enabledStyle.hashCode ^ disabledStyle.hashCode; +} diff --git a/forui/lib/src/widgets/old_calendar/calendar.dart b/forui/lib/src/widgets/old_calendar/calendar.dart deleted file mode 100644 index cd5439302..000000000 --- a/forui/lib/src/widgets/old_calendar/calendar.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'dart:collection'; -import 'dart:ffi'; -import 'dart:math'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import 'package:forui/forui.dart'; -import 'package:meta/meta.dart'; -import 'package:sugar/sugar.dart' hide Offset; - -part 'day/day.dart'; -part 'day/day_picker.dart'; -part 'day/paged_day_picker.dart'; - -part 'year_month/year_month.dart'; -part 'year_month/year_month_picker.dart'; -part 'year_month/month/month_picker.dart'; -part 'year_month/month/paged_month_picker.dart'; -part 'year_month/year/paged_year_picker.dart'; -part 'year_month/year/year_picker.dart'; - -part 'controls.dart'; -part 'paged_picker.dart'; -part 'toggle.dart'; - -enum FCalendarPickerMode { - day, - yearMonth, -} - -@internal -class Calendar extends StatefulWidget { - final FCalendarStyle style; // TODO: Make this nullable. - final FCalendarPickerMode initialMode; - final LocalDate start; - final LocalDate end; - final LocalDate today; - final LocalDate initialMonth; - final bool Function(LocalDate day) enabledPredicate; - final bool Function(LocalDate day) selectedPredicate; - final ValueChanged? onMonthChange; - final ValueChanged onPress; - final ValueChanged onLongPress; - - const Calendar({ - required this.style, - required this.start, - required this.end, - required this.today, - required this.initialMonth, - required this.enabledPredicate, - required this.selectedPredicate, - this.onMonthChange, - required this.onPress, - required this.onLongPress, - this.initialMode = FCalendarPickerMode.day, - super.key, - }); - - @override - State createState() => _CalendarState(); -} - -class _CalendarState extends State with TickerProviderStateMixin { - late ValueNotifier mode; - late LocalDate month; - late AnimationController _yearMonthPickerController; - - @override - void initState() { - super.initState(); - mode = ValueNotifier(widget.initialMode); - month = widget.initialMonth; - _yearMonthPickerController = AnimationController(vsync: this, duration: const Duration(milliseconds: 200)); - } - - @override - Widget build(BuildContext context) => DecoratedBox( - decoration: widget.style.decoration, - child: Padding( - padding: widget.style.padding, - child: SizedBox( - height: (maxDayPickerTileDimension * maxDayPickerGridRows) + toggleHeight + 5, - width: maxDayPickerTileDimension * DateTime.daysPerWeek, - child: Stack( - alignment: Alignment.topCenter, - children: [ - ValueListenableBuilder( - valueListenable: mode, - builder: (context, value, child) => switch (value) { - FCalendarPickerMode.day => PagedDayPicker( - style: widget.style, - start: widget.start, - end: widget.end, - today: widget.today, - initial: month.truncate(to: DateUnit.months), - enabledPredicate: widget.enabledPredicate, - selectedPredicate: widget.selectedPredicate, - onMonthChange: (month) { - print('called'); - setState(() { - this.month = month.toLocalDate(); - }); - widget.onMonthChange?.call(month); - }, - onPress: widget.onPress, - onLongPress: widget.onLongPress, - ), - FCalendarPickerMode.yearMonth => YearMonthPicker( - style: widget.style, - start: widget.start, - end: widget.end, - today: widget.today, - onMonthChange: (date) => setState(() { - mode.value = FCalendarPickerMode.day; - month = date; - }), - ), - }, - ), - Toggle( - style: widget.style, - month: month, - mode: mode, - yearMonthPickerController: _yearMonthPickerController, - ), - ], - ), - ), - ), - ); -} - -final class FCalendarStyle with Diagnosticable { - final FCalendarHeaderStyle headerStyle; - final FCalendarDayPickerStyle dayPickerStyle; - final FCalendarYearMonthPickerStyle yearMonthPickerStyle; - final BoxDecoration decoration; - final EdgeInsets padding; - final Duration pageAnimationDuration; - - FCalendarStyle({ - required this.headerStyle, - required this.dayPickerStyle, - required this.yearMonthPickerStyle, - required this.decoration, - this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 16), - this.pageAnimationDuration = const Duration(milliseconds: 200), - }); - - FCalendarStyle.inherit({ - required FColorScheme colorScheme, - required FTypography typography, - required FStyle style, - }) : this( - headerStyle: FCalendarHeaderStyle.inherit(colorScheme: colorScheme, typography: typography), - dayPickerStyle: FCalendarDayPickerStyle.inherit(colorScheme: colorScheme, typography: typography), - yearMonthPickerStyle: FCalendarYearMonthPickerStyle.inherit(colorScheme: colorScheme, typography: typography), - decoration: BoxDecoration( - borderRadius: style.borderRadius, - border: Border.all( - color: colorScheme.border, - ), - color: colorScheme.background, - ), - ); -} diff --git a/forui/lib/src/widgets/old_calendar/controls.dart b/forui/lib/src/widgets/old_calendar/controls.dart deleted file mode 100644 index 231d45287..000000000 --- a/forui/lib/src/widgets/old_calendar/controls.dart +++ /dev/null @@ -1,143 +0,0 @@ -part of 'calendar.dart'; - -@internal -class Controls extends StatelessWidget { - final FCalendarHeaderStyle style; - final VoidCallback? onPrevious; - final VoidCallback? onNext; - - const Controls({ - required this.style, - required this.onPrevious, - required this.onNext, - super.key, - }); - - @override - Widget build(BuildContext context) { - final buttonStyle = context.theme.buttonStyles.outline; - final effectiveButtonStyle = buttonStyle.copyWith( - enabledBoxDecoration: buttonStyle.enabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), - disabledBoxDecoration: buttonStyle.disabledBoxDecoration.copyWith(borderRadius: BorderRadius.circular(4)), - ); - - return Padding( - padding: const EdgeInsets.only(bottom: 5), - child: SizedBox( - height: toggleHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 7), - child: FButton.raw( - // TODO: Replace with FButton.icon. - style: effectiveButtonStyle, - onPress: onPrevious, - child: Padding( - padding: const EdgeInsets.all(7), - child: FAssets.icons.chevronLeft( - height: 17, - colorFilter: ColorFilter.mode( - style.iconColor, - BlendMode.srcIn, - ), - ), - ), - ), - ), - const Expanded(child: SizedBox()), - Padding( - padding: const EdgeInsets.only(right: 7), - child: FButton.raw( - // TODO: Replace with FButton.icon. - style: effectiveButtonStyle, - onPress: onNext, - child: Padding( - padding: const EdgeInsets.all(7), - child: FAssets.icons.chevronRight( - height: 17, - colorFilter: ColorFilter.mode( - style.iconColor, - BlendMode.srcIn, - ), - ), - ), - ), - ), - ], - ), - ), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style)) - ..add(DiagnosticsProperty('onPrevious', onPrevious)) - ..add(DiagnosticsProperty('onNext', onNext)); - } -} - -/// The calendar header's style. -final class FCalendarHeaderStyle { - /// The header's text style. - final TextStyle headerTextStyle; - - /// The unfocused header icons' color. - final Color iconColor; - - /// Creates a [FCalendarHeaderStyle]. - FCalendarHeaderStyle({ - required this.headerTextStyle, - required this.iconColor, - }); - - /// Creates a [FCalendarHeaderStyle] that inherits its values from the given [colorScheme] and [typography]. - FCalendarHeaderStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) - : this( - headerTextStyle: typography.sm.copyWith( - color: colorScheme.primary, - fontWeight: FontWeight.w600, - ), - iconColor: colorScheme.mutedForeground, - ); - - /// Creates a copy of this but with the given fields replaced with the new values. - /// - /// ```dart - /// final style = FCalendarHeaderStyle( - /// headerTextStyle: ..., - /// iconColor:..., - /// // Other arguments omitted for brevity. - /// ); - /// - /// final copy = style.copyWith( - /// iconColor: ..., - /// ); - /// - /// print(style.headerTextStyle == copy.headerTextStyle); // true - /// print(style.iconColor == copy.iconColor); // false - /// ``` - FCalendarHeaderStyle copyWith({ - TextStyle? headerTextStyle, - Color? iconColor, - }) => - FCalendarHeaderStyle( - headerTextStyle: headerTextStyle ?? this.headerTextStyle, - iconColor: iconColor ?? this.iconColor, - ); - - @override - bool operator ==(Object other) => - identical(this, other) || - other is FCalendarHeaderStyle && - runtimeType == other.runtimeType && - headerTextStyle == other.headerTextStyle && - iconColor == other.iconColor; - - @override - int get hashCode => headerTextStyle.hashCode ^ iconColor.hashCode; -} diff --git a/forui/lib/src/widgets/old_calendar/day/day.dart b/forui/lib/src/widgets/old_calendar/day/day.dart deleted file mode 100644 index e0eb5cada..000000000 --- a/forui/lib/src/widgets/old_calendar/day/day.dart +++ /dev/null @@ -1,338 +0,0 @@ -part of '../calendar.dart'; - -/// Returns the [date]. -@internal -Widget day( - FCalendarDayPickerStyle pickerStyle, - LocalDate date, - FocusNode focusNode, - bool Function(LocalDate day) selectedPredicate, - ValueChanged onPress, - ValueChanged onLongPress, { - required bool enabled, - required bool current, - required bool today, - required bool selected, -}) { - final styles = enabled ? pickerStyle.enabledStyles : pickerStyle.disabledStyles; - final dayStyle = current ? styles.current : styles.enclosing; - final style = selected ? dayStyle.selectedStyle : dayStyle.unselectedStyle; - - if (enabled) { - return EnabledDay( - style: style, - date: date, - focusNode: focusNode, - selectedPredicate: selectedPredicate, - onPress: onPress, - onLongPress: onLongPress, - today: today, - selected: selected, - ); - } else { - return DisabledDay(style: style, date: date, today: today, selectedPredicate: selectedPredicate); - } -} - -@internal -class EnabledDay extends StatefulWidget { - final FCalendarDayStateStyle style; - final LocalDate date; - final FocusNode focusNode; - final bool Function(LocalDate day) selectedPredicate; - final ValueChanged onPress; - final ValueChanged onLongPress; - final bool today; - final bool selected; - - const EnabledDay({ - required this.style, - required this.date, - required this.focusNode, - required this.selectedPredicate, - required this.onPress, - required this.onLongPress, - required this.today, - required this.selected, - super.key, - }); - - @override - State createState() => _EnabledDayState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('onLongPress', onLongPress, level: DiagnosticLevel.debug)) - ..add(FlagProperty('today', value: today, ifTrue: 'today', level: DiagnosticLevel.debug)) - ..add(FlagProperty('selected', value: selected, ifTrue: 'selected', level: DiagnosticLevel.debug)); - } -} - -class _EnabledDayState extends State { - bool _focused = false; - bool _hovered = false; - - @override - void initState() { - super.initState(); - widget.focusNode.addListener(_updateFocused); - } - - @override - void didUpdateWidget(EnabledDay old) { - super.didUpdateWidget(old); - old.focusNode.removeListener(_updateFocused); - widget.focusNode.addListener(_updateFocused); - } - - @override - Widget build(BuildContext context) { - var textStyle = _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; - if (widget.today) { - textStyle = textStyle.copyWith(decoration: TextDecoration.underline); - } - - return Focus( - focusNode: widget.focusNode, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => _hovered = true), - onExit: (_) => setState(() => _hovered = false), - child: Semantics( - label: '${widget.date}${widget.today ? ', Today' : ''}', // TODO: localization - button: true, - selected: widget.selected, - excludeSemantics: true, - child: GestureDetector( - onTap: () => widget.onPress(widget.date), - onLongPress: () => widget.onLongPress(widget.date), - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.horizontal( - left: widget.selectedPredicate(widget.date.yesterday) ? Radius.zero : const Radius.circular(4), - right: widget.selectedPredicate(widget.date.tomorrow) ? Radius.zero : const Radius.circular(4), - ), - color: _focused || _hovered ? widget.style.focusedBackgroundColor : widget.style.backgroundColor, - ), - child: Center( - child: Text('${widget.date.day}', style: textStyle), // TODO: localization - ), - ), - ), - ), - ), - ); - } - - @override - void dispose() { - widget.focusNode.removeListener(_updateFocused); - super.dispose(); - } - - void _updateFocused() => setState(() => _focused = widget.focusNode.hasFocus); -} - -@internal -class DisabledDay extends StatelessWidget { - final FCalendarDayStateStyle style; - final LocalDate date; - final bool today; - final bool Function(LocalDate day) selectedPredicate; - - const DisabledDay({ - required this.style, - required this.date, - required this.today, - required this.selectedPredicate, - super.key, - }); - - @override - Widget build(BuildContext context) { - var textStyle = style.textStyle; - if (today) { - textStyle = textStyle.copyWith(decoration: TextDecoration.underline); - } - - return ExcludeSemantics( - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.horizontal( - left: selectedPredicate(date.yesterday) ? Radius.zero : const Radius.circular(4), - right: selectedPredicate(date.tomorrow) ? Radius.zero : const Radius.circular(4), - ), - color: style.backgroundColor, - ), - child: Center( - child: Text('${date.day}', style: textStyle), // TODO: localization - ), - ), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('today', today)) - ..add(DiagnosticsProperty('selectedPredicate', selectedPredicate)); - } -} - -/// A calender day's style. -final class FCalendarDayStyle with Diagnosticable { - /// The selected dates' style. - final FCalendarDayStateStyle selectedStyle; - - /// The unselected dates' style. - final FCalendarDayStateStyle unselectedStyle; - - /// Creates a [FCalendarDayStyle]. - const FCalendarDayStyle({ - required this.unselectedStyle, - required this.selectedStyle, - }); - - /// Returns a copy of this [FCalendarDayStyle] but with the given fields replaced with the new values. - /// - /// ```dart - /// final style = FDayStyle( - /// selectedStyle: ..., - /// unselectedStyle: ..., - /// // Other arguments omitted for brevity - /// ); - /// - /// final copy = style.copyWith( - /// unselectedStyle: ..., - /// ); - /// - /// print(style.selectedStyle == copy.selectedStyle); // true - /// print(style.unselectedStyle == copy.unselectedStyle); // false - /// ``` - FCalendarDayStyle copyWith({ - FCalendarDayStateStyle? selectedStyle, - FCalendarDayStateStyle? unselectedStyle, - }) => - FCalendarDayStyle( - selectedStyle: selectedStyle ?? this.selectedStyle, - unselectedStyle: unselectedStyle ?? this.unselectedStyle, - ); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('selectedStyle', selectedStyle)) - ..add(DiagnosticsProperty('unselectedStyle', unselectedStyle)); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is FCalendarDayStyle && - runtimeType == other.runtimeType && - unselectedStyle == other.unselectedStyle && - selectedStyle == other.selectedStyle; - - @override - int get hashCode => unselectedStyle.hashCode ^ selectedStyle.hashCode; -} - -/// A calendar day state's style. -final class FCalendarDayStateStyle with Diagnosticable { - /// The unfocused day's background color. - final Color backgroundColor; - - /// The unfocused day's text style. - final TextStyle textStyle; - - /// The focused day's background color. Defaults to [backgroundColor]. - final Color focusedBackgroundColor; - - /// The focused day's text style. Defaults to [textStyle]. - final TextStyle focusedTextStyle; - - /// Creates a [FCalendarDayStateStyle]. - FCalendarDayStateStyle({ - required this.backgroundColor, - required this.textStyle, - Color? focusedBackgroundColor, - TextStyle? focusedTextStyle, - }) : focusedBackgroundColor = focusedBackgroundColor ?? backgroundColor, - focusedTextStyle = focusedTextStyle ?? textStyle; - - /// Creates a [FCalendarDayStateStyle] that inherits the given colors. - FCalendarDayStateStyle.inherit({ - required Color backgroundColor, - required TextStyle textStyle, - Color? focusedBackgroundColor, - TextStyle? focusedTextStyle, - }) : this( - backgroundColor: backgroundColor, - textStyle: textStyle, - focusedBackgroundColor: focusedBackgroundColor ?? backgroundColor, - focusedTextStyle: focusedTextStyle ?? textStyle, - ); - - /// Returns a copy of this [FCalendarDayStateStyle] but with the given fields replaced with the new values. - /// - /// ```dart - /// final style = FDayStateStyle( - /// backgroundColor: ..., - /// textStyle: ..., - /// ); - /// - /// final copy = style.copyWith( - /// textStyle: ..., - /// ); - /// - /// print(style.backgroundColor == copy.backgroundColor); // true - /// print(style.textStyle == copy.textStyle); // false - /// ``` - FCalendarDayStateStyle copyWith({ - Color? backgroundColor, - TextStyle? textStyle, - Color? focusedBackgroundColor, - TextStyle? focusedTextStyle, - }) => - FCalendarDayStateStyle( - backgroundColor: backgroundColor ?? this.backgroundColor, - textStyle: textStyle ?? this.textStyle, - focusedBackgroundColor: focusedBackgroundColor ?? this.focusedBackgroundColor, - focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, - ); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('backgroundColor', backgroundColor)) - ..add(DiagnosticsProperty('textStyle', textStyle)) - ..add(DiagnosticsProperty('focusedBackgroundColor', focusedBackgroundColor)) - ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is FCalendarDayStateStyle && - runtimeType == other.runtimeType && - backgroundColor == other.backgroundColor && - textStyle == other.textStyle && - focusedBackgroundColor == other.focusedBackgroundColor && - focusedTextStyle == other.focusedTextStyle; - - @override - int get hashCode => - backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; -} diff --git a/forui/lib/src/widgets/old_calendar/toggle.dart b/forui/lib/src/widgets/old_calendar/toggle.dart deleted file mode 100644 index 4295b45af..000000000 --- a/forui/lib/src/widgets/old_calendar/toggle.dart +++ /dev/null @@ -1,82 +0,0 @@ -part of 'calendar.dart'; - -/// The toggle's height. This is a workaround to the pickers being in a stack alongside the toggle. -@internal -const toggleHeight = 31.0; - -class Toggle extends StatefulWidget { - final FCalendarStyle style; - final LocalDate month; - final ValueNotifier mode; - final AnimationController yearMonthPickerController; - - const Toggle({ - super.key, - required this.style, - required this.month, - required this.mode, - required this.yearMonthPickerController, - }); - - @override - State createState() => _ToggleState(); -} - -class _ToggleState extends State with SingleTickerProviderStateMixin { - late AnimationController _controller; - - @override - void initState() { - super.initState(); - _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 100)); - widget.mode.addListener(() { - if (_controller.isCompleted) { - _controller.reverse(); - } else { - widget.yearMonthPickerController.forward(); - _controller.forward(); - } - }); - } - - @override - Widget build(BuildContext context) => - SizedBox( - height: toggleHeight, - child: GestureDetector( - onTap: () { - final value = widget.mode.value; - if (value == FCalendarPickerMode.day) { - widget.mode.value = FCalendarPickerMode.yearMonth; - } else { - widget.mode.value = FCalendarPickerMode.day; - } - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('${widget.month.month} ${widget.month.year}', style: widget.style.headerStyle.headerTextStyle), // TODO: Localization - RotationTransition( - turns: Tween(begin: 0.0, end: 0.25).animate(_controller), - child: Padding( - padding: const EdgeInsets.all(2.0), - child: FAssets.icons.chevronRight( - height: 15, - colorFilter: ColorFilter.mode( - context.theme.colorScheme.primary, - BlendMode.srcIn, - ), - ), - ), - ), - ], - ), - ), - ); - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } -} diff --git a/forui/lib/src/widgets/old_calendar/year_month/year_month.dart b/forui/lib/src/widgets/old_calendar/year_month/year_month.dart deleted file mode 100644 index 9873ed116..000000000 --- a/forui/lib/src/widgets/old_calendar/year_month/year_month.dart +++ /dev/null @@ -1,182 +0,0 @@ -part of '../calendar.dart'; - -/// Returns the current year/month. -@internal -Widget yearMonth( - FCalendarYearMonthPickerStyle pickerStyle, - LocalDate date, - FocusNode focusNode, - ValueChanged onPress, - String Function(LocalDate) localize, { - required bool enabled, - required bool current, -}) { - final style = enabled ? pickerStyle.enabledStyle : pickerStyle.disabledStyle; - if (enabled) { - return EnabledYearMonth( - style: style, - date: date, - focusNode: focusNode, - onPress: onPress, - localize: localize, - current: current, - ); - } else { - return DisabledYearMonth( - style: style, - date: date, - localize: localize, - current: current, - ); - } -} - -@internal -class EnabledYearMonth extends StatefulWidget { - final FCalendarYearMonthPickerStateStyle style; - final LocalDate date; - final FocusNode focusNode; - final bool current; - final ValueChanged onPress; - final String Function(LocalDate) localize; - - const EnabledYearMonth({ - required this.style, - required this.date, - required this.focusNode, - required this.current, - required this.onPress, - required this.localize, - super.key, - }); - - @override - State createState() => _EnabledYearMonthState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('focusNode', focusNode, level: DiagnosticLevel.debug)) - ..add(FlagProperty('current', value: current, ifTrue: 'current', level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('onPress', onPress, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('localize', localize, level: DiagnosticLevel.debug)); - } -} - -class _EnabledYearMonthState extends State { - bool _focused = false; - bool _hovered = false; - - @override - void initState() { - super.initState(); - widget.focusNode.addListener(_updateFocused); - } - - @override - void didUpdateWidget(EnabledYearMonth old) { - super.didUpdateWidget(old); - old.focusNode.removeListener(_updateFocused); - widget.focusNode.addListener(_updateFocused); - } - - @override - Widget build(BuildContext context) { - var textStyle = _focused || _hovered ? widget.style.focusedTextStyle : widget.style.textStyle; - if (widget.current) { - textStyle = textStyle.copyWith(decoration: TextDecoration.underline); - } - - return Focus( - focusNode: widget.focusNode, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) => setState(() => _hovered = true), - onExit: (_) => setState(() => _hovered = false), - child: Semantics( - label: widget.localize(widget.date), - button: true, - excludeSemantics: true, - child: GestureDetector( - onTap: () => widget.onPress(widget.date), - child: DecoratedBox( - decoration: _focused || _hovered ? widget.style.focusedDecoration : widget.style.decoration, - child: Center( - child: Text(widget.localize(widget.date), style: textStyle), - ), - ), - ), - ), - ), - ); - } - - @override - void dispose() { - widget.focusNode.removeListener(_updateFocused); - super.dispose(); - } - - void _updateFocused() => setState(() => _focused = widget.focusNode.hasFocus); -} - -@internal -class DisabledYearMonth extends StatelessWidget { - final FCalendarYearMonthPickerStateStyle style; - final LocalDate date; - final bool current; - final String Function(LocalDate) localize; - - const DisabledYearMonth({ - required this.style, - required this.date, - required this.current, - required this.localize, - super.key, - }); - - @override - Widget build(BuildContext context) { - var textStyle = style.textStyle; - if (current) { - textStyle = textStyle.copyWith(decoration: TextDecoration.underline); - } - - return ExcludeSemantics( - child: DecoratedBox( - decoration: style.decoration, - child: Center( - child: Text(localize(date), style: textStyle), - ), - ), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('date', date, level: DiagnosticLevel.debug)) - ..add(DiagnosticsProperty('current', current)) - ..add(DiagnosticsProperty('localize', localize)); - } -} - -final class FCalendarYearMonthPickerStateStyle with Diagnosticable { - final BoxDecoration decoration; - final TextStyle textStyle; - final BoxDecoration focusedDecoration; - final TextStyle focusedTextStyle; - - FCalendarYearMonthPickerStateStyle({ - required this.decoration, - required this.textStyle, - BoxDecoration? focusedDecoration, - TextStyle? focusedTextStyle, - }) : focusedDecoration = focusedDecoration ?? decoration, - focusedTextStyle = focusedTextStyle ?? textStyle; -} diff --git a/forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart b/forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart deleted file mode 100644 index d30be3ca4..000000000 --- a/forui/lib/src/widgets/old_calendar/year_month/year_month_picker.dart +++ /dev/null @@ -1,91 +0,0 @@ -part of '../calendar.dart'; - -/// The number of columns in a year & month picker. -@internal -const yearMonthPickerColumns = 3; - -/// The number of rows in a year & month picker. -@internal -const yearMonthPickerRows = 4; - -/// The total number of items in a year & month picker. -@internal -const yearMonthPickerItems = yearMonthPickerColumns * yearMonthPickerRows; - -class YearMonthPicker extends StatefulWidget { - final FCalendarStyle style; - final LocalDate start; - final LocalDate end; - final LocalDate today; - final ValueChanged onMonthChange; - - const YearMonthPicker({ - required this.style, - required this.start, - required this.end, - required this.today, - required this.onMonthChange, - super.key, - }); - - @override - State createState() => _YearMonthPickerState(); -} - -class _YearMonthPickerState extends State { - LocalDate? _date; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - if (_date == null) { - return PagedYearPicker( - onPress: (year) => setState(() { - _date = year; - }), - style: widget.style, - start: widget.start, - end: widget.end, - today: widget.today, - initial: widget.today.truncate(to: DateUnit.years), - ); - } else { - return PagedMonthPicker( - onPress: widget.onMonthChange, - style: widget.style, - start: widget.start, - end: widget.end, - today: widget.today, - initial: _date!, - ); - } - } -} - -final class FCalendarYearMonthPickerStyle with Diagnosticable { - final FCalendarYearMonthPickerStateStyle enabledStyle; - final FCalendarYearMonthPickerStateStyle disabledStyle; - - FCalendarYearMonthPickerStyle({required this.enabledStyle, required this.disabledStyle}); - - FCalendarYearMonthPickerStyle.inherit({required FColorScheme colorScheme, required FTypography typography}) - : this( - enabledStyle: FCalendarYearMonthPickerStateStyle( - decoration: const BoxDecoration(), - textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), - focusedDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: colorScheme.secondary, - ), - ), - disabledStyle: FCalendarYearMonthPickerStateStyle( - decoration: const BoxDecoration(), - textStyle: typography.sm - .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), - ), - ); -} diff --git a/forui/pubspec.yaml b/forui/pubspec.yaml index 87d78832d..9ce013bd0 100644 --- a/forui/pubspec.yaml +++ b/forui/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: flutter_svg: ^2.0.10+1 forui_assets: ^0.2.0 google_fonts: ^6.2.0 + intl: any meta: ^1.11.0 nitrogen_flutter_svg: ^0.3.0+1 nitrogen_types: ^0.3.0+1 diff --git a/forui/test/src/foundation/inkwell_test.dart b/forui/test/src/foundation/inkwell_test.dart index 59e045b4c..2dc309a01 100644 --- a/forui/test/src/foundation/inkwell_test.dart +++ b/forui/test/src/foundation/inkwell_test.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; From 6677cb94371850fbd8a236622cd32b0cab385328 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sat, 13 Jul 2024 21:05:40 +0800 Subject: [PATCH 24/35] Expose FCalendar.raw(...) --- forui/example/lib/main.dart | 21 +- forui/lib/src/theme/theme_data.dart | 10 + forui/lib/src/widgets/calendar/calendar.dart | 199 +++++++++++------- .../widgets/calendar/year/year_picker.dart | 4 +- .../widgets/calendar/year_month_picker.dart | 2 - forui/lib/widgets.dart | 1 + 6 files changed, 137 insertions(+), 100 deletions(-) diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index d664140ce..15b403d85 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; -import 'package:sugar/sugar.dart'; void main() { runApp(const Application()); @@ -43,22 +42,14 @@ class Application extends StatelessWidget { } class Testing extends StatelessWidget { - - static final _selected = { LocalDate(2024, 7, 16), LocalDate(2024, 7, 17), LocalDate(2024, 7, 18), LocalDate(2024, 7, 29)}; + static final _selected = {DateTime(2024, 7, 16), DateTime(2024, 7, 17), DateTime(2024, 7, 18), DateTime(2024, 7, 29)}; const Testing({super.key}); @override - Widget build(BuildContext context) => Calendar( - style: FCalendarStyle.inherit(colorScheme: context.theme.colorScheme, typography: context.theme.typography, style: context.theme.style), - start: LocalDate(1900, 1, 8), - end: LocalDate(2024, 7, 10), - current: LocalDate.now(), - initialMonth: LocalDate(2023, 7), - enabled: (_) => true, - selected: _selected.contains, - date: print, - onPress: print, - onLongPress: print, - ); + Widget build(BuildContext context) => FCalendar.raw( + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + selected: _selected.contains, + ); } diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart index 6743e80fa..937966b98 100644 --- a/forui/lib/src/theme/theme_data.dart +++ b/forui/lib/src/theme/theme_data.dart @@ -31,6 +31,9 @@ final class FThemeData with Diagnosticable { /// The button styles. final FButtonStyles buttonStyles; + /// The calendar style. + final FCalendarStyle calendarStyle; + /// The card style. final FCardStyle cardStyle; @@ -71,6 +74,7 @@ final class FThemeData with Diagnosticable { required this.colorScheme, required this.badgeStyles, required this.buttonStyles, + required this.calendarStyle, required this.cardStyle, required this.checkboxStyle, required this.dialogStyle, @@ -99,6 +103,7 @@ final class FThemeData with Diagnosticable { style: style, badgeStyles: FBadgeStyles.inherit(colorScheme: colorScheme, typography: typography, style: style), buttonStyles: FButtonStyles.inherit(colorScheme: colorScheme, typography: typography, style: style), + calendarStyle: FCalendarStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), cardStyle: FCardStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), checkboxStyle: FCheckboxStyle.inherit(colorScheme: colorScheme), dialogStyle: FDialogStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), @@ -135,6 +140,7 @@ final class FThemeData with Diagnosticable { FStyle? style, FBadgeStyles? badgeStyles, FButtonStyles? buttonStyles, + FCalendarStyle? calendarStyle, FCardStyle? cardStyle, FCheckboxStyle? checkboxStyle, FDialogStyle? dialogStyle, @@ -152,6 +158,7 @@ final class FThemeData with Diagnosticable { style: style ?? this.style, badgeStyles: badgeStyles ?? this.badgeStyles, buttonStyles: buttonStyles ?? this.buttonStyles, + calendarStyle: calendarStyle ?? this.calendarStyle, cardStyle: cardStyle ?? this.cardStyle, checkboxStyle: checkboxStyle ?? this.checkboxStyle, dialogStyle: dialogStyle ?? this.dialogStyle, @@ -173,6 +180,7 @@ final class FThemeData with Diagnosticable { ..add(DiagnosticsProperty('style', style, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('badgeStyles', badgeStyles, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('buttonStyles', buttonStyles, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('calendarStyle', calendarStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('cardStyle', cardStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('checkboxStyle', checkboxStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('dialogStyle', dialogStyle, level: DiagnosticLevel.debug)) @@ -195,6 +203,7 @@ final class FThemeData with Diagnosticable { style == other.style && badgeStyles == other.badgeStyles && buttonStyles == other.buttonStyles && + calendarStyle == other.calendarStyle && cardStyle == other.cardStyle && checkboxStyle == other.checkboxStyle && dialogStyle == other.dialogStyle && @@ -213,6 +222,7 @@ final class FThemeData with Diagnosticable { style.hashCode ^ badgeStyles.hashCode ^ buttonStyles.hashCode ^ + calendarStyle.hashCode ^ cardStyle.hashCode ^ checkboxStyle.hashCode ^ dialogStyle.hashCode ^ diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index ed929410f..57107c3be 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -7,97 +7,134 @@ import 'package:forui/src/widgets/calendar/shared/header.dart'; import 'package:forui/src/widgets/calendar/year_month_picker.dart'; import 'package:sugar/sugar.dart'; +export 'day/day_picker.dart' show FCalendarDayPickerStyle, FCalendarDayStyle; +export 'shared/entry.dart' show FCalendarEntryStyle; +export 'shared/header.dart' show FCalendarHeaderStyle, FCalendarPickerType; +export 'year_month_picker.dart' show FCalendarYearMonthPickerStyle; + +/// A calendar. +/// +/// See: +/// * https://forui.dev/docs/calendar for working examples. +/// * [FCalendarDayStyle] for customizing a card's appearance. class FCalendar extends StatelessWidget { + static bool _true(DateTime _) => true; - @override - Widget build(BuildContext context) { - // TODO: implement build - throw UnimplementedError(); - } + /// The style. Defaults to [FThemeData.calendarStyle]. + final FCalendarStyle? style; -} + /// The start date. It is truncated to the nearest date. + /// + /// ## Contract: + /// Throws an [AssertionError] if [end] <= [start] + final DateTime start; + + /// The end date. It is truncated to the nearest date. + /// + /// ## Contract: + /// Throws an [AssertionError] if [end] <= [start] + final DateTime end; + + /// The current date. It is truncated to the nearest date. Defaults to the [DateTime.now]. + final DateTime today; + + /// A predicate that determines if a date can be selected. It may be called more than once for a single date. + /// + /// Defaults to returning true for all dates. + final Predicate enabled; -class _Calendar extends StatelessWidget { - final FCalendarStyle style; - final LocalDate start; - final LocalDate end; - final LocalDate today; - final ValueNotifier type; - final ValueNotifier month; - final Predicate enabled; - final Predicate selected; - final ValueChanged onMonthChange; - final ValueChanged onPress; - final ValueChanged onLongPress; - - const _Calendar({ - required this.style, + /// A predicate that determines if a date is selected. It may be called more than once for a single date. + final Predicate selected; + + /// A callback for when the displayed month changes. + final ValueChanged? onMonthChange; + + /// A callback for when a date in a [FCalendarPickerType.day] picker is pressed. + final ValueChanged? onPress; + + /// A callback for when a date in a [FCalendarPickerType.day] picker is long pressed. + final ValueChanged? onLongPress; + final ValueNotifier _type; + final ValueNotifier _month; + + /// Creates a [FCalendar] with custom date selection. + /// + /// [initialDate] defaults to [today]. It is truncated to the nearest date. + FCalendar.raw({ required this.start, required this.end, - required this.today, - required this.type, - required this.month, - required this.enabled, required this.selected, - required this.onMonthChange, - required this.onPress, - required this.onLongPress, - }); + this.style, + this.enabled = _true, + this.onMonthChange, + this.onPress, + this.onLongPress, + FCalendarPickerType initialType = FCalendarPickerType.day, + DateTime? today, + DateTime? initialDate, + super.key, + }) : assert(start.toLocalDate() < end.toLocalDate(), 'end date must be greater than start date'), + today = today ?? DateTime.now(), + _type = ValueNotifier(initialType), + _month = ValueNotifier((initialDate ?? today ?? DateTime.now()).toLocalDate().truncate(to: DateUnit.months)); @override - Widget build(BuildContext context) => DecoratedBox( - decoration: style.decoration, - child: Padding( - padding: style.padding, - child: SizedBox( - height: (DayPicker.maxRows * DayPicker.tileDimension) + Header.height + 5, - width: DateTime.daysPerWeek * DayPicker.tileDimension, - child: Stack( - alignment: Alignment.topCenter, - children: [ - ValueListenableBuilder( - valueListenable: month, - builder: (context, month, child) => Header( - style: style.headerStyle, - type: type, - month: month, - ), - ), - ValueListenableBuilder( - valueListenable: type, - builder: (context, value, child) => switch (value) { - FCalendarPickerType.day => PagedDayPicker( - style: style, - start: start, - end: end, - today: today, - initial: month.value.truncate(to: DateUnit.months), - enabled: enabled, - selected: selected, - onMonthChange: (date) { - month.value = date; - onMonthChange(date); - }, - onPress: onPress, - onLongPress: onLongPress, - ), - FCalendarPickerType.yearMonth => YearMonthPicker( - style: style, - start: start, - end: end, - today: today, - onChange: (date) { - month.value = date; - type.value = FCalendarPickerType.day; - }, - ), - }, + Widget build(BuildContext context) { + final style = this.style ?? context.theme.calendarStyle; + return DecoratedBox( + decoration: style.decoration, + child: Padding( + padding: style.padding, + child: SizedBox( + height: (DayPicker.maxRows * DayPicker.tileDimension) + Header.height + 5, + width: DateTime.daysPerWeek * DayPicker.tileDimension, + child: Stack( + alignment: Alignment.topCenter, + children: [ + ValueListenableBuilder( + valueListenable: _month, + builder: (context, month, child) => Header( + style: style.headerStyle, + type: _type, + month: month, ), - ], - ), + ), + ValueListenableBuilder( + valueListenable: _type, + builder: (context, value, child) => switch (value) { + FCalendarPickerType.day => PagedDayPicker( + style: style, + start: start.toLocalDate(), + end: end.toLocalDate(), + today: today.toLocalDate(), + initial: _month.value, + enabled: (date) => enabled(date.toNative()), + selected: (date) => selected(date.toNative()), + onMonthChange: (date) { + _month.value = date; + onMonthChange?.call(date.toNative()); + }, + onPress: (date) => onPress?.call(date.toNative()), + onLongPress: (date) => onLongPress?.call(date.toNative()), + ), + FCalendarPickerType.yearMonth => YearMonthPicker( + style: style, + start: start.toLocalDate(), + end: end.toLocalDate(), + today: today.toLocalDate(), + onChange: (date) { + _month.value = date; + _type.value = FCalendarPickerType.day; + }, + ), + }, + ), + ], ), ), - ); + ), + ); + } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -107,8 +144,8 @@ class _Calendar extends StatelessWidget { ..add(DiagnosticsProperty('start', start)) ..add(DiagnosticsProperty('end', end)) ..add(DiagnosticsProperty('today', today)) - ..add(DiagnosticsProperty('type', type)) - ..add(DiagnosticsProperty('month', month)) + ..add(DiagnosticsProperty('type', _type)) + ..add(DiagnosticsProperty('month', _month)) ..add(DiagnosticsProperty('enabled', enabled)) ..add(DiagnosticsProperty('selected', selected)) ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) diff --git a/forui/lib/src/widgets/calendar/year/year_picker.dart b/forui/lib/src/widgets/calendar/year/year_picker.dart index 799f2aed9..c51668b31 100644 --- a/forui/lib/src/widgets/calendar/year/year_picker.dart +++ b/forui/lib/src/widgets/calendar/year/year_picker.dart @@ -19,7 +19,7 @@ class YearPicker extends StatefulWidget { final LocalDate? focused; final ValueChanged onPress; - const YearPicker({ + YearPicker({ required this.style, required this.startYear, required this.start, @@ -28,7 +28,7 @@ class YearPicker extends StatefulWidget { required this.focused, required this.onPress, super.key, - }); + }): assert(startYear == startYear.truncate(to: DateUnit.years), 'startYear must be truncated to years.'); @override State createState() => _YearPickerState(); diff --git a/forui/lib/src/widgets/calendar/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month_picker.dart index 33e8e8a93..e5ea884a5 100644 --- a/forui/lib/src/widgets/calendar/year_month_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month_picker.dart @@ -1,9 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; -import 'package:forui/src/widgets/calendar/calendar.dart'; import 'package:forui/src/widgets/calendar/month/paged_month_picker.dart'; -import 'package:forui/src/widgets/calendar/shared/entry.dart'; import 'package:forui/src/widgets/calendar/year/paged_year_picker.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; diff --git a/forui/lib/widgets.dart b/forui/lib/widgets.dart index 25e657a06..dc9ff14de 100644 --- a/forui/lib/widgets.dart +++ b/forui/lib/widgets.dart @@ -3,6 +3,7 @@ library forui.widgets; export 'src/widgets/badge/badge.dart' hide Variant; export 'src/widgets/button/button.dart' hide Variant; +export 'src/widgets/calendar/calendar.dart'; export 'src/widgets/card/card.dart'; export 'src/widgets/checkbox.dart'; export 'src/widgets/dialog/dialog.dart'; From d9a41873b445ab930b9d90869d2668666d15523f Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sat, 13 Jul 2024 22:14:34 +0800 Subject: [PATCH 25/35] Add calendar controllers --- forui/example/lib/main.dart | 4 +- forui/lib/src/widgets/calendar/calendar.dart | 31 ++++-- .../widgets/calendar/calendar_controller.dart | 105 ++++++++++++++++++ 3 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 forui/lib/src/widgets/calendar/calendar_controller.dart diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 15b403d85..7bddef031 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -47,9 +47,9 @@ class Testing extends StatelessWidget { const Testing({super.key}); @override - Widget build(BuildContext context) => FCalendar.raw( + Widget build(BuildContext context) => FCalendar( start: DateTime(1900, 1, 8), end: DateTime(2024, 7, 10), - selected: _selected.contains, + controller: FCalendarMultiValueController(), ); } diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index 57107c3be..c3d36a645 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; @@ -10,6 +11,7 @@ import 'package:sugar/sugar.dart'; export 'day/day_picker.dart' show FCalendarDayPickerStyle, FCalendarDayStyle; export 'shared/entry.dart' show FCalendarEntryStyle; export 'shared/header.dart' show FCalendarHeaderStyle, FCalendarPickerType; +export 'calendar_controller.dart'; export 'year_month_picker.dart' show FCalendarYearMonthPickerStyle; /// A calendar. @@ -23,6 +25,9 @@ class FCalendar extends StatelessWidget { /// The style. Defaults to [FThemeData.calendarStyle]. final FCalendarStyle? style; + /// A controller that determines if a date is selected. + final FCalendarController controller; + /// The start date. It is truncated to the nearest date. /// /// ## Contract: @@ -43,9 +48,6 @@ class FCalendar extends StatelessWidget { /// Defaults to returning true for all dates. final Predicate enabled; - /// A predicate that determines if a date is selected. It may be called more than once for a single date. - final Predicate selected; - /// A callback for when the displayed month changes. final ValueChanged? onMonthChange; @@ -57,13 +59,13 @@ class FCalendar extends StatelessWidget { final ValueNotifier _type; final ValueNotifier _month; - /// Creates a [FCalendar] with custom date selection. + /// Creates a [FCalendar]. /// /// [initialDate] defaults to [today]. It is truncated to the nearest date. - FCalendar.raw({ + FCalendar({ + required this.controller, required this.start, required this.end, - required this.selected, this.style, this.enabled = _true, this.onMonthChange, @@ -102,21 +104,28 @@ class FCalendar extends StatelessWidget { ValueListenableBuilder( valueListenable: _type, builder: (context, value, child) => switch (value) { - FCalendarPickerType.day => PagedDayPicker( + FCalendarPickerType.day => ValueListenableBuilder( + valueListenable: controller, + builder: (context, _, __) => PagedDayPicker( style: style, start: start.toLocalDate(), end: end.toLocalDate(), today: today.toLocalDate(), initial: _month.value, enabled: (date) => enabled(date.toNative()), - selected: (date) => selected(date.toNative()), + selected: (date) => controller.contains(date.toNative()), onMonthChange: (date) { _month.value = date; onMonthChange?.call(date.toNative()); }, - onPress: (date) => onPress?.call(date.toNative()), + onPress: (date) { + final native = date.toNative(); + controller.onPress(native); + onPress?.call(native); + }, onLongPress: (date) => onLongPress?.call(date.toNative()), ), + ), FCalendarPickerType.yearMonth => YearMonthPicker( style: style, start: start.toLocalDate(), @@ -141,13 +150,11 @@ class FCalendar extends StatelessWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('style', style)) + ..add(DiagnosticsProperty('controller', controller)) ..add(DiagnosticsProperty('start', start)) ..add(DiagnosticsProperty('end', end)) ..add(DiagnosticsProperty('today', today)) - ..add(DiagnosticsProperty('type', _type)) - ..add(DiagnosticsProperty('month', _month)) ..add(DiagnosticsProperty('enabled', enabled)) - ..add(DiagnosticsProperty('selected', selected)) ..add(DiagnosticsProperty('onMonthChange', onMonthChange)) ..add(DiagnosticsProperty('onPress', onPress)) ..add(DiagnosticsProperty('onLongPress', onLongPress)); diff --git a/forui/lib/src/widgets/calendar/calendar_controller.dart b/forui/lib/src/widgets/calendar/calendar_controller.dart new file mode 100644 index 000000000..a92fab906 --- /dev/null +++ b/forui/lib/src/widgets/calendar/calendar_controller.dart @@ -0,0 +1,105 @@ +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:sugar/sugar.dart'; + +/// A controller that controls date selection in a calendar. +abstract class FCalendarController extends ValueNotifier { + /// Creates a [FCalendarController] with the given initial [value]. + FCalendarController(super._value); + + /// Called when the given [date] in a [FCalendarPickerType.day] picker is pressed. + /// + /// [date] is always in UTC timezone and truncated to the nearest date. + void onPress(DateTime date); + + /// Returns true if the given [date] is selected. + bool contains(DateTime date); +} + +/// A date selection controller that allows only a single date to be selected. +/// +/// The selected date is always in UTC timezone and truncated to the nearest date. +final class FCalendarSingleValueController extends FCalendarController { + /// Creates a [FCalendarSingleValueController] with the given initial [value]. + /// + /// ## Contract: + /// Throws an [AssertionError] if the given [value] is not in UTC timezone. + FCalendarSingleValueController([super.value]) : assert(value?.isUtc ?? true, 'value must be in UTC timezone'); + + @override + bool contains(DateTime date) => value?.toLocalDate() == date.toLocalDate(); + + @override + void onPress(DateTime date) { + if (value?.toLocalDate() == date.toLocalDate()) { + value = null; + } else { + value = date; + } + } +} + +/// A date selection controller that allows multiple dates to be selected. +/// +/// The selected dates are always in UTC timezone and truncated to the nearest date. +final class FCalendarMultiValueController extends FCalendarController> { + /// Creates a [FCalendarMultiValueController] with the given initial [value]. + /// + /// ## Contract: + /// Throws an [AssertionError] if the given dates in [value] is not in UTC timezone. + FCalendarMultiValueController([super.value = const {}]) : assert(value.every((d) => d.isUtc), 'dates must be in UTC timezone'); + + @override + bool contains(DateTime date) => value.contains(date); + + @override + void onPress(DateTime date) { + final copy = { ...value }; + value = copy..toggle(date); + } +} + +/// 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 date. +final class FCalendarSingleRangeController extends FCalendarController<(DateTime, DateTime)?> { + /// Creates a [FCalendarSingleRangeController] with the given initial [value]. + /// + /// ## Contract: + /// Throws an [AssertionError] if the given [value] is not in UTC timezone. + FCalendarSingleRangeController([super.value]) + : assert(value == null || (value.$1.isUtc && value.$2.isUtc), 'value must be in UTC timezone'); + + @override + bool contains(DateTime date) { + if (value case (final first, final last)) { + final current = date.toLocalDate(); + return first.toLocalDate() <= current && current <= last.toLocalDate(); + } + + return false; + } + + @override + void onPress(DateTime date) { + if (value == null) { + value = (date, date); + return; + } + + final (first, last) = value!; + final pressed = date.toLocalDate(); + + switch ((first.toLocalDate(), last.toLocalDate())) { + case (final first, final last) when pressed == first || pressed == last: + value = null; + + case (final first, final last) when pressed < first: + value = (pressed.toNative(), last.toNative()); + + case (final first, _): + value = (first.toNative(), pressed.toNative()); + } + } +} From 61f513af1663c38dec3ac78ddf9a8a836b148c0a Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sun, 14 Jul 2024 16:21:16 +0800 Subject: [PATCH 26/35] Add documentation and tests --- docs/pages/docs/calendar.mdx | 91 +++++++++ forui/CHANGELOG.md | 3 + forui/example/lib/main.dart | 24 +-- forui/lib/src/widgets/calendar/calendar.dart | 9 +- .../widgets/calendar/calendar_controller.dart | 30 +-- .../widgets/calendar/month/month_picker.dart | 5 +- .../src/widgets/calendar/shared/header.dart | 19 +- .../widgets/calendar/year_month_picker.dart | 5 +- .../calendar/day-picker/zinc-dark-default.png | Bin 0 -> 76005 bytes .../day-picker/zinc-dark-max-rows.png | Bin 0 -> 83986 bytes .../day-picker/zinc-light-default.png | Bin 0 -> 74398 bytes .../day-picker/zinc-light-max-rows.png | Bin 0 -> 82711 bytes .../month-picker/zinc-dark-default.png | Bin 0 -> 54474 bytes .../month-picker/zinc-light-default.png | Bin 0 -> 54108 bytes .../year-picker/zinc-dark-default.png | Bin 0 -> 59300 bytes .../year-picker/zinc-dark-initial-date.png | Bin 0 -> 65202 bytes .../year-picker/zinc-light-default.png | Bin 0 -> 58275 bytes .../year-picker/zinc-light-initial-date.png | Bin 0 -> 64378 bytes .../calendar/calendar_controller_test.dart | 90 +++++++++ .../calendar/calendar_golden_test.dart | 178 ++++++++++++++++++ .../src/widgets/calendar/calendar_test.dart | 100 ++++++++++ samples/lib/main.dart | 12 ++ samples/lib/widgets/calendar.dart | 46 +++++ samples/pubspec.lock | 16 +- 24 files changed, 568 insertions(+), 60 deletions(-) create mode 100644 docs/pages/docs/calendar.mdx create mode 100644 forui/test/golden/calendar/day-picker/zinc-dark-default.png create mode 100644 forui/test/golden/calendar/day-picker/zinc-dark-max-rows.png create mode 100644 forui/test/golden/calendar/day-picker/zinc-light-default.png create mode 100644 forui/test/golden/calendar/day-picker/zinc-light-max-rows.png create mode 100644 forui/test/golden/calendar/month-picker/zinc-dark-default.png create mode 100644 forui/test/golden/calendar/month-picker/zinc-light-default.png create mode 100644 forui/test/golden/calendar/year-picker/zinc-dark-default.png create mode 100644 forui/test/golden/calendar/year-picker/zinc-dark-initial-date.png create mode 100644 forui/test/golden/calendar/year-picker/zinc-light-default.png create mode 100644 forui/test/golden/calendar/year-picker/zinc-light-initial-date.png create mode 100644 forui/test/src/widgets/calendar/calendar_controller_test.dart create mode 100644 forui/test/src/widgets/calendar/calendar_golden_test.dart create mode 100644 forui/test/src/widgets/calendar/calendar_test.dart create mode 100644 samples/lib/widgets/calendar.dart diff --git a/docs/pages/docs/calendar.mdx b/docs/pages/docs/calendar.mdx new file mode 100644 index 000000000..e61f480fb --- /dev/null +++ b/docs/pages/docs/calendar.mdx @@ -0,0 +1,91 @@ +import { Tabs } from 'nextra/components'; +import { Widget } from "../../components/widget"; + +# Calendar +A date field component that allows users to enter and edit date. + +The calendar pages are designed to be navigable through swipe gestures on mobile platforms, allowing left and right swipes +to transition between pages. + + + + + + + ```dart + FCalendar( + controller: FCalendarSingleRangeController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); + ``` + + + +## Usage + +### `FCalendar(...)` + +```dart +FCalendar( + controller: FCalendarSingleRangeController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + today: DateTime.utc(2024, 7, 14), + initalType = FCalendarPickerType.yearMonth, + initialDate = DateTime.utc(2024, 9, 12), + enabled: (date) => allowed.contains(date), + onMonthChange: (date) => print(date), + onPress: (date) => print(date), + onLongPress: (date) => print(date), +); +``` +## Examples + +### Single Date + + + + + + ```dart + FCalendar( + controller: FCalendarSingleValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); + ``` + + + +### Multiple Dates + + + + + + ```dart + FCalendar( + controller: FCalendarMultiValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); + ``` + + + +### Single Range + + + + + + ```dart + FCalendar( + controller: FCalendarSingleRangeController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ) + ``` + + diff --git a/forui/CHANGELOG.md b/forui/CHANGELOG.md index ea9447369..66d455791 100644 --- a/forui/CHANGELOG.md +++ b/forui/CHANGELOG.md @@ -1,5 +1,8 @@ ## Next +### Additions +* Add `FCalendar` + ### Enhancements * **Breaking** Change `FSwitch` to be usable in `Form`s. * **Breaking** Rename `FThemeData.checkBoxStyle` to `FThemeData.checkboxStyle` for consistency. diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 7bddef031..d22d19137 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; +import 'package:forui_example/example.dart'; void main() { @@ -29,27 +30,6 @@ class Application extends StatelessWidget { content: child ?? const SizedBox(), ), ), - home: Column( - children: [ - const Testing(), - // FHeaderAction( - // icon: FAssets.icons.plus, - // onPress: () => showDatePicker(context: context, firstDate: DateTime(2024, 7, 1), lastDate: DateTime(2024, 7, 31), initialDate: DateTime(2024, 7, 8)), - // ), - ], - ), - ); -} - -class Testing extends StatelessWidget { - static final _selected = {DateTime(2024, 7, 16), DateTime(2024, 7, 17), DateTime(2024, 7, 18), DateTime(2024, 7, 29)}; - - const Testing({super.key}); - - @override - Widget build(BuildContext context) => FCalendar( - start: DateTime(1900, 1, 8), - end: DateTime(2024, 7, 10), - controller: FCalendarMultiValueController(), + home: const Example(), ); } diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index c3d36a645..e2a03f38f 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -16,6 +16,9 @@ export 'year_month_picker.dart' show FCalendarYearMonthPickerStyle; /// A calendar. /// +/// The calendar pages are designed to be navigable through swipe gestures on mobile Android, iOS & iPadOS, allowing +/// left and right swipes to transition between pages. +/// /// See: /// * https://forui.dev/docs/calendar for working examples. /// * [FCalendarDayStyle] for customizing a card's appearance. @@ -104,9 +107,7 @@ class FCalendar extends StatelessWidget { ValueListenableBuilder( valueListenable: _type, builder: (context, value, child) => switch (value) { - FCalendarPickerType.day => ValueListenableBuilder( - valueListenable: controller, - builder: (context, _, __) => PagedDayPicker( + FCalendarPickerType.day => PagedDayPicker( style: style, start: start.toLocalDate(), end: end.toLocalDate(), @@ -125,12 +126,12 @@ class FCalendar extends StatelessWidget { }, onLongPress: (date) => onLongPress?.call(date.toNative()), ), - ), FCalendarPickerType.yearMonth => YearMonthPicker( style: style, start: start.toLocalDate(), end: end.toLocalDate(), today: today.toLocalDate(), + initial: _month.value, onChange: (date) { _month.value = date; _type.value = FCalendarPickerType.day; diff --git a/forui/lib/src/widgets/calendar/calendar_controller.dart b/forui/lib/src/widgets/calendar/calendar_controller.dart index a92fab906..35e3dc762 100644 --- a/forui/lib/src/widgets/calendar/calendar_controller.dart +++ b/forui/lib/src/widgets/calendar/calendar_controller.dart @@ -3,6 +3,11 @@ import 'package:forui/forui.dart'; import 'package:sugar/sugar.dart'; /// A controller that controls date selection in a calendar. +/// +/// This class should be extended to customize date selection. By default, the following controllers are provided: +/// * [FCalendarSingleValueController] for selecting a single date. +/// * [FCalendarMultiValueController] for selecting multiple date. +/// * [FCalendarSingleRangeController] for selecting a single range. abstract class FCalendarController extends ValueNotifier { /// Creates a [FCalendarController] with the given initial [value]. FCalendarController(super._value); @@ -30,13 +35,7 @@ final class FCalendarSingleValueController extends FCalendarController value?.toLocalDate() == date.toLocalDate(); @override - void onPress(DateTime date) { - if (value?.toLocalDate() == date.toLocalDate()) { - value = null; - } else { - value = date; - } - } + void onPress(DateTime date) => value = value?.toLocalDate() == date.toLocalDate() ? null : date; } /// A date selection controller that allows multiple dates to be selected. @@ -47,14 +46,15 @@ final class FCalendarMultiValueController extends FCalendarController d.isUtc), 'dates must be in UTC timezone'); + FCalendarMultiValueController([super.value = const {}]) + : assert(value.every((d) => d.isUtc), 'dates must be in UTC timezone'); @override bool contains(DateTime date) => value.contains(date); @override void onPress(DateTime date) { - final copy = { ...value }; + final copy = {...value}; value = copy..toggle(date); } } @@ -67,9 +67,15 @@ final class FCalendarSingleRangeController extends FCalendarController<(DateTime /// Creates a [FCalendarSingleRangeController] with the given initial [value]. /// /// ## Contract: - /// Throws an [AssertionError] if the given [value] is not in UTC timezone. + /// Throws an [AssertionError] if: + /// * the given dates in [value] is not in UTC timezone. + /// * the end date is less than start date. FCalendarSingleRangeController([super.value]) - : assert(value == null || (value.$1.isUtc && value.$2.isUtc), 'value must be in UTC timezone'); + : assert(value == null || (value.$1.isUtc && value.$2.isUtc), 'value must be in UTC timezone'), + assert( + value == null || (value.$1.isBefore(value.$2) || value.$1.isAtSameMomentAs(value.$2)), + 'end date must be greater than or equal to start date', + ); @override bool contains(DateTime date) { @@ -98,7 +104,7 @@ final class FCalendarSingleRangeController extends FCalendarController<(DateTime case (final first, final last) when pressed < first: value = (pressed.toNative(), last.toNative()); - case (final first, _): + case (final first, _): value = (first.toNative(), pressed.toNative()); } } diff --git a/forui/lib/src/widgets/calendar/month/month_picker.dart b/forui/lib/src/widgets/calendar/month/month_picker.dart index cad228eb8..6c17bc46b 100644 --- a/forui/lib/src/widgets/calendar/month/month_picker.dart +++ b/forui/lib/src/widgets/calendar/month/month_picker.dart @@ -6,7 +6,8 @@ import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; -final _yMMMM = DateFormat.yMMMM(); +// ignore: non_constant_identifier_names +final _MMM = DateFormat.MMM(); @internal class MonthPicker extends StatefulWidget { @@ -74,7 +75,7 @@ class _MonthPickerState extends State { focusNode: _months[i], current: widget.today.truncate(to: DateUnit.months) == month, enabled: widget.start <= month && month <= widget.end, - format: (date) => _yMMMM.format(date.toNative()), // TODO: localize + format: (date) => _MMM.format(date.toNative()), // TODO: localize onPress: widget.onPress, ), ], diff --git a/forui/lib/src/widgets/calendar/shared/header.dart b/forui/lib/src/widgets/calendar/shared/header.dart index facb8e82a..591cc3589 100644 --- a/forui/lib/src/widgets/calendar/shared/header.dart +++ b/forui/lib/src/widgets/calendar/shared/header.dart @@ -51,8 +51,9 @@ class _HeaderState extends State
with SingleTickerProviderStateMixin { @override void initState() { super.initState(); - _controller = AnimationController(vsync: this, duration: widget.style.animationDuration); widget.type.addListener(_animate); + _controller = AnimationController(vsync: this, duration: widget.style.animationDuration); + _controller.value = widget.type.value == FCalendarPickerType.day ? 0.0 : 1.0; } @override @@ -60,8 +61,8 @@ class _HeaderState extends State
with SingleTickerProviderStateMixin { height: Header.height, child: FInkWell( onPress: () => widget.type.value = switch (widget.type.value) { - FCalendarPickerType.day => FCalendarPickerType.day, - FCalendarPickerType.yearMonth => FCalendarPickerType.yearMonth, + FCalendarPickerType.day => FCalendarPickerType.yearMonth, + FCalendarPickerType.yearMonth => FCalendarPickerType.day, }, builder: (context, _, child) => child!, child: Row( @@ -98,10 +99,14 @@ class _HeaderState extends State
with SingleTickerProviderStateMixin { } void _animate() { - if (_controller.isCompleted) { - _controller.reverse(); - } else { - _controller.forward(); + // we check the picker type to prevent de-syncs + switch ((widget.type.value, _controller.isCompleted)) { + case (FCalendarPickerType.yearMonth, false): + _controller.forward(); + case (FCalendarPickerType.day, true): + _controller.reverse(); + + case _: } } } diff --git a/forui/lib/src/widgets/calendar/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month_picker.dart index e5ea884a5..9198ea65e 100644 --- a/forui/lib/src/widgets/calendar/year_month_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month_picker.dart @@ -12,6 +12,7 @@ class YearMonthPicker extends StatefulWidget { final LocalDate start; final LocalDate end; final LocalDate today; + final LocalDate initial; final ValueChanged onChange; const YearMonthPicker({ @@ -19,6 +20,7 @@ class YearMonthPicker extends StatefulWidget { required this.start, required this.end, required this.today, + required this.initial, required this.onChange, super.key, }); @@ -34,6 +36,7 @@ class YearMonthPicker extends StatefulWidget { ..add(DiagnosticsProperty('start', start)) ..add(DiagnosticsProperty('end', end)) ..add(DiagnosticsProperty('today', today)) + ..add(DiagnosticsProperty('initial', initial)) ..add(DiagnosticsProperty('onChange', onChange)); } } @@ -54,7 +57,7 @@ class _YearMonthPickerState extends State { start: widget.start, end: widget.end, today: widget.today, - initial: widget.today.truncate(to: DateUnit.years), + initial: widget.initial.truncate(to: DateUnit.years), onPress: (year) => setState(() => _date = year), ); } else { diff --git a/forui/test/golden/calendar/day-picker/zinc-dark-default.png b/forui/test/golden/calendar/day-picker/zinc-dark-default.png new file mode 100644 index 0000000000000000000000000000000000000000..0f3dfc9db93e6e8692a0057f0c76c80fe2a37d8c GIT binary patch literal 76005 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 z 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

9U@xNdGEd0cvhP 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�bf=~a^&!j%66Uo)Jiky&#L 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/calendar/day-picker/zinc-light-default.png b/forui/test/golden/calendar/day-picker/zinc-light-default.png new file mode 100644 index 0000000000000000000000000000000000000000..499ba0104b61f2dd1ab5f27cd493057a234701ba GIT binary patch literal 74398 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 z zIz=~z*_&Sif+}!+z`e@+_ot1~jp+61En#xnOSt8=jVQ4P|AzeW!_wSnF;we>E=~r$ zHlbFu*<|b|QH>&AbM2d2dAshj5gpj*zHC<(Sl$^nbAshzjTM`ICpnJ2V0#FiJiP}_zCfNTQ6al zMYH#Isb`)T!40W?I0f^epdNJX5sjaRjVd?n31$HhUVh1%)BwJ#H!Xyd3FRULcjebb zN&aTNbxv;lLou%)UEG75tt$}#sPy?hzx!jwyBVy--_GNGZYdkJBx#NnvUKgmo|sz! zkq@xd&Rud*`G2U#O12V7mNe1)NMyND>2gt$PeJEp*j|v61uq+;wzzB8 zJ0YnvOPjL8EGbQ+`_v|_R?>!n?~B@Y*$~SXZ5Nd^sBa_uDj>0$lOA!eI%U>V6v#Uo zoHhsjLSze;So|rwjKyh|#_(|hHC~z@_28<$z>hYCrQ?=Yb=p3dX(jSKeTF2 zqDAf1J-G7*=uThGG)za*^2~DSDw^@W#KI2smsKTRU=PRvNg9STx&f3k8zS47J`%dY zIE4Rn3ggB8Ho$N2{kV|Oh5k(NhYl7s+gqoqt|z_v8hoA&()e~_UIdOM2aSwkIY_q8 z>h_f@_RdjEzF>%>PitRf6qW~uXdSaKXPZIo9mfuoXg19DIM0bv$m3S?j# z@tjmtzr~;vCU6p*HRIwuo%_-vA!gV~xF3~$$VZFY&+27)oeXh*$O4D|%s_AegAJGK zx3UC6@Ao8wNi_=M3qDB`c8+ts$zhGD1muI^hxrzC`;kId@+>V)Or-5@mJMo>1661id)W$Q#t$~ zXXJHQM(+>w=l1@o5PI>}d*B!n2Es0+6pm{hQIpN87Dj$BJ&G1`u<@`(`<*>ZGrgd( zjti+hatoao)e1f#j&p83e=4|q4tl!7F6s&YXfO+V=u8)!cy4)UWps0SnOQf*2{k?zL`2Y_rMs;oNxD-0QuVB0v#*G>! zm;q1HEMPlGxzm+v119BxS{+*%L^N5a^=`~n|E6=A>987AF3TyDS6sAP`90dR=_gxL zb^2r2+TIg;UFkN*e*Wd;c8mE*${r*seR@9A7-QY0Ipil_ju5ut&c?Br@!ov;wulMm zhFgeMtM|tii-RRE#Y$4F4%cs0TC4Poe{zyG`Szy>&$ph)fbV)TSX|tieJ}v52|Kgh zuj*Q$m}y$wb4{7%HQSBkZ`|0y+hOXUyhubQQIHJM^z6eejHRv#iZXzpBDx(vIJ0TSI4rys^G1uQJ2V214q68MIuR=rytq5t8 z0uv~lmCJ^=th(duOZs$4{%`5p$c%g-g#yvR8Agp=n{{q_H0&iaEicm zJvp79AN`wKx8@_b-%0)^`Ky>Ih+dstM1AT?YZBE6bGDkQ#0TE`hK5h!=~WEt>N;;) z2>u}zv)`H>!G9jUv-NA0P8KYP17RXMCoCFv=bX7$?&mp4_@mTLqN_#2%F%wRRi_vV zdA|WZlG9t!(J%!AL&NSsz3eW~U%h4Qd(vX^xFpm0VTdBeAN}r~qMIEt8CFosH*!Sk zz+@6{aGipA^ebo7okxRc`sH-SybZ`mL?)z{Uf}Y+9G&f*KC!Jxb98yFS?lKhch*Ts#w4WmCR)rwYOd9 zdYT8WO2E8xZH_Fe>t>DRMZ&x7mK`knddfM-`t`G;Hq~Q#=~I8%4A{c!@2;}!)O3N< zo63Ggc*sI5P&Wj!XVmmRlGOKq{z#4eso6YH2wB*>-1lDn;T+9i{R6HD8UinxF;q- zXQ+^I$A`2wpjxSQOd&dLX|a0gM2O`e$9taE+S)NZYu#z7sBDDV+v+?TeX(ygBb|Mf*_v@_?BR$lz^#rQgqF?Ru?L@s3jOZ)xV$gl-J*To&O;XAZ`Pk`{T`ZfSaHfLI{++WLj}pP_}l?N zScui|&0~#v%~8FCzh?4MrHOiGyM;;qY!oblq~n%*_AIx5&mT}FveTW?_hpn9i9PV9 zLe$2D?h%+Gd!h8F)|<4bI?r#gh^27%#Yz?)J2x>HVs^X+;!1jKkL4#cPN~7(_QLYQ z(=;MF(=htkOf-P|y)OGKzjYJ}M6LO$ul&aeGBDKUXRGHl1J_Syh52{v5B#S(Ww zKI@g@Rd?1$?KduJQU8e@St?FmL4j~9?FFh~JeiA@2ejT;XqEXM)+>d_&_w*yH7lu5 z`}+t$xt+^u=4Fw3%}}U1cyPNh^PS%4bg=C`iX!B{^+QDROC+!fq1J`8-99$sRbp|O z^q=3&XZ=cX5|0yDoTxX$Vk^Z`Jrg>PZo!g{tkKH7b#q@tt14{KT29q^dp#=(kXVAk zM?=guA}wf3CIFux6JyVml<(J-+jt3EYyt-wZs&-=eT-w%6Y=igwVgU{IOzzK`3ZIu z-Rnf*j`#}{w;R+ZGYThs{Nd~B`A3@)rC0>^Ziflk7lqMvcV%$rVbXa5ay8$vnQx!g z!4)85`1Q0u?6LN;v{e%BoCISd&cv1h3#GsdHsTAE0!JRSCj2HGw%88dnf=p8xGT++ z$vD;xRUJjP?-SC+TSh?RP)FrdSDf`tLq&1y*fFm7sGPY!0R=mFyJia0=0I>I%%F7M z4cA7a3v&ZuI56N?*LY}eZ}-x$#c92|cb?7JVRylXea98g9{K`Ni0?G|6;DI1v z-MR8avx(Z&2#o^AWVB_$nA>S5@p2`lv*76uZxxuRNz{i0!yC0fp_xJe?GM$N40nsR zy?n_am&s9CSvl6CMXl@*U}v`rTo{lO?T)@7PLOB>a9gs+u>HMGbtqt~uWDUx9a+H1 zdgD`-N8HW6o=)wBKXJi6%PXRO0VbZr7{)aRpSgE~hQZe+`a-tP{7BBpsta8Fz3;Gh z6cGMaU&_<7U-7+pmvu_Xfx2sJ+wcw*y z@BQ_LXs3jf)Sqs(oK#|NHpJFj@mrZHLUgzf=w%OFb8ge~_i`F^Pjy)3^k*QgbkCc| zHZ9!@5lP^A3uSyP>j6F_SEsc~(mGuu2r#R}GqyIzdbDWz)p?8T-@8fMO=#_==iHoT z+&;|y4C1p7p^%rC)EV+0=2gPx2Aq85lj?5N4rnn6K5lhIkst@4dJDlmo^nx-07VjW zeo|`?Tkz|Z#S4`kH9B*tVD2cFi_pP(qVCC(FreqB_` z2Lbnx(b^j6@t+|(=>%sk!X?`@r&?g(&1u4R3bs8C5j*+TrND!p4?P>lVH923<}gAO zmjF#l2Fe5)ezl60!n?8GN~ozCr3XR)nLrw)hoEykz`v4~ZiN1#(0~e?aDd=ICfKBp`cmO$rCaf2-Aj|vFC(L0H=zz^< z^KSY!qmj;$fwwxvax$ER6W4hH#~!s>L>K7}-p+}7><6)d+?1FT1J6`fimwDVE!VOH z1o-=-b}~=t90ok$5u@`qD=VupotSjCL$NSnnl9FhcK91eOLmf6ic!ahWc2*WnY9~b z5*D{sS!_*2jj^=A-}7LjBMY0zA-i>OTe+xMZYOx}trK($5&uE`P8o7@^WQzI ziGTpCXP;uUi`dqy$SErBfdmm7)_xSoD@~l(ENrJwJOSEsZ&ID=kRoh0(3GlA%y3SX zj4RclE@;i-cSSP-Buh{0>ZXQ`Kd^Hg72`>vp4tW436`FvrI$8(Jwf;oCCDm36aFVP znBhYH6rV>mv*n(?ewV|i&y$qq((&q(KExvd@Bqk3?sl9n7M$PIWF7f`tHIz4qN2~W z%Vk=pM4}@~ry4U6!WC}y>wh&D|Nj-5kmN8kvW(XZtc{F}#3LY`tt$i$stJ8ahgbfo z&~;WFv$*BOzZ5+;z>O6KJz1-??|(4pTHdchDD=)JPFarx<2ji88&?gOF7jH!R&a%r zpILdi)c<-pz)FE!rB&x(hzy%Et%jKES;oki{`*pX!2?nOINS>1PvCLra|rn#x&g?j zTL@eWT-BSM3*R>KUV&*AL(MdS6}Nko!L-qbV*OK2Z35uS#n%l3-i>J zQB7QSp6vg#*5fS1s)?OUW#AEQU+m(GNf&mrBepI2vy5lw)`Qo zK

xoq$b8*RHO~RUM1-FY(A5wKX-{XlcE&j9qwa?an2F96Wds8w0>*S>g;Mj9Jji zi3cqngqTZBEiWW-YAybtwxtEJM1Xkp=3(M_R5eeTSL89yzhcNHFni=fdU_3+OIuqu zh>I_l94pUCyG#^Ow@=ozwEX=pbx$0gS|Y-B81oJJF&puDoCP{mv^KU9v^^1>R&E@Q z+1gJG_o212>ewn)wE$D5w6sPPz;5cVfCZKub$F^Ta9>i_(KmzPLgUi(>|EkuEeN|l`$B`Uk5pW3|xT}EJ{EILYs#gTWMJ87d zaRYZvu@%TBY&Z#}24S}gW(czdd@Cy&fS7B^#nfA;xXE(iqCF8YS--pcV`a0QXKd2;N0B6t>J8STxf@B zAzcqN|2S@du$Nz68dY53LpN+#+8oahVT?zAs0uUK4>5io>k+%Q{WUH5c?SvAc6xd` z=TM&AwD((|(AseI!9YXD1fV(pQ-Z>@osePo+<7pss%vcQ9iXAkfFZYSOC~T_fCPrk zlPGDlfCZqeI;|B$;e;{1`{HyrI)aS5C$WB0DhmYh&{;P(Nx?Edk7kkm1j@KD5iQg? z+y>0`!{StXFAy@HiWBqE;Gj7o6v^spHHTXju3z7dmchXjj}%RArQ8)mlft3=#bJ}u zYDX&x^obu;t6?3U{FPcwq{e4JMEk#_I4sXMm!b_jz1@aL z`J&iQFW#o&KYb^!9D6zRI~~!dw|I}n6X;G}xKw?~Fmy;@VhTbdUmtvh`f}9TfzOZ& z@{csd+pr<)K385YLK^5wtH!KFfgFj1viZ9KH*_r2Cv$fZohJ2jND_;1HSn}#HNzPZ zIL*k>%?@+s+Gq6+JdpSa84N5p(~sIuN)v4cB^&mr22O7GC*>364WR6{UHP^-n5z)) zr=sg(&WznsWCv02LVsZZO?`a43mK{d6XF%D2z2Xf$b47){gcD=3{)f*(!Zf@m0aQ3*EIHT_R4*-SR!+Yu~kA zyIgl<{WYrg6fdJz-(3A}!-TibMJjZ)9i7fa`H${5&?bq#-CkXKK6u@z-Kb7iS)=Fi z&VcT)!9fTntz|1K6Z{{OMMO&{06=ZeS9XohZ59lZfvoA|yWfqGYacj!vzRotrVe}9 zIy^4vACHafdptENqdf3&OQS)pP8TrhH{MvQWM(y&ocQMn&k*(s=;@AZQjd#r9Z zobFC`g0J*MR&}SArl@;HYwInCZ|j^Ar>4HJymtEYBCHNW#6g{N`5lg3BMaCi*0K56 z7pHK;zj*m7iYnPF&DothvuA&1Qhv4aRLp()%*UTI+1{OhBA_CDAl+Ut43{Xc)yujz zqvF}iX=UH8`)|vV((j(D3f80M&vp4tL+3Mq`6XvZ`G}})*SyWV1oZ)h~rmilcKXg8SFc}9KTmudG z7Bw)Z7@x&YPsc^dp2?5v==N4QAoH1kOlVoJGu!g|@SdibKLN|qUS3{Nr67{jJFVJ{ zuz>uUDe`i1FP6qwmc=lg=xFAvz(s;03_p7 zGSRZU5H?zyklFPff;MT#0u8)!HZF=rQ!vx+@^ps<8T1Z=gx#a(rCgDKuF8h3R8qQX zYLdK}1roEe&Py~svW(Af_9ZPXJQEQSp|K3AjFOMj_X`So8y_!OSyiP^YKW|=GOquo zXfcjTk^YNz>a8ZG6Oys|dgsHJmexo#4^t>~bCx%+Ur&sPSbOi@y>ji;vOdP^& zRC)yWl~y!3TT4>VW*TgqJLYPWj?IM_!}oD2(J=mRr)dTq)jKz&SityFP%~uAEOTjT zv~sk*+Hp#*lT`0zvXoi)y#}tE6F9dBZL7)}^KH%jA){6@1IeY#&3V&j)^O50PUm!Q zpw;Mv!>;XMWcQch&`oxo;7UfNC{X^CPDGw`sQt}n;xykrxisA!j+Uf=aqq=nIzn<< zT5sWyz1xazlbVW(Xw8AEnwk%)!dPew@_zo@8TFk5aW8N0s}1b*)kAiiV#CAx zU0+vf*C(pAzYGbP)P@M;>fysjaWqiFSZ@OC62q*$nkkK07LV{Nnw*X6dC#5Ob=Drw zJsel!Gu~3lVfEk;RD^LOUKAZ+oIu>Pc4zTY>7mpA`eJj)Ep*WgN<7g>2Kx>bkb= z7g`86^L=?}vDE1T?@4>hEH`FbStxj-!PPCqE8}a}wFa z#H1PLco@exeOou$Tu2vWA{Gb@4U~#zKx-Mi1#oJM=CpIMgtTBrN**be)gvv&vCp;!SMERPYN9HoRn=RCi}Iy_D--4Bo7- ze+9>cPp_oi&sXfa zaJx$Y=CSCTnD90T{du0FRYMzpQ#t#$aNg4`z3bOU*Xx-d@elIe+G{13*=^i$qfYYj z<%h;uee{dpHjYQ@4!37&I8BH;-4%1%q;cue17fEh3c*c`Xr2Qcex?CUPSeM@xU@bQ zESE0N2=CstOV`wNiANW^tM&EpQ;&~ubIarA-4rSLJbi4}h7GfAN#U2o#J($9e-%dPcWxA=Vnl_MrLrzX!qo7JQ=f;<*h_tgA zdx?ONbYZo~PC9r$Pu*e6L*q4VKvP6f~&IAv~bdustF4@=jyb}@5ZLYx{X3JymO!TEH#n%lS~olhHz*} zWcX74bRO?J3gAr=?(iT}_l%njm~$H!DurG5baalQz)MeWWZj@ce?#^eaXcI}yGk|t z2c^R#S+cyr2h^o21-rcT#C*PAM8d`*H z6rQezcK+KjYWdu!ag|iZH#ky*8K*ihLW~%APM!v#*)o|Jn9KdOU-R@x?)XXCba>it z%wAq9c-cM5yKj8f9{Z8q#EYI7ix`uf)GJr@^VhlI#mTl<6?7atNlE`x2(jgD83L~1aN&zLHg zlOsm(0At|FzH(s1VbrcVCNr~HwqSmQuJjGlaRpFW==h@>3|kru>u)TWOfVVzQTD>N zIj1WUWR!Sz68CpF9zF!cxx0{$WpP0C=JoBZRy<0|>FM0A7r%nLc|V=oFGHW()H^m% zD#YVDdZ?_={3wUVAp4l%-J+S>c?c@;-1_=oS&C$&rH=^+q#ZS&^3T*NRsLzD^0(Ml zH{q}Mw^GcgrmQZJE<%Gp2HaR21G zl|7Q?Vq{^-j2A6(ZN2*fm}yc|Qu}cE7t`|L&_G4&EYNUQXXVqw~se#L$qZoGGx8~>eUH`RBVJ=lDr!#HI+d5Z{T{`%z0R5)*6Gb~^ z2I4dv&JJV)$MBzUYhhquINfk?bF;QKV{~|+OAb|0!1L$V_wzU1iQx~CmRC5l!QyaW zXy~oq!8ijTK|=!_cRV|@SH_QP;Vcmh4;V|y$WTB9BTisvdk?kKU;96a<1K4o6U7xG zV8`>rKv`LNqD9LmE`9RKF8)W2NWmsxe6+lG2&qcfn78#1&JwKq@#Eb)YL%@#JUl}g z?MsqiD*KE?>XG%;o%DxzlBdDk-2AgTJ11wOY|ae#h693GojdvN|4s@wPHjyyYS(Tx z%-BnEQ3`zZs&-%?u%tva*_g0e1y*xS-@d&GubPOPnJ(J7tca6N^9bMe zBr?uhi^i!$%~wgBclr^BgrYu`efo51v9jADfja$zS5%R6?9q?@Jg|lmd)kp^eQr8C$AFjoc>}~`ux$#o9Sq{4- z1!=r9GTdb%!|iXZ{LJru5{c2*s5@$99UZ}g&C*s@Rz(hL+(QNj8HPLC{|>9xIoDJp zi-6mK5!Ed#E32ytX+NYkbAg4$x&qne%mR`S4uU|bG8HfC{<%thsV)oCf zii{4Ov#uXhgo|z;XIWD2)-hss8#k9wiZyeC~ZJ>F-5$@4kmSQ0o^M7}L?QytS8}erY=GYhogE zdPeA3)%woPxbkxI^C4A-2Uix|p;dG2ZEhEsee#i#G7W{zcjzEC^h21nSxWM2*v(!N zAG*j-GX0y-1$F1@-ml>~d-ffG)?>%=4&togror@P^?IR&!sS{l@<*Z8#0FRNgdQh5 z^%G4rfu=V#G@y)lr<>{VH&>8zV~2gmkFVccU0tOphL<)K1+?BGPYv_m=9`R3Nx2-S z*j)04qv*!Hds)bXPXtwJpR@XNSNGCN_g~VMohuD=MIm_ma?)I*n;=P%Ci}rl;#@5z zeYAZn$KiE1kUKw^y#-S`J%HsFtmuS_dg4`epoyM)U)i8!bBJ|UY{862fvk>Bbaswi zLwkE1a_WRzsS1sa^5WNKMm4YpkQkfL6F|9<;R*4?X=!qMj&&F$3_l%cRmD`=ZwW); zt6iJ7Mu|^-G#Hov28C{6a!SgL#%8kDB}JvJ=H@B#s;cjnmLAwlnnoWcBFM)(tC{0A zMU42;$SCvahS98k3t(U#mqe4EqE^$1K7GxiUW(Txw*<4=N|-7xHB}B1P*V7*FmgLA zIcnE?5WU_KHmZ-3s?~=L95%D4$)+X+@L;FkaRWtSVbq7XZ9HObZ4&9{Py4paQRk?r zD4J3T+|x9L9cZ#Yo1^JMchhZ~JoVW{$JSxPwZz5U)>}=7wkg6O&Pi*oaZ8_hmLvu0 zKvqJtp{LBkz;N9x+01vVzgtO(NZ#C#!MOhD{ZdZQ{fiHqtG<36fFvm@d}*W8Z>x$q z;a`W?*(v@i#xQI`kweHMe)zOF*<-KEjz2WGh zS0Ck4Aai?`Y416c52ff>fY_RLaPG(5@n?&_;uVh`E%O+mBi7&LODipX7drxjgBzew zGmPoB8x<(8tn|WA5-kFHiyt3|K!4+sCZg55rruUsTDr)Abq<4f9w#Vvzg7fj61X(n zouB$G{bcTMYQ)%a{mDto_hg-e<>F?Aw9QOwm3#!I0^u>i4D3#AtW9H~XHV3mL8492 zy~Q=|TMN3$B_+IPPoLI2=l|lxTWlB=+Ns5FxResIvgA>Ej_bd8!HnDTo4&#K?74Gy zmFeie5+m)bdwb~w@%RDl2+R7Ll&{sPSv#EitMjA&lP6E!zds|LWBYx>I8|{UU=e6U z!x)AD6N*b~&wVnts^l)wyHYJU9}IMge802oMf3z(y*gykW7BPN%fvkowMD1v>vjPo zQD^=#KZy~Do*$Xd4R>smx4U`c#+_SERPlQ@ttWl^sOjb7!{m+1TEEnr^D$ZBnWra> za6*C8MZqwWPX-QxVRLhT(M+OgEMJ5e@#9BV5tp8acyU0E6|Qs8r&dhF?JhEG|3Dn8 zgAkaht*!k~omW600pzW)?QEZ-WYfYr3A@LWu>9n!pJQ1bvuo(=G_s9PPnXB06rw3n zhnx@zo^*xXm0xhV5Lu=;EoOx;(JlY>0p07wo2PyE?v+s_RgLZK2Ir<+PTGI^!@Nd` zecPsiZ=cxE$jY_Pf-j^k%OdEPm19DlFRbwx^dDTjNY2l$o;azY`eRITuu*YZ&(^lh zH2%YfFLi{VjOsQkVhc+;21mxl{C^0VVpO=@XoSCSO=2M~QE?Kg+?ENh@6Sb-q!}2hBK7x6{NM_kO+&Cg5K2dfO3; zL_$JBfE@&YjFTCh802ythi2%AnssNoMC}>pP3zaL*)Q1f?)mfW^}QQ5*bM#pwb`H& z*==N0lyWU|#Jl(JRgH{>U7skTn6q7+Ts+3XAulbRafa)py_0oT2P2aOj>yq?aPcFl z61Yr67tyatrTTP*e{;TPV&9Q~9FJq=7RLn#2k#|4){Tw%yBYW`*^PzAnA7U_H`c{I z4OiaQ0i;B-w{E?XA7*_Dpt{f&(Nl!>q|B6-%^&D0MRWKNuR)clb{26bJR% z7t>#ELJQ9w(VWcrK}5t=4k}9PT3tHltAA~D!&2Ebao^5Pr^SFTWN>|w|9Q8<@JR}# zq2X@+q^XHXn62IXWp(Hi;dlK+A$`UBBdZau5MRcU8 zRB)>HDtR0N9AEPDbH1-$#ljD`lsNihU`{Q^YLLI%Ms=%OVNX?(Dj{mEMMLxxck=R} zOjt9ZY0h7poEsm~aD7&}C?=LXL}})<4dFIWh>dvoTYz}aNYRx@^fBe9c@_@3^kE!= z&cdO*s>=J4sL~cpgfL<|#aZ624n}% zdxKt69mG738#+oS;9_-&*hN2Q!&~GcYAh!`l=jz$wou)6!A?#jUFaCm)Cj_ckD>=h zlJIQ_Atv|7&#QE=QWL_*9-4YGP_k@H?~)j{<1evO6FGSEWI9>kJ@ON?Pva)JVwrb7RKe0D86Q*Qu>I~*yew;&L24^$ zc`;1Uz#tXNxLn1Te%G!6r{z&H1xY~Ou#w`)45=&6E45Qec|}F*C7K^u(q}h!YB<;V2gk*pam6t2euy%?+4_#{7 z%tT8^7nhJA1w*rXq|Hb@5e_4u9&_8>@u~cWl}t=(sxZ!AVPs%v>-X-t z?AW96!F%B$A4Lsa@qLQAIirthAj_9cNy#Oe8+r>et1`t9R_*pK*fI|Ni2?1_R&x z?|9rMR`!2={nvPG6E);fiC6jeA5e?Dg-&|&e<@0Ha55rFJVZJ$jZNmyy+ zTKTu*Cl{iaiSK#>3%|QtQY+ory!pTXO#0tHvp6?H{8cy$yJPdPb^hxM@E-Y8Dq1Cz8{~9=l|G40PE~V&vPN(##e$E5u&p#Pd zB;EyINi?e&v-9o)tgM%wJdymY9E;`n^4T*$NUKkwqB=4&Ot^bc#c#ugV1Dk`>sPPj z4{UR{&RL|(als9MJ{iKU7UVdU4{@5U-5@lYe*_3R)m%XN2how zWdc8(-9;In?FzoXa=;l?56fy%Pt~J(U|UT`hbr-;$Dc;0EAZcU(^K15q$1AeR(ByP z=W`_u98~Tmz`T8Nl0ES@+e&9*SMIR$IZHF!EmQ~cw?`3Ciuh*b(^4JSx?$}D-smVy zg0Sj-Ib!gbh$m1TSo_Zvx(iE+uW^3qR&BNN`<|WuUeq?a!8N!0zNfCt3+I^?OCZF# zbA{_{sg$y2JXf~o152y51=WG7-=@q|3MT|tz)321p?_bV>%qkXO}L8@kE`#mz60Gq z@38U{{znAUf4^UO{NG>v?|A&jg!n(04zicySEjYI$AV))xOS$>{Im#4Ec}O`*RCo1 z{vj#9Qu_rK_eA=(?BWi)RD;6eMGf0M-5vqTzZ?QXLK=&T;HV$P%}+sBPQ;BHzAr;V z6aD;t6lc&-yUd4X_Bb#P8GN!;DCk~vEGQ}Md>tBE3)tw;(evkTp>_r3^lj)@(T^szM7--n7Z5UWJgfe`7qxXFZ^D=J{ZlVh8)j7&l^UN z4Gn%r*aiOFkGh-L-bacePK_KLCx+mT_iElA81(8Dj(+nX7}rwpFGngKo<`up8P614 z3D3TYii$?>{VJR``yW>U+(KtQcoHC5*m1r;Co<$yh%rJx&d)Lhbl<+j)P z`D=h4oq4Q(jH4pmxN|6}ncv!2HYB9eJgekUXfG&;hzLnos%nzyC?8aNQ7Sb}Onl9? zwY7bnm~R^}$PIUAc^#e1NCzlV+5t`J4!%C6(>L!xB1z&^z_OfPZ+9Z4)v&y}THew! zG9@+j;0TjPeS16E-+!m;yt=$R41u^=$-Tf8@k?;VK&|U7kbdFBOo;Zv|NObJwo#&p zGWq`PTL}RH2VnZNw(3?^{wR5n;q4kTkdmn$`1*dZ4b>rmfj12(M=hXZ2^NGP!ut&7>%7U4_FJ6vLgImRT z)_wdqyP=wP{aVI-`vBA?iA#9MD`tvpbSUo=ab!FR`{Z`6{^&yz;kCg^D!O z*Y=Fe0y$PzmL@*Ta7(g0s>rJaf)APY?W?POTiQ21OMk%{3_$Yf0H9j%?*8jAyBlxp z5H0~~C8giF)L}c>Eq_V|fdZ1GA`1s0}$fOrrSF?F%g@U#r=yy=tqX)=1G;@ida!;Mw?}V z&m~kkw{EURUsCE1bx2mJIIz!wi_??{hW1)AQ+0%S^9>RPLK^ zJlKzESZ98DBONoV{UrT%ujzRVJ=+!yHKKrsjcxT+zikYN+isd!)_@`=F_N>YkGN{@ zfZZDyZzH<8BJ4idYiT9Ae^%Us4vX02G1+Sx>^fCxF8lMd|K7GqcX{d2>%c(I0b62z zy02fwJdeNfplj$bp7zZ*mXQf7DJ>0{;6B~`ABu}+Zo3blA0iNMlA1P8+dq!Nr^f0_ zx9?2VX_s2Z000q40nkSD^tfv471&<$mQh;V@;&w3SBEKWWy3p{vn{DuFg27 za0A6sb4%dZc$nU`CXbT&&OS!E>|$Lbqn8k>{vbt3WS{DUYsI*}3GZJ#sNFGJlQ`9O z0X+o~R_~uc08PKYY1TV?Lo@MSp8FUlrviY{+^+MqTekw$NOiqvg>eZN7PYM8wmVLt ztxMM8jG6>@{W2inC@-%lGCD?3M)&XE)Tz#37>O+Hy>4PsP+lSND8H(qfmBnL4z~Z; z(W5smUCMvw4C2$Wr|4+mbkM~EZ+c5r(sio6e=ms=pxeLsveFqNqy3i(6>&->pOa(F zpXT6@$@l4#@A@bQFH}~tOFr7m6C?%c5aa&+9=d9&oSQg~l^@({@R3iQ%&WVX?dZ|# zn>TO%bN_RgG=lb9Z*ODa&hMtW)uF>E+Jh9UD=SekW=)L<{2gYpR1{ZL#f(nBqo<#1 z_$Vbr_Wju1HU5fmKdr;sJCMwoTUdM^VcoU~vcr1WlboEsh2J;X39R3fFl{I5Haihi z8Ppt?lyqC2ldW*}r;wCX$+K%JDsBXQ3U!FFRTC3L9Pq%HpJ(oxNC^+$UT>O?QEpTm zRZwnoGT9GQ;7wiK9T3U7qh0G>2L}rc>mu`h^hmgXZs>M0Xrrj<)TE?~&;UXaVVCM3 z5)ug*9BYnPNehn4xdv6CMg@1MI9i&~Hur?b*f3C$gM;I`nOQg^Q}?L_7wUkD$mh>% z-SgduiF)zF48@W7=FTzfcIcmx6&6;z*<@mD%za_v`=|Lo&j6BA$WB3+fd|zKf3X^g zi)!xBjo$KrRSH_z( z)Ubod!On=gAv!u*N+|5Go_QTkIH_V90yF^$Le~T%peZ0PflCZw1@1($eLMCa6rBrH zLiR{@+*_UmNU&Q-@0&`zC~yDRZt}t#?idTKt&02oFhiGMNlRk&(sXVz*v1ca_KAFOaAMOB9Zy?Q_0a;<8;|w@yt^skSg8F!A$OOa$MS8=IT=x^z+u zw#J3KH8`*yEG-RaC!ahK>slsmzW;izDPkawXEik3grev=h}Y|Ov_Sd6mk2vlzLpo4 zx_9|TJiOox3SIw#VU2Q1S0A1H&K*1G?YFr{qNOGlfF!+x34*;Od)w|^dkg8c!7}a5 z$oX2y?V55sWMSa~2wI(1d}3_(Q7Q*;>r>x3vb}QQ*R~Bnq%p|diBaY>!*o; zfmOj_J=2=Ko>i5Vw0b$;u#yNCZQ+*Y{rmUJqD~Sqk{<1AqCXJ@mNQ?(l(zL2HowB+rb(8otQv&{i^^$-6pz4IJ_L{ICKYl!m)`JKLS`!0AXLX0Wcm1gR zH$Z{-?#Yufn{?Ueme*3OT-4%oi;e^>Fr?l7^mTIkFmC=04UOg8xo-zn%dgsh&`#f@ zCpBJgWa;fShGdm#D2P|XhO*;|jIeM>pMkUt6H9}7u;-3V>%or1LPCdBIHlbP*DH^_ z5OHsYPiZZ-BWQY3NK&b8DSds1$CvE1wMBOBd;vAoS>Ap*$XV*@ZUDo}ib<&17CL9! z%OfjsxMd=)F%A?ZXDwznB1ROeGxsS|^?UaYUrPM&(J-zK>Ou*-LYH}%htO9v<=E># zKU6>c=VhRjn0c0GH~+T$YrWJl@PJxme7BFuf-EgVW76x)fNdOorYpy?9tw{E`EM@Ev>AO8rHiGD(!)E4*X0^RFwGU%?nEV zWI9H~ggFoQeZColG$=hS`0Qiu6Db(VlPBe+q#_|fiD+ZL!;Vjql5*!TJJ;f|E-V#> z&o|lF-tsx-%44-Nd``n!F7-|il>YcWA;DXptd#2!)*k@Qr+#80ZSXXgwq{%fd&C{R zkn{E0F&l#JWVRgD^_{($X!>a7WcY2H9qVcEF>YTS92kHO^_8N;wQDummIikkwnyC4 zFW;LsI5ML4n-9w}BV#M_E4}_IBSW!0?78Y>O}?jv-(?YQk&Q7jGt-*)Z9p!hrY3*{ zxqfOmNVtn<^H^j~jv|IpRwMoCpyJry0s>M9IztquK*iBfp=d+{Y&(B*P(ItW_L=M5 z{+6rhaaIh`6b_6-z7w8bHnblk-M@e6-EeP*aps_c_4=ecrNg1JqM`xe%)cC8cgC3t z*MIt~W?>s1Vo6*r0h%TSo^e=sfm( z>3iDRN)5XsiVbbA0{($Ue-Dj@S~;@uj}HoA$?^!jISGc_Pyd{rx12I`TTw|g)g(y+ zGwH9Qt%}R(+=)p@pPQd_N+?R@&Os95f}Wn9>w(2sIURY~XHLZjq%l6v*-AFY_(}@D za>qzS7rF(}SYkT>Fkf$gYoSg5@#FVeCHyI7+NsTrl*tvNWU6iQ;ngDq{Nj8MEkCWl zlMZ98A{!x8Ja;psD*Fh0D=={H#QoL8=>9pTjbGO)F<1K`zoNCw=|sJGw{Yri0H1A| zO)ab7@sqeUk_E~SP!YjIjf|G1#2FjMtRFuP!2v}IXX1V6(OKgkFf=4CY-DAnfXsAL zwil8866N0~&Z4SfA&pm395}2-tA=v}BIVAcgPUt!Cz#NW5J8TL<1}$ZCe_EMHQi3q zZ{KQ-W4%bhNuel)?Mi!}W{w9&6Apx4AOlPUor920#l@*0TVtvUL%|G!vav>XPorb< zISUJFw;x2MqoR@k>AcvUe37aUew2A~uD6NtMCu0?Pvz!ZaowL;`%6(8FHbG%6N;g@ zf@M`Dm9omOUy-TGK_@49-jfaUjnAydPqU&G%sY;yaBOT$kk{1A$1q^@xzC)5YHE6+ zNYlLSql&GRRHds>fCRFESAhK=s_W3FNQiF{xNq~k)0o%3o86G0ln=D6Vx8`GVDusN zKHWeWYI4mp+T2t6vyv&zOzRPfZ=_Lv$mn5xfJn+vB_%H2Fw~eXE+eBT_rlC0A~aMG zmqE+-d`)s@%_F%~&J9L9K_K3LkoZtTuokXcOingKcNFw~jei`I(@>|;PAlG-YZR~P z>WbvjX*-y0WooMQ=ushrE-%sUeSCzb_8amOOUeaE&RS7qptb$g~O zKTSIHLc)Uw7OuA7ypbt@rhdG>w|7fw^^{BChO8EEoaP0|>R3HH9-Tilx7pVHHZ2(> z;S|OTBKtLCA+Wl4_Z*>Az;0O&wX3-JQ_1Lv4QtoX(ggb`1SNfZ$sC-hu4aIAs2th} zzz34iZ%EeD%5^Mv`pfIdo4%K%hKE0Y^Bu=zN+Q|St?>71%eH*`K90lh9 z4aQ0Z&2VgHjZNz3FEAXpPuCRA3m5sVJs5nxKFZtsgs=cofr07o60f9k{@7M#hSD6_ zwkgoj;mR4Y)z$wGY-?t8_papP;yTwk+>|>tv^|$@-NIRZwr2$e1<8UuJW+LZJ$o%( zTn-(1y}X4D2ySB|wM<4?c{%*K60w5%8`ToW4k#W_Cs|Gs(+k0&4huoj$EYh;9m{ZB ze@`Y(9WjTMk!#n@mYPnf3gxIXVfA~o|qsNo_@$H z@fKM;DXzb$=n7QCg{17pK3`wY@K)0d=9jxj{N+Vg)@I=jP(^rbCOX`xdi=-tso-+WMgf7W_@%G!zB;}qPfA87u_0?t?tq)y zvyX?)5*J=uyo#Tjp-aLFOLFfJu&klsVQSluiawqOlwd#AUW9}sfE6=fEKYghubrD& zUtdB#e4ORek=ysQU6*bPu(P+z28Ga?r2OR{P*pW@pq~7mkQ9?fI^KjUCR~a`w9VVyN$yi}~Wdij893`ZYbaJ0Rf7C}u97=6*F)?|N$g#2G?60My zZD|Z1k2|dWP63_+NJhBRIMbjyG=vb6*d$bpMjrxx1i1TIVUzZQ1lcGPB3u1ll@a?Zq%z;XZx^mK99ruifGWE1W^j18ruDTifu|vq$`!sy}|T0pevCqtSAVWOwC7>50FFJ4R;f_3douE@%7T^F=w8R8&_} z=Ma5xRGa?k&b-($c0Y>r=ZBs!bzZ$^3H3@W;=e7#%h?EmjjL zXhRHQ%({E)JA!8?;+}4a(nwhU=`#;fBUU#)5s|OacU^b36f`sn5FJm<=;SUfSwvZ`Qd0hF z$1{lAUzDJ0%vzM1-N)H-cW0_|WgnUzq%sfC=ooMmiI^piUCIXfitUM7y}h;7h%uMr z#EGPMq2nRm-qQ7AF6rsmemDQJ%Gt5Q)5(N%`JwH@&^x&*AJ`@XjRNgdk=&81_22p?_q(Jl2(5WjY+YZ}`lH*Y565Q;31t?M-NpFcm1U9DxJ1+o0$ z(k#b5G=QK9!NAm1S3M8%6qLJA(4JD|T7?AhHZ-Lu1&?PFn;F%nm2=7yP7Zh0Kjll#{yJ(&K0^@rl{?dc6g%EN5ht9xNUG%PI&kWn*h=0{V;U(-p{xURF6t z*8pY_LZ|N)p`nh59yjIWBC(UT8txgfv$i&=;e4X6f6S)4G<<66c0HNCD}rVW9x%$n zRKUI*bbzd&$h)Df?HXJ~5~~9}fKmr&Yt2NOS^0MtZi9$6E_yOh7UYkA?q3)mIuU?_ zAtzK4l;xp0loZ>O@opa@V8aVPM{1#-q1yPk4FrxTHyIYyZ{WSj=CqPSAVwnuqmmKxi zR!De%9fQ)CkQa%Fv4iv{zO;AqY?mq=aOuxFgEfhI|6Uw56oWTfnO^<%`=kz}%}^&Q z39N?W-^~|@Z>Y=+C{0r3U)&eg7-(xp0fI_OVmt2A)ARYN6hFd#Q&R#H+v_)OEn5T^ zpPuRzPt&eECb1UfWTYgYCmW(#Tds|8QFDObE{lSxdno4ywj$OPfxi&m^l?B;<-kAH1; zrJXbTsHoqK(_N9`4rkR1PA>7!gc~pD*6;E21&||Cywu^ zatL_m>w6HZEH*Ds0=sK@@2f4g#(*b~ZTh`f+QOMU3 z_aN9hi|!uVP`n%@RQd*Sm;l=HaUUe_+=&455U^m$#5e>lCsr=HYG7gZ)0_U*VXMZb zrkL#Phtn$}tH2~~xAEpH#GJ@I8fX2j(&;1zhqop>)rsAk)&qLiwY3#dAB{g0gz_4+ z84lFB**ZL>l=(pyxNQ^XaS7DZP-A-eU!u4~72k z&s6_!e&M%`uvmw}z#dL;%^;hUGPghP>A8#~m$k|0-vrgb*S^f|P)Tq9Pz-Xn~+aY9Jv(3M3(Se>msfv+i2={JDSb zx<}TUC1jE>-}jcipZ)CT-JAN5p%;SV7bIM$xup=`{d9%GDcQq^?;Mif)bqZ7?g0VA z_v^5lK1m6Cc<+}Lhpn%CpvbLf@Et!cyx5`r_}#DBf&G7tFKn?WIe0_ces@0&9|e~_ zWbxh2FMrF{@0CuLe?R|kFBIgDzixdO%pkx2cl$ux`Oum{N68getVWcO5Lo%U)`a)Q z`GGhuyrvZrq%T^(F9Xv9GUF>u-54x*+bnBYH*zH-wK?XBbvD`-nR4@e^o4#R%^yz~2DE9b|VHjmv8~ayV)O=aIF``-^nJ^?KQ59jOKWFNlZ*Pud!vB5kda=v4s8`?;B(R{1?W; z{`)eG#=2^>e*J3yzO%D+a4-&vn6H(v-Ma;fjb*(VpHt{@DzQIN1)CxL1i{|F9C`$J zL)L$6eB3)BVf(j*`+K*ng?ASaB3f_E|33P-*avck8gKx`JElfXLW14Z=bQ+Qt)QyP z@Y96k<`GO|gN)a?bK7@}G>((DyP%?;_h19yN+8IG51Puz$`+QFYsf3C>jLi0$|@~q zAgaVZIkZNx=!}7%UnoG(9j}B9^18Goltwn}4Lmwv3^Qjx7wh5doH{uHokoy8hB6B>c_fGi}5%8L0^b zzQMt5gS|~n=Up2U_QO*;Rp~*y9BVV--G!KvQ-rZt;Dd8bXEJWxy5*pJr*pipxY!8j z7vKEI&Fbpv&E3WEEWtvGv#YBsJ7i`iu#1BJ73w(Lslh`@5KE8YIk|1yP;4#uK6q8( zrlfKz49@#_R>Ekg!6IM0pb_&cAPuK@SLm=gJv_V_8pij{uKt#-DNcj3yCtnlG_!=n zZALD-Rc6$__k8Au50_o*BEyEf1$m-5QTo6@+PVl4*?}LctQfb=I*-!~#TrU80M#c^ zslt%YhpfjEp1im4nBy|d5{s?*y5XrJs4KA(A}`%}12A6H%(_Y`4~11?R~r8zUVUk{ zR9Ec7lu7?exuepUn48PcNlTN2L+t4adO?;I&Sks@4~-}^I^O!|kt3t|sr~&m&!NyJ zT9($WXcT!6lpIx$!+1~Ofb{cNw#EC74#&9DP>BaxCG~do^we(mc6M<|7tLXo8Xd0X zu5?zw%X5d}CZ40Y+_EErYhpbuC1dP{s;Vt|L4z^DAI9BaYC<^EPC4#@OuTPp`2yTV z>*vqdG`SJwpPrfqe70_+oaQ0*uMXIvffVRF03UP@`&DJ6edY9MTdykhhHpTCF&v-I zbCU3=SSZ!%ZT8YiSXvmlFSBwd)t>P@o*!f!JAb~N<{i-qIaaJwaM?a+2Q(Hd95>T! zdG%_F{A>wGQN!iWAiakqm5h_&03mL{*pVA)+Ow%8F%cF`YKp98V|8r5i-1ERNesVA zCOgoV_>pZc#G8KZ%#@UqtWJ!(s~yj8RBpT{T!}fZ4R?F!d%xh_)Sx5TWF9Yikc1YI zGWN-&gzz~-&%-Bsxk2$QW2G&wmgcUcSnUeJR~O?rUUd7qq(=(Md5Lfr7fmrSF$NlL zi|lJJ>!8Tw^UGhp)&8N|nJ3vaH?Dagud@+Z+eIgx_HSr?ToXDvPTr@)qCGVJ+z^k5)-*52Dj3eSfdGxa`F3H0f%-z@k(NgZj z)W9~QD57Ok&aW^TbUC?WYj(jN7=gCDC6sqirlcuNp&G6e<1OBK-`=}?=MMKqrSz_@ zE^{<2tU^mkOUu>{Uw{8JsDdP?kdx@sxoEe4&rnU6ChX;%*=@Md*00;DgM?WF4PicL zWH)WwW>nbFps`1#*z5dxH7ExBz_|(7|Fo-Dvnw#7Daw|iM$vCNahYwSBYhQxAZ*f( zoc2u`9ra4h$gsqS4y~6|!4?nJanbYh)7nh>{Op%Iuo6#H$*#SwANO3(&@j>h*roUH z-?#MjMZ*~DOFh|}-NxcGC28;Pb>C~TQOz7_Nu%8B*q!4?#Xw!>*7SIp1;IdrcWqDW z9s72=@a45uEp6>PzIZ6pTVCGLN5IlDdi&_TuS=w@v$L{Bx(Zc71Uw&q!SR^hiym`) zZj>b&je1-mv7sTE#X9fd-%kW4{n!17k^5(AaWS`;h*=mN2Q%b(l)@OQ^Wrkxx~SAF z7u#_btvF=rQ+5&u7C_Mrd}xhpRdsbU+;~e@r40ElJuy+mI(N?iy#4^X&?g_QKb*gj z&yn_GQp=I$ULVa0Z8m^j6Rat+&GZn3{W32toJQMRLV;9!M9V$xVkfmKVs-UVxW8%Y zkW{vY@cz$sCa_7!Vm$)E;rcj(yS|{hNDpo_*_@Vk-E3frKCJc;dYZKi)itWfjHfhv z!F%L}hWI`6mEVG4!!7df^rG`^66eM{kH*IjDF>>nw|9N~sEFo-!{Th*^M^F_6iUB- zz1i3IiN~D2lJT({#(l2jdeLKtL4(k*pA9XnWytl^@p0J^=--vZi8ECm@61aX8+$B0 zQx_T01Vz0^JVcATD^@cqed0sDzR7=rol{}4`=!^M&`tG<@|>e3zD*x~KFmphJDk5?}gUsu>oKPnjEU zw2pU6O-sYYtOvzj$?p=G*1FaNW+U?keQN5X2P&W(OpBzl>FFv6Wm}*hyJXTV83nGF z1*fQX4YZ9uj)(j`pq^A!*riY)A7)~dGYvblnK7hXp8HpiwF`TXYBom{%%qwq z4^r_Yk~&-K(wu^nmVrU0FQuk3p4==lqfZY$^v$_ntHkI^8_sqd&S+C0c;ypCA4{cA8yZEm zme{GNuD$TIqEx5%66y@0sw(cc+09a2UAJ6+c6WXn-yi$FefKzg$5+vK6ifoh&(e~T zGBb4?DW}V^SnY}@F2~KJq^zvomhOY<38S~{RRgI}Gbe5+f1Dm5Xxpyv!S$Z=@W7n1 zw#NGc6~h|M&TA$3>-EmN+Lyy)RW(qZX42d3aC8u*s#WL&0+%n*_1GX}Bsw*{d>UI= z_$=ghP+h{<6jS-wP^ShtxqX%<$D@LOBCsRD7ZL~EE6OndxxwEDNH|J zX=Rub+{1p(^rY+XmA7RsVNh7D9QsjXr9m+3&=S2raC-M_FdtM`EQbPFXc4OY?+# zr7$j>!<$dy3Rw9t$m<*spJ{2iE$k}~h<~OLEt}HZ zG!meZO_@F9TH&0UpZ~=i?eE`qgEQx3=iwoX=I*J^E^PvXSAe^HA_n@lMd;ZE;tRcf z##lBrV4sJbR$!ggT0p;d>h$TB`T0{wmvgAo0F@W;lLYe%u*9rSo!T=1Tly@Exv+2@ z3NxgaluSCiyQf1RETlUchtuPLExbJxDR@tCVPiW@jh->af%0%(hZyM3g||2}k?XK| zkNw`WM@GEnxn|Z?)x=n+(oucYHDhkZ`){S$m0B4iLJ^xJKKbMxX?3!fo@P`STom5*_n+PaNt?e zg?u*}DiGJphbJqT37iOm{t%~6lY4R3e@vDkto>%L%Q{|djl3Q z2w3p0VUaOnI=$M=OZ_WN!*HC2@(JK*6)mV{sFd)xDmh!=vrf1Kc)2TrsZ zgg^yC9?M($A%@FfCIuG5gpGXueXi!=1(K+vQ?m>^Tv5T|A&Ai0?4j)Q!Il0bYIfFb z)H|Jn2bk!TP$7Cv^pzY6z` z3YAm0LRGH}1WVjo^o$26v`N!r!=3@jZBw|t0S2a~Qma;JZkqAwc#!U@QN7*!JPkL# zWMn4#La&8F`QH}EuN~H{TUX+6x6k!#IXCKcrj!(%|JOQr@WC>4Ih;RB^%pI&QPQLv zea<-x_n@)F(x)k>*7TADVABF5q@h5rC!g2ZBJ`%e3F~`KfKpJjx1ghOb0IEv>I&(>I)Q@}{ zPCoDibCTjC??yuhpWj;FHP2D9kq%KnF@@Zr%M8@b4eXYytN4W#tlh4*)bNYkA#}rwTYsc zYM+7%+nh3Lg9&0G_DMx{?#LHqCMEn zdR@7lq#f+%M&!{F&k zP-#f(SHy%rG~$jd%w26_fp=U`v|UZFp?0e(2+s~={qb*TiqvX^a^FWw>|H|Q;^KB( z^cgQGDG8AIs^eG0DG35l)nzbyDB4z?7(YO@5GXnJt ziDd!bqkdD>1p@-PbS(|n=UV_8CwU|Gc9nRn?jvQ@IUcJrdVb<~0SO2WXiro31m`Bo zQ@wv*-pO9SzdAVByuO4O2_c)g+|C^%oSET*$~h5IZaso){Smy>l%u^=aA|%Ok?~|A zCWv|}$fS=6$-$m`&!uSV-ocj3hrF%QK-{;}Y2YJ~w-XgRp$*U+~Gu^0n2-rVS8sv<@7& ztxtrW6g);I346$k}c&!oVVCGfcv^I)t4{jA>96kHn@&avDZXBNX zgVHKGEV7ddEk)DRS`h`Vv7uo+XF%iuk*c|CL!1t~4;G|@tHcG*&qq(4Dl5xEs@1Dl zC)6;sp0SAF#XwK8X8t3QbU~;)73-mXg%B0&)SM^zaV$Qlqdqvx&vh=i)MNLNLGcYw zmTim4ciV#SB}pe%BY?|_^;&Yc^wiuhB`vNXU~dHrZztQ2j;*D&Y2MkcsM`ra?g(RO zc=HT$v$Tw1{1azFKdi=$8Oml>YMUAr80Ul#G>&{M^4Ltixq}*@z-tI>S_-&yXL0-7b==DG2vV=voI&yH88MADtM(Kn#(BhRkXiYH-v#^U?W4>P~hjVL+h;5 zQ`=s2Q%-5(C4l_<6VlVuA0`p2E^nke;ry2-yBok(T4t>M1knX*nGWug2^v~dUnB0Z zdtlx5!vY?Sd#iK2+S5MZ20({zp;{X5^@<1%_l7S_vMaWKU-DR1a}BNIVcqgZfi@p* z09%~mPr1201cK^CG7*4EX$H+s*TiHS0x)z^p-{UlCP3nB60)6+aw{q-DKmY9 z$77ls6%-UeI`qv`97{>(4lgX6?<;+5akM?H>K5`Gp67v{+3_2p%0A|b>df4qzlmC~ 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%0AuP|E%cm( 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/calendar/month-picker/zinc-dark-default.png b/forui/test/golden/calendar/month-picker/zinc-dark-default.png new file mode 100644 index 0000000000000000000000000000000000000000..ea656d363758a9cdaeecd1b684a64f5d12fddd2d GIT binary patch literal 54474 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

{d?29_% zTfw1Abq!@G(9{@Zw#}U(o>-DdcuhoPm)lbCkm0SN?;}i^oq72b!!29xc@V4a-R(N_ zz1YQm@k7kL zh?*){p`e$hI^(39F2St{Y%|Lan{X5dZ7u54CuWlS!s@6Qo5yU&t(;t17Bt|}$W4*b ztMz0_Y$uTk$GP=fuQ06;3Q6*hX^@41@U>{`mb@}-tFg)r$2>R5UvaZ~H;8Ygx=M~w zUDcAQ79!#2#KiC`E7Cn(_=>I}=P1wR@X(e{KkO!Y4_Z>O9bqy_y~QJQcQ}hNPqx7qX<@h?{>_KRdh55`xdFePx(2R5N_o$^ z#FM%@N;v?%r?`|Y(v2A>=PYuo=RWnjxGq=S3Sbfa-v%5{d_M^sQXB7HWG^oKzk274 znKxt4K6`)v%(FiaW!}s?e{j?6=E!FWd&Sa#1Of=ZDCc5C^ceR_QU`KQOV{6Jkmupr_+DE=YfK>t*boe-b^p2>%> zA;T+Rc7q3KZV&;qov|7 bE)`$g@4h{qor~W{8Wh`}u6{1-oD!M<>>3Y= literal 0 HcmV?d00001 diff --git a/forui/test/golden/calendar/year-picker/zinc-dark-initial-date.png b/forui/test/golden/calendar/year-picker/zinc-dark-initial-date.png new file mode 100644 index 0000000000000000000000000000000000000000..a2dc2edf0c87680ea8d459deba209a18909ebc3d GIT binary patch literal 65202 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

||MT`=t%BCTBg+K$ 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

db*6g@2R7h7The@_< z?28MxGuJ!!ijg^&4=pMC+kmx6`ZW9V4s{p6NeN;MU(2?MZ8`)D&$CG7i=uCd*EYLP z%O<)3NfqVrH-dxR^urW9_D1VB_v!|35f$}=4bbMz$ETxi6R72(0LJjN=AIDyp?VaP zKvCP~Qs^RFxA$n$gJYQfa z3Cqw?JrV#gcSD4+WzDj3-Ldz&wx9leJQio~#)L*&7Vnv_Hs>?Yh5UFp;MN!SZKEw)$|>vt)xpY4t-g0e5%6dCJ1v zEzGJx-ejGE!lYWsKvw^)QCR`$bHBTu<>i8ecZOoJRm%sT9}!evP)QQ6ab4R7>TJ;` zj5+$n6cohNTh6zfmm0Te$+B9HqY0u)J9fhYw?i>mE$Xd(qy>zy-~ss$Vb1^!g0COFxUf`C>;J?>2G zx~@9Ms;$}ngd&!o9+TKbJ1SZQdkJa>8{%?7FHWj+ZtmqV%Y3MDE@6j*`A9+((j`rc zA5YGr@EZA$2aFtaIRxzb6i$`=5YLQNxgK|R>+!3y?_-V2Tj#HQdgXqUd42Td&q9`c z=JtZ4fX4`#>*t-THjDH|?J=Qa?zZppULa&w!YA}VH0fR(XC}LmVEF-f zl1K*g<14v1jWnPZ21%5_ts#%uJTIwSP%x_5`uQ!Eid;l@7!>?@f&4z*mr)jQeVy;a zJ9V%kN(}F8k)Pek+XSQGgof3RrowjihSp6%hbz>1{fk}5b0wfJ;@&a^)F zXr>5dIdyWcdgG!V>@A}=ae$hRCpYXeuPcpblCBM~gvE8HRCB#`Xw-6&(7rBYVR%T~ zrfufd_RhD8`RHwwh}RrW*!eq|AeMn0!|mi$VexGJdSBmb^U}~@7BUxf{k-?Sh05q~ z`4ULnBwq5ooryhj0h^YGt=Eh>wMK6~Fr0%>2+P)*8vK1p5codEr?8=Xrq+4=7+_z0 zK%r1*eFxc_`>%1byI%v6ykW2S$=V~>4!}2TVfua~qfh3C_|%z>Rjd^>D8FCBzw`IO zpafjlpf^!M)Zw5WM=m7&a`ISWY<@6@q#a7H-=0TB6`U7EUO+Dmc(!6C5R^7_R9QR> zlknB-J4-CNR44)J7G%F8Y=Z$Ne*bz%shH^|23G�EHf%iq)**y! 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 Vk1xz=y@!u%@DKDWTDRxazW~#FB$xmI literal 0 HcmV?d00001 diff --git a/forui/test/golden/calendar/year-picker/zinc-light-default.png b/forui/test/golden/calendar/year-picker/zinc-light-default.png new file mode 100644 index 0000000000000000000000000000000000000000..78a0f9a036a8e89a72cf2f6d69b74eff9e1d364c GIT binary patch literal 58275 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/calendar/year-picker/zinc-light-initial-date.png b/forui/test/golden/calendar/year-picker/zinc-light-initial-date.png new file mode 100644 index 0000000000000000000000000000000000000000..cfb7ae9286c47ef42d07043b7cbecede920f23af GIT binary patch literal 64378 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 literal 0 HcmV?d00001 diff --git a/forui/test/src/widgets/calendar/calendar_controller_test.dart b/forui/test/src/widgets/calendar/calendar_controller_test.dart new file mode 100644 index 000000000..ed12189d0 --- /dev/null +++ b/forui/test/src/widgets/calendar/calendar_controller_test.dart @@ -0,0 +1,90 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; + +void main() { + group('FCalendarSingleValueController', () { + test( + 'constructor throws error', + () => expect(() => FCalendarSingleValueController(DateTime.now()), throwsAssertionError), + ); + + for (final (date, expected) in [ + (DateTime.utc(2024, 5, 4), true), + (DateTime.utc(2024, 5, 5), false), + ]) { + test('contains(...) contains date', () { + final controller = FCalendarSingleValueController(DateTime.utc(2024, 5, 4)); + expect(controller.contains(date), expected); + }); + } + + for (final (initial, date, expected) in [ + (null, DateTime.utc(2024), DateTime.utc(2024)), + (null, DateTime.utc(2025), DateTime.utc(2025)), + (DateTime.utc(2024), DateTime.utc(2025), DateTime.utc(2025)), + (DateTime.utc(2024), DateTime.utc(2024), null), + ]) { + test('onPress(...)', () { + final controller = FCalendarSingleValueController(initial)..onPress(date); + expect(controller.value, expected); + }); + } + }); + + group('FCalendarMultiValueController', () { + for (final (date, expected) in [ + (DateTime.utc(2024), true), + (DateTime.utc(2025), false), + ]) { + test('contains(...)', () { + final controller = FCalendarMultiValueController({DateTime.utc(2024)}); + expect(controller.contains(date), expected); + }); + } + + for (final (initial, date, expected) in [ + ({DateTime.utc(2024)}, DateTime.utc(2024), {}), + ({}, DateTime.utc(2024), {DateTime.utc(2024)}), + ({DateTime.utc(2024)}, DateTime.utc(2025), {DateTime.utc(2024), DateTime.utc(2025)}), + ]) { + test('onPress(...)', () { + final controller = FCalendarMultiValueController(initial)..onPress(date); + expect(controller.value, expected); + }); + } + }); + + group('FCalendarSingleRangeController', () { + test( + 'constructor throws error', + () => expect(() => FCalendarSingleRangeController((DateTime(2025), DateTime(2024))), throwsAssertionError), + ); + + for (final (initial, date, expected) in [ + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2024), true), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2025), true), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2023), false), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2026), false), + (null, DateTime.utc(2023), false), + ]) { + test('contains(...)', () { + final controller = FCalendarSingleRangeController(initial); + expect(controller.contains(date), expected); + }); + } + + for (final (initial, date, expected) in [ + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2024), null), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2025), null), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2023), (DateTime.utc(2023), DateTime.utc(2025))), + ((DateTime.utc(2024), DateTime.utc(2025)), DateTime.utc(2026), (DateTime.utc(2024), DateTime.utc(2026))), + ((DateTime.utc(2024), DateTime.utc(2027)), DateTime.utc(2025), (DateTime.utc(2024), DateTime.utc(2025))), + (null, DateTime.utc(2023), (DateTime.utc(2023), DateTime.utc(2023))), + ]) { + test('onPress(...)', () { + final controller = FCalendarSingleRangeController(initial)..onPress(date); + expect(controller.value, expected); + }); + } + }); +} diff --git a/forui/test/src/widgets/calendar/calendar_golden_test.dart b/forui/test/src/widgets/calendar/calendar_golden_test.dart new file mode 100644 index 000000000..4fed22c6e --- /dev/null +++ b/forui/test/src/widgets/calendar/calendar_golden_test.dart @@ -0,0 +1,178 @@ +@Tags(['golden']) +library; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import '../../test_scaffold.dart'; + +void main() { + final selected = { + DateTime.utc(2024, 7, 4), + DateTime.utc(2024, 7, 5), + DateTime.utc(2024, 7, 16), + DateTime.utc(2024, 7, 17), + DateTime.utc(2024, 7, 18), + }; + + group('FCalendar', () { + for (final (name, theme, background) in TestScaffold.themes) { + group('day picker', () { + testWidgets('default - $name', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Padding( + padding: const EdgeInsets.all(16), + child: FCalendar( + controller: FCalendarMultiValueController(selected), + enabled: (date) => date != DateTime.utc(2024, 7, 2), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + ), + ), + ), + ); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(tester.getCenter(find.text('8'))); + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('calendar/day-picker/$name-default.png'), + ); + }); + + testWidgets('max rows - $name', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Padding( + padding: const EdgeInsets.all(16), + child: FCalendar( + controller: FCalendarMultiValueController(selected), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 6, 14), + ), + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('calendar/day-picker/$name-max-rows.png'), + ); + }); + }); + + group('month picker', () { + testWidgets('default - $name', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Padding( + padding: const EdgeInsets.all(16), + child: FCalendar( + controller: FCalendarMultiValueController(selected), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + initialType: FCalendarPickerType.yearMonth, + ), + ), + ), + ); + + await tester.tap(find.text('2020')); + await tester.pumpAndSettle(); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(tester.getCenter(find.text('Feb'))); + await tester.pumpAndSettle(); + + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('calendar/month-picker/$name-default.png'), + ); + }); + }); + + group('year picker', () { + testWidgets('default - $name', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Padding( + padding: const EdgeInsets.all(16), + child: FCalendar( + controller: FCalendarMultiValueController(selected), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + initialType: FCalendarPickerType.yearMonth, + ), + ), + ), + ); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('calendar/year-picker/$name-default.png'), + ); + }); + + testWidgets('initial date different from today - $name', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: theme, + background: background, + child: Padding( + padding: const EdgeInsets.all(16), + child: FCalendar( + controller: FCalendarMultiValueController(selected), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + initialDate: DateTime(1984, 4, 2), + initialType: FCalendarPickerType.yearMonth, + ), + ), + ), + ); + + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(location: Offset.zero); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(tester.getCenter(find.text('1991'))); + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('calendar/year-picker/$name-initial-date.png'), + ); + }); + }); + } + }); +} diff --git a/forui/test/src/widgets/calendar/calendar_test.dart b/forui/test/src/widgets/calendar/calendar_test.dart new file mode 100644 index 000000000..53c0c168c --- /dev/null +++ b/forui/test/src/widgets/calendar/calendar_test.dart @@ -0,0 +1,100 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; + +import '../../test_scaffold.dart'; + +void main() { + group('FCalendar', () { + group('previous button', () { + testWidgets('navigates to previous page', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FCalendar( + controller: FCalendarMultiValueController(), + enabled: (date) => date != DateTime.utc(2024, 7, 2), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + ), + ), + ); + + expect(find.text('July 2024'), findsOneWidget); + + await tester.tap(find.byType(FButton).first); + await tester.pumpAndSettle(); + + expect(find.text('June 2024'), findsOneWidget); + }); + + testWidgets('did not navigate to previous page', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FCalendar( + controller: FCalendarMultiValueController(), + enabled: (date) => date != DateTime.utc(2024, 7, 2), + start: DateTime(2024, 7), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + ), + ), + ); + + expect(find.text('July 2024'), findsOneWidget); + + await tester.tap(find.byType(FButton).first); + await tester.pumpAndSettle(); + + expect(find.text('June 2024'), findsNothing); + }); + }); + + group('next button', () { + testWidgets('navigates to next page', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FCalendar( + controller: FCalendarMultiValueController(), + enabled: (date) => date != DateTime.utc(2024, 7, 2), + start: DateTime(1900, 1, 8), + end: DateTime(2024, 8, 10), + today: DateTime(2024, 7, 14), + ), + ), + ); + + expect(find.text('July 2024'), findsOneWidget); + + await tester.tap(find.byType(FButton).last); + await tester.pumpAndSettle(); + + expect(find.text('August 2024'), findsOneWidget); + }); + + testWidgets('did not navigate to next page', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: FCalendar( + controller: FCalendarMultiValueController(), + enabled: (date) => date != DateTime.utc(2024, 7, 2), + start: DateTime(2024), + end: DateTime(2024, 7, 10), + today: DateTime(2024, 7, 14), + ), + ), + ); + + expect(find.text('July 2024'), findsOneWidget); + + await tester.tap(find.byType(FButton).first); + await tester.pumpAndSettle(); + + expect(find.text('August 2024'), findsNothing); + }); + }); + }); +} diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 3b5b40075..75af89b89 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -49,6 +49,18 @@ class _AppRouter extends $_AppRouter { path: '/button/icon', page: ButtonIconRoute.page, ), + AutoRoute( + path: '/calendar/default', + page: CalendarRoute.page, + ), + AutoRoute( + path: '/calendar/multi-value', + page: MultiValueCalendarRoute.page, + ), + AutoRoute( + path: '/calendar/single-range', + page: SingleRangeCalendarRoute.page, + ), AutoRoute( path: '/card/default', page: CardRoute.page, diff --git a/samples/lib/widgets/calendar.dart b/samples/lib/widgets/calendar.dart new file mode 100644 index 000000000..cde955a5f --- /dev/null +++ b/samples/lib/widgets/calendar.dart @@ -0,0 +1,46 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui_samples/sample_scaffold.dart'; + +@RoutePage() +class CalendarPage extends SampleScaffold { + CalendarPage({ + @queryParam super.theme, + }); + + @override + Widget child(BuildContext context) => FCalendar( + controller: FCalendarSingleValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); +} + +@RoutePage() +class MultiValueCalendarPage extends SampleScaffold { + MultiValueCalendarPage({ + @queryParam super.theme, + }); + + @override + Widget child(BuildContext context) => FCalendar( + controller: FCalendarMultiValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); +} + +@RoutePage() +class SingleRangeCalendarPage extends SampleScaffold { + SingleRangeCalendarPage({ + @queryParam super.theme, + }); + + @override + Widget child(BuildContext context) => FCalendar( + controller: FCalendarSingleRangeController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); +} diff --git a/samples/pubspec.lock b/samples/pubspec.lock index 4fac45f3b..9968df5e8 100644 --- a/samples/pubspec.lock +++ b/samples/pubspec.lock @@ -479,10 +479,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.6" + version: "2.2.7" path_provider_foundation: dependency: transitive description: @@ -511,10 +511,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -744,14 +744,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" - win32: - dependency: transitive - description: - name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 - url: "https://pub.dev" - source: hosted - version: "5.5.1" xdg_directories: dependency: transitive description: From d31370e1adeeaca6971fecc1010055555e6caa84 Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 14 Jul 2024 08:23:20 +0000 Subject: [PATCH 27/35] Commit from GitHub Actions (Forui Presubmit) --- forui/example/lib/main.dart | 1 - forui/lib/src/foundation/inkwell.dart | 1 + forui/lib/src/widgets/calendar/calendar.dart | 4 +- .../widgets/calendar/calendar_controller.dart | 4 +- .../src/widgets/calendar/day/day_picker.dart | 84 +++++++++---------- .../calendar/day/paged_day_picker.dart | 6 +- .../widgets/calendar/month/month_picker.dart | 8 +- .../calendar/month/paged_month_picker.dart | 32 +++---- .../src/widgets/calendar/shared/entry.dart | 7 +- .../src/widgets/calendar/shared/header.dart | 6 +- .../widgets/calendar/shared/paged_picker.dart | 9 +- .../calendar/year/paged_year_picker.dart | 6 +- .../widgets/calendar/year/year_picker.dart | 8 +- .../widgets/calendar/year_month_picker.dart | 23 +++-- forui/test/src/foundation/inkwell_test.dart | 3 +- .../calendar/calendar_controller_test.dart | 1 + .../calendar/calendar_golden_test.dart | 1 - .../src/widgets/calendar/calendar_test.dart | 2 +- 18 files changed, 115 insertions(+), 91 deletions(-) diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index d22d19137..6755d86ea 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; import 'package:forui_example/example.dart'; - void main() { runApp(const Application()); } diff --git a/forui/lib/src/foundation/inkwell.dart b/forui/lib/src/foundation/inkwell.dart index 31f45e7fe..4ee4cd0cc 100644 --- a/forui/lib/src/foundation/inkwell.dart +++ b/forui/lib/src/foundation/inkwell.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; + import 'package:meta/meta.dart'; @internal diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index e2a03f38f..e2e2018aa 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -1,12 +1,14 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; + +import 'package:sugar/sugar.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/widgets/calendar/day/day_picker.dart'; import 'package:forui/src/widgets/calendar/day/paged_day_picker.dart'; import 'package:forui/src/widgets/calendar/shared/header.dart'; import 'package:forui/src/widgets/calendar/year_month_picker.dart'; -import 'package:sugar/sugar.dart'; export 'day/day_picker.dart' show FCalendarDayPickerStyle, FCalendarDayStyle; export 'shared/entry.dart' show FCalendarEntryStyle; diff --git a/forui/lib/src/widgets/calendar/calendar_controller.dart b/forui/lib/src/widgets/calendar/calendar_controller.dart index 35e3dc762..ea2d8b710 100644 --- a/forui/lib/src/widgets/calendar/calendar_controller.dart +++ b/forui/lib/src/widgets/calendar/calendar_controller.dart @@ -1,7 +1,9 @@ import 'package:flutter/widgets.dart'; -import 'package:forui/forui.dart'; + import 'package:sugar/sugar.dart'; +import 'package:forui/forui.dart'; + /// A controller that controls date selection in a calendar. /// /// This class should be extended to customize date selection. By default, the following controllers are provided: diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 268734b0b..c92e06491 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -3,16 +3,18 @@ import 'dart:collection'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:forui/forui.dart'; -import 'package:forui/src/widgets/calendar/shared/entry.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; + @internal class DayPicker extends StatefulWidget { static const maxRows = 7; static const tileDimension = 42.0; - + final FCalendarDayPickerStyle style; final LocalDate month; final LocalDate today; @@ -91,35 +93,34 @@ class _DayPickerState extends State { return (first, last); } - @override Widget build(BuildContext context) => SizedBox( - width: DateTime.daysPerWeek * DayPicker.tileDimension, - child: GridView.custom( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const _GridDelegate(), - childrenDelegate: SliverChildListDelegate( - addRepaintBoundaries: false, - [ - ..._headers(context), - for (final MapEntry(key: date, value: focusNode) in _days.entries) - Entry.day( - style: widget.style, - date: date, - focusNode: focusNode, - current: date.month == widget.month.month, - today: date == widget.today, - enabled: widget.enabled, - selected: widget.selected, - onPress: widget.onPress, - onLongPress: widget.onLongPress, - ), - ], - ), - ), - ); + width: DateTime.daysPerWeek * DayPicker.tileDimension, + child: GridView.custom( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const _GridDelegate(), + childrenDelegate: SliverChildListDelegate( + addRepaintBoundaries: false, + [ + ..._headers(context), + for (final MapEntry(key: date, value: focusNode) in _days.entries) + Entry.day( + style: widget.style, + date: date, + focusNode: focusNode, + current: date.month == widget.month.month, + today: date == widget.today, + enabled: widget.enabled, + selected: widget.selected, + onPress: widget.onPress, + onLongPress: widget.onLongPress, + ), + ], + ), + ), + ); List _headers(BuildContext context) { final firstDayOfWeek = widget.style.startDayOfWeek ?? DateTime.sunday; // TODO: Localization @@ -158,19 +159,18 @@ class _GridDelegate extends SliverGridDelegate { @override SliverGridLayout getLayout(SliverConstraints constraints) => SliverGridRegularTileLayout( - childCrossAxisExtent: DayPicker.tileDimension, - childMainAxisExtent: DayPicker.tileDimension, - crossAxisCount: DateTime.daysPerWeek, - crossAxisStride: DayPicker.tileDimension, - mainAxisStride: DayPicker.tileDimension, - reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), - ); + childCrossAxisExtent: DayPicker.tileDimension, + childMainAxisExtent: DayPicker.tileDimension, + crossAxisCount: DateTime.daysPerWeek, + crossAxisStride: DayPicker.tileDimension, + mainAxisStride: DayPicker.tileDimension, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); @override bool shouldRelayout(_GridDelegate oldDelegate) => false; } - /// A day picker's style. final class FCalendarDayPickerStyle with Diagnosticable { /// The text style for the day of th week headers. @@ -364,10 +364,10 @@ final class FCalendarDayStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FCalendarDayStyle && - runtimeType == other.runtimeType && - unselectedStyle == other.unselectedStyle && - selectedStyle == other.selectedStyle; + other is FCalendarDayStyle && + runtimeType == other.runtimeType && + unselectedStyle == other.unselectedStyle && + selectedStyle == other.selectedStyle; @override int get hashCode => unselectedStyle.hashCode ^ selectedStyle.hashCode; diff --git a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart index 9ec611d66..f98ffe294 100644 --- a/forui/lib/src/widgets/calendar/day/paged_day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/paged_day_picker.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/day/day_picker.dart'; -import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/day/day_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; + @internal class PagedDayPicker extends PagedPicker { final Predicate selected; diff --git a/forui/lib/src/widgets/calendar/month/month_picker.dart b/forui/lib/src/widgets/calendar/month/month_picker.dart index 6c17bc46b..2d4db053a 100644 --- a/forui/lib/src/widgets/calendar/month/month_picker.dart +++ b/forui/lib/src/widgets/calendar/month/month_picker.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/shared/entry.dart'; -import 'package:forui/src/widgets/calendar/year_month_picker.dart'; + import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; + // ignore: non_constant_identifier_names final _MMM = DateFormat.MMM(); @@ -30,7 +32,7 @@ class MonthPicker extends StatefulWidget { required this.focused, required this.onPress, super.key, - }): assert(currentYear == currentYear.truncate(to: DateUnit.years), 'currentYear must be truncated to years'); + }) : assert(currentYear == currentYear.truncate(to: DateUnit.years), 'currentYear must be truncated to years'); @override State createState() => _MonthPickerState(); diff --git a/forui/lib/src/widgets/calendar/month/paged_month_picker.dart b/forui/lib/src/widgets/calendar/month/paged_month_picker.dart index 118be0be2..a59e9afc9 100644 --- a/forui/lib/src/widgets/calendar/month/paged_month_picker.dart +++ b/forui/lib/src/widgets/calendar/month/paged_month_picker.dart @@ -1,10 +1,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/month/month_picker.dart'; -import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/month/month_picker.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; + @internal class PagedMonthPicker extends PagedPicker { final ValueChanged onPress; @@ -32,14 +34,14 @@ class PagedMonthPicker extends PagedPicker { class _PagedMonthPickerState extends PagedPickerState { @override Widget buildItem(BuildContext context, int page) => MonthPicker( - style: widget.style.yearMonthPickerStyle, - currentYear: widget.initial, - start: widget.start, - end: widget.end, - today: widget.today, - focused: focusedDate, - onPress: widget.onPress, - ); + style: widget.style.yearMonthPickerStyle, + currentYear: widget.initial, + start: widget.start, + end: widget.end, + today: widget.today, + focused: focusedDate, + onPress: widget.onPress, + ); @override void onPageChange(int page) {} // Months will only appear on a single page. @@ -74,9 +76,9 @@ class _PagedMonthPickerState extends PagedPickerState { @override Map get directionOffset => const { - TraversalDirection.up: Period(months: -MonthPicker.columns), - TraversalDirection.right: Period(months: 1), - TraversalDirection.down: Period(months: MonthPicker.columns), - TraversalDirection.left: Period(months: -1), - }; + TraversalDirection.up: Period(months: -MonthPicker.columns), + TraversalDirection.right: Period(months: 1), + TraversalDirection.down: Period(months: MonthPicker.columns), + TraversalDirection.left: Period(months: -1), + }; } diff --git a/forui/lib/src/widgets/calendar/shared/entry.dart b/forui/lib/src/widgets/calendar/shared/entry.dart index 708e5248a..7d75c0ad5 100644 --- a/forui/lib/src/widgets/calendar/shared/entry.dart +++ b/forui/lib/src/widgets/calendar/shared/entry.dart @@ -1,12 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/foundation/inkwell.dart'; -import 'package:forui/src/widgets/calendar/year_month_picker.dart'; + import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/foundation/inkwell.dart'; import 'package:forui/src/widgets/calendar/day/day_picker.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; final _yMMMMd = DateFormat.yMMMMd(); @@ -71,7 +72,7 @@ abstract class Entry extends StatelessWidget { required String Function(LocalDate) format, }) { final entryStyle = enabled ? style.enabledStyle : style.disabledStyle; - + // ignore: avoid_positional_boolean_parameters Widget builder(BuildContext context, bool focused, Widget? child) => _Content( style: entryStyle, diff --git a/forui/lib/src/widgets/calendar/shared/header.dart b/forui/lib/src/widgets/calendar/shared/header.dart index 591cc3589..39ddea130 100644 --- a/forui/lib/src/widgets/calendar/shared/header.dart +++ b/forui/lib/src/widgets/calendar/shared/header.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/forui.dart'; -import 'package:forui/src/foundation/inkwell.dart'; + import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/foundation/inkwell.dart'; + /// The current picker type. enum FCalendarPickerType { /// The day picker. diff --git a/forui/lib/src/widgets/calendar/shared/paged_picker.dart b/forui/lib/src/widgets/calendar/shared/paged_picker.dart index 239ff8b64..b991a9715 100644 --- a/forui/lib/src/widgets/calendar/shared/paged_picker.dart +++ b/forui/lib/src/widgets/calendar/shared/paged_picker.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/calendar.dart'; -import 'package:forui/src/widgets/calendar/shared/header.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/calendar.dart'; +import 'package:forui/src/widgets/calendar/shared/header.dart'; + @internal abstract class PagedPicker extends StatefulWidget { final FCalendarStyle style; @@ -23,8 +25,7 @@ abstract class PagedPicker extends StatefulWidget { required this.initial, Predicate? enabled, super.key, - }): - enabled = ((date) => start <= date && date <= end && (enabled?.call(date) ?? true)); + }) : enabled = ((date) => start <= date && date <= end && (enabled?.call(date) ?? true)); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/forui/lib/src/widgets/calendar/year/paged_year_picker.dart b/forui/lib/src/widgets/calendar/year/paged_year_picker.dart index 34773142e..ceabfe331 100644 --- a/forui/lib/src/widgets/calendar/year/paged_year_picker.dart +++ b/forui/lib/src/widgets/calendar/year/paged_year_picker.dart @@ -1,10 +1,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; -import 'package:forui/src/widgets/calendar/year/year_picker.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/shared/paged_picker.dart'; +import 'package:forui/src/widgets/calendar/year/year_picker.dart'; + @internal class PagedYearPicker extends PagedPicker { final ValueChanged onPress; diff --git a/forui/lib/src/widgets/calendar/year/year_picker.dart b/forui/lib/src/widgets/calendar/year/year_picker.dart index c51668b31..492fb9877 100644 --- a/forui/lib/src/widgets/calendar/year/year_picker.dart +++ b/forui/lib/src/widgets/calendar/year/year_picker.dart @@ -1,10 +1,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/calendar/shared/entry.dart'; -import 'package:forui/src/widgets/calendar/year_month_picker.dart'; + import 'package:meta/meta.dart'; import 'package:sugar/sugar.dart'; +import 'package:forui/src/widgets/calendar/shared/entry.dart'; +import 'package:forui/src/widgets/calendar/year_month_picker.dart'; + @internal class YearPicker extends StatefulWidget { static const columns = 3; @@ -28,7 +30,7 @@ class YearPicker extends StatefulWidget { required this.focused, required this.onPress, super.key, - }): assert(startYear == startYear.truncate(to: DateUnit.years), 'startYear must be truncated to years.'); + }) : assert(startYear == startYear.truncate(to: DateUnit.years), 'startYear must be truncated to years.'); @override State createState() => _YearPickerState(); diff --git a/forui/lib/src/widgets/calendar/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month_picker.dart index 9198ea65e..6581eb6da 100644 --- a/forui/lib/src/widgets/calendar/year_month_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month_picker.dart @@ -1,10 +1,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; + +import 'package:meta/meta.dart'; +import 'package:sugar/sugar.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/widgets/calendar/month/paged_month_picker.dart'; import 'package:forui/src/widgets/calendar/year/paged_year_picker.dart'; -import 'package:meta/meta.dart'; -import 'package:sugar/sugar.dart'; @internal class YearMonthPicker extends StatefulWidget { @@ -73,11 +75,11 @@ class _YearMonthPickerState extends State { } } - /// The year/month picker's style. final class FCalendarYearMonthPickerStyle with Diagnosticable { /// The enabled years/months' styles. final FCalendarEntryStyle enabledStyle; + /// The disabled years/months' styles. final FCalendarEntryStyle disabledStyle; @@ -115,10 +117,11 @@ final class FCalendarYearMonthPickerStyle with Diagnosticable { FCalendarYearMonthPickerStyle copyWith({ FCalendarEntryStyle? enabledStyle, FCalendarEntryStyle? disabledStyle, - }) => FCalendarYearMonthPickerStyle( - enabledStyle: enabledStyle ?? this.enabledStyle, - disabledStyle: disabledStyle ?? this.disabledStyle, - ); + }) => + FCalendarYearMonthPickerStyle( + enabledStyle: enabledStyle ?? this.enabledStyle, + disabledStyle: disabledStyle ?? this.disabledStyle, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { @@ -131,8 +134,10 @@ final class FCalendarYearMonthPickerStyle with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is FCalendarYearMonthPickerStyle && runtimeType == other.runtimeType && - enabledStyle == other.enabledStyle && disabledStyle == other.disabledStyle; + other is FCalendarYearMonthPickerStyle && + runtimeType == other.runtimeType && + enabledStyle == other.enabledStyle && + disabledStyle == other.disabledStyle; @override int get hashCode => enabledStyle.hashCode ^ disabledStyle.hashCode; diff --git a/forui/test/src/foundation/inkwell_test.dart b/forui/test/src/foundation/inkwell_test.dart index 2dc309a01..654708929 100644 --- a/forui/test/src/foundation/inkwell_test.dart +++ b/forui/test/src/foundation/inkwell_test.dart @@ -1,9 +1,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; + import 'package:flutter_test/flutter_test.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/foundation/inkwell.dart'; - import '../test_scaffold.dart'; void main() { diff --git a/forui/test/src/widgets/calendar/calendar_controller_test.dart b/forui/test/src/widgets/calendar/calendar_controller_test.dart index ed12189d0..820f8bc7a 100644 --- a/forui/test/src/widgets/calendar/calendar_controller_test.dart +++ b/forui/test/src/widgets/calendar/calendar_controller_test.dart @@ -1,4 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; + import 'package:forui/forui.dart'; void main() { diff --git a/forui/test/src/widgets/calendar/calendar_golden_test.dart b/forui/test/src/widgets/calendar/calendar_golden_test.dart index 4fed22c6e..dc78db1f3 100644 --- a/forui/test/src/widgets/calendar/calendar_golden_test.dart +++ b/forui/test/src/widgets/calendar/calendar_golden_test.dart @@ -107,7 +107,6 @@ void main() { await gesture.moveTo(tester.getCenter(find.text('Feb'))); await tester.pumpAndSettle(); - await expectLater( find.byType(TestScaffold), matchesGoldenFile('calendar/month-picker/$name-default.png'), diff --git a/forui/test/src/widgets/calendar/calendar_test.dart b/forui/test/src/widgets/calendar/calendar_test.dart index 53c0c168c..386d31e6c 100644 --- a/forui/test/src/widgets/calendar/calendar_test.dart +++ b/forui/test/src/widgets/calendar/calendar_test.dart @@ -1,6 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:forui/forui.dart'; +import 'package:forui/forui.dart'; import '../../test_scaffold.dart'; void main() { From 6767661d400ce50cb81e84750e73b52cfc12cb3a Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 14 Jul 2024 08:24:58 +0000 Subject: [PATCH 28/35] Commit from GitHub Actions (Forui Example Presubmit) --- forui/example/lib/main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/forui/example/lib/main.dart b/forui/example/lib/main.dart index 6755d86ea..4fe50a2bd 100644 --- a/forui/example/lib/main.dart +++ b/forui/example/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; + import 'package:forui_example/example.dart'; void main() { From f1a13770905d69bc03fb6aadcd900801ce1e46ee Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 14 Jul 2024 08:25:01 +0000 Subject: [PATCH 29/35] Commit from GitHub Actions (Forui Samples Presubmit) --- samples/lib/main.dart | 4 +++- samples/lib/widgets/calendar.dart | 28 +++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 75af89b89..a6a06a53a 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -1,6 +1,8 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' hide DialogRoute; + +import 'package:auto_route/auto_route.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample_scaffold.dart'; diff --git a/samples/lib/widgets/calendar.dart b/samples/lib/widgets/calendar.dart index cde955a5f..45309e96a 100644 --- a/samples/lib/widgets/calendar.dart +++ b/samples/lib/widgets/calendar.dart @@ -1,6 +1,8 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/widgets.dart'; + +import 'package:auto_route/auto_route.dart'; import 'package:forui/forui.dart'; + import 'package:forui_samples/sample_scaffold.dart'; @RoutePage() @@ -11,10 +13,10 @@ class CalendarPage extends SampleScaffold { @override Widget child(BuildContext context) => FCalendar( - controller: FCalendarSingleValueController(), - start: DateTime.utc(2024), - end: DateTime.utc(2030), - ); + controller: FCalendarSingleValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); } @RoutePage() @@ -25,10 +27,10 @@ class MultiValueCalendarPage extends SampleScaffold { @override Widget child(BuildContext context) => FCalendar( - controller: FCalendarMultiValueController(), - start: DateTime.utc(2024), - end: DateTime.utc(2030), - ); + controller: FCalendarMultiValueController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); } @RoutePage() @@ -39,8 +41,8 @@ class SingleRangeCalendarPage extends SampleScaffold { @override Widget child(BuildContext context) => FCalendar( - controller: FCalendarSingleRangeController(), - start: DateTime.utc(2024), - end: DateTime.utc(2030), - ); + controller: FCalendarSingleRangeController(), + start: DateTime.utc(2024), + end: DateTime.utc(2030), + ); } From ef33bb1f0444f0ff17a03bc14203912bb9e8ede6 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 15 Jul 2024 20:40:52 +0800 Subject: [PATCH 30/35] Apply suggestions from code review Co-authored-by: Joe Kawai --- forui/lib/src/widgets/calendar/calendar.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/calendar/calendar.dart b/forui/lib/src/widgets/calendar/calendar.dart index e2e2018aa..af11481fb 100644 --- a/forui/lib/src/widgets/calendar/calendar.dart +++ b/forui/lib/src/widgets/calendar/calendar.dart @@ -178,7 +178,7 @@ final class FCalendarStyle with Diagnosticable { /// The decoration surrounding the header & picker. final BoxDecoration decoration; - /// The padding surrounding the header & picker. Defaults to `const EdgeInsets.symmetric(horizontal: 12, vertical: 16)`. + /// The padding surrounding the header & picker. Defaults to `EdgeInsets.symmetric(horizontal: 12, vertical: 16)`. final EdgeInsets padding; /// The duration of the page switch animation. Defaults to 200 milliseconds. From b0293b0c2b70c01fa7735b8868dfe3de18e71535 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 15 Jul 2024 20:42:16 +0800 Subject: [PATCH 31/35] Fix PR issues --- forui/lib/src/widgets/calendar/day/day_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index c92e06491..529851d7a 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -1,7 +1,7 @@ import 'dart:collection'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; import 'package:meta/meta.dart'; From 43f28f69752a23524ef7443b56c291cd6aa6605c Mon Sep 17 00:00:00 2001 From: Pante Date: Mon, 15 Jul 2024 12:43:33 +0000 Subject: [PATCH 32/35] Commit from GitHub Actions (Forui Presubmit) --- forui/lib/src/widgets/calendar/day/day_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 529851d7a..c92e06491 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -1,7 +1,7 @@ import 'dart:collection'; import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:meta/meta.dart'; From 5139cf33aff90746a1ef4173ad8a26f76763bf2e Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 15 Jul 2024 20:44:47 +0800 Subject: [PATCH 33/35] Revert fix --- forui/lib/src/widgets/calendar/day/day_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index 529851d7a..c92e06491 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -1,7 +1,7 @@ import 'dart:collection'; import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:meta/meta.dart'; From 81697d8eac7ef1731659836227883e99b25d510c Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 15 Jul 2024 21:07:47 +0800 Subject: [PATCH 34/35] Make radius configurable --- .../src/widgets/calendar/day/day_picker.dart | 6 +++++ .../src/widgets/calendar/shared/entry.dart | 24 ++++++++++++++----- .../widgets/calendar/year_month_picker.dart | 2 ++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/forui/lib/src/widgets/calendar/day/day_picker.dart b/forui/lib/src/widgets/calendar/day/day_picker.dart index c92e06491..aa72f84b2 100644 --- a/forui/lib/src/widgets/calendar/day/day_picker.dart +++ b/forui/lib/src/widgets/calendar/day/day_picker.dart @@ -213,10 +213,12 @@ final class FCalendarDayPickerStyle with Diagnosticable { selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, + radius: const Radius.circular(4), ), unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: mutedTextStyle, + radius: const Radius.circular(4), ), ); @@ -227,22 +229,26 @@ final class FCalendarDayPickerStyle with Diagnosticable { selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.foreground, textStyle: typography.sm.copyWith(color: colorScheme.background, fontWeight: FontWeight.w500), + radius: const Radius.circular(4), ), unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: textStyle, focusedBackgroundColor: colorScheme.secondary, + radius: const Radius.circular(4), ), ), enclosing: FCalendarDayStyle( selectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.primaryForeground, textStyle: mutedTextStyle, + radius: const Radius.circular(4), ), unselectedStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: mutedTextStyle, focusedBackgroundColor: colorScheme.primaryForeground, + radius: const Radius.circular(4), ), ), ), diff --git a/forui/lib/src/widgets/calendar/shared/entry.dart b/forui/lib/src/widgets/calendar/shared/entry.dart index 7d75c0ad5..e937562eb 100644 --- a/forui/lib/src/widgets/calendar/shared/entry.dart +++ b/forui/lib/src/widgets/calendar/shared/entry.dart @@ -38,8 +38,8 @@ abstract class Entry extends StatelessWidget { Widget builder(BuildContext context, bool focused, Widget? child) => _Content( style: entryStyle, borderRadius: BorderRadius.horizontal( - left: selected(date.yesterday) ? Radius.zero : const Radius.circular(4), - right: selected(date.tomorrow) ? Radius.zero : const Radius.circular(4), + left: selected(date.yesterday) ? Radius.zero : entryStyle.radius, + right: selected(date.tomorrow) ? Radius.zero : entryStyle.radius, ), text: '${date.day}', // TODO: localization focused: focused, @@ -76,7 +76,7 @@ abstract class Entry extends StatelessWidget { // ignore: avoid_positional_boolean_parameters Widget builder(BuildContext context, bool focused, Widget? child) => _Content( style: entryStyle, - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.all(entryStyle.radius), text: format(date), focused: focused, current: current, @@ -221,10 +221,14 @@ final class FCalendarEntryStyle with Diagnosticable { /// The focused day's text style. Defaults to [textStyle]. final TextStyle focusedTextStyle; + /// The entry border's radius. Defaults to `Radius.circular(4)`. + final Radius radius; + /// Creates a [FCalendarEntryStyle]. FCalendarEntryStyle({ required this.backgroundColor, required this.textStyle, + required this.radius, Color? focusedBackgroundColor, TextStyle? focusedTextStyle, }) : focusedBackgroundColor = focusedBackgroundColor ?? backgroundColor, @@ -250,12 +254,14 @@ final class FCalendarEntryStyle with Diagnosticable { TextStyle? textStyle, Color? focusedBackgroundColor, TextStyle? focusedTextStyle, + Radius? radius, }) => FCalendarEntryStyle( backgroundColor: backgroundColor ?? this.backgroundColor, textStyle: textStyle ?? this.textStyle, focusedBackgroundColor: focusedBackgroundColor ?? this.focusedBackgroundColor, focusedTextStyle: focusedTextStyle ?? this.focusedTextStyle, + radius: radius ?? this.radius, ); @override @@ -265,7 +271,8 @@ final class FCalendarEntryStyle with Diagnosticable { ..add(ColorProperty('backgroundColor', backgroundColor)) ..add(DiagnosticsProperty('textStyle', textStyle)) ..add(ColorProperty('focusedBackgroundColor', focusedBackgroundColor)) - ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)); + ..add(DiagnosticsProperty('focusedTextStyle', focusedTextStyle)) + ..add(DiagnosticsProperty('radius', radius)); } @override @@ -276,9 +283,14 @@ final class FCalendarEntryStyle with Diagnosticable { backgroundColor == other.backgroundColor && textStyle == other.textStyle && focusedBackgroundColor == other.focusedBackgroundColor && - focusedTextStyle == other.focusedTextStyle; + focusedTextStyle == other.focusedTextStyle && + radius == other.radius; @override int get hashCode => - backgroundColor.hashCode ^ textStyle.hashCode ^ focusedBackgroundColor.hashCode ^ focusedTextStyle.hashCode; + backgroundColor.hashCode ^ + textStyle.hashCode ^ + focusedBackgroundColor.hashCode ^ + focusedTextStyle.hashCode ^ + radius.hashCode; } diff --git a/forui/lib/src/widgets/calendar/year_month_picker.dart b/forui/lib/src/widgets/calendar/year_month_picker.dart index 6581eb6da..7b1da364e 100644 --- a/forui/lib/src/widgets/calendar/year_month_picker.dart +++ b/forui/lib/src/widgets/calendar/year_month_picker.dart @@ -93,11 +93,13 @@ final class FCalendarYearMonthPickerStyle with Diagnosticable { backgroundColor: colorScheme.background, textStyle: typography.sm.copyWith(color: colorScheme.foreground, fontWeight: FontWeight.w500), focusedBackgroundColor: colorScheme.secondary, + radius: const Radius.circular(8), ), disabledStyle: FCalendarEntryStyle( backgroundColor: colorScheme.background, textStyle: typography.sm .copyWith(color: colorScheme.mutedForeground.withOpacity(0.5), fontWeight: FontWeight.w500), + radius: const Radius.circular(8), ), ); From 19677bbf4563caa1638370e6ebcbc396c7b07ffb Mon Sep 17 00:00:00 2001 From: Pante Date: Mon, 15 Jul 2024 13:08:49 +0000 Subject: [PATCH 35/35] Commit from GitHub Actions (Forui Presubmit) --- forui/lib/src/widgets/calendar/shared/entry.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/calendar/shared/entry.dart b/forui/lib/src/widgets/calendar/shared/entry.dart index e937562eb..a2b137128 100644 --- a/forui/lib/src/widgets/calendar/shared/entry.dart +++ b/forui/lib/src/widgets/calendar/shared/entry.dart @@ -38,7 +38,7 @@ abstract class Entry extends StatelessWidget { Widget builder(BuildContext context, bool focused, Widget? child) => _Content( style: entryStyle, borderRadius: BorderRadius.horizontal( - left: selected(date.yesterday) ? Radius.zero : entryStyle.radius, + left: selected(date.yesterday) ? Radius.zero : entryStyle.radius, right: selected(date.tomorrow) ? Radius.zero : entryStyle.radius, ), text: '${date.day}', // TODO: localization