Skip to content

Commit 3680d06

Browse files
Merge pull request #10 from harshyadavDeveloper/develop
New version
2 parents 64d9764 + 2a16942 commit 3680d06

9 files changed

Lines changed: 993 additions & 70 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
## 2.6.0
2+
3+
* SmartParser — Gujarati, Bengali, Tamil parsing
4+
* SmartParser — new English expressions:
5+
* "first/last monday of month"
6+
* "2 mondays ago", "in 2 fridays"
7+
* "beginning/end of next month"
8+
* "this coming monday"
9+
* "q1", "q2", "quarter 3"
10+
* SmartCalendar — range selection mode
11+
* `rangeSelectionMode` param
12+
* `onRangeSelected` callback
13+
* Visual range highlight in month view
14+
* SmartCalendar — event overlap detection in week view
15+
* `supportedParseLocales` updated — now includes gu, bn, ta
16+
117
## 2.5.0
218

319
- Added `themeMode` to SmartCalendar — light/dark/system

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<a href="https://github.com/harshyadavDeveloper/smart_date_formatter/actions">
2020
<img src="https://github.com/harshyadavDeveloper/smart_date_formatter/actions/workflows/ci.yml/badge.svg" alt="CI"/>
2121
</a>
22+
<a href="https://pub.dev/packages/smart_date_formatter/score">
23+
<img src="https://img.shields.io/pub/points/smart_date_formatter?color=2E8B57&label=pub%20points" alt="Pub Points"/>
24+
</a>
2225
</p>
2326

2427
<p align="center">

example/pubspec.lock

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ packages:
2121
dependency: transitive
2222
description:
2323
name: characters
24-
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
24+
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
2525
url: "https://pub.dev"
2626
source: hosted
27-
version: "1.4.1"
27+
version: "1.4.0"
2828
clock:
2929
dependency: transitive
3030
description:
@@ -111,26 +111,26 @@ packages:
111111
dependency: transitive
112112
description:
113113
name: matcher
114-
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
114+
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
115115
url: "https://pub.dev"
116116
source: hosted
117-
version: "0.12.19"
117+
version: "0.12.17"
118118
material_color_utilities:
119119
dependency: transitive
120120
description:
121121
name: material_color_utilities
122-
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
122+
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
123123
url: "https://pub.dev"
124124
source: hosted
125-
version: "0.13.0"
125+
version: "0.11.1"
126126
meta:
127127
dependency: transitive
128128
description:
129129
name: meta
130-
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
130+
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
131131
url: "https://pub.dev"
132132
source: hosted
133-
version: "1.18.0"
133+
version: "1.16.0"
134134
path:
135135
dependency: transitive
136136
description:
@@ -166,7 +166,7 @@ packages:
166166
path: ".."
167167
relative: true
168168
source: path
169-
version: "2.3.0"
169+
version: "2.6.0"
170170
source_span:
171171
dependency: transitive
172172
description:
@@ -211,10 +211,10 @@ packages:
211211
dependency: transitive
212212
description:
213213
name: test_api
214-
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
214+
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
215215
url: "https://pub.dev"
216216
source: hosted
217-
version: "0.7.11"
217+
version: "0.7.6"
218218
vector_math:
219219
dependency: transitive
220220
description:
@@ -248,5 +248,5 @@ packages:
248248
source: hosted
249249
version: "3.1.3"
250250
sdks:
251-
dart: ">=3.10.0-0 <4.0.0"
251+
dart: ">=3.9.0 <4.0.0"
252252
flutter: ">=3.18.0-18.0.pre.54"

lib/src/calendar/smart_calendar.dart

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'package:flutter/material.dart';
2+
import 'package:smart_date_formatter/smart_date_formatter.dart';
23
import 'package:smart_date_formatter/src/calendar/views/agenda_view.dart';
3-
import 'calendar_event.dart';
4-
import 'calendar_controller.dart';
54
import 'views/month_view.dart';
65
import 'views/week_view.dart';
76
import 'views/day_view.dart';
@@ -96,6 +95,12 @@ class SmartCalendar extends StatefulWidget {
9695
/// Theme mode for calendar
9796
final ThemeMode themeMode;
9897

98+
/// Enable range selection mode
99+
final bool rangeSelectionMode;
100+
101+
/// Called when range is selected in calendar
102+
final void Function(DateTime start, DateTime end)? onRangeSelected;
103+
99104
/// Custom cell builder for month view dates.
100105
///
101106
/// ```dart
@@ -155,6 +160,8 @@ class SmartCalendar extends StatefulWidget {
155160
this.showWeekNumbers = false,
156161
this.themeMode = ThemeMode.light,
157162
this.cellBuilder,
163+
this.rangeSelectionMode = false,
164+
this.onRangeSelected,
158165
});
159166

