diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e28339..cdf79eab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Adds `showWeekends` flag in month view to hide & show weekends view. Default is `showWeekends = true` shows all weekdays. [#385](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/385) - Events are now hidden for days not in the current month when hideDaysNotInMonth = true +- Adds support for dark theme. [#263](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/263) # [1.3.0 - 12 Nov 2024](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.3.0) diff --git a/README.md b/README.md index 55732861..3eb951e0 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,68 @@ WeekView( Above code will create `WeekView` with only five days, from monday to friday. +## **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 | NA | 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`. +* 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/example/lib/extension.dart b/example/lib/extension.dart index 03596819..f70df402 100644 --- a/example/lib/extension.dart +++ b/example/lib/extension.dart @@ -113,10 +113,12 @@ extension DateUtils on DateTime { } extension ColorExtension on Color { - Color get accentColor => - (blue / 2 >= 255 / 2 || red / 2 >= 255 / 2 || green / 2 >= 255 / 2) - ? AppColors.black - : AppColors.white; + /// TODO(Shubham): Update this getter as it uses `computeLuminance()` + /// which is computationally expensive + Color get accentColor { + final brightness = ThemeData.estimateBrightnessForColor(this); + return brightness == Brightness.light ? AppColors.black : AppColors.white; + } } extension StringExt on String { diff --git a/example/lib/main.dart b/example/lib/main.dart index 146e23af..5e40f35c 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.lightTheme, + darkTheme: AppTheme.darkTheme, + 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..3af18cfb 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,24 @@ class CreateEventPage extends StatelessWidget { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Scaffold( appBar: AppBar( elevation: 0, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, + backgroundColor: color.surfaceContainerHigh, centerTitle: false, leading: IconButton( onPressed: context.pop, icon: Icon( Icons.arrow_back, - color: AppColors.black, + color: color.onSurface, ), ), title: Text( event == null ? "Create New Event" : "Update Event", style: TextStyle( - color: AppColors.black, + color: color.onSurface, 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..89043cc1 100644 --- a/example/lib/pages/day_view_page.dart +++ b/example/lib/pages/day_view_page.dart @@ -22,6 +22,11 @@ class _DayViewPageDemoState extends State { selectedView: CalendarView.day, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), elevation: 8, diff --git a/example/lib/pages/event_details_page.dart b/example/lib/pages/event_details_page.dart index 2785688d..a19342d1 100644 --- a/example/lib/pages/event_details_page.dart +++ b/example/lib/pages/event_details_page.dart @@ -90,18 +90,23 @@ class DetailsPage extends StatelessWidget { children: [ Expanded( child: ElevatedButton( + child: Text('Delete Event'), + style: ElevatedButton.styleFrom( + backgroundColor: + Theme.of(context).colorScheme.surfaceContainer, + ), onPressed: () { CalendarControllerProvider.of(context) .controller .remove(event); Navigator.of(context).pop(); }, - child: Text('Delete Event'), ), ), SizedBox(width: 30), Expanded( child: ElevatedButton( + child: Text('Edit Event'), onPressed: () async { final result = await Navigator.of(context).push( MaterialPageRoute( @@ -115,7 +120,10 @@ class DetailsPage extends StatelessWidget { Navigator.of(context).pop(); } }, - child: Text('Edit Event'), + style: ElevatedButton.styleFrom( + backgroundColor: + Theme.of(context).colorScheme.surfaceContainer, + ), ), ), ], 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..8b35415d 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,15 @@ class MobileHomePage extends StatelessWidget { ], ), ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.dark_mode), + 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..fcd9816d 100644 --- a/example/lib/pages/month_view_page.dart +++ b/example/lib/pages/month_view_page.dart @@ -24,6 +24,11 @@ class _MonthViewPageDemoState extends State { selectedView: CalendarView.month, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), elevation: 8, 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..8ac91c2c 100644 --- a/example/lib/pages/week_view_page.dart +++ b/example/lib/pages/week_view_page.dart @@ -22,6 +22,11 @@ class _WeekViewDemoState extends State { selectedView: CalendarView.week, ), mobileWidget: Scaffold( + primary: false, + appBar: AppBar( + leading: const SizedBox.shrink(), + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), elevation: 8, diff --git a/example/lib/theme/app_theme.dart b/example/lib/theme/app_theme.dart new file mode 100644 index 00000000..47726b6a --- /dev/null +++ b/example/lib/theme/app_theme.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class AppTheme { + static final lightTheme = ThemeData( + appBarTheme: AppBarTheme( + backgroundColor: Colors.blue, + ), + colorScheme: ColorScheme.fromSeed( + seedColor: Colors.blue, + primary: Colors.blue, + ), + ); + + static final darkTheme = ThemeData( + appBarTheme: AppBarTheme( + backgroundColor: Colors.blueAccent, + ), + colorScheme: ColorScheme.fromSeed( + brightness: Brightness.dark, + seedColor: Colors.blueAccent, + primary: Colors.blue, + ), + ); +} diff --git a/example/lib/widgets/add_event_form.dart b/example/lib/widgets/add_event_form.dart index 40b18718..94d94591 100644 --- a/example/lib/widgets/add_event_form.dart +++ b/example/lib/widgets/add_event_form.dart @@ -58,6 +58,8 @@ class _AddOrEditEventFormState extends State { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Form( key: _form, child: Column( @@ -67,9 +69,12 @@ class _AddOrEditEventFormState extends State { controller: _titleController, decoration: AppConstants.inputDecoration.copyWith( labelText: "Event Title", + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), ), style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), validator: (value) { @@ -93,6 +98,9 @@ class _AddOrEditEventFormState extends State { child: DateTimeSelectorFormField( decoration: AppConstants.inputDecoration.copyWith( labelText: "Start Date", + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), ), initialDateTime: _startDate, onSelect: (date) { @@ -115,7 +123,7 @@ class _AddOrEditEventFormState extends State { return null; }, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), onSave: (date) => _startDate = date ?? _startDate, @@ -128,6 +136,9 @@ class _AddOrEditEventFormState extends State { initialDateTime: _endDate, decoration: AppConstants.inputDecoration.copyWith( labelText: "End Date", + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), ), onSelect: (date) { if (date.withoutTime.withoutTime @@ -151,7 +162,7 @@ class _AddOrEditEventFormState extends State { return null; }, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), onSave: (date) => _endDate = date ?? _endDate, @@ -167,6 +178,9 @@ class _AddOrEditEventFormState extends State { child: DateTimeSelectorFormField( decoration: AppConstants.inputDecoration.copyWith( labelText: "Start Time", + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), ), initialDateTime: _startTime, minimumDateTime: CalendarConstants.epochDate, @@ -183,7 +197,7 @@ class _AddOrEditEventFormState extends State { }, onSave: (date) => _startTime = date, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), type: DateTimeSelectionType.time, @@ -194,6 +208,9 @@ class _AddOrEditEventFormState extends State { child: DateTimeSelectorFormField( decoration: AppConstants.inputDecoration.copyWith( labelText: "End Time", + labelStyle: TextStyle( + color: color.onSurfaceVariant, + ), ), initialDateTime: _endTime, onSelect: (date) { @@ -212,7 +229,7 @@ class _AddOrEditEventFormState extends State { }, onSave: (date) => _endTime = date, textStyle: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), type: DateTimeSelectionType.time, @@ -227,7 +244,7 @@ class _AddOrEditEventFormState extends State { controller: _descriptionController, focusNode: _descriptionNode, style: TextStyle( - color: AppColors.black, + color: color.onSurface, fontSize: 17.0, ), keyboardType: TextInputType.multiline, @@ -245,6 +262,7 @@ class _AddOrEditEventFormState extends State { }, decoration: AppConstants.inputDecoration.copyWith( hintText: "Event Description", + counterStyle: TextStyle(color: color.onSurfaceVariant), ), ), SizedBox( @@ -255,7 +273,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..8cb503d9 100644 --- a/example/lib/widgets/calendar_configs.dart +++ b/example/lib/widgets/calendar_configs.dart @@ -6,18 +6,29 @@ import '../enumerations.dart'; import '../extension.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/day_view_widget.dart b/example/lib/widgets/day_view_widget.dart index bc8cf3f8..00b7d610 100644 --- a/example/lib/widgets/day_view_widget.dart +++ b/example/lib/widgets/day_view_widget.dart @@ -24,6 +24,7 @@ class DayViewWidget extends StatelessWidget { timeLineBuilder: _timeLineBuilder, scrollPhysics: const BouncingScrollPhysics(), eventArranger: SideEventArranger(maxWidth: 30), + showQuarterHours: true, hourIndicatorSettings: HourIndicatorSettings( color: Theme.of(context).dividerColor, ), @@ -74,7 +75,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/lib/src/components/day_view_components.dart b/lib/src/components/day_view_components.dart index b8e28e9e..c4492259 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: Theme.of(context).colorScheme.onSurface, fontSize: 15.0, ), ), diff --git a/lib/src/components/headers/calendar_page_header.dart b/lib/src/components/headers/calendar_page_header.dart index 21086ea8..b0d4eea5 100644 --- a/lib/src/components/headers/calendar_page_header.dart +++ b/lib/src/components/headers/calendar_page_header.dart @@ -7,7 +7,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../constants.dart'; import '../../style/header_style.dart'; import '../../typedefs.dart'; @@ -55,7 +54,7 @@ class CalendarPageHeader extends StatelessWidget { /// NOTE: This property is deprecated. /// Use [HeaderStyle.decoration] to provide colors to header. @Deprecated("Use HeaderStyle.decoration to provide background") - final Color backgroundColor; + final Color? backgroundColor; // TODO: Need to remove after next major release /// Color of icons at both sides of header. @@ -82,9 +81,8 @@ class CalendarPageHeader extends StatelessWidget { this.onPreviousDay, this.secondaryDate, @Deprecated("Use HeaderStyle.decoration to provide background") - this.backgroundColor = Constants.headerBackground, - @Deprecated("Use HeaderStyle to provide icon color") - this.iconColor = Constants.black, + this.backgroundColor, + @Deprecated("Use HeaderStyle to provide icon color") this.iconColor, this.headerStyle = const HeaderStyle(), }) : assert( titleBuilder != null || dateStringBuilder != null, @@ -94,11 +92,15 @@ class CalendarPageHeader extends StatelessWidget { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Container( margin: headerStyle.headerMargin, padding: headerStyle.headerPadding, - decoration: - headerStyle.decoration ?? BoxDecoration(color: backgroundColor), + decoration: headerStyle.decoration ?? + BoxDecoration( + color: backgroundColor ?? color.primaryContainer, + ), clipBehavior: Clip.antiAlias, child: Row( mainAxisSize: headerStyle.mainAxisSize, @@ -118,7 +120,9 @@ class CalendarPageHeader extends StatelessWidget { Icon( Icons.chevron_left, size: headerStyle.leftIconConfig!.size, - color: iconColor ?? headerStyle.leftIconConfig!.color, + color: iconColor ?? + headerStyle.leftIconConfig?.color ?? + color.onPrimaryContainer, ), ), Expanded( @@ -154,7 +158,9 @@ class CalendarPageHeader extends StatelessWidget { Icon( Icons.chevron_right, size: headerStyle.rightIconConfig?.size, - color: iconColor ?? headerStyle.rightIconConfig?.color, + color: iconColor ?? + headerStyle.rightIconConfig?.color ?? + color.onPrimaryContainer, ), ), ], diff --git a/lib/src/components/headers/day_page_header.dart b/lib/src/components/headers/day_page_header.dart index 420906ef..6e66ece5 100644 --- a/lib/src/components/headers/day_page_header.dart +++ b/lib/src/components/headers/day_page_header.dart @@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../constants.dart'; import '../../style/header_style.dart'; import '../../typedefs.dart'; import 'calendar_page_header.dart'; @@ -20,10 +19,8 @@ class DayPageHeader extends CalendarPageHeader { VoidCallback? onPreviousDay, StringProvider? dateStringBuilder, required DateTime date, - @Deprecated("Use HeaderStyle to provide icon color") - Color iconColor = Constants.black, - @Deprecated("Use HeaderStyle to provide background") - Color backgroundColor = Constants.headerBackground, + @Deprecated("Use HeaderStyle to provide icon color") Color? iconColor, + @Deprecated("Use HeaderStyle to provide background") Color? backgroundColor, HeaderStyle headerStyle = const HeaderStyle(), }) : super( key: key, diff --git a/lib/src/components/headers/month_page_header.dart b/lib/src/components/headers/month_page_header.dart index f514f55d..ab2c78b0 100644 --- a/lib/src/components/headers/month_page_header.dart +++ b/lib/src/components/headers/month_page_header.dart @@ -5,10 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../constants.dart'; -import '../../style/header_style.dart'; -import '../../typedefs.dart'; -import 'calendar_page_header.dart'; +import '../../../calendar_view.dart'; class MonthPageHeader extends CalendarPageHeader { /// A header widget to display on month view. @@ -17,10 +14,9 @@ class MonthPageHeader extends CalendarPageHeader { VoidCallback? onNextMonth, AsyncCallback? onTitleTapped, VoidCallback? onPreviousMonth, - @Deprecated("Use HeaderStyle to provide icon color") - Color iconColor = Constants.black, + @Deprecated("Use HeaderStyle to provide icon color") Color? iconColor, @Deprecated("Use HeaderStyle to provide background color") - Color backgroundColor = Constants.headerBackground, + Color? backgroundColor, StringProvider? dateStringBuilder, required DateTime date, HeaderStyle headerStyle = const HeaderStyle(), diff --git a/lib/src/components/headers/week_page_header.dart b/lib/src/components/headers/week_page_header.dart index c7efaa3e..d97adc78 100644 --- a/lib/src/components/headers/week_page_header.dart +++ b/lib/src/components/headers/week_page_header.dart @@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import '../../constants.dart'; import '../../style/header_style.dart'; import '../../typedefs.dart'; import 'calendar_page_header.dart'; @@ -19,10 +18,9 @@ class WeekPageHeader extends CalendarPageHeader { VoidCallback? onPreviousDay, required DateTime startDate, required DateTime endDate, - @Deprecated("Use HeaderStyle to provide icon color") - Color iconColor = Constants.black, + @Deprecated("Use HeaderStyle to provide icon color") Color? iconColor, @Deprecated("Use HeaderStyle to provide background color") - Color backgroundColor = Constants.headerBackground, + Color? backgroundColor, StringProvider? headerStringBuilder, HeaderStyle headerStyle = const HeaderStyle(), }) : super( diff --git a/lib/src/components/month_view_components.dart b/lib/src/components/month_view_components.dart index c09d6e12..c7783058 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. @@ -142,11 +140,7 @@ class FilledCell extends StatelessWidget { child: Text( dateStringBuilder?.call(date) ?? "${date.day}", style: TextStyle( - color: shouldHighlight - ? highlightedTitleColor - : isInMonth - ? titleColor - : titleColor.withOpacity(0.4), + color: shouldHighlight ? highlightedTitleColor : titleColor, fontSize: 12, ), ), @@ -215,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; @@ -227,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, @@ -235,15 +232,17 @@ class WeekDayTile extends StatelessWidget { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + return Container( alignment: Alignment.center, margin: EdgeInsets.zero, padding: EdgeInsets.symmetric(vertical: 10.0), decoration: BoxDecoration( - color: backgroundColor, + color: backgroundColor ?? color.surfaceContainerHigh, border: displayBorder ? Border.all( - color: Constants.defaultBorderColor, + color: borderColor ?? color.secondaryContainer, width: 0.5, ) : null, @@ -253,7 +252,7 @@ class WeekDayTile extends StatelessWidget { style: textStyle ?? TextStyle( fontSize: 17, - color: Constants.black, + color: color.onSecondaryContainer, ), ), ); diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 158379c8..1a229cdb 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -17,11 +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 { return Color.fromRGBO(_random.nextInt(_maxColor), diff --git a/lib/src/day_view/day_view.dart b/lib/src/day_view/day_view.dart index 35e76bf4..0e857e98 100644 --- a/lib/src/day_view/day_view.dart +++ b/lib/src/day_view/day_view.dart @@ -252,7 +252,7 @@ class DayView extends StatefulWidget { this.dayTitleBuilder, this.eventArranger, this.verticalLineOffset = 10, - this.backgroundColor = Colors.white, + this.backgroundColor, this.scrollOffset, this.onEventTap, this.onEventLongTap, @@ -431,6 +431,8 @@ class DayViewState extends State> { @override Widget build(BuildContext context) { + final color = Theme.of(context).colorScheme; + 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 ?? color.surfaceContainerLow, + ), child: SizedBox( height: _height, child: PageView.builder( @@ -545,7 +549,7 @@ class DayViewState extends State> { _liveTimeIndicatorSettings = widget.liveTimeIndicatorSettings ?? LiveTimeIndicatorSettings( - color: Constants.defaultLiveTimeIndicatorColor, + color: Theme.of(context).primaryColorLight, 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: Theme.of(context).colorScheme.surfaceContainerHighest, offset: 5, ); @@ -566,7 +570,7 @@ class DayViewState extends State> { _halfHourIndicatorSettings = widget.halfHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: Theme.of(context).colorScheme.surfaceContainerHighest, offset: 5, ); @@ -576,7 +580,7 @@ class DayViewState extends State> { _quarterHourIndicatorSettings = widget.quarterHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: Theme.of(context).colorScheme.surfaceContainerHighest, offset: 5, ); diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index 6a07c690..7e6165d7 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -163,10 +163,14 @@ extension DateTimeExtensions on DateTime { } extension ColorExtension on Color { - Color get accent => - (blue / 2 >= 255 / 2 || red / 2 >= 255 / 2 || green / 2 >= 255 / 2) - ? Colors.black - : Colors.white; + /// TODO(Shubham): Update this getter as it uses `computeLuminance()` + /// which is computationally expensive + Color get accent { + final brightness = ThemeData.estimateBrightnessForColor(this); + return brightness == Brightness.light + ? Color(0xff626262) + : Color(0xfff0f0f0); + } } extension MaterialColorExtension on MaterialColor { diff --git a/lib/src/month_view/month_view.dart b/lib/src/month_view/month_view.dart index b4fbc428..2c458c08 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] @@ -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, @@ -562,28 +561,37 @@ class MonthViewState extends State> { isInMonth, hideDaysNotInMonth, ) { + final color = Theme.of(context).colorScheme; + if (hideDaysNotInMonth) { return FilledCell( date: date, shouldHighlight: isToday, - backgroundColor: isInMonth ? Constants.white : Constants.offWhite, + backgroundColor: isInMonth + ? color.surfaceContainerLowest + : color.surfaceContainerLow, events: events, isInMonth: isInMonth, onTileTap: widget.onEventTap, dateStringBuilder: widget.dateStringBuilder, hideDaysNotInMonth: hideDaysNotInMonth, + titleColor: color.onPrimaryContainer, ); } return FilledCell( date: date, shouldHighlight: isToday, - backgroundColor: isInMonth ? Constants.white : Constants.offWhite, + backgroundColor: + isInMonth ? color.surfaceContainerLowest : color.surfaceContainerLow, events: events, onTileTap: widget.onEventTap, onTileLongTap: widget.onEventLongTap, dateStringBuilder: widget.dateStringBuilder, onTileDoubleTap: widget.onEventDoubleTap, hideDaysNotInMonth: hideDaysNotInMonth, + titleColor: isInMonth + ? color.onPrimaryContainer + : color.onSurfaceVariant.withAlpha(150), ); } @@ -665,7 +673,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; @@ -683,7 +691,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, @@ -695,6 +702,7 @@ class _MonthPageBuilder extends StatelessWidget { required this.physics, required this.hideDaysNotInMonth, required this.weekDays, + this.borderColor, }) : super(key: key); @override @@ -704,6 +712,7 @@ class _MonthPageBuilder extends StatelessWidget { hideDaysNotInMonth: hideDaysNotInMonth, showWeekends: weekDays == 7, ); + final color = Theme.of(context).colorScheme; // Highlight tiles which is not in current month return SizedBox( @@ -731,7 +740,7 @@ class _MonthPageBuilder extends StatelessWidget { decoration: BoxDecoration( border: showBorder ? Border.all( - color: borderColor, + color: borderColor ?? color.surfaceContainerHigh, 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/week_view/_internal_week_view_page.dart b/lib/src/week_view/_internal_week_view_page.dart index 85d36b54..def8201a 100644 --- a/lib/src/week_view/_internal_week_view_page.dart +++ b/lib/src/week_view/_internal_week_view_page.dart @@ -166,6 +166,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, @@ -216,6 +219,7 @@ class InternalWeekViewPage extends StatefulWidget { required this.weekViewScrollController, this.lastScrollOffset = 0.0, this.keepScrollOffset = false, + this.backgroundColor, }) : super(key: key); @override @@ -252,6 +256,8 @@ class _InternalWeekViewPageState Widget build(BuildContext context) { final filteredDates = _filteredDate(); return Container( + color: widget.backgroundColor ?? + Theme.of(context).colorScheme.surfaceContainerLowest, height: widget.height + widget.weekTitleHeight, width: widget.width, child: Column( @@ -262,26 +268,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: Theme.of(context).colorScheme.surfaceContainerHigh, + 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 +428,10 @@ 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 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 2b074370..8807d3f2 100644 --- a/lib/src/week_view/week_view.dart +++ b/lib/src/week_view/week_view.dart @@ -144,7 +144,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; @@ -278,7 +278,7 @@ class WeekView extends StatefulWidget { this.weekTitleHeight = 50, this.weekDayBuilder, this.weekNumberBuilder, - this.backgroundColor = Colors.white, + this.backgroundColor, this.scrollPhysics, this.scrollOffset = 0.0, this.onEventTap, @@ -501,85 +501,80 @@ 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, + 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, + ), + ); + }, ), ), ), @@ -642,7 +637,7 @@ class WeekViewState extends State> { _hourIndicatorSettings = widget.hourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: Theme.of(context).colorScheme.surfaceContainerHighest, offset: 5, ); @@ -656,7 +651,7 @@ class WeekViewState extends State> { _halfHourIndicatorSettings = widget.halfHourIndicatorSettings ?? HourIndicatorSettings( height: widget.heightPerMinute, - color: Constants.defaultBorderColor, + color: Theme.of(context).colorScheme.surfaceContainerHighest, offset: 5, ); @@ -665,7 +660,7 @@ class WeekViewState extends State> { _quarterHourIndicatorSettings = widget.quarterHourIndicatorSettings ?? HourIndicatorSettings( - color: Constants.defaultBorderColor, + color: Theme.of(context).colorScheme.surfaceContainerHighest, ); assert(_quarterHourIndicatorSettings.height < _hourHeight,