diff --git a/CHANGELOG.md b/CHANGELOG.md index 982d4db6..79c4f4e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # [1.4.1 - Unreleased] - Adds clear method to `EventController`. +- Adds support for dark theme. [#263](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/263) # [1.4.0 - 7 Jan 2025](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.4.0) diff --git a/README.md b/README.md index 4984a0ee..c74d84f2 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,46 @@ WeekView( Above code will create `WeekView` with only five days, from monday to friday. +## **Customise theme** +* The default theme includes support for dark mode. +* For detailed instructions on how to override the default colors please refer to [this](doc/theme_guide.md) guide. + +### Day view +* Default timeline text color is `colorScheme.onSurface`. +* Default hour, half hour & quarter color is `colorScheme.surfaceContainerHighest`. +* Default timeline color `colorScheme.primaryColorLight`. + +Default hour indicator settings. +```dart + HourIndicatorSettings( + height: widget.heightPerMinute, + // Color of horizontal and vertical lines + color: Theme.of(context).colorScheme.surfaceContainerHighest, + offset: 5, + ); +``` + +### Week view +* Week-number text color - Default color `onSecondaryContainer`. +* To customise week number & weekdays use `weekNumberBuilder` & `weekDayBuilder`. +* Default week tile color is `colorScheme.surfaceContainerHigh`. +* To give background color use `backgroundColor` Default background color is `colorScheme.surfaceContainerLowest`. +* To customise timeline use `timeLineBuilder`. Default text color is `colorScheme.onSurface`. +* To change Hour lines color use `HourIndicatorSettings`. +* To style hours, half hours & quarter hours use `HourIndicatorSettings`. Default color used is `surfaceContainerHighest` + +```dart + hourIndicatorSettings: HourIndicatorSettings( + color: Colors.greenAccent, + lineStyle: LineStyle.dashed, + ), + showHalfHours: true, + halfHourIndicatorSettings: HourIndicatorSettings( + color: Colors.redAccent, + lineStyle: LineStyle.dashed, + ), +``` + ## Main Contributors diff --git a/doc/theme_guide.md b/doc/theme_guide.md new file mode 100644 index 00000000..21a3d7ec --- /dev/null +++ b/doc/theme_guide.md @@ -0,0 +1,66 @@ +## **Customise theme** +The default theme supports dark mode. Refer this colors to override it. + +| Name | Parameter | Default color | +|-----------------------------------------------|------------------------|-------------------------------------| +| `MonthView` Border color | Color? borderColor | colorScheme.surfaceContainerHigh | +| `WeekView` Background color of week view page | Color? backgroundColor | colorScheme.surfaceContainerLowest | +| `DayView` Default background color | Color? backgroundColor | colorScheme.surfaceContainerLow | +| `FilledCell` Dates in month cell color | Color? backgroundColor | colorScheme.surfaceContainerLowest | +| `FilledCell` Dates not in month cell color | Color? backgroundColor | colorScheme.surfaceContainerLow | +| `WeekDayTile` Border color | Color? borderColor | colorScheme.secondaryContainer | +| `WeekDayTile` Background color | Color? backgroundColor | colorScheme.surfaceContainerHigh | +| `WeekDayTile` Text style color | TextStyle? textStyle | colorScheme.onSecondaryContainer | + +To customise `MonthView`, `DayView` & `WeekView` page header use `HeaderStyle`. + +```dart + headerStyle: HeaderStyle( + leftIconConfig: IconDataConfig(color: Colors.red), + rightIconConfig: IconDataConfig(color: Colors.red), + decoration: BoxDecoration( + color: Theme.of(context).highlightColor, + ), + ), +``` + +### Day view +* Default timeline text color is `colorScheme.onSurface`. + * Use `markingStyle` in `DefaultTimeLineMark` to give text style. +* Default `LiveTimeIndicatorSettings` color `colorScheme.primaryColorLight`. + * Use `liveTimeIndicatorSettings` to customise it. +* Default hour, half hour & quarter color is `colorScheme.surfaceContainerHighest`. + * Use `hourIndicatorSettings` to customise it. + +Default hour indicator settings. +```dart + HourIndicatorSettings( + height: widget.heightPerMinute, + // Color of horizontal and vertical lines + color: Theme.of(context).colorScheme.surfaceContainerHighest, + offset: 5, + ); +``` + +### Week view +* To customise week number & weekdays use `weekNumberBuilder` & `weekDayBuilder`. +* Default week tile background color is `colorScheme.surfaceContainerHigh`. + * Use `weekTitleBackgroundColor` to change background color. +* Default page background color is `colorScheme.surfaceContainerLowest`. + * Use `backgroundColor` to change background color. +* Default timeline text color is `colorScheme.onSurface`. Use `markingStyle` in `DefaultTimeLineMark` to give text style. + * To customise timeline use `timeLineBuilder`. +* To change Hour lines color use `HourIndicatorSettings`. +* To style hours, half hours & quarter hours use `HourIndicatorSettings`. Default color used is `surfaceContainerHighest` + +```dart + hourIndicatorSettings: HourIndicatorSettings( + color: Colors.greenAccent, + lineStyle: LineStyle.dashed, + ), + showHalfHours: true, + halfHourIndicatorSettings: HourIndicatorSettings( + color: Colors.redAccent, + lineStyle: LineStyle.dashed, + ), +``` diff --git a/example/lib/constants.dart b/example/lib/constants.dart index 21da78d8..a305b1ad 100644 --- a/example/lib/constants.dart +++ b/example/lib/constants.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'app_colors.dart'; +import 'theme/app_colors.dart'; class AppConstants { AppConstants._(); @@ -11,7 +11,7 @@ class AppConstants { borderRadius: BorderRadius.circular(7), borderSide: BorderSide( width: 2, - color: AppColors.lightNavyBlue, + color: AppColors.outlineVariant, ), ); diff --git a/example/lib/extension.dart b/example/lib/extension.dart index f70df402..ca795552 100644 --- a/example/lib/extension.dart +++ b/example/lib/extension.dart @@ -1,8 +1,9 @@ +import 'package:example/theme/app_theme_extension.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'app_colors.dart'; import 'enumerations.dart'; +import 'theme/app_colors.dart'; enum TimeStampFormat { parse_12, parse_24 } @@ -128,3 +129,9 @@ extension StringExt on String { extension ViewNameExt on CalendarView { String get name => toString().split(".").last; } + +extension BuildContextExtension on BuildContext { + AppThemeExtension get appColors => + Theme.of(this).extension() ?? + AppThemeExtension.light(); +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 1bb7d9da..4aa29ff0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:calendar_view/calendar_view.dart'; +import 'package:example/theme/app_theme.dart'; import 'package:flutter/material.dart'; import 'pages/home_page.dart'; @@ -11,7 +12,14 @@ void main() { runApp(MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatefulWidget { + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + bool isDarkMode = false; + // This widget is the root of your application. @override Widget build(BuildContext context) { @@ -20,7 +28,9 @@ class MyApp extends StatelessWidget { child: MaterialApp( title: 'Flutter Calendar Page Demo', debugShowCheckedModeBanner: false, - theme: ThemeData.light(), + theme: AppTheme.light, + darkTheme: AppTheme.dark, + themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light, scrollBehavior: ScrollBehavior().copyWith( dragDevices: { PointerDeviceKind.trackpad, @@ -28,7 +38,9 @@ class MyApp extends StatelessWidget { PointerDeviceKind.touch, }, ), - home: HomePage(), + home: HomePage( + onChangeTheme: (isDark) => setState(() => isDarkMode = isDark), + ), ), ); } diff --git a/example/lib/pages/create_event_page.dart b/example/lib/pages/create_event_page.dart index 3b8e2499..9b5ba021 100644 --- a/example/lib/pages/create_event_page.dart +++ b/example/lib/pages/create_event_page.dart @@ -1,7 +1,6 @@ import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.dart'; -import '../app_colors.dart'; import '../extension.dart'; import '../widgets/add_event_form.dart'; @@ -12,22 +11,23 @@ class CreateEventPage extends StatelessWidget { @override Widget build(BuildContext context) { + final themeColor = context.appColors; + return Scaffold( appBar: AppBar( elevation: 0, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, centerTitle: false, leading: IconButton( onPressed: context.pop, icon: Icon( Icons.arrow_back, - color: AppColors.black, + color: themeColor.onPrimary, ), ), title: Text( event == null ? "Create New Event" : "Update Event", style: TextStyle( - color: AppColors.black, + color: themeColor.onPrimary, fontSize: 20.0, fontWeight: FontWeight.bold, ), diff --git a/example/lib/pages/day_view_page.dart b/example/lib/pages/day_view_page.dart index 1a80aba2..b2269bac 100644 --- a/example/lib/pages/day_view_page.dart +++ b/example/lib/pages/day_view_page.dart @@ -17,13 +17,22 @@ class DayViewPageDemo extends StatefulWidget { class _DayViewPageDemoState extends State { @override Widget build(BuildContext context) { + final appColors = context.appColors; + return ResponsiveWidget( webWidget: WebHomePage( selectedView: CalendarView.day, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + ), floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), + child: Icon( + Icons.add, + color: appColors.onPrimary, + ), elevation: 8, onPressed: () => context.pushRoute(CreateEventPage()), ), diff --git a/example/lib/pages/event_details_page.dart b/example/lib/pages/event_details_page.dart index a9f38220..1f4748e4 100644 --- a/example/lib/pages/event_details_page.dart +++ b/example/lib/pages/event_details_page.dart @@ -1,4 +1,5 @@ import 'package:calendar_view/calendar_view.dart'; +import 'package:example/theme/app_colors.dart'; import 'package:example/widgets/delete_event_dialog.dart'; import 'package:flutter/material.dart'; @@ -97,16 +98,30 @@ class DetailsPage extends StatelessWidget { children: [ Expanded( child: ElevatedButton( + child: Text( + 'Delete Event', + style: TextStyle( + color: AppColors.black, + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white70, + ), onPressed: () async { await _handleDeleteEvent(context); Navigator.of(context).pop(); }, - child: Text('Delete Event'), ), ), SizedBox(width: 30), Expanded( child: ElevatedButton( + child: Text( + 'Edit Event', + style: TextStyle( + color: AppColors.black, + ), + ), onPressed: () async { final result = await Navigator.of(context).push( MaterialPageRoute( @@ -120,7 +135,9 @@ class DetailsPage extends StatelessWidget { Navigator.of(context).pop(); } }, - child: Text('Edit Event'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white70, + ), ), ), ], diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 85d8f05d..a0cb5d40 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -5,13 +5,20 @@ import 'mobile/mobile_home_page.dart'; import 'web/web_home_page.dart'; class HomePage extends StatelessWidget { - const HomePage({super.key}); + const HomePage({ + this.onChangeTheme, + super.key, + }); + + /// Return true for dark mode + /// false for light mode + final void Function(bool)? onChangeTheme; @override Widget build(BuildContext context) { return ResponsiveWidget( - mobileWidget: MobileHomePage(), - webWidget: WebHomePage(), + mobileWidget: MobileHomePage(onChangeTheme: onChangeTheme), + webWidget: WebHomePage(onThemeChange: onChangeTheme), ); } } diff --git a/example/lib/pages/mobile/mobile_home_page.dart b/example/lib/pages/mobile/mobile_home_page.dart index 640dde95..113c03d0 100644 --- a/example/lib/pages/mobile/mobile_home_page.dart +++ b/example/lib/pages/mobile/mobile_home_page.dart @@ -5,7 +5,21 @@ import '../day_view_page.dart'; import '../month_view_page.dart'; import '../week_view_page.dart'; -class MobileHomePage extends StatelessWidget { +class MobileHomePage extends StatefulWidget { + MobileHomePage({ + this.onChangeTheme, + super.key, + }); + + final void Function(bool)? onChangeTheme; + + @override + State createState() => _MobileHomePageState(); +} + +class _MobileHomePageState extends State { + bool isDarkMode = false; + @override Widget build(BuildContext context) { return Scaffold( @@ -38,6 +52,19 @@ class MobileHomePage extends StatelessWidget { ], ), ), + floatingActionButton: FloatingActionButton( + child: Icon( + Icons.dark_mode, + color: context.appColors.onPrimary, + ), + onPressed: () { + isDarkMode = !isDarkMode; + if (widget.onChangeTheme != null) { + widget.onChangeTheme!(isDarkMode); + } + setState(() {}); + }, + ), ); } } diff --git a/example/lib/pages/month_view_page.dart b/example/lib/pages/month_view_page.dart index 9bd798c2..d71f289b 100644 --- a/example/lib/pages/month_view_page.dart +++ b/example/lib/pages/month_view_page.dart @@ -19,13 +19,22 @@ class MonthViewPageDemo extends StatefulWidget { class _MonthViewPageDemoState extends State { @override Widget build(BuildContext context) { + final appColors = context.appColors; + return ResponsiveWidget( webWidget: WebHomePage( selectedView: CalendarView.month, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + ), floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), + child: Icon( + Icons.add, + color: appColors.onPrimary, + ), elevation: 8, onPressed: () => context.pushRoute(CreateEventPage()), ), diff --git a/example/lib/pages/web/web_home_page.dart b/example/lib/pages/web/web_home_page.dart index 3fe2b836..71c3b0fa 100644 --- a/example/lib/pages/web/web_home_page.dart +++ b/example/lib/pages/web/web_home_page.dart @@ -7,9 +7,11 @@ import '../../widgets/calendar_views.dart'; class WebHomePage extends StatefulWidget { WebHomePage({ this.selectedView = CalendarView.month, + this.onThemeChange, }); final CalendarView selectedView; + final void Function(bool)? onThemeChange; @override _WebHomePageState createState() => _WebHomePageState(); @@ -35,6 +37,7 @@ class _WebHomePageState extends State { child: CalendarConfig( onViewChange: _setView, currentView: _selectedView, + onThemeChange: widget.onThemeChange, ), ), Expanded( diff --git a/example/lib/pages/week_view_page.dart b/example/lib/pages/week_view_page.dart index 3a183f5e..08a8d2d4 100644 --- a/example/lib/pages/week_view_page.dart +++ b/example/lib/pages/week_view_page.dart @@ -17,13 +17,22 @@ class WeekViewDemo extends StatefulWidget { class _WeekViewDemoState extends State { @override Widget build(BuildContext context) { + final themeColors = context.appColors; + return ResponsiveWidget( webWidget: WebHomePage( selectedView: CalendarView.week, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + ), floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), + child: Icon( + Icons.add, + color: themeColors.onPrimary, + ), elevation: 8, onPressed: () => context.pushRoute(CreateEventPage()), ), diff --git a/example/lib/app_colors.dart b/example/lib/theme/app_colors.dart similarity index 64% rename from example/lib/app_colors.dart rename to example/lib/theme/app_colors.dart index 96ba7680..b667b109 100644 --- a/example/lib/app_colors.dart +++ b/example/lib/theme/app_colors.dart @@ -1,8 +1,13 @@ import 'dart:ui'; +// TODO(Shubham): Remove if not required class AppColors { AppColors._(); + static const Color primary = Color(0xffEF5366); + static const Color onPrimary = Color(0xfff0f0f0); + static const Color outlineVariant = Color(0xffd7c1c2); + static const Color outline = Color(0xff857373); static const Color black = Color(0xff626262); static const Color radiantWhite = Color(0xffffffff); static const Color white = Color(0xfff0f0f0); diff --git a/example/lib/theme/app_theme.dart b/example/lib/theme/app_theme.dart new file mode 100644 index 00000000..b888d91a --- /dev/null +++ b/example/lib/theme/app_theme.dart @@ -0,0 +1,142 @@ +import 'package:calendar_view/calendar_view.dart'; +import 'package:example/constants.dart'; +import 'package:example/theme/app_colors.dart'; +import 'package:example/theme/app_theme_extension.dart'; +import 'package:flutter/material.dart'; + +import 'dark_app_colors.dart'; + +class AppTheme { + // Base InputDecorationTheme + static final baseInputDecorationTheme = InputDecorationTheme( + border: AppConstants.inputBorder, + disabledBorder: AppConstants.inputBorder, + errorBorder: AppConstants.inputBorder.copyWith( + borderSide: const BorderSide( + width: 2, + color: AppColors.red, + ), + ), + enabledBorder: AppConstants.inputBorder, + focusedBorder: AppConstants.inputBorder.copyWith( + borderSide: const BorderSide( + width: 2, + color: AppColors.outline, + ), + ), + focusedErrorBorder: AppConstants.inputBorder, + hintStyle: const TextStyle( + color: AppColors.black, + fontSize: 17, + ), + labelStyle: const TextStyle( + color: AppColors.black, + fontSize: 17, + ), + helperStyle: const TextStyle( + color: AppColors.black, + fontSize: 17, + ), + errorStyle: const TextStyle( + color: AppColors.red, + fontSize: 12, + ), + contentPadding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 20, + ), + ); + + // Light colors + static final _lightAppColors = CalendarThemeExtension.light(); + static final _dayViewTheme = DayViewTheme.light().copyWith( + halfHourLine: Colors.red, + ); + static final _appTheme = AppThemeExtension.light(); + + // Dark colors + static final _appDarkTheme = AppThemeExtension.dark(); + static final _calendarDarkTheme = CalendarThemeExtension.dark(); + static final _monthViewDarkTheme = MonthViewTheme.dark(); + static final _dayViewDarkTheme = DayViewTheme.dark(); + static final _weekViewDarkTheme = WeekViewTheme.dark(); + + // Light theme + static final light = CalendarTheme.light.copyWith( + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: AppColors.primary, + foregroundColor: AppColors.onPrimary, + ), + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: AppColors.primary, + ), + inputDecorationTheme: baseInputDecorationTheme, + appBarTheme: const AppBarTheme( + backgroundColor: AppColors.primary, + foregroundColor: AppColors.onPrimary, + ), + radioTheme: RadioThemeData( + fillColor: WidgetStateColor.resolveWith( + (_) => AppColors.primary, + ), + ), + extensions: [ + _appTheme, + _lightAppColors, + _dayViewTheme, + ], + ); + + // Dark theme + static final dark = CalendarTheme.dark.copyWith( + appBarTheme: const AppBarTheme( + backgroundColor: DarkAppColors.primary, + foregroundColor: DarkAppColors.onPrimary, + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: DarkAppColors.primary, + foregroundColor: DarkAppColors.onPrimary, + ), + ), + inputDecorationTheme: baseInputDecorationTheme.copyWith( + disabledBorder: AppConstants.inputBorder.copyWith( + borderSide: const BorderSide( + width: 2, + color: DarkAppColors.outlineVariant, + ), + ), + enabledBorder: AppConstants.inputBorder.copyWith( + borderSide: const BorderSide( + width: 2, + color: DarkAppColors.outlineVariant, + ), + ), + focusedBorder: AppConstants.inputBorder.copyWith( + borderSide: const BorderSide( + width: 2, + color: DarkAppColors.outline, + ), + ), + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: DarkAppColors.primary, + ), + radioTheme: RadioThemeData( + fillColor: WidgetStateColor.resolveWith( + (_) => DarkAppColors.primary, + ), + ), + // TODO(Shubham): Test dark theme update + // extensions: + extensions: [ + _appDarkTheme, + _calendarDarkTheme, + _monthViewDarkTheme, + _dayViewDarkTheme, + _weekViewDarkTheme, + ], + ); +} diff --git a/example/lib/theme/app_theme_extension.dart b/example/lib/theme/app_theme_extension.dart new file mode 100644 index 00000000..72a57b6a --- /dev/null +++ b/example/lib/theme/app_theme_extension.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +import 'app_colors.dart'; +import 'dark_app_colors.dart'; + +// TODO(Shubham): May not required to export remove it +// Default theme is light theme +class AppThemeExtension extends ThemeExtension { + AppThemeExtension({ + this.primary = AppColors.primary, + this.onPrimary = AppColors.onPrimary, + this.outlineVariant = AppColors.outlineVariant, + }); + + // Light theme constructor + AppThemeExtension.light() + : primary = AppColors.primary, + onPrimary = AppColors.onPrimary, + outlineVariant = AppColors.outlineVariant; + + // Dark theme constructor + AppThemeExtension.dark() + : primary = DarkAppColors.primary, + onPrimary = DarkAppColors.onPrimary, + outlineVariant = DarkAppColors.outlineVariant; + + final Color primary; + final Color onPrimary; + final Color outlineVariant; + + @override + ThemeExtension copyWith({ + Color? primary, + Color? onPrimary, + Color? outlineVariant, + }) { + return AppThemeExtension( + primary: primary ?? this.primary, + onPrimary: onPrimary ?? this.onPrimary, + outlineVariant: outlineVariant ?? this.outlineVariant, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! AppThemeExtension) { + return this; + } + return AppThemeExtension( + primary: Color.lerp(primary, other.primary, t) ?? primary, + onPrimary: Color.lerp(onPrimary, other.onPrimary, t) ?? onPrimary, + outlineVariant: + Color.lerp(outlineVariant, other.outlineVariant, t) ?? outlineVariant, + ); + } +} diff --git a/example/lib/theme/dark_app_colors.dart b/example/lib/theme/dark_app_colors.dart new file mode 100644 index 00000000..a5ec0a7d --- /dev/null +++ b/example/lib/theme/dark_app_colors.dart @@ -0,0 +1,10 @@ +import 'dart:ui'; + +class DarkAppColors { + DarkAppColors._(); + + static const Color primary = Color(0xffffb3b6); + static const Color onPrimary = Color(0xff561d23); + static const Color outline = Color(0xff9f8c8c); + static const Color outlineVariant = Color(0xff524343); +} diff --git a/example/lib/widgets/add_event_form.dart b/example/lib/widgets/add_event_form.dart index dbdf31c9..f9702456 100644 --- a/example/lib/widgets/add_event_form.dart +++ b/example/lib/widgets/add_event_form.dart @@ -2,9 +2,9 @@ import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_colorpicker/flutter_colorpicker.dart'; -import '../app_colors.dart'; import '../constants.dart'; import '../extension.dart'; +import '../theme/app_colors.dart'; import 'custom_button.dart'; import 'date_time_selector.dart'; @@ -63,6 +63,8 @@ class _AddOrEditEventFormState extends State { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Form( key: _form, child: Column( @@ -70,11 +72,14 @@ class _AddOrEditEventFormState extends State { children: [ TextFormField( controller: _titleController, - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: "Event Title", - ), + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), validator: (value) { @@ -96,9 +101,12 @@ class _AddOrEditEventFormState extends State { children: [ Expanded( child: DateTimeSelectorFormField( - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: "Start Date", - ), + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), initialDateTime: _startDate, onSelect: (date) { if (date.withoutTime.withoutTime @@ -121,7 +129,7 @@ class _AddOrEditEventFormState extends State { return null; }, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), onSave: (date) => _startDate = date ?? _startDate, @@ -132,9 +140,12 @@ class _AddOrEditEventFormState extends State { Expanded( child: DateTimeSelectorFormField( initialDateTime: _endDate, - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: "End Date", - ), + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), onSelect: (date) { if (date.withoutTime.withoutTime .isBefore(_startDate.withoutTime)) { @@ -159,7 +170,7 @@ class _AddOrEditEventFormState extends State { return null; }, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), onSave: (date) => _endDate = date ?? _endDate, @@ -173,9 +184,12 @@ class _AddOrEditEventFormState extends State { children: [ Expanded( child: DateTimeSelectorFormField( - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: "Start Time", - ), + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), initialDateTime: _startTime, minimumDateTime: CalendarConstants.epochDate, onSelect: (date) { @@ -191,7 +205,7 @@ class _AddOrEditEventFormState extends State { }, onSave: (date) => _startTime = date, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), type: DateTimeSelectionType.time, @@ -200,9 +214,12 @@ class _AddOrEditEventFormState extends State { SizedBox(width: 20.0), Expanded( child: DateTimeSelectorFormField( - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: "End Time", - ), + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), initialDateTime: _endTime, onSelect: (date) { if (_startTime != null && @@ -220,7 +237,7 @@ class _AddOrEditEventFormState extends State { }, onSave: (date) => _endTime = date, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), type: DateTimeSelectionType.time, @@ -235,7 +252,7 @@ class _AddOrEditEventFormState extends State { controller: _descriptionController, focusNode: _descriptionNode, style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), keyboardType: TextInputType.multiline, @@ -251,9 +268,10 @@ class _AddOrEditEventFormState extends State { return null; }, - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( hintText: "Event Description", - ), + counterStyle: TextStyle(color: color.onSurfaceVariant), + ).applyDefaults(Theme.of(context).inputDecorationTheme), ), Align( alignment: Alignment.centerLeft, @@ -271,6 +289,7 @@ class _AddOrEditEventFormState extends State { Radio( value: RepeatFrequency.doNotRepeat, groupValue: _selectedFrequency, + // activeColor: context.themeColor.primary, onChanged: (value) { setState( () => _selectedFrequency = value, @@ -459,9 +478,9 @@ class _AddOrEditEventFormState extends State { if (_selectedRecurrenceEnd == RecurrenceEnd.onDate) DateTimeSelectorFormField( initialDateTime: _recurrenceEndDate, - decoration: AppConstants.inputDecoration.copyWith( + decoration: InputDecoration( labelText: 'Ends on', - ), + ).applyDefaults(Theme.of(context).inputDecorationTheme), onSelect: (date) { if (date.withoutTime.isBefore(_endDate.withoutTime)) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( @@ -521,7 +540,7 @@ class _AddOrEditEventFormState extends State { Text( "Event Color: ", style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17, ), ), diff --git a/example/lib/widgets/calendar_configs.dart b/example/lib/widgets/calendar_configs.dart index 9f976f88..5902c02d 100644 --- a/example/lib/widgets/calendar_configs.dart +++ b/example/lib/widgets/calendar_configs.dart @@ -1,23 +1,34 @@ import 'package:calendar_view/calendar_view.dart'; import 'package:flutter/material.dart'; -import '../app_colors.dart'; import '../enumerations.dart'; import '../extension.dart'; +import '../theme/app_colors.dart'; import 'add_event_form.dart'; -class CalendarConfig extends StatelessWidget { +class CalendarConfig extends StatefulWidget { final void Function(CalendarView view) onViewChange; + final void Function(bool)? onThemeChange; final CalendarView currentView; const CalendarConfig({ super.key, required this.onViewChange, + this.onThemeChange, this.currentView = CalendarView.month, }); + @override + State createState() => _CalendarConfigState(); +} + +class _CalendarConfigState extends State { + bool isDarkMode = false; + @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -27,7 +38,7 @@ class CalendarConfig extends StatelessWidget { child: Text( "Flutter Calendar Page", style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 30, ), ), @@ -42,11 +53,32 @@ class CalendarConfig extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Dark mode: ', + style: TextStyle( + fontSize: 20.0, + color: color.onSurface, + ), + ), + Switch( + value: isDarkMode, + onChanged: (value) { + setState(() => isDarkMode = value); + if (widget.onThemeChange != null) { + widget.onThemeChange!(isDarkMode); + } + }, + ), + ], + ), Text( "Active View:", style: TextStyle( fontSize: 20.0, - color: AppColors.black, + color: Theme.of(context).colorScheme.onSurface, ), ), Wrap( @@ -55,7 +87,7 @@ class CalendarConfig extends StatelessWidget { (index) { final view = CalendarView.values[index]; return GestureDetector( - onTap: () => onViewChange(view), + onTap: () => widget.onViewChange(view), child: Container( padding: EdgeInsets.symmetric( vertical: 10, @@ -67,14 +99,14 @@ class CalendarConfig extends StatelessWidget { ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(7), - color: view == currentView + color: view == widget.currentView ? AppColors.navyBlue : AppColors.bluishGrey, ), child: Text( view.name.capitalized, style: TextStyle( - color: view == currentView + color: view == widget.currentView ? AppColors.white : AppColors.black, fontSize: 17, @@ -92,7 +124,7 @@ class CalendarConfig extends StatelessWidget { "Add Event: ", style: TextStyle( fontSize: 20.0, - color: AppColors.black, + color: color.onSurface, ), ), SizedBox( diff --git a/example/lib/widgets/calendar_views.dart b/example/lib/widgets/calendar_views.dart index 28509775..715d2830 100644 --- a/example/lib/widgets/calendar_views.dart +++ b/example/lib/widgets/calendar_views.dart @@ -2,8 +2,8 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import '../app_colors.dart'; import '../enumerations.dart'; +import '../theme/app_colors.dart'; import 'day_view_widget.dart'; import 'month_view_widget.dart'; import 'week_view_widget.dart'; diff --git a/example/lib/widgets/custom_button.dart b/example/lib/widgets/custom_button.dart index 02a92a9b..c9af5d6b 100644 --- a/example/lib/widgets/custom_button.dart +++ b/example/lib/widgets/custom_button.dart @@ -1,6 +1,7 @@ +import 'package:example/extension.dart'; import 'package:flutter/material.dart'; -import '../app_colors.dart'; +import '../theme/app_colors.dart'; class CustomButton extends StatelessWidget { final String title; @@ -10,6 +11,8 @@ class CustomButton extends StatelessWidget { @override Widget build(BuildContext context) { + final themeColors = context.appColors; + return GestureDetector( onTap: onTap, child: Container( @@ -18,7 +21,7 @@ class CustomButton extends StatelessWidget { horizontal: 40, ), decoration: BoxDecoration( - color: AppColors.navyBlue, + color: themeColors.primary, borderRadius: BorderRadius.circular(7.0), boxShadow: [ BoxShadow( @@ -32,7 +35,7 @@ class CustomButton extends StatelessWidget { child: Text( title, style: TextStyle( - color: AppColors.white, + color: themeColors.onPrimary, fontSize: 20, ), ), diff --git a/example/lib/widgets/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart index a02c189f..88639666 100644 --- a/example/lib/widgets/day_view_widget.dart +++ b/example/lib/widgets/day_view_widget.dart @@ -21,9 +21,10 @@ class DayViewWidget extends StatelessWidget { startDuration: Duration(hours: 8), showHalfHours: true, heightPerMinute: 3, - timeLineBuilder: _timeLineBuilder, + // timeLineBuilder: _timeLineBuilder, scrollPhysics: const BouncingScrollPhysics(), eventArranger: SideEventArranger(maxWidth: 30), + showQuarterHours: false, hourIndicatorSettings: HourIndicatorSettings( color: Theme.of(context).dividerColor, ), @@ -48,18 +49,18 @@ class DayViewWidget extends StatelessWidget { ScaffoldMessenger.of(context).showSnackBar(snackBar); }, halfHourIndicatorSettings: HourIndicatorSettings( - color: Theme.of(context).dividerColor, + color: context.dayViewColors.halfHourLine, lineStyle: LineStyle.dashed, ), verticalLineOffset: 0, timeLineWidth: 65, showLiveTimeLineInAllDays: true, - liveTimeIndicatorSettings: LiveTimeIndicatorSettings( - color: Colors.redAccent, - showBullet: false, - showTime: true, - showTimeBackgroundView: true, - ), + // liveTimeIndicatorSettings: LiveTimeIndicatorSettings( + // color: Colors.redAccent, + // showBullet: false, + // showTime: true, + // showTimeBackgroundView: true, + // ), ); } @@ -75,7 +76,7 @@ class DayViewWidget extends StatelessWidget { "${date.hour}:${date.minute}", textAlign: TextAlign.right, style: TextStyle( - color: Colors.black.withAlpha(50), + color: Colors.grey, fontStyle: FontStyle.italic, fontSize: 12, ), diff --git a/example/lib/widgets/month_view_widget.dart b/example/lib/widgets/month_view_widget.dart index d9102d0c..84cbbad6 100644 --- a/example/lib/widgets/month_view_widget.dart +++ b/example/lib/widgets/month_view_widget.dart @@ -21,6 +21,7 @@ class MonthViewWidget extends StatelessWidget { showWeekends: true, startDay: WeekDays.friday, useAvailableVerticalSpace: true, + hideDaysNotInMonth: true, onEventTap: (event, date) { Navigator.of(context).push( MaterialPageRoute( diff --git a/example/lib/widgets/week_view_widget.dart b/example/lib/widgets/week_view_widget.dart index 4222c531..8ffce0c2 100644 --- a/example/lib/widgets/week_view_widget.dart +++ b/example/lib/widgets/week_view_widget.dart @@ -19,10 +19,10 @@ class WeekViewWidget extends StatelessWidget { eventArranger: SideEventArranger(maxWidth: 30), timeLineWidth: 65, scrollPhysics: const BouncingScrollPhysics(), - liveTimeIndicatorSettings: LiveTimeIndicatorSettings( - color: Colors.redAccent, - showTime: true, - ), + // liveTimeIndicatorSettings: LiveTimeIndicatorSettings( + // color: Colors.redAccent, + // showTime: true, + // ), onTimestampTap: (date) { SnackBar snackBar = SnackBar( content: Text("On tap: ${date.hour} Hr : ${date.minute} Min"), diff --git a/lib/calendar_view.dart b/lib/calendar_view.dart index 80e038ea..b7b656fa 100644 --- a/lib/calendar_view.dart +++ b/lib/calendar_view.dart @@ -16,5 +16,10 @@ export './src/extensions.dart'; export './src/modals.dart'; export './src/month_view/month_view.dart'; export './src/style/header_style.dart'; +export './src/theme/calendar_theme.dart'; +export './src/theme/calendar_theme_extension.dart'; // TODO(Shubham): Check if it is required +export './src/theme/day_view_theme.dart'; +export './src/theme/month_view_theme.dart'; +export './src/theme/week_view_theme.dart'; export './src/typedefs.dart'; export './src/week_view/week_view.dart'; diff --git a/lib/src/components/day_view_components.dart b/lib/src/components/day_view_components.dart index b8e28e9e..47e4d5d2 100644 --- a/lib/src/components/day_view_components.dart +++ b/lib/src/components/day_view_components.dart @@ -145,6 +145,7 @@ class DefaultTimeLineMark extends StatelessWidget { textAlign: TextAlign.right, style: markingStyle ?? TextStyle( + color: context.themeColor.timelineText, fontSize: 15.0, ), ), diff --git a/lib/src/components/headers/calendar_page_header.dart b/lib/src/components/headers/calendar_page_header.dart index b84bcbe1..90dae67e 100644 --- a/lib/src/components/headers/calendar_page_header.dart +++ b/lib/src/components/headers/calendar_page_header.dart @@ -7,9 +7,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import '../../../calendar_view.dart'; import '../../constants.dart'; -import '../../style/header_style.dart'; -import '../../typedefs.dart'; class CalendarPageHeader extends StatelessWidget { /// When user taps on right arrow. @@ -104,8 +103,10 @@ class CalendarPageHeader extends StatelessWidget { return Container( margin: headerStyle.headerMargin, padding: headerStyle.headerPadding, - decoration: - headerStyle.decoration ?? BoxDecoration(color: backgroundColor), + decoration: headerStyle.decoration ?? + BoxDecoration( + color: backgroundColor, + ), clipBehavior: Clip.antiAlias, child: Row( mainAxisSize: headerStyle.mainAxisSize, @@ -130,7 +131,7 @@ class CalendarPageHeader extends StatelessWidget { Icons.chevron_left, size: headerStyle.leftIconConfig!.size, color: - iconColor ?? headerStyle.leftIconConfig!.color, + iconColor ?? headerStyle.leftIconConfig?.color, ), ), ), diff --git a/lib/src/components/headers/day_page_header.dart b/lib/src/components/headers/day_page_header.dart index 22e43a5e..07d5d5f2 100644 --- a/lib/src/components/headers/day_page_header.dart +++ b/lib/src/components/headers/day_page_header.dart @@ -33,7 +33,6 @@ class DayPageHeader extends CalendarPageHeader { backgroundColor: backgroundColor, iconColor: iconColor, onNextDay: onNextDay, - showNextIcon: showNextIcon, onPreviousDay: onPreviousDay, showPreviousIcon: showPreviousIcon, diff --git a/lib/src/components/headers/month_page_header.dart b/lib/src/components/headers/month_page_header.dart index 2df8f6c4..1db8390f 100644 --- a/lib/src/components/headers/month_page_header.dart +++ b/lib/src/components/headers/month_page_header.dart @@ -5,10 +5,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import '../../../calendar_view.dart'; import '../../constants.dart'; -import '../../style/header_style.dart'; -import '../../typedefs.dart'; -import 'calendar_page_header.dart'; class MonthPageHeader extends CalendarPageHeader { /// A header widget to display on month view. @@ -24,7 +22,8 @@ class MonthPageHeader extends CalendarPageHeader { Color backgroundColor = Constants.headerBackground, StringProvider? dateStringBuilder, required DateTime date, - HeaderStyle headerStyle = const HeaderStyle(), + HeaderStyle headerStyle = + const HeaderStyle(), // TODO(Shubham): Update default header style }) : super( key: key, date: date, diff --git a/lib/src/components/month_view_components.dart b/lib/src/components/month_view_components.dart index a7cd5c5f..6a2023b4 100644 --- a/lib/src/components/month_view_components.dart +++ b/lib/src/components/month_view_components.dart @@ -4,10 +4,8 @@ import 'package:flutter/material.dart'; -import '../calendar_event_data.dart'; +import '../../calendar_view.dart'; import '../constants.dart'; -import '../extensions.dart'; -import '../typedefs.dart'; class CircularCell extends StatelessWidget { /// Date of cell. @@ -211,7 +209,9 @@ class WeekDayTile extends StatelessWidget { final String Function(int)? weekDayStringBuilder; /// Background color of single week day tile. - final Color backgroundColor; + final Color? backgroundColor; + + final Color? borderColor; /// Should display border or not. final bool displayBorder; @@ -223,7 +223,8 @@ class WeekDayTile extends StatelessWidget { const WeekDayTile({ Key? key, required this.dayIndex, - this.backgroundColor = Constants.white, + this.backgroundColor, + this.borderColor, this.displayBorder = true, this.textStyle, this.weekDayStringBuilder, @@ -231,15 +232,17 @@ class WeekDayTile extends StatelessWidget { @override Widget build(BuildContext context) { + final themeColors = context.monthViewColors; + return Container( alignment: Alignment.center, margin: EdgeInsets.zero, padding: EdgeInsets.symmetric(vertical: 10.0), decoration: BoxDecoration( - color: backgroundColor, + color: backgroundColor ?? themeColors.weekDayTile, border: displayBorder ? Border.all( - color: Constants.defaultBorderColor, + color: borderColor ?? themeColors.weekDayBorder, width: 0.5, ) : null, @@ -249,7 +252,7 @@ class WeekDayTile extends StatelessWidget { style: textStyle ?? TextStyle( fontSize: 17, - color: Constants.black, + color: themeColors.weekDayText, ), ), ); diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 158379c8..920a0ccb 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -17,10 +17,8 @@ class Constants { static final List weekTitles = ["M", "T", "W", "T", "F", "S", "S"]; static const Color defaultLiveTimeIndicatorColor = Color(0xff444444); - static const Color defaultBorderColor = Color(0xffdddddd); static const Color black = Color(0xff000000); static const Color white = Color(0xffffffff); - static const Color offWhite = Color(0xfff0f0f0); static const Color headerBackground = Color(0xFFDCF0FF); static Color get randomColor { diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index c290fd19..98807222 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -193,7 +193,7 @@ class DayView extends StatefulWidget { final ScrollPhysics? pageViewPhysics; /// Style for DayView header. - final HeaderStyle headerStyle; + final HeaderStyle? headerStyle; /// Option for SafeArea. final SafeAreaOption safeAreaOption; @@ -252,14 +252,14 @@ class DayView extends StatefulWidget { this.dayTitleBuilder, this.eventArranger, this.verticalLineOffset = 10, - this.backgroundColor = Colors.white, + this.backgroundColor, this.scrollOffset, this.onEventTap, this.onEventLongTap, this.onDateLongPress, this.onDateTap, this.minuteSlotSize = MinuteSlotSize.minutes60, - this.headerStyle = const HeaderStyle(), + this.headerStyle, this.fullDayEventBuilder, this.safeAreaOption = const SafeAreaOption(), this.scrollPhysics, @@ -431,6 +431,8 @@ class DayViewState extends State> { @override Widget build(BuildContext context) { + final themeColor = context.dayViewColors; + return SafeAreaWrapper( option: widget.safeAreaOption, child: LayoutBuilder(builder: (context, constraint) { @@ -445,7 +447,9 @@ class DayViewState extends State> { _dayTitleBuilder(_currentDate), Expanded( child: DecoratedBox( - decoration: BoxDecoration(color: widget.backgroundColor), + decoration: BoxDecoration( + color: widget.backgroundColor ?? themeColor.pageBackground, + ), child: SizedBox( height: _height, child: PageView.builder( @@ -545,7 +549,7 @@ class DayViewState extends State> { _liveTimeIndicatorSettings = widget.liveTimeIndicatorSettings ?? LiveTimeIndicatorSettings( - color: Constants.defaultLiveTimeIndicatorColor, + color: context.dayViewColors.liveIndicator, height: widget.heightPerMinute, offset: 5 + widget.verticalLineOffset, ); @@ -556,7 +560,7 @@ class DayViewState extends State> { _hourIndicatorSettings = widget.hourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: context.dayViewColors.hourLine, offset: 5, ); @@ -566,7 +570,7 @@ class DayViewState extends State> { _halfHourIndicatorSettings = widget.halfHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: context.dayViewColors.halfHourLine, offset: 5, ); @@ -576,7 +580,7 @@ class DayViewState extends State> { _quarterHourIndicatorSettings = widget.quarterHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: context.dayViewColors.quarterHourLine, offset: 5, ); @@ -703,7 +707,22 @@ class DayViewState extends State> { jumpToDate(selectedDate); } }, - headerStyle: widget.headerStyle, + headerStyle: widget.headerStyle ?? + HeaderStyle( + decoration: BoxDecoration( + color: context.dayViewColors.headerBackground, + ), + leftIconConfig: IconDataConfig( + color: context.dayViewColors.headerIcon, + ), + rightIconConfig: IconDataConfig( + color: context.dayViewColors.headerIcon, + ), + headerTextStyle: TextStyle( + color: context.dayViewColors.headerText, + fontWeight: FontWeight.w500, + ), + ), ); } diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 7e6165d7..0eca4b6f 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -252,3 +252,20 @@ void debugLog(String message) { return false; }(), ''); } + +extension BuildContextExtension on BuildContext { + // TODO(Shubham): Update here theme based if possible + // Update to colors + CalendarThemeExtension get themeColor => + Theme.of(this).extension() ?? + CalendarThemeExtension.light(); + + MonthViewTheme get monthViewColors => + Theme.of(this).extension() ?? MonthViewTheme.light(); + + DayViewTheme get dayViewColors => + Theme.of(this).extension() ?? DayViewTheme.light(); + + WeekViewTheme get weekViewColors => + Theme.of(this).extension() ?? WeekViewTheme.light(); +} diff --git a/lib/src/month_view/month_view.dart b/lib/src/month_view/month_view.dart index 194d4759..9e8fabfd 100644 --- a/lib/src/month_view/month_view.dart +++ b/lib/src/month_view/month_view.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import '../../calendar_view.dart'; -import '../constants.dart'; class MonthView extends StatefulWidget { /// A function that returns a [Widget] that determines appearance of @@ -101,7 +100,7 @@ class MonthView extends StatefulWidget { /// Default value is [Colors.blue] /// /// It will take affect only if [showBorder] is set. - final Color borderColor; + final Color? borderColor; /// Page transition duration used when user try to change page using /// [MonthView.nextPage] or [MonthView.previousPage] @@ -148,7 +147,7 @@ class MonthView extends StatefulWidget { final WeekDays startDay; /// Style for MontView header. - final HeaderStyle headerStyle; + final HeaderStyle? headerStyle; /// Option for SafeArea. final SafeAreaOption safeAreaOption; @@ -174,7 +173,7 @@ class MonthView extends StatefulWidget { const MonthView({ Key? key, this.showBorder = true, - this.borderColor = Constants.defaultBorderColor, + this.borderColor, this.cellBuilder, this.minMonth, this.maxMonth, @@ -198,7 +197,7 @@ class MonthView extends StatefulWidget { this.headerStringBuilder, this.dateStringBuilder, this.weekDayStringBuilder, - this.headerStyle = const HeaderStyle(), + this.headerStyle, this.safeAreaOption = const SafeAreaOption(), this.onHeaderTitleTap, this.pagePhysics = const ClampingScrollPhysics(), @@ -543,7 +542,22 @@ class MonthViewState extends State> { date: date, dateStringBuilder: widget.headerStringBuilder, onNextMonth: nextPage, - headerStyle: widget.headerStyle, + headerStyle: widget.headerStyle ?? + HeaderStyle( + decoration: BoxDecoration( + color: context.monthViewColors.headerBackground, + ), + leftIconConfig: IconDataConfig( + color: context.monthViewColors.headerIcon, + ), + rightIconConfig: IconDataConfig( + color: context.monthViewColors.headerIcon, + ), + headerTextStyle: TextStyle( + color: context.monthViewColors.headerText, + fontWeight: FontWeight.w500, + ), + ), ); } @@ -564,11 +578,14 @@ class MonthViewState extends State> { isInMonth, hideDaysNotInMonth, ) { + final themeColor = context.monthViewColors; + if (hideDaysNotInMonth) { return FilledCell( date: date, shouldHighlight: isToday, - backgroundColor: isInMonth ? Constants.white : Constants.offWhite, + backgroundColor: + isInMonth ? themeColor.cellInMonth : themeColor.cellNotInMonth, events: events, isInMonth: isInMonth, onTileTap: widget.onEventTap, @@ -576,21 +593,22 @@ class MonthViewState extends State> { onTileLongTap: widget.onEventLongTap, dateStringBuilder: widget.dateStringBuilder, hideDaysNotInMonth: hideDaysNotInMonth, + titleColor: themeColor.cellText, ); } return FilledCell( date: date, shouldHighlight: isToday, - backgroundColor: isInMonth ? Constants.white : Constants.offWhite, + backgroundColor: + isInMonth ? themeColor.cellInMonth : themeColor.cellNotInMonth, events: events, onTileTap: widget.onEventTap, onTileLongTap: widget.onEventLongTap, dateStringBuilder: widget.dateStringBuilder, onTileDoubleTap: widget.onEventDoubleTap, hideDaysNotInMonth: hideDaysNotInMonth, - titleColor: isInMonth - ? Theme.of(context).colorScheme.onPrimaryContainer - : Theme.of(context).colorScheme.onSurfaceVariant.withAlpha(150), + titleColor: + isInMonth ? themeColor.cellText : themeColor.cellText.withAlpha(150), ); } @@ -672,7 +690,7 @@ class _MonthPageBuilder extends StatelessWidget { final double cellRatio; final bool showBorder; final double borderSize; - final Color borderColor; + final Color? borderColor; final CellBuilder cellBuilder; final DateTime date; final EventController controller; @@ -690,7 +708,6 @@ class _MonthPageBuilder extends StatelessWidget { required this.cellRatio, required this.showBorder, required this.borderSize, - required this.borderColor, required this.cellBuilder, required this.date, required this.controller, @@ -702,6 +719,7 @@ class _MonthPageBuilder extends StatelessWidget { required this.physics, required this.hideDaysNotInMonth, required this.weekDays, + this.borderColor, }) : super(key: key); @override @@ -738,7 +756,8 @@ class _MonthPageBuilder extends StatelessWidget { decoration: BoxDecoration( border: showBorder ? Border.all( - color: borderColor, + color: + borderColor ?? context.monthViewColors.cellBorder, width: borderSize, ) : null, diff --git a/lib/src/style/header_style.dart b/lib/src/style/header_style.dart index b7728ff3..e1b67d0b 100644 --- a/lib/src/style/header_style.dart +++ b/lib/src/style/header_style.dart @@ -137,8 +137,8 @@ class HeaderStyle { /// Defines the data for icons used in calendar_view. class IconDataConfig { - /// Color of the default Icon. - final Color color; + /// Color of the Icon. + final Color? color; /// Size of the default Icon. final double size; @@ -164,7 +164,7 @@ class IconDataConfig { /// Defines the data for icons used in calendar_view. const IconDataConfig({ - this.color = Colors.black, + this.color, this.size = 30, this.padding = const EdgeInsets.all(10), this.icon, diff --git a/lib/src/theme/calendar_theme.dart b/lib/src/theme/calendar_theme.dart new file mode 100644 index 00000000..2223a26d --- /dev/null +++ b/lib/src/theme/calendar_theme.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../../calendar_view.dart'; + +class CalendarTheme { + CalendarTheme._(); + + // Light theme + static final light = ThemeData.light().copyWith( + extensions: [ + CalendarThemeExtension.light(), + MonthViewTheme.light(), + DayViewTheme.light(), + WeekViewTheme.light(), + ], + ); + + // Dark theme + static final dark = ThemeData.dark().copyWith( + extensions: [ + CalendarThemeExtension.dark(), + MonthViewTheme.dark(), + DayViewTheme.dark(), + WeekViewTheme.dark(), + ], + ); +} diff --git a/lib/src/theme/calendar_theme_extension.dart b/lib/src/theme/calendar_theme_extension.dart new file mode 100644 index 00000000..3d3d6735 --- /dev/null +++ b/lib/src/theme/calendar_theme_extension.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +import 'dark_app_colors.dart'; +import 'light_app_colors.dart'; + +/// Contains global colors which applies to month-view, day-view & week-view components. +class CalendarThemeExtension extends ThemeExtension { + CalendarThemeExtension({ + required this.timelineText, + }); + + final Color timelineText; + + // Light theme constructor + CalendarThemeExtension.light() : timelineText = LightAppColors.onSurface; + + // Dark theme constructor + CalendarThemeExtension.dark() : timelineText = DarkAppColors.onSurface; + + @override + ThemeExtension copyWith({ + Color? timelineText, + }) { + return CalendarThemeExtension( + timelineText: timelineText ?? this.timelineText, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! CalendarThemeExtension) { + return this; + } + return CalendarThemeExtension( + timelineText: + Color.lerp(timelineText, other.timelineText, t) ?? timelineText, + ); + } +} diff --git a/lib/src/theme/dark_app_colors.dart b/lib/src/theme/dark_app_colors.dart new file mode 100644 index 00000000..2538021e --- /dev/null +++ b/lib/src/theme/dark_app_colors.dart @@ -0,0 +1,14 @@ +import 'dart:ui'; + +class DarkAppColors { + DarkAppColors._(); + + static const Color primary = Color(0xffffb3b6); + static const Color onPrimary = Color(0xff561d23); + static const Color surfaceContainerHigh = Color(0xff322828); + static const Color outlineVariant = Color(0xff524343); + static const Color onSurface = Color(0xfff0dede); + static const Color surfaceContainerLowest = Color(0xff140c0c); + static const Color surfaceContainerLow = Color(0xff22191a); + static const Color surfaceContainerHighest = Color(0xff3d3232); +} diff --git a/lib/src/theme/day_view_theme.dart b/lib/src/theme/day_view_theme.dart new file mode 100644 index 00000000..d2a64c47 --- /dev/null +++ b/lib/src/theme/day_view_theme.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; + +import 'dark_app_colors.dart'; +import 'light_app_colors.dart'; + +class DayViewTheme extends ThemeExtension { + DayViewTheme({ + required this.hourLine, + required this.halfHourLine, + required this.quarterHourLine, + required this.pageBackground, + required this.liveIndicator, + required this.headerIcon, + required this.headerText, + required this.headerBackground, + }); + + final Color hourLine; + final Color halfHourLine; + final Color quarterHourLine; + final Color pageBackground; + final Color liveIndicator; + + // Calendar page header + final Color headerIcon; + final Color headerText; + final Color headerBackground; + + // Light theme + DayViewTheme.light() + : hourLine = LightAppColors.surfaceContainerHighest, + halfHourLine = LightAppColors.surfaceContainerHighest, + quarterHourLine = LightAppColors.surfaceContainerHighest, + pageBackground = LightAppColors.surfaceContainerLowest, + liveIndicator = LightAppColors.primary, + headerIcon = LightAppColors.onPrimary, + headerText = LightAppColors.onPrimary, + headerBackground = LightAppColors.primary; + + // Dark theme + DayViewTheme.dark() + : hourLine = DarkAppColors.surfaceContainerHighest, + halfHourLine = DarkAppColors.surfaceContainerHighest, + quarterHourLine = DarkAppColors.surfaceContainerHighest, + pageBackground = DarkAppColors.surfaceContainerLowest, + liveIndicator = DarkAppColors.primary, + headerIcon = DarkAppColors.onPrimary, + headerText = DarkAppColors.onPrimary, + headerBackground = DarkAppColors.primary; + + @override + ThemeExtension copyWith({ + Color? hourLine, + Color? halfHourLine, + Color? quarterHourLine, + Color? pageBackground, + Color? liveIndicator, + Color? headerIcon, + Color? headerText, + Color? headerBackground, + }) { + return DayViewTheme( + hourLine: hourLine ?? this.hourLine, + halfHourLine: halfHourLine ?? this.halfHourLine, + quarterHourLine: quarterHourLine ?? this.quarterHourLine, + pageBackground: pageBackground ?? this.pageBackground, + liveIndicator: liveIndicator ?? this.liveIndicator, + headerIcon: headerIcon ?? this.headerIcon, + headerText: headerText ?? this.headerText, + headerBackground: headerBackground ?? this.headerBackground, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! DayViewTheme) { + return this; + } + return DayViewTheme( + hourLine: Color.lerp(hourLine, other.hourLine, t) ?? hourLine, + halfHourLine: + Color.lerp(halfHourLine, other.halfHourLine, t) ?? halfHourLine, + quarterHourLine: Color.lerp(quarterHourLine, other.quarterHourLine, t) ?? + quarterHourLine, + pageBackground: + Color.lerp(pageBackground, other.pageBackground, t) ?? pageBackground, + liveIndicator: + Color.lerp(liveIndicator, other.liveIndicator, t) ?? liveIndicator, + headerIcon: Color.lerp(headerIcon, other.headerIcon, t) ?? headerIcon, + headerText: Color.lerp(headerText, other.headerText, t) ?? headerText, + headerBackground: + Color.lerp(headerBackground, other.headerBackground, t) ?? + headerBackground, + ); + } +} diff --git a/lib/src/theme/light_app_colors.dart b/lib/src/theme/light_app_colors.dart new file mode 100644 index 00000000..50c31788 --- /dev/null +++ b/lib/src/theme/light_app_colors.dart @@ -0,0 +1,14 @@ +import 'dart:ui'; + +class LightAppColors { + LightAppColors(); + + static const Color primary = Color(0xffEF5366); + static const Color onPrimary = Color(0xffffffff); + static const Color surfaceContainerHigh = Color(0xfff6e4e4); + static const Color outlineVariant = Color(0xffd7c1c2); + static const Color onSurface = Color(0xff22191a); + static const Color surfaceContainerLowest = Color(0xffffffff); + static const Color surfaceContainerLow = Color(0xfffff0f0); + static const Color surfaceContainerHighest = Color(0xfff0dede); +} diff --git a/lib/src/theme/month_view_theme.dart b/lib/src/theme/month_view_theme.dart new file mode 100644 index 00000000..28a7a548 --- /dev/null +++ b/lib/src/theme/month_view_theme.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; + +import 'dark_app_colors.dart'; +import 'light_app_colors.dart'; + +class MonthViewTheme extends ThemeExtension { + MonthViewTheme({ + required this.cellInMonth, + required this.cellNotInMonth, + required this.cellText, + required this.cellBorder, + required this.weekDayTile, + required this.weekDayText, + required this.weekDayBorder, + required this.headerIcon, + required this.headerText, + required this.headerBackground, + }); + + final Color cellInMonth; + final Color cellNotInMonth; + final Color cellText; + final Color cellBorder; + final Color weekDayTile; + final Color weekDayText; + final Color weekDayBorder; + + // Calendar page header + final Color headerIcon; + final Color headerText; + final Color headerBackground; + + // Light theme + MonthViewTheme.light() + : cellInMonth = LightAppColors.surfaceContainerLowest, + cellNotInMonth = LightAppColors.surfaceContainerLow, + cellText = LightAppColors.onSurface, + cellBorder = LightAppColors.surfaceContainerHigh, + weekDayTile = LightAppColors.surfaceContainerHigh, + weekDayText = LightAppColors.onSurface, + weekDayBorder = LightAppColors.outlineVariant, + headerIcon = LightAppColors.onPrimary, + headerText = LightAppColors.onPrimary, + headerBackground = LightAppColors.primary; + + // Dark theme + MonthViewTheme.dark() + : cellInMonth = DarkAppColors.surfaceContainerLowest, + cellNotInMonth = DarkAppColors.surfaceContainerLow, + cellText = DarkAppColors.onSurface, + cellBorder = DarkAppColors.surfaceContainerHigh, + weekDayTile = DarkAppColors.surfaceContainerHigh, + weekDayText = DarkAppColors.onSurface, + weekDayBorder = DarkAppColors.outlineVariant, + headerIcon = DarkAppColors.onPrimary, + headerText = DarkAppColors.onPrimary, + headerBackground = DarkAppColors.primary; + + @override + ThemeExtension copyWith({ + Color? cellInMonth, + Color? cellNotInMonth, + Color? cellText, + Color? cellBorder, + Color? weekDayTile, + Color? weekDayText, + Color? weekDayBorder, + Color? headerIcon, + Color? headerText, + Color? headerBackground, + }) { + return MonthViewTheme( + cellInMonth: cellInMonth ?? this.cellInMonth, + cellNotInMonth: cellNotInMonth ?? this.cellNotInMonth, + cellText: cellText ?? this.cellText, + cellBorder: cellBorder ?? this.cellBorder, + weekDayTile: weekDayTile ?? this.weekDayTile, + weekDayText: weekDayText ?? this.weekDayText, + weekDayBorder: weekDayBorder ?? this.weekDayBorder, + headerIcon: headerIcon ?? this.headerIcon, + headerText: headerText ?? this.headerText, + headerBackground: headerBackground ?? this.headerBackground, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! MonthViewTheme) { + return this; + } + return MonthViewTheme( + cellInMonth: Color.lerp(cellInMonth, other.cellInMonth, t) ?? cellInMonth, + cellNotInMonth: + Color.lerp(cellNotInMonth, other.cellNotInMonth, t) ?? cellNotInMonth, + cellText: Color.lerp(cellText, other.cellText, t) ?? cellText, + cellBorder: Color.lerp(cellBorder, other.cellBorder, t) ?? cellBorder, + weekDayTile: Color.lerp(weekDayTile, other.weekDayTile, t) ?? weekDayTile, + weekDayText: Color.lerp(weekDayText, other.weekDayText, t) ?? weekDayText, + weekDayBorder: + Color.lerp(weekDayBorder, other.weekDayBorder, t) ?? weekDayBorder, + headerIcon: Color.lerp(headerIcon, other.headerIcon, t) ?? headerIcon, + headerText: Color.lerp(headerText, other.headerText, t) ?? headerText, + headerBackground: + Color.lerp(headerBackground, other.headerBackground, t) ?? + headerBackground, + ); + } +} diff --git a/lib/src/theme/week_view_theme.dart b/lib/src/theme/week_view_theme.dart new file mode 100644 index 00000000..4d480f05 --- /dev/null +++ b/lib/src/theme/week_view_theme.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; + +import 'dark_app_colors.dart'; +import 'light_app_colors.dart'; + +class WeekViewTheme extends ThemeExtension { + WeekViewTheme({ + required this.weekDayTile, + required this.weekDayText, + required this.weekDayBorder, + required this.hourLine, + required this.halfHourLine, + required this.quarterHourLine, + required this.liveIndicator, + required this.pageBackground, + required this.headerIcon, + required this.headerText, + required this.headerBackground, + }); + + final Color weekDayTile; + final Color weekDayText; + final Color weekDayBorder; + final Color hourLine; + final Color halfHourLine; + final Color quarterHourLine; + final Color liveIndicator; + final Color pageBackground; + + // Calendar page header + final Color headerIcon; + final Color headerText; + final Color headerBackground; + + // Light theme + WeekViewTheme.light() + : weekDayTile = LightAppColors.surfaceContainerHigh, + weekDayText = LightAppColors.onSurface, + weekDayBorder = LightAppColors.outlineVariant, + hourLine = LightAppColors.surfaceContainerHighest, + halfHourLine = LightAppColors.surfaceContainerHighest, + quarterHourLine = LightAppColors.surfaceContainerHighest, + liveIndicator = LightAppColors.primary, + pageBackground = LightAppColors.surfaceContainerLowest, + headerIcon = LightAppColors.onPrimary, + headerText = LightAppColors.onPrimary, + headerBackground = LightAppColors.primary; + + // Dark theme + WeekViewTheme.dark() + : weekDayTile = DarkAppColors.surfaceContainerHigh, + weekDayText = DarkAppColors.onSurface, + weekDayBorder = DarkAppColors.outlineVariant, + hourLine = DarkAppColors.surfaceContainerHighest, + halfHourLine = DarkAppColors.surfaceContainerHighest, + quarterHourLine = DarkAppColors.surfaceContainerHighest, + liveIndicator = DarkAppColors.primary, + pageBackground = DarkAppColors.surfaceContainerLowest, + headerIcon = DarkAppColors.onPrimary, + headerText = DarkAppColors.onPrimary, + headerBackground = DarkAppColors.primary; + + @override + ThemeExtension copyWith({ + Color? weekDayTile, + Color? weekDayText, + Color? weekDayBorder, + Color? hourLine, + Color? halfHourLine, + Color? quarterHourLine, + Color? liveIndicator, + Color? pageBackground, + Color? headerIcon, + Color? headerText, + Color? headerBackground, + }) { + return WeekViewTheme( + weekDayTile: weekDayTile ?? this.weekDayTile, + weekDayText: weekDayText ?? this.weekDayText, + weekDayBorder: weekDayBorder ?? this.weekDayBorder, + hourLine: hourLine ?? this.hourLine, + halfHourLine: halfHourLine ?? this.halfHourLine, + quarterHourLine: quarterHourLine ?? this.quarterHourLine, + liveIndicator: liveIndicator ?? this.liveIndicator, + pageBackground: pageBackground ?? this.pageBackground, + headerIcon: headerIcon ?? this.headerIcon, + headerText: headerText ?? this.headerText, + headerBackground: headerBackground ?? this.headerBackground, + ); + } + + @override + ThemeExtension lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! WeekViewTheme) { + return this; + } + return WeekViewTheme( + weekDayTile: Color.lerp(weekDayTile, other.weekDayTile, t) ?? weekDayTile, + weekDayText: Color.lerp(weekDayText, other.weekDayText, t) ?? weekDayText, + weekDayBorder: + Color.lerp(weekDayBorder, other.weekDayBorder, t) ?? weekDayBorder, + hourLine: Color.lerp(hourLine, other.hourLine, t) ?? hourLine, + halfHourLine: + Color.lerp(halfHourLine, other.halfHourLine, t) ?? halfHourLine, + quarterHourLine: Color.lerp(quarterHourLine, other.quarterHourLine, t) ?? + quarterHourLine, + liveIndicator: + Color.lerp(liveIndicator, other.liveIndicator, t) ?? liveIndicator, + pageBackground: + Color.lerp(pageBackground, other.pageBackground, t) ?? pageBackground, + headerIcon: Color.lerp(headerIcon, other.headerIcon, t) ?? headerIcon, + headerText: Color.lerp(headerText, other.headerText, t) ?? headerText, + headerBackground: + Color.lerp(headerBackground, other.headerBackground, t) ?? + headerBackground, + ); + } +} diff --git a/lib/src/week_view/_internal_week_view_page.dart b/lib/src/week_view/_internal_week_view_page.dart index 85d36b54..3d17e1cb 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -4,15 +4,9 @@ import 'package:flutter/material.dart'; +import '../../calendar_view.dart'; import '../components/_internal_components.dart'; -import '../components/event_scroll_notifier.dart'; -import '../components/week_view_components.dart'; -import '../enumerations.dart'; -import '../event_arrangers/event_arrangers.dart'; -import '../event_controller.dart'; -import '../modals.dart'; import '../painters.dart'; -import '../typedefs.dart'; /// A single page for week view. class InternalWeekViewPage extends StatefulWidget { @@ -89,6 +83,9 @@ class InternalWeekViewPage extends StatefulWidget { /// Width of week title. final double weekTitleWidth; + /// Background color of week title + final Color? weekTitleBackgroundColor; + /// Called when user taps on event tile. final CellTapCallback? onTileTap; @@ -166,6 +163,9 @@ class InternalWeekViewPage extends StatefulWidget { /// This method will be called when user taps on timestamp in timeline. final TimestampCallback? onTimestampTap; + /// Use this to change background color of week view page + final Color? backgroundColor; + /// A single page for week view. const InternalWeekViewPage({ Key? key, @@ -192,6 +192,7 @@ class InternalWeekViewPage extends StatefulWidget { required this.eventArranger, required this.verticalLineOffset, required this.weekTitleWidth, + required this.weekTitleBackgroundColor, required this.onTileTap, required this.onTileLongTap, required this.onDateLongPress, @@ -216,6 +217,7 @@ class InternalWeekViewPage extends StatefulWidget { required this.weekViewScrollController, this.lastScrollOffset = 0.0, this.keepScrollOffset = false, + this.backgroundColor, }) : super(key: key); @override @@ -251,7 +253,10 @@ class _InternalWeekViewPageState @override Widget build(BuildContext context) { final filteredDates = _filteredDate(); + final themeColor = context.weekViewColors; + return Container( + color: widget.backgroundColor ?? themeColor.pageBackground, height: widget.height + widget.weekTitleHeight, width: widget.width, child: Column( @@ -262,26 +267,29 @@ class _InternalWeekViewPageState children: [ SizedBox( width: widget.width, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: widget.weekTitleHeight, - width: widget.timeLineWidth + - widget.hourIndicatorSettings.offset, - child: widget.weekNumberBuilder.call(filteredDates[0]), - ), - ...List.generate( - filteredDates.length, - (index) => SizedBox( + child: ColoredBox( + color: widget.weekTitleBackgroundColor ?? themeColor.weekDayTile, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( height: widget.weekTitleHeight, - width: widget.weekTitleWidth, - child: widget.weekDayBuilder( - filteredDates[index], - ), + width: widget.timeLineWidth + + widget.hourIndicatorSettings.offset, + child: widget.weekNumberBuilder.call(filteredDates[0]), ), - ) - ], + ...List.generate( + filteredDates.length, + (index) => SizedBox( + height: widget.weekTitleHeight, + width: widget.weekTitleWidth, + child: widget.weekDayBuilder( + filteredDates[index], + ), + ), + ) + ], + ), ), ), Divider( @@ -419,6 +427,11 @@ class _InternalWeekViewPageState (index) => Container( decoration: widget.showVerticalLine ? BoxDecoration( + // To apply different colors to the timeline + // and cells, use the background color for the timeline. + // Additionally, set the `color` property here with an alpha value + // to see horizontal & vertical lines + // color: Colors.red, border: Border( right: BorderSide( color: widget diff --git a/lib/src/week_view/week_view.dart b/lib/src/week_view/week_view.dart index b91efa13..c6ab37ec 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -137,6 +137,9 @@ class WeekView extends StatefulWidget { /// Height of week day title, final double weekTitleHeight; + /// Background color of week title + final Color? weekTitleBackgroundColor; + /// Builder to build week day. final DateWidgetBuilder? weekDayBuilder; @@ -144,7 +147,7 @@ class WeekView extends StatefulWidget { final WeekNumberBuilder? weekNumberBuilder; /// Background color of week view page. - final Color backgroundColor; + final Color? backgroundColor; /// Scroll offset of week view page. final double scrollOffset; @@ -204,7 +207,7 @@ class WeekView extends StatefulWidget { final MinuteSlotSize minuteSlotSize; /// Style for WeekView header. - final HeaderStyle headerStyle; + final HeaderStyle? headerStyle; /// Option for SafeArea. final SafeAreaOption safeAreaOption; @@ -276,9 +279,10 @@ class WeekView extends StatefulWidget { this.weekPageHeaderBuilder, this.eventArranger, this.weekTitleHeight = 50, + this.weekTitleBackgroundColor, this.weekDayBuilder, this.weekNumberBuilder, - this.backgroundColor = Colors.white, + this.backgroundColor, this.scrollPhysics, this.scrollOffset = 0.0, this.onEventTap, @@ -294,7 +298,7 @@ class WeekView extends StatefulWidget { this.timeLineStringBuilder, this.weekDayStringBuilder, this.weekDayDateStringBuilder, - this.headerStyle = const HeaderStyle(), + this.headerStyle, this.safeAreaOption = const SafeAreaOption(), this.fullDayEventBuilder, this.startHour = 0, @@ -508,85 +512,82 @@ class WeekViewState extends State> { _currentEndDate, ), Expanded( - child: DecoratedBox( - decoration: BoxDecoration(color: widget.backgroundColor), - child: SizedBox( - height: _height, - width: _width, - child: PageView.builder( - itemCount: _totalWeeks, - controller: _pageController, - physics: widget.pageViewPhysics, - onPageChanged: _onPageChange, - itemBuilder: (_, index) { - final dates = DateTime(_minDate.year, _minDate.month, - _minDate.day + (index * DateTime.daysPerWeek)) - .datesOfWeek( - start: widget.startDay, - showWeekEnds: widget.showWeekends, - ); - - return ValueListenableBuilder( - valueListenable: _scrollConfiguration, - builder: (_, __, ___) => InternalWeekViewPage( - key: ValueKey( - _hourHeight.toString() + dates[0].toString()), - height: _height, - width: _width, - weekTitleWidth: _weekTitleWidth, - weekTitleHeight: widget.weekTitleHeight, - weekDayBuilder: _weekDayBuilder, - weekNumberBuilder: _weekNumberBuilder, - weekDetectorBuilder: _weekDetectorBuilder, - liveTimeIndicatorSettings: - _liveTimeIndicatorSettings, - timeLineBuilder: _timeLineBuilder, - onTimestampTap: widget.onTimestampTap, - onTileTap: widget.onEventTap, - onTileLongTap: widget.onEventLongTap, - onDateLongPress: widget.onDateLongPress, - onDateTap: widget.onDateTap, - onTileDoubleTap: widget.onEventDoubleTap, - eventTileBuilder: _eventTileBuilder, - heightPerMinute: widget.heightPerMinute, - hourIndicatorSettings: _hourIndicatorSettings, - hourLinePainter: _hourLinePainter, - halfHourIndicatorSettings: - _halfHourIndicatorSettings, - quarterHourIndicatorSettings: - _quarterHourIndicatorSettings, - dates: dates, - showLiveLine: widget.showLiveTimeLineInAllDays || - _showLiveTimeIndicator(dates), - timeLineOffset: widget.timeLineOffset, - timeLineWidth: _timeLineWidth, - verticalLineOffset: 0, - showVerticalLine: widget.showVerticalLines, - controller: controller, - hourHeight: _hourHeight, - weekViewScrollController: _scrollController, - eventArranger: _eventArranger, - weekDays: _weekDays, - minuteSlotSize: widget.minuteSlotSize, - scrollConfiguration: _scrollConfiguration, - fullDayEventBuilder: _fullDayEventBuilder, - startHour: _startHour, - showHalfHours: widget.showHalfHours, - showQuarterHours: widget.showQuarterHours, - emulateVerticalOffsetBy: - widget.emulateVerticalOffsetBy, - showWeekDayAtBottom: widget.showWeekDayAtBottom, - endHour: _endHour, - fullDayHeaderTitle: _fullDayHeaderTitle, - fullDayHeaderTextConfig: _fullDayHeaderTextConfig, - lastScrollOffset: _lastScrollOffset, - scrollPhysics: widget.scrollPhysics, - scrollListener: _scrollPageListener, - keepScrollOffset: widget.keepScrollOffset, - ), - ); - }, - ), + child: SizedBox( + height: _height, + width: _width, + child: PageView.builder( + itemCount: _totalWeeks, + controller: _pageController, + physics: widget.pageViewPhysics, + onPageChanged: _onPageChange, + itemBuilder: (_, index) { + final dates = DateTime(_minDate.year, _minDate.month, + _minDate.day + (index * DateTime.daysPerWeek)) + .datesOfWeek( + start: widget.startDay, + showWeekEnds: widget.showWeekends, + ); + return ValueListenableBuilder( + valueListenable: _scrollConfiguration, + builder: (_, __, ___) => InternalWeekViewPage( + key: ValueKey( + _hourHeight.toString() + dates[0].toString()), + height: _height, + width: _width, + weekTitleWidth: _weekTitleWidth, + weekTitleHeight: widget.weekTitleHeight, + weekTitleBackgroundColor: + widget.weekTitleBackgroundColor, + weekDayBuilder: _weekDayBuilder, + weekNumberBuilder: _weekNumberBuilder, + weekDetectorBuilder: _weekDetectorBuilder, + liveTimeIndicatorSettings: _liveTimeIndicatorSettings, + timeLineBuilder: _timeLineBuilder, + onTimestampTap: widget.onTimestampTap, + onTileTap: widget.onEventTap, + onTileLongTap: widget.onEventLongTap, + onDateLongPress: widget.onDateLongPress, + onDateTap: widget.onDateTap, + onTileDoubleTap: widget.onEventDoubleTap, + eventTileBuilder: _eventTileBuilder, + heightPerMinute: widget.heightPerMinute, + backgroundColor: widget.backgroundColor, + hourIndicatorSettings: _hourIndicatorSettings, + hourLinePainter: _hourLinePainter, + halfHourIndicatorSettings: _halfHourIndicatorSettings, + quarterHourIndicatorSettings: + _quarterHourIndicatorSettings, + dates: dates, + showLiveLine: widget.showLiveTimeLineInAllDays || + _showLiveTimeIndicator(dates), + timeLineOffset: widget.timeLineOffset, + timeLineWidth: _timeLineWidth, + verticalLineOffset: 0, + showVerticalLine: widget.showVerticalLines, + controller: controller, + hourHeight: _hourHeight, + weekViewScrollController: _scrollController, + eventArranger: _eventArranger, + weekDays: _weekDays, + minuteSlotSize: widget.minuteSlotSize, + scrollConfiguration: _scrollConfiguration, + fullDayEventBuilder: _fullDayEventBuilder, + startHour: _startHour, + showHalfHours: widget.showHalfHours, + showQuarterHours: widget.showQuarterHours, + emulateVerticalOffsetBy: + widget.emulateVerticalOffsetBy, + showWeekDayAtBottom: widget.showWeekDayAtBottom, + endHour: _endHour, + fullDayHeaderTitle: _fullDayHeaderTitle, + fullDayHeaderTextConfig: _fullDayHeaderTextConfig, + lastScrollOffset: _lastScrollOffset, + scrollPhysics: widget.scrollPhysics, + scrollListener: _scrollPageListener, + keepScrollOffset: widget.keepScrollOffset, + ), + ); + }, ), ), ), @@ -639,7 +640,7 @@ class WeekViewState extends State> { _liveTimeIndicatorSettings = widget.liveTimeIndicatorSettings ?? LiveTimeIndicatorSettings( - color: Constants.defaultLiveTimeIndicatorColor, + color: context.weekViewColors.liveIndicator, height: widget.heightPerMinute, ); @@ -649,7 +650,7 @@ class WeekViewState extends State> { _hourIndicatorSettings = widget.hourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: context.weekViewColors.hourLine, offset: 5, ); @@ -663,7 +664,7 @@ class WeekViewState extends State> { _halfHourIndicatorSettings = widget.halfHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: context.weekViewColors.halfHourLine, offset: 5, ); @@ -672,7 +673,7 @@ class WeekViewState extends State> { _quarterHourIndicatorSettings = widget.quarterHourIndicatorSettings ?? HourIndicatorSettings( - color: Constants.defaultBorderColor, + color: context.weekViewColors.quarterHourLine, ); assert(_quarterHourIndicatorSettings.height < _hourHeight, @@ -855,7 +856,22 @@ class WeekViewState extends State> { } }, headerStringBuilder: widget.headerStringBuilder, - headerStyle: widget.headerStyle, + headerStyle: widget.headerStyle ?? + HeaderStyle( + decoration: BoxDecoration( + color: context.monthViewColors.headerBackground, + ), + leftIconConfig: IconDataConfig( + color: context.monthViewColors.headerIcon, + ), + rightIconConfig: IconDataConfig( + color: context.monthViewColors.headerIcon, + ), + headerTextStyle: TextStyle( + color: context.monthViewColors.headerText, + fontWeight: FontWeight.w500, + ), + ), ); }