160167
@override
@@ -165,6 +172,9 @@ class _SmartCalendarState extends State<SmartCalendar> {
165172
late SmartCalendarController _controller;
166173
late CalendarView _currentView;
167174
bool _ownsController = false;
175+
DateTime? _rangeStart;
176+
DateTime? _rangeEnd;
177+
// bool _selectingRangeStart = true;
168178

169179
@override
170180
void initState() {
@@ -204,6 +214,26 @@ class _SmartCalendarState extends State<SmartCalendar> {
204214
Color get _subtleTextColor =>
205215
_isDark ? Colors.grey.shade400 : Colors.grey.shade600;
206216

217+
// void _handleRangeTap(DateTime date) {
218+
// setState(() {
219+
// if (_selectingRangeStart || _rangeEnd != null) {
220+
// _rangeStart = date;
221+
// _rangeEnd = null;
222+
// _selectingRangeStart = false;
223+
// } else {
224+
// if (date.isBefore(_rangeStart!)) {
225+
// _rangeEnd = _rangeStart;
226+
// _rangeStart = date;
227+
// } else {
228+
// _rangeEnd = date;
229+
// }
230+
// _selectingRangeStart = true;
231+
// widget.onRangeSelected?.call(_rangeStart!, _rangeEnd!);
232+
// }
233+
// _controller.selectDate(date);
234+
// });
235+
// }
236+
207237
@override
208238
void dispose() {
209239
if (_ownsController) _controller.dispose();
@@ -240,6 +270,40 @@ class _SmartCalendarState extends State<SmartCalendar> {
240270
),
241271
],
242272
),
273+
// After view switcher row
274+
if (widget.rangeSelectionMode) ...[
275+
Container(
276+
margin: const EdgeInsets.only(bottom: 8),
277+
padding:
278+
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
279+
decoration: BoxDecoration(
280+
color: widget.selectedColor.withValues(alpha: 0.08),
281+
borderRadius: BorderRadius.circular(8),
282+
),
283+
child: Row(
284+
mainAxisAlignment: MainAxisAlignment.center,
285+
children: [
286+
Icon(Icons.date_range,
287+
size: 14, color: widget.selectedColor),
288+
const SizedBox(width: 6),
289+
Text(
290+
_rangeStart == null
291+
? 'Tap to select start date'
292+
: _rangeEnd == null
293+
? 'Tap to select end date'
294+
: '${_rangeStart!.format('dd MMM')} → '
295+
'${_rangeEnd!.format('dd MMM')} '
296+
'(${_rangeEnd!.daysUntil(_rangeStart!) * -1 + 1} days)',
297+
style: TextStyle(
298+
fontSize: 12,
299+
color: widget.selectedColor,
300+
fontWeight: FontWeight.w500,
301+
),
302+
),
303+
],
304+
),
305+
),
306+
],
243307

244308
// Calendar view
245309
_buildCurrentView(),
@@ -343,6 +407,8 @@ class _SmartCalendarState extends State<SmartCalendar> {
343407
showWeekNumbers: widget.showWeekNumbers,
344408
isDark: _isDark,
345409
cellBuilder: widget.cellBuilder,
410+
rangeStart: widget.rangeSelectionMode ? _rangeStart : null, // 👈 new
411+
rangeEnd: widget.rangeSelectionMode ? _rangeEnd : null,
346412
);
347413
case CalendarView.week:
348414
return WeekView(

lib/src/calendar/views/month_view.dart

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ class MonthView extends StatelessWidget {
5252
/// Whether dark theme is active
5353
final bool isDark;
5454

55+
/// Range selection start date
56+
final DateTime? rangeStart;
57+
58+
/// Range selection end date
59+
final DateTime? rangeEnd;
60+
5561
/// Custom cell builder for month view dates.
5662
///
5763
/// ```dart
@@ -94,6 +100,8 @@ class MonthView extends StatelessWidget {
94100
this.showWeekNumbers = false,
95101
this.isDark = false,
96102
this.cellBuilder,
103+
this.rangeStart,
104+
this.rangeEnd,
97105
});
98106

99107
List<DateTime> _daysInMonth(DateTime month) {
@@ -243,22 +251,8 @@ class MonthView extends StatelessWidget {
243251
isToday,
244252
),
245253
)
246-
: DayCell(
247-
date: date,
248-
events: dayEvents,
249-
isSelected: isSelected,
250-
isToday: isToday,
251-
isCurrentMonth: isCurrentMonth,
252-
isWeekend: isWeekend,
253-
markerStyle: markerStyle,
254-
selectedColor: selectedColor,
255-
todayColor: todayColor,
256-
isDark: isDark,
257-
onTap: () {
258-
controller.selectDate(date);
259-
onDateSelected?.call(date, dayEvents);
260-
},
261-
),
254+
: _buildRangeCell(date, dayEvents, isSelected, isToday,
255+
isCurrentMonth, isWeekend),
262256
);
263257
}),
264258
],
@@ -272,4 +266,73 @@ class MonthView extends StatelessWidget {
272266
final dayOfYear = date.difference(firstDayOfYear).inDays + 1;
273267
return ((dayOfYear + firstDayOfYear.weekday - 2) / 7).ceil().clamp(1, 53);
274268
}
269+
270+
bool _isInSelectedRange(DateTime date) {
271+
if (rangeStart == null || rangeEnd == null) return false;
272+
final d = DateTime(date.year, date.month, date.day);
273+
final s = DateTime(rangeStart!.year, rangeStart!.month, rangeStart!.day);
274+
final e = DateTime(rangeEnd!.year, rangeEnd!.month, rangeEnd!.day);
275+
return d.isAfter(s) && d.isBefore(e);
276+
}
277+
278+
bool _isRangeStart(DateTime date) =>
279+
rangeStart != null && date.isSameDay(rangeStart!);
280+
281+
bool _isRangeEnd(DateTime date) =>
282+
rangeEnd != null && date.isSameDay(rangeEnd!);
283+
284+
Widget _buildRangeCell(
285+
DateTime date,
286+
List<CalendarEvent> events,
287+
bool isSelected,
288+
bool isToday,
289+
bool isCurrentMonth,
290+
bool isWeekend,
291+
) {
292+
final inRange = _isInSelectedRange(date);
293+
final isStart = _isRangeStart(date);
294+
final isEnd = _isRangeEnd(date);
295+
296+
return GestureDetector(
297+
onTap: () {
298+
controller.selectDate(date);
299+
onDateSelected?.call(date, events);
300+
},
301+
child: Container(
302+
margin: EdgeInsets.zero,
303+
decoration: BoxDecoration(
304+
color: isStart || isEnd
305+
? selectedColor
306+
: inRange
307+
? selectedColor.withValues(alpha: 0.12)
308+
: Colors.transparent,
309+
borderRadius: isStart
310+
? const BorderRadius.only(
311+
topLeft: Radius.circular(8),
312+
bottomLeft: Radius.circular(8),
313+
)
314+
: isEnd
315+
? const BorderRadius.only(
316+
topRight: Radius.circular(8),
317+
bottomRight: Radius.circular(8),
318+
)
319+
: inRange
320+
? BorderRadius.zero
321+
: BorderRadius.circular(8),
322+
),
323+
child: DayCell(
324+
date: date,
325+
events: events,
326+
isSelected: isSelected || isStart || isEnd,
327+
isToday: isToday,
328+
isCurrentMonth: isCurrentMonth,
329+
isWeekend: isWeekend,
330+
markerStyle: markerStyle,
331+
selectedColor: selectedColor,
332+
todayColor: todayColor,
333+
isDark: isDark,
334+
),
335+
),
336+
);
337+
}
275338
}

0 commit comments

Comments
 (0)