bs_ad_calendar 1.0.1
bs_ad_calendar: ^1.0.1 copied to clipboard
A fully customizable Nepali (Bikram Sambat) and Gregorian calendar widget for Flutter. Dual calendar modes, AD ↔ BS date conversion, interactive monthly calendar, modal date pickers, dual locale (Engl [...]
bs_ad_calendar #
A fully customizable Nepali (Bikram Sambat) and English (Gregorian) calendar widget for Flutter.
Demo #
Check out the demo video and screenshots to see the calendar in action!
Try it on Your Device #
Want to test the calendar on your device? Clone and run the full test application:
git clone https://github.com/bibashpoudel7/calendar_test_app.git
cd calendar_test_app
flutter pub get
flutter run
- Dual calendar modes: Nepali (Bikram Sambat) OR English (Gregorian) calendar display
- AD ↔ BS date conversion (BS 1970 – 2250)
- Interactive monthly calendar widget with tap-to-jump year/month picker
- Single-date picker dialog (
showNepaliDatePicker) - Date range picker dialog (
showNepaliDateRangePicker) - Range selection mode with highlighted start/end caps and in-range bar
- Tri-locale: English (
Baisakh), Nepali (बैशाख), or Both simultaneously - Optional dual date display – show both calendars simultaneously
DatePriority– choose whether BS or AD is the large primary number- Secondary date color customization – customize sub-date colors for selected/today states
- One-stop theme object (
NepaliCalendarThemeData) - Event markers with custom builder
- Zero extra dependencies – Flutter SDK only
Installation #
dependencies:
bs_ad_calendar: ^1.0.0
Quick start #
import 'package:bs_ad_calendar/bs_ad_calendar.dart';
Calendar Modes #
This package supports two distinct calendar modes:
- Nepali (Bikram Sambat) Calendar – Uses Nepali month structure (Baisakh, Jestha, Ashadh, etc.)
- Gregorian (English) Calendar – Uses standard English month structure (January, February, March, etc.)
You can choose the calendar mode and display format based on your needs:
| Calendar Mode | Primary Display | Optional Secondary Display |
|---|---|---|
| Nepali | BS dates (Baisakh-Chaitra) | AD dates (optional sub-label) |
| Gregorian | AD dates (January-December) | BS dates (optional sub-label) |
Usage #
1. Gregorian (English) calendar with optional Nepali dates #
Display a standard English calendar with Gregorian month structure:
GregorianCalendarWidget(
initialDate: DateTime.now(),
theme: NepaliCalendarThemeData(
primaryColor: Colors.deepPurple,
dayFontSize: 14,
showNepaliDate: true, // Show BS dates as sub-labels
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
todaySecondaryDateColor: Colors.white,
),
onDaySelected: (DateTime adDate, NepaliDate bsDate) {
print('AD: $adDate, BS: $bsDate');
},
)
Key features:
- Standard Gregorian month structure (January has 31 days, February has 28/29, etc.)
- Optional Nepali date sub-labels with customizable colors
- Perfect for apps that primarily use English calendar but need BS reference
2. Nepali calendar with optional English dates #
Display a Nepali (Bikram Sambat) calendar:
NepaliCalendarWidget(
initialDate: NepaliDateConverter.today(),
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(
primaryColor: Colors.indigo,
showEnglishDate: true, // Show AD dates as sub-labels
datePriority: DatePriority.nepali, // BS large, AD small
dayFontSize: 14,
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
),
onDaySelected: (NepaliDate bsDate, DateTime adDate) {
print('BS: $bsDate, AD: $adDate');
},
)
3. Single date picker dialog #
final result = await showNepaliDatePicker(
context: context,
initialDate: NepaliDateConverter.today(),
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(
primaryColor: Colors.indigo,
showEnglishDate: true,
dayFontSize: 14,
),
);
if (result != null) {
print('BS : ${result.bsDate}'); // 2081-04-15
print('Readable : ${result.bsDate.toReadableStringEn()}'); // 15 Shrawan, 2081
print('AD : ${result.adDate}'); // 2024-07-30
}
4. Date range picker dialog #
final result = await showNepaliDateRangePicker(
context: context,
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(primaryColor: Colors.teal),
rangeStyle: NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Colors.teal,
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Colors.teal,
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x2200897B), // 13% teal
),
inRangeTextStyle: TextStyle(color: Colors.teal),
),
);
if (result != null) {
print('BS start : ${result.bsRange.start}'); // 2081-04-10
print('BS end : ${result.bsRange.end}'); // 2081-04-20
print('AD start : ${result.adStart}');
print('AD end : ${result.adEnd}');
}
5. Inline calendar widget — range selection #
NepaliCalendarWidget(
selectionMode: NepaliSelectionMode.range,
rangeStyle: NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x33E53935),
),
),
onRangeSelected: (NepaliDateRange range) {
print('Start: ${range.start}');
print('End : ${range.end}');
print('Days : ${range.contains(NepaliDate(2081, 4, 15))}');
},
)
Range selection works in two taps:
- First tap — sets the start date, highlights it with a circle cap.
- Second tap — sets the end date (auto-swaps if end < start), highlights the bar between them and fires
onRangeSelected. - Third tap — resets and starts a new range.
6. Event markers #
NepaliCalendarWidget(
eventLoader: (NepaliDate day) => myEvents[day] ?? [],
markerBuilder: (context, day, events) {
return Container(
width: 6, height: 6,
decoration: const BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
);
},
onDaySelected: (bs, ad) {},
)
7. Manual conversion #
// AD → BS
final bs = NepaliDateConverter.adToBs(DateTime.now());
print(bs.toReadableStringEn()); // "30 Shrawan, 2081"
print(bs.toReadableStringNp()); // "३० साउन, २०८१"
// BS → AD
final ad = NepaliDateConverter.bsToAd(NepaliDate(2081, 4, 15));
print(ad); // 2024-07-30
// Days in a month
print(NepaliDateConverter.daysInMonth(2081, 1)); // 31
// Today in BS
final today = NepaliDateConverter.today();
Theming #
One-stop theme object (recommended) #
Pass a single NepaliCalendarThemeData to style everything at once:
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
primaryColor: Colors.deepPurple, // accent for today, selected, chevrons
dayFontSize: 14,
showEnglishDate: true, // show AD day number in each cell
datePriority: DatePriority.nepali, // BS day large, AD day small
headerBackgroundColor: Colors.deepPurple.shade50,
weekdayRowBackgroundColor: Colors.deepPurple.shade50,
todayCellShape: BoxShape.circle,
selectedCellShape: BoxShape.circle,
),
onDaySelected: (bs, ad) {},
)
NepaliCalendarThemeData field |
Default | Description |
|---|---|---|
primaryColor |
Color(0xFFE53935) |
Accent for today circle, chevrons, confirm button |
backgroundColor |
null |
Calendar card background |
headerBackgroundColor |
null |
Header row background |
weekdayRowBackgroundColor |
null |
Day-of-week row background |
dayColor |
Colors.black87 |
Regular day number colour |
disabledDayColor |
Colors.black26 |
Out-of-range day colour |
todayTextColor |
Colors.white |
Today's number colour |
selectedTextColor |
Colors.white |
Selected day number colour |
weekdayColor |
Colors.black54 |
Weekday label colour |
secondaryDateColor |
Colors.black54 |
Sub-date colour for normal days |
selectedSecondaryDateColor |
Colors.white |
Sub-date colour when selected |
todaySecondaryDateColor |
Colors.white |
Sub-date colour for today |
dayFontSize |
13 |
Day number font size |
englishDateFontSize |
9 |
AD sub-label font size |
titleFontSize |
16 |
Header title font size |
weekdayFontSize |
12 |
Weekday label font size |
showEnglishDate |
false |
Show AD day in small text (Nepali calendar) |
showNepaliDate |
true |
Show BS day in small text (Gregorian calendar) |
datePriority |
DatePriority.nepali |
Which date is the large primary number |
cellSize |
auto (38 / 46) |
Day cell size in logical pixels |
weekdayRowHeight |
28 |
Height of weekday header row |
todayCellShape |
BoxShape.circle |
Today circle shape |
selectedCellShape |
BoxShape.circle |
Selected day shape |
Granular style overrides #
For fine-grained control, pass individual style objects. These override theme when provided.
NepaliCalendarWidget(
calendarStyle: NepaliCalendarStyle(
showEnglishDate: true,
datePriority: DatePriority.english, // AD day large, BS day small
cellSize: 42.0,
todayDecoration: BoxDecoration(color: Colors.blue, shape: BoxShape.circle),
selectedDecoration: BoxDecoration(color: Colors.blue.shade200, shape: BoxShape.circle),
defaultTextStyle: TextStyle(fontSize: 14),
englishDateTextStyle: TextStyle(fontSize: 9, color: Colors.grey),
),
headerStyle: NepaliHeaderStyle(
titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
leftChevronIcon: Icon(Icons.arrow_back_ios, color: Colors.blue),
rightChevronIcon: Icon(Icons.arrow_forward_ios, color: Colors.blue),
),
daysOfWeekStyle: NepaliDaysOfWeekStyle(
weekdayTextStyle: TextStyle(fontSize: 13, color: Colors.black54),
weekendTextStyle: TextStyle(fontSize: 13, color: Colors.red),
rowHeight: 32,
),
onDaySelected: (bs, ad) {},
)
| Style class | Controls |
|---|---|
NepaliCalendarStyle |
Day cell decorations, text styles, showEnglishDate, datePriority, cell size |
NepaliHeaderStyle |
Month/year title, chevron icons, background colour |
NepaliDaysOfWeekStyle |
Weekday label styles, row height, background |
NepaliCalendarRangeStyle |
Range start/end cap decorations, in-range bar colour and text styles |
Range style #
NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Color(0xFFE53935),
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Color(0xFFE53935),
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x33E53935), // 20% opacity red
),
rangeStartTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
rangeEndTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
inRangeTextStyle: TextStyle(color: Color(0xFFE53935)),
useRoundedRangeBar: true,
)
Locale options #
| Value | Weekday header | Month title |
|---|---|---|
NepaliLocale.english |
Sun, Mon … Sat | Baisakh 2081 |
NepaliLocale.nepali |
आइत, सोम … शनि | बैशाख २०८१ |
NepaliLocale.both |
Two-line: Nepali top, English below | Baisakh 2081 / बैशाख २०८१ |
NepaliCalendarWidget(
locale: NepaliLocale.both,
onDaySelected: (bs, ad) {},
)
Date priority #
Controls which calendar system's day number is rendered large (primary) when showEnglishDate is true:
DatePriority |
Large (primary) | Small (secondary) |
|---|---|---|
DatePriority.nepali (default) |
BS day | AD day |
DatePriority.english |
AD day | BS day (or hidden) |
Variant 1 — BS only (default) #
BS day large, no AD sub-label.
NepaliCalendarWidget(
onDaySelected: (bs, ad) {},
)
Variant 2 — BS large, AD small #
BS day large, AD day shown as a small sub-label below.
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.nepali, // default
),
onDaySelected: (bs, ad) {},
)
Variant 3 — AD large, BS small #
AD day large, BS day shown as a small sub-label below.
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.english,
),
onDaySelected: (bs, ad) {},
)
Variant 4 — AD only (no BS sub-label) #
AD day large, BS sub-label hidden entirely. Header and weekday row also show in English (Gregorian month name + English weekday abbreviations).
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.english,
showNepaliDate: false, // hide BS sub-label
),
onDaySelected: (bs, ad) {},
)
Year / month picker #
Tapping the header title opens an interactive picker with a scrollable 4-column year grid (respecting firstDate and lastDate) and a 12-button month grid. The year list auto-scrolls to the currently displayed year.
Supported date range #
| Calendar | From | To |
|---|---|---|
| BS | 1970/01/01 | 2250/12/30 |
| AD | 1913/04/13 | ~2193 |
Years 1970–2100 use a verified lookup table. Years 2101–2250 use the 91-year BS cycle algorithm for month-length calculation.
API reference #
GregorianCalendarWidget #
A calendar widget that displays standard Gregorian (English) months with optional Nepali date sub-labels.
| Parameter | Type | Default | Description |
|---|---|---|---|
initialDate |
DateTime |
required | Month displayed on first render |
selectedDate |
DateTime? |
null |
Pre-selected date |
firstDate |
DateTime |
DateTime(1900) |
Earliest selectable date |
lastDate |
DateTime |
DateTime(2100) |
Latest selectable date |
theme |
NepaliCalendarThemeData |
required | Calendar theme |
showNepaliDate |
bool |
false |
Show BS dates as sub-labels |
onDaySelected |
void Function(DateTime, NepaliDate)? |
null |
Day tap callback |
Example:
GregorianCalendarWidget(
initialDate: DateTime.now(),
theme: NepaliCalendarThemeData(
primaryColor: Colors.blue,
showNepaliDate: true,
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
),
onDaySelected: (adDate, bsDate) {
print('Selected: $adDate (BS: $bsDate)');
},
)
NepaliCalendarWidget #
A calendar widget that displays Nepali (Bikram Sambat) months with optional English date sub-labels.
| Parameter | Type | Default | Description |
|---|---|---|---|
initialDate |
NepaliDate? |
today | Month displayed on first render |
selectedDate |
NepaliDate? |
null |
Controlled selected date (single mode) |
firstDate |
NepaliDate |
NepaliDate(1970,1,1) |
Earliest selectable date |
lastDate |
NepaliDate |
NepaliDate(2250,12,30) |
Latest selectable date |
locale |
NepaliLocale |
.english |
Label language |
theme |
NepaliCalendarThemeData? |
null |
One-stop theme |
calendarStyle |
NepaliCalendarStyle? |
null |
Day cell overrides |
headerStyle |
NepaliHeaderStyle? |
null |
Header overrides |
daysOfWeekStyle |
NepaliDaysOfWeekStyle? |
null |
Weekday row overrides |
selectionMode |
NepaliSelectionMode |
.single |
Single or range selection |
rangeStartDate |
NepaliDate? |
null |
Pre-selected range start |
rangeEndDate |
NepaliDate? |
null |
Pre-selected range end |
rangeStyle |
NepaliCalendarRangeStyle |
red defaults | Range highlight style |
eventLoader |
List<Object> Function(NepaliDate)? |
null |
Provide events per day |
markerBuilder |
Widget Function(...)? |
null |
Custom event marker widget |
onDaySelected |
void Function(NepaliDate, DateTime)? |
null |
Single-mode tap callback |
onRangeSelected |
void Function(NepaliDateRange)? |
null |
Range-mode complete callback |
onPageChanged |
void Function(int year, int month)? |
null |
Month navigation callback |
showNepaliDatePicker #
Returns NepaliDatePickerResult? with .bsDate and .adDate.
showNepaliDateRangePicker #
Returns NepaliDateRangePickerResult? with .bsRange (NepaliDateRange), .adStart, and .adEnd.
NepaliDate #
NepaliDate(2081, 4, 15)
date.year // 2081
date.month // 4
date.day // 15
date.monthNameEn // "Shrawan"
date.monthNameNp // "साउन"
date.toFormattedString() // "2081-04-15"
date.toReadableStringEn() // "15 Shrawan, 2081"
date.toReadableStringNp() // "१५ साउन, २०८१"
date.isSameDay(other)
date.isBefore(other)
date.isAfter(other)
date.isAtOrAfter(other)
date.isAtOrBefore(other)
date.copyWith(year: 2082)
NepaliDate.toNepaliNumerals(2081) // "२०८१"
NepaliDateRange #
NepaliDateRange(
start: NepaliDate(2081, 4, 10),
end: NepaliDate(2081, 4, 20),
)
range.isSingleDay // false
range.contains(someDate) // true/false
range.toString() // "2081-04-10 – 2081-04-20"
Author #
Bibash Poudel Sr. Full Stack Developer pdlbibash77@gmail.com
License #
MIT © Bibash Poudel