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 [...]
import 'package:flutter/material.dart';
import 'package:bs_ad_calendar/bs_ad_calendar.dart';
void main() => runApp(const NepaliCalendarExampleApp());
class NepaliCalendarExampleApp extends StatelessWidget {
const NepaliCalendarExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Nepali Calendar Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFFE53935)),
useMaterial3: true,
),
home: const ExampleHomePage(),
);
}
}
class ExampleHomePage extends StatefulWidget {
const ExampleHomePage({super.key});
@override
State<ExampleHomePage> createState() => _ExampleHomePageState();
}
class _ExampleHomePageState extends State<ExampleHomePage> {
NepaliDate? _selectedDate;
NepaliLocale _locale = NepaliLocale.english;
bool _showEnglishDate = true;
// Sample events
final Map<String, List<String>> _events = {
NepaliDateConverter.today().toFormattedString(): ['Today event'],
NepaliDateConverter.adToBs(
DateTime.now().add(const Duration(days: 2)))
.toFormattedString(): ['Upcoming event 1', 'Upcoming event 2'],
};
@override
Widget build(BuildContext context) {
final today = NepaliDateConverter.today();
return Scaffold(
appBar: AppBar(
title: const Text('Nepali Calendar Demo'),
backgroundColor: const Color(0xFFE53935),
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ── Controls ────────────────────────────────────────────────────
Row(
children: [
const Text('Locale: ', style: TextStyle(fontWeight: FontWeight.bold)),
ChoiceChip(
label: const Text('English'),
selected: _locale == NepaliLocale.english,
onSelected: (_) =>
setState(() => _locale = NepaliLocale.english),
),
const SizedBox(width: 8),
ChoiceChip(
label: const Text('नेपाली'),
selected: _locale == NepaliLocale.nepali,
onSelected: (_) =>
setState(() => _locale = NepaliLocale.nepali),
),
],
),
const SizedBox(height: 8),
Row(
children: [
const Text('Show AD date: ',
style: TextStyle(fontWeight: FontWeight.bold)),
Switch(
value: _showEnglishDate,
activeTrackColor: const Color(0xFFE53935),
onChanged: (v) => setState(() => _showEnglishDate = v),
),
],
),
const SizedBox(height: 16),
const Divider(),
// ── Inline calendar ──────────────────────────────────────────────
const Text(
'Inline Calendar',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(8),
child: NepaliCalendarWidget(
initialDate: today,
selectedDate: _selectedDate,
locale: _locale,
calendarStyle: NepaliCalendarStyle(
showEnglishDate: _showEnglishDate,
todayDecoration: const BoxDecoration(
color: Color(0xFFE53935),
shape: BoxShape.circle,
),
selectedDecoration: BoxDecoration(
color: const Color(0xFFE53935).withValues(alpha: 0.5),
shape: BoxShape.circle,
),
),
headerStyle: const NepaliHeaderStyle(
leftChevronIcon:
Icon(Icons.chevron_left, color: Color(0xFFE53935)),
rightChevronIcon:
Icon(Icons.chevron_right, color: Color(0xFFE53935)),
titleTextStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xFFE53935),
),
),
eventLoader: (day) => _events[day.toFormattedString()] ?? [],
onDaySelected: (bsDate, adDate) {
setState(() => _selectedDate = bsDate);
},
),
),
),
const SizedBox(height: 16),
// ── Selected date info ───────────────────────────────────────────
if (_selectedDate != null) ...[
const Text(
'Selected Date',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Card(
color: const Color(0xFFE53935).withValues(alpha: 0.08),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_InfoRow(
label: 'BS (formatted)',
value: _selectedDate!.toFormattedString()),
_InfoRow(
label: 'BS (English)',
value: _selectedDate!.toReadableStringEn()),
_InfoRow(
label: 'BS (Nepali)',
value: _selectedDate!.toReadableStringNp()),
_InfoRow(
label: 'AD',
value: NepaliDateConverter.bsToAd(_selectedDate!)
.toLocal()
.toString()
.split(' ')[0]),
],
),
),
),
],
const SizedBox(height: 16),
const Divider(),
// ── Date picker button ───────────────────────────────────────────
const Text(
'Date Picker Dialog',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFE53935),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
),
icon: const Icon(Icons.calendar_today),
label: const Text('Open Nepali Date Picker'),
onPressed: () async {
final result = await showNepaliDatePicker(
context: context,
initialDate: _selectedDate ?? today,
locale: _locale,
showEnglishDate: _showEnglishDate,
primaryColor: const Color(0xFFE53935),
);
if (result != null) {
setState(() => _selectedDate = result.bsDate);
}
},
),
const SizedBox(height: 32),
const Divider(),
// ── Converter demo ───────────────────────────────────────────────
const Text(
'Converter: Today',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_InfoRow(
label: 'AD today',
value: DateTime.now()
.toLocal()
.toString()
.split(' ')[0]),
_InfoRow(
label: 'BS today',
value: NepaliDateConverter.toReadableEn(DateTime.now())),
_InfoRow(
label: 'BS (Nepali)',
value: NepaliDateConverter.toReadableNp(DateTime.now())),
],
),
),
),
const SizedBox(height: 32),
],
),
),
);
}
}
class _InfoRow extends StatelessWidget {
final String label;
final String value;
const _InfoRow({required this.label, required this.value});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Row(
children: [
Text('$label: ',
style: const TextStyle(
fontWeight: FontWeight.w600, color: Colors.black54)),
Text(value,
style: const TextStyle(fontWeight: FontWeight.bold)),
],
),
);
}
}