Skip to content

Commit ec4c3e1

Browse files
author
Shubham Jitiya
committed
feat: Fixes issue #263: ✨ Support for dark theme
1 parent 18d6c0e commit ec4c3e1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1347
-237
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- Adds clear method to `EventController`.
44
- Adds `onEventTapDetails`, `onEventDoubleTapDetails` & `onEventLongTapDetails` gesture recognizers to get tap details. [#390](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/390)
5+
- Adds support for dark theme. [#263](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/issues/263)
56

67
# [1.4.0 - 7 Jan 2025](https://github.com/SimformSolutionsPvtLtd/flutter_calendar_view/tree/1.4.0)
78

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,47 @@ WeekView(
360360

361361
Above code will create `WeekView` with only five days, from monday to friday.
362362

363+
## **Customise theme**
364+
* The default theme includes support for dark mode.
365+
_
366+
_### Use default light & dark theme
367+
* CalendarTheme.light() & CalendarTheme.dark() provides the default colors for light & dark mode.
368+
* If no any theme is provided then default light theme is taken.
369+
```dart
370+
child: MaterialApp(
371+
theme: CalendarTheme.light,
372+
darkTheme: CalendarTheme.dark,
373+
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
374+
)
375+
```
376+
* Month-view, day-view & week-view each have separate theme to customise its component.
377+
* Refer [app_theme](example/lib/theme/app_theme.dart) of example to understand how to change colors of components.
378+
```dart
379+
// app_theme.dart
380+
static final _monthViewTheme = MonthViewTheme.light().copyWith(
381+
cellInMonth: Colors.redAccent,
382+
cellNotInMonth: Colors.red,
383+
cellText: Colors.amber,
384+
);
385+
386+
// Light theme: Use this in MaterialApp theme & dark theme.
387+
static final light = CalendarTheme.light.copyWith(
388+
extensions: [
389+
_monthViewTheme,
390+
],
391+
);
392+
393+
// main.dart
394+
MaterialApp(
395+
theme: AppTheme.light,
396+
)
397+
398+
## Inherited widget
399+
* Use Inherited widget CalendarThemeProvider() to access Calendar theme month-view, day-view & week-view.
400+
401+
```
402+
[//]: # (TODO(Shubham): Add docs)
403+
363404
## Main Contributors
364405

365406
<table>

doc/theme_guide.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
## **Customise theme**
2+
The default theme supports dark mode. Refer this colors to override it.
3+
4+
| Name | Parameter | Default color |
5+
|-----------------------------------------------|------------------------|-------------------------------------|
6+
| `MonthView` Border color | Color? borderColor | colorScheme.surfaceContainerHigh |
7+
| `WeekView` Background color of week view page | Color? backgroundColor | colorScheme.surfaceContainerLowest |
8+
| `DayView` Default background color | Color? backgroundColor | colorScheme.surfaceContainerLow |
9+
| `FilledCell` Dates in month cell color | Color? backgroundColor | colorScheme.surfaceContainerLowest |
10+
| `FilledCell` Dates not in month cell color | Color? backgroundColor | colorScheme.surfaceContainerLow |
11+
| `WeekDayTile` Border color | Color? borderColor | colorScheme.secondaryContainer |
12+
| `WeekDayTile` Background color | Color? backgroundColor | colorScheme.surfaceContainerHigh |
13+
| `WeekDayTile` Text style color | TextStyle? textStyle | colorScheme.onSecondaryContainer |
14+
15+
To customise `MonthView`, `DayView` & `WeekView` page header use `HeaderStyle`.
16+
17+
```dart
18+
headerStyle: HeaderStyle(
19+
leftIconConfig: IconDataConfig(color: Colors.red),
20+
rightIconConfig: IconDataConfig(color: Colors.red),
21+
decoration: BoxDecoration(
22+
color: Theme.of(context).highlightColor,
23+
),
24+
),
25+
```
26+
27+
### Day view
28+
* Default timeline text color is `colorScheme.onSurface`.
29+
* Use `markingStyle` in `DefaultTimeLineMark` to give text style.
30+
* Default `LiveTimeIndicatorSettings` color `colorScheme.primaryColorLight`.
31+
* Use `liveTimeIndicatorSettings` to customise it.
32+
* Default hour, half hour & quarter color is `colorScheme.surfaceContainerHighest`.
33+
* Use `hourIndicatorSettings` to customise it.
34+
35+
Default hour indicator settings.
36+
```dart
37+
HourIndicatorSettings(
38+
height: widget.heightPerMinute,
39+
// Color of horizontal and vertical lines
40+
color: Theme.of(context).colorScheme.surfaceContainerHighest,
41+
offset: 5,
42+
);
43+
```
44+
45+
### Week view
46+
* To customise week number & weekdays use `weekNumberBuilder` & `weekDayBuilder`.
47+
* Default week tile background color is `colorScheme.surfaceContainerHigh`.
48+
* Use `weekTitleBackgroundColor` to change background color.
49+
* Default page background color is `colorScheme.surfaceContainerLowest`.
50+
* Use `backgroundColor` to change background color.
51+
* Default timeline text color is `colorScheme.onSurface`. Use `markingStyle` in `DefaultTimeLineMark` to give text style.
52+
* To customise timeline use `timeLineBuilder`.
53+
* To change Hour lines color use `HourIndicatorSettings`.
54+
* To style hours, half hours & quarter hours use `HourIndicatorSettings`. Default color used is `surfaceContainerHighest`
55+
56+
```dart
57+
hourIndicatorSettings: HourIndicatorSettings(
58+
color: Colors.greenAccent,
59+
lineStyle: LineStyle.dashed,
60+
),
61+
showHalfHours: true,
62+
halfHourIndicatorSettings: HourIndicatorSettings(
63+
color: Colors.redAccent,
64+
lineStyle: LineStyle.dashed,
65+
),
66+
```

example/lib/constants.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22

3-
import 'app_colors.dart';
3+
import 'theme/app_colors.dart';
44

55
class AppConstants {
66
AppConstants._();
@@ -11,7 +11,7 @@ class AppConstants {
1111
borderRadius: BorderRadius.circular(7),
1212
borderSide: BorderSide(
1313
width: 2,
14-
color: AppColors.lightNavyBlue,
14+
color: AppColors.outlineVariant,
1515
),
1616
);
1717

example/lib/extension.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import 'package:flutter/material.dart';
22
import 'package:intl/intl.dart';
33

4-
import 'app_colors.dart';
54
import 'enumerations.dart';
5+
import 'theme/app_colors.dart';
6+
import 'theme/app_theme_extension.dart';
67

78
enum TimeStampFormat { parse_12, parse_24 }
89

@@ -128,3 +129,9 @@ extension StringExt on String {
128129
extension ViewNameExt on CalendarView {
129130
String get name => toString().split(".").last;
130131
}
132+
133+
extension BuildContextExtension on BuildContext {
134+
AppThemeExtension get appColors =>
135+
Theme.of(this).extension<AppThemeExtension>() ??
136+
AppThemeExtension.light();
137+
}

example/lib/main.dart

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,59 @@
11
import 'dart:ui';
22

33
import 'package:calendar_view/calendar_view.dart';
4+
import 'package:example/theme/app_theme.dart';
45
import 'package:flutter/material.dart';
56

67
import 'pages/home_page.dart';
8+
import 'theme/app_colors.dart';
79

810
DateTime get _now => DateTime.now();
911

1012
void main() {
1113
runApp(MyApp());
1214
}
1315

14-
class MyApp extends StatelessWidget {
16+
class MyApp extends StatefulWidget {
17+
@override
18+
State<MyApp> createState() => _MyAppState();
19+
}
20+
21+
class _MyAppState extends State<MyApp> {
22+
bool isDarkMode = false;
23+
1524
// This widget is the root of your application.
1625
@override
1726
Widget build(BuildContext context) {
18-
return CalendarControllerProvider(
19-
controller: EventController()..addAll(_events),
20-
child: MaterialApp(
21-
title: 'Flutter Calendar Page Demo',
22-
debugShowCheckedModeBanner: false,
23-
theme: ThemeData.light(),
24-
scrollBehavior: ScrollBehavior().copyWith(
25-
dragDevices: {
26-
PointerDeviceKind.trackpad,
27-
PointerDeviceKind.mouse,
28-
PointerDeviceKind.touch,
29-
},
27+
return CalendarThemeProvider(
28+
calendarTheme: CalendarTheme(
29+
monthViewTheme:
30+
isDarkMode ? MonthViewTheme.dark() : MonthViewTheme.light(),
31+
dayViewTheme: isDarkMode
32+
? DayViewTheme.dark()
33+
: DayViewTheme.light().copyWith(hourLineColor: AppColors.primary)
34+
as DayViewTheme,
35+
weekViewTheme:
36+
isDarkMode ? WeekViewTheme.dark() : WeekViewTheme.light(),
37+
),
38+
child: CalendarControllerProvider(
39+
controller: EventController()..addAll(_events),
40+
child: MaterialApp(
41+
title: 'Flutter Calendar Page Demo',
42+
debugShowCheckedModeBanner: false,
43+
theme: AppTheme.light,
44+
darkTheme: AppTheme.dark,
45+
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
46+
scrollBehavior: ScrollBehavior().copyWith(
47+
dragDevices: {
48+
PointerDeviceKind.trackpad,
49+
PointerDeviceKind.mouse,
50+
PointerDeviceKind.touch,
51+
},
52+
),
53+
home: HomePage(
54+
onChangeTheme: (isDark) => setState(() => isDarkMode = isDark),
55+
),
3056
),
31-
home: HomePage(),
3257
),
3358
);
3459
}

example/lib/pages/create_event_page.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'package:calendar_view/calendar_view.dart';
22
import 'package:flutter/material.dart';
33

4-
import '../app_colors.dart';
54
import '../extension.dart';
65
import '../widgets/add_event_form.dart';
76

@@ -12,22 +11,23 @@ class CreateEventPage extends StatelessWidget {
1211

1312
@override
1413
Widget build(BuildContext context) {
14+
final themeColor = context.appColors;
15+
1516
return Scaffold(
1617
appBar: AppBar(
1718
elevation: 0,
18-
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
1919
centerTitle: false,
2020
leading: IconButton(
2121
onPressed: context.pop,
2222
icon: Icon(
2323
Icons.arrow_back,
24-
color: AppColors.black,
24+
color: themeColor.onPrimary,
2525
),
2626
),
2727
title: Text(
2828
event == null ? "Create New Event" : "Update Event",
2929
style: TextStyle(
30-
color: AppColors.black,
30+
color: themeColor.onPrimary,
3131
fontSize: 20.0,
3232
fontWeight: FontWeight.bold,
3333
),

example/lib/pages/day_view_page.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ class DayViewPageDemo extends StatefulWidget {
1717
class _DayViewPageDemoState extends State<DayViewPageDemo> {
1818
@override
1919
Widget build(BuildContext context) {
20+
final appColors = context.appColors;
21+
2022
return ResponsiveWidget(
2123
webWidget: WebHomePage(
2224
selectedView: CalendarView.day,
2325
),
2426
mobileWidget: Scaffold(
27+
primary: false,
28+
appBar: AppBar(
29+
leading: const SizedBox.shrink(),
30+
),
2531
floatingActionButton: FloatingActionButton(
26-
child: Icon(Icons.add),
32+
child: Icon(
33+
Icons.add,
34+
color: appColors.onPrimary,
35+
),
2736
elevation: 8,
2837
onPressed: () => context.pushRoute(CreateEventPage()),
2938
),

example/lib/pages/event_details_page.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:calendar_view/calendar_view.dart';
2+
import 'package:example/theme/app_colors.dart';
23
import 'package:example/widgets/delete_event_dialog.dart';
34
import 'package:flutter/material.dart';
45

@@ -97,16 +98,30 @@ class DetailsPage extends StatelessWidget {
9798
children: [
9899
Expanded(
99100
child: ElevatedButton(
101+
child: Text(
102+
'Delete Event',
103+
style: TextStyle(
104+
color: AppColors.black,
105+
),
106+
),
107+
style: ElevatedButton.styleFrom(
108+
backgroundColor: Colors.white70,
109+
),
100110
onPressed: () async {
101111
await _handleDeleteEvent(context);
102112
Navigator.of(context).pop();
103113
},
104-
child: Text('Delete Event'),
105114
),
106115
),
107116
SizedBox(width: 30),
108117
Expanded(
109118
child: ElevatedButton(
119+
child: Text(
120+
'Edit Event',
121+
style: TextStyle(
122+
color: AppColors.black,
123+
),
124+
),
110125
onPressed: () async {
111126
final result = await Navigator.of(context).push(
112127
MaterialPageRoute(
@@ -120,7 +135,9 @@ class DetailsPage extends StatelessWidget {
120135
Navigator.of(context).pop();
121136
}
122137
},
123-
child: Text('Edit Event'),
138+
style: ElevatedButton.styleFrom(
139+
backgroundColor: Colors.white70,
140+
),
124141
),
125142
),
126143
],

example/lib/pages/home_page.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@ import 'mobile/mobile_home_page.dart';
55
import 'web/web_home_page.dart';
66

77
class HomePage extends StatelessWidget {
8-
const HomePage({super.key});
8+
const HomePage({
9+
this.onChangeTheme,
10+
super.key,
11+
});
12+
13+
/// Return true for dark mode
14+
/// false for light mode
15+
final void Function(bool)? onChangeTheme;
916

1017
@override
1118
Widget build(BuildContext context) {
1219
return ResponsiveWidget(
13-
mobileWidget: MobileHomePage(),
14-
webWidget: WebHomePage(),
20+
mobileWidget: MobileHomePage(onChangeTheme: onChangeTheme),
21+
webWidget: WebHomePage(onThemeChange: onChangeTheme),
1522
);
1623
}
1724
}

0 commit comments

Comments
 (0)