mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-08-25 14:29:41 +00:00
Implement-Calendar-ui
This commit is contained in:
@ -1,52 +1,235 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:calendar_view/calendar_view.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/date_selection/date_selection_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/date_selection/date_selection_event.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/date_selection/date_selection_state.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/selected_bookable_space_bloc/selected_bookable_space_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/booking_sidebar.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/custom_calendar_page.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/icon_text_button.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/weekly_calendar_page.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class BookingPage extends StatelessWidget {
|
||||
class BookingPage extends StatefulWidget {
|
||||
const BookingPage({super.key});
|
||||
|
||||
@override
|
||||
State<BookingPage> createState() => _BookingPageState();
|
||||
}
|
||||
|
||||
class _BookingPageState extends State<BookingPage> {
|
||||
late final EventController _eventController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_eventController = EventController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_eventController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
List<CalendarEventData> _generateDummyEventsForWeek(DateTime weekStart) {
|
||||
final List<CalendarEventData> events = [];
|
||||
for (int i = 0; i < 7; i++) {
|
||||
final date = weekStart.add(Duration(days: i));
|
||||
events.add(CalendarEventData(
|
||||
date: date,
|
||||
startTime: date.copyWith(hour: 9, minute: 0),
|
||||
endTime: date.copyWith(hour: 10, minute: 30),
|
||||
title: 'Team Meeting',
|
||||
description: 'Daily standup',
|
||||
color: Colors.blue,
|
||||
));
|
||||
events.add(CalendarEventData(
|
||||
date: date,
|
||||
startTime: date.copyWith(hour: 14, minute: 0),
|
||||
endTime: date.copyWith(hour: 15, minute: 0),
|
||||
title: 'Client Call',
|
||||
description: 'Project discussion',
|
||||
color: Colors.green,
|
||||
));
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
void _loadEventsForWeek(DateTime weekStart) {
|
||||
_eventController.removeWhere((_) => true);
|
||||
_eventController.addAll(_generateDummyEventsForWeek(weekStart));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: Colors.blueGrey[100],
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Side bar',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(create: (_) => SelectedBookableSpaceBloc()),
|
||||
BlocProvider(create: (_) => DateSelectionBloc()),
|
||||
],
|
||||
child: BlocListener<DateSelectionBloc, DateSelectionState>(
|
||||
listenWhen: (previous, current) =>
|
||||
previous.weekStart != current.weekStart,
|
||||
listener: (context, state) {
|
||||
_loadEventsForWeek(state.weekStart);
|
||||
},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: BlocBuilder<SelectedBookableSpaceBloc,
|
||||
SelectedBookableSpaceState>(
|
||||
builder: (context, state) {
|
||||
return BookingSidebar(
|
||||
onRoomSelected: (id) {
|
||||
context
|
||||
.read<SelectedBookableSpaceBloc>()
|
||||
.add(SelectBookableSpace(id));
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: BlocBuilder<DateSelectionBloc, DateSelectionState>(
|
||||
builder: (context, dateState) {
|
||||
return Container(
|
||||
color: Colors.grey[300],
|
||||
child: CustomCalendarPage(
|
||||
selectedDate: dateState.selectedDate,
|
||||
onDateChanged: (day, month, year) {
|
||||
final newDate = DateTime(year, month, day);
|
||||
context
|
||||
.read<DateSelectionBloc>()
|
||||
.add(SelectDate(newDate));
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SvgTextButton(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SvgTextButton(
|
||||
svgAsset: Assets.homeIcon,
|
||||
label: 'Manage Bookable Spaces',
|
||||
onPressed: () {}),
|
||||
SizedBox(width: 20),
|
||||
SvgTextButton(
|
||||
onPressed: () {},
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
SvgTextButton(
|
||||
svgAsset: Assets.groupIcon,
|
||||
label: 'Manage Users',
|
||||
onPressed: () {})
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
BlocBuilder<DateSelectionBloc, DateSelectionState>(
|
||||
builder: (context, state) {
|
||||
final weekStart = state.weekStart;
|
||||
final weekEnd =
|
||||
weekStart.add(const Duration(days: 6));
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: ColorsManager.textGray,
|
||||
blurRadius: 12,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios,
|
||||
color: Colors.black),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<DateSelectionBloc>()
|
||||
.add(PreviousWeek());
|
||||
},
|
||||
),
|
||||
Text(
|
||||
_getMonthYearText(weekStart, weekEnd),
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_forward_ios,
|
||||
color: Colors.black),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<DateSelectionBloc>()
|
||||
.add(NextWeek());
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: BlocBuilder<DateSelectionBloc, DateSelectionState>(
|
||||
builder: (context, dateState) {
|
||||
return WeeklyCalendarPage(
|
||||
weekStart: dateState.weekStart,
|
||||
selectedDate: dateState.selectedDate,
|
||||
eventController: _eventController,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getMonthYearText(DateTime start, DateTime end) {
|
||||
final startMonth = DateFormat('MMM').format(start);
|
||||
final endMonth = DateFormat('MMM').format(end);
|
||||
final year = start.year == end.year
|
||||
? start.year.toString()
|
||||
: '${start.year}-${end.year}';
|
||||
|
||||
if (start.month == end.month) {
|
||||
return '$startMonth $year';
|
||||
} else {
|
||||
return '$startMonth - $endMonth $year';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,182 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/sidebar/sidebar_bloc.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/sidebar/sidebar_event.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/bloc/sidebar/sidebar_state.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/room_list_item.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class BookingSidebar extends StatelessWidget {
|
||||
final void Function(int) onRoomSelected;
|
||||
|
||||
const BookingSidebar({
|
||||
super.key,
|
||||
required this.onRoomSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SidebarBloc()..add(LoadRoomsEvent()),
|
||||
child: _SidebarContent(onRoomSelected: onRoomSelected),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SidebarContent extends StatelessWidget {
|
||||
final void Function(int) onRoomSelected;
|
||||
|
||||
const _SidebarContent({
|
||||
required this.onRoomSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: ColorsManager.blackColor.withOpacity(0.1),
|
||||
offset: const Offset(3, 0),
|
||||
blurRadius: 6,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: BlocBuilder<SidebarBloc, SidebarState>(
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: [
|
||||
const _SidebarHeader(title: 'Spaces'),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: ColorsManager.blackColor.withOpacity(0.1),
|
||||
offset: const Offset(0, -2),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
BoxShadow(
|
||||
color: ColorsManager.blackColor.withOpacity(0.1),
|
||||
offset: const Offset(0, 2),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 8.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.counterBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
child: TextField(
|
||||
style:
|
||||
Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
controller: searchController,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<SidebarBloc>()
|
||||
.add(SearchRoomsEvent(value));
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search',
|
||||
suffixIcon: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: SvgPicture.asset(
|
||||
Assets.searchIconUser,
|
||||
color: ColorsManager.primaryTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 8, horizontal: 12),
|
||||
border: const OutlineInputBorder(
|
||||
borderSide: BorderSide.none),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (state.isLoading)
|
||||
const Expanded(
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
)
|
||||
else if (state.errorMessage != null)
|
||||
Expanded(
|
||||
child: Center(child: Text(state.errorMessage!)),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: state.displayedRooms.length,
|
||||
itemBuilder: (context, index) {
|
||||
final room = state.displayedRooms[index];
|
||||
return RoomListItem(
|
||||
room: room,
|
||||
isSelected: state.selectedRoomId == room.id,
|
||||
onTap: () {
|
||||
context
|
||||
.read<SidebarBloc>()
|
||||
.add(SelectRoomEvent(room.id));
|
||||
onRoomSelected(room.id);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SidebarHeader extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const _SidebarHeader({
|
||||
required this.title,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.primaryTextColor,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomCalendarPage extends StatefulWidget {
|
||||
final DateTime selectedDate;
|
||||
final Function(int day, int month, int year) onDateChanged;
|
||||
|
||||
const CustomCalendarPage({
|
||||
super.key,
|
||||
required this.selectedDate,
|
||||
required this.onDateChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CustomCalendarPage> createState() => _CustomCalendarPageState();
|
||||
}
|
||||
|
||||
class _CustomCalendarPageState extends State<CustomCalendarPage> {
|
||||
late DateTime _selectedDate;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedDate = widget.selectedDate;
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(CustomCalendarPage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.selectedDate != oldWidget.selectedDate) {
|
||||
setState(() {
|
||||
_selectedDate = widget.selectedDate;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CalendarDatePicker(
|
||||
initialDate: _selectedDate,
|
||||
firstDate: DateTime(2000),
|
||||
lastDate: DateTime(2100),
|
||||
onDateChanged: (date) {
|
||||
widget.onDateChanged(date.day, date.month, date.year);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/access_management/booking_system/model/bookable_room.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class RoomListItem extends StatelessWidget {
|
||||
final BookableRoom room;
|
||||
final bool isSelected;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const RoomListItem({
|
||||
required this.room,
|
||||
required this.isSelected,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
hoverColor: ColorsManager.primaryColor.withOpacity(0.05),
|
||||
child: Container(
|
||||
height: 40,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Row(
|
||||
children: [
|
||||
IgnorePointer(
|
||||
child: Radio<int>(
|
||||
value: room.id,
|
||||
groupValue: isSelected ? room.id : null,
|
||||
onChanged: (value) {},
|
||||
activeColor: ColorsManager.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
room.name,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
fontWeight:
|
||||
isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,236 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:calendar_view/calendar_view.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class WeeklyCalendarPage extends StatelessWidget {
|
||||
final DateTime weekStart;
|
||||
final DateTime selectedDate;
|
||||
final EventController eventController;
|
||||
|
||||
const WeeklyCalendarPage({
|
||||
super.key,
|
||||
required this.weekStart,
|
||||
required this.selectedDate,
|
||||
required this.eventController,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final weekDays = _getWeekDays(weekStart);
|
||||
weekDays.indexWhere((d) => isSameDay(d, selectedDate));
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final double calendarWidth = constraints.maxWidth;
|
||||
const double timeLineWidth = 80;
|
||||
const int totalDays = 7;
|
||||
final double dayColumnWidth =
|
||||
(calendarWidth - timeLineWidth) / totalDays;
|
||||
final selectedDayIndex = (selectedDate != null)
|
||||
? weekDays.indexWhere((d) => isSameDay(d, selectedDate))
|
||||
: -1;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 25.0, right: 25.0, top: 25),
|
||||
child: Stack(
|
||||
children: [
|
||||
WeekView(
|
||||
key: ValueKey(weekStart),
|
||||
controller: eventController,
|
||||
initialDay: weekStart,
|
||||
startHour: 7,
|
||||
endHour: 18,
|
||||
heightPerMinute: 1.1,
|
||||
showLiveTimeLineInAllDays: false,
|
||||
showVerticalLines: true,
|
||||
emulateVerticalOffsetBy: -80,
|
||||
startDay: WeekDays.monday,
|
||||
liveTimeIndicatorSettings: const LiveTimeIndicatorSettings(
|
||||
showBullet: false,
|
||||
height: 0,
|
||||
),
|
||||
weekDayBuilder: (date) {
|
||||
final weekDays = _getWeekDays(weekStart);
|
||||
final selectedDayIndex =
|
||||
weekDays.indexWhere((d) => isSameDay(d, selectedDate));
|
||||
final index = weekDays.indexWhere((d) => isSameDay(d, date));
|
||||
final isSelectedDay = index == selectedDayIndex;
|
||||
final isToday = isSameDay(date, DateTime.now());
|
||||
|
||||
return Container(
|
||||
decoration: isSelectedDay
|
||||
? BoxDecoration(
|
||||
color: ColorsManager.blue1.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
)
|
||||
: isToday
|
||||
? BoxDecoration(
|
||||
color: ColorsManager.blue1.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
)
|
||||
: null,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
DateFormat('EEE').format(date).toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
color: isSelectedDay ? Colors.blue : Colors.black,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
DateFormat('d').format(date),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
color: isSelectedDay
|
||||
? ColorsManager.blue1
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
timeLineBuilder: (date) {
|
||||
int hour = date.hour == 0
|
||||
? 12
|
||||
: (date.hour > 12 ? date.hour - 12 : date.hour);
|
||||
String period = date.hour >= 12 ? 'PM' : 'AM';
|
||||
return Container(
|
||||
height: 60,
|
||||
alignment: Alignment.center,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '$hour',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 24,
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 2, top: 6),
|
||||
child: Text(
|
||||
period,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor,
|
||||
letterSpacing: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
alignment: PlaceholderAlignment.baseline,
|
||||
baseline: TextBaseline.alphabetic,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
timeLineWidth: timeLineWidth,
|
||||
weekPageHeaderBuilder: (start, end) => Container(),
|
||||
weekTitleHeight: 60,
|
||||
weekNumberBuilder: (firstDayOfWeek) => Text(
|
||||
firstDayOfWeek.timeZoneName,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
eventTileBuilder: (date, events, boundary, start, end) {
|
||||
return Container(
|
||||
margin:
|
||||
const EdgeInsets.symmetric(vertical: 2, horizontal: 2),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: events.map((event) {
|
||||
final bool isEventEnded = event.endTime != null &&
|
||||
event.endTime!.isBefore(DateTime.now());
|
||||
return Expanded(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: isEventEnded
|
||||
? ColorsManager.grayColor
|
||||
: ColorsManager.lightGrayColor
|
||||
.withOpacity(0.25),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
DateFormat('h:mm a').format(event.startTime!),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
event.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// Highlight the selected day column
|
||||
if (selectedDayIndex >= 0)
|
||||
Positioned(
|
||||
left: timeLineWidth + dayColumnWidth * selectedDayIndex,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: dayColumnWidth,
|
||||
child: IgnorePointer(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 0, horizontal: 2),
|
||||
color: ColorsManager.blue1.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 50,
|
||||
bottom: 0,
|
||||
child: IgnorePointer(
|
||||
child: Container(
|
||||
width: 1,
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
List<DateTime> _getWeekDays(DateTime date) {
|
||||
final int weekday = date.weekday;
|
||||
final DateTime monday = date.subtract(Duration(days: weekday - 1));
|
||||
return List.generate(7, (i) => monday.add(Duration(days: i)));
|
||||
}
|
||||
}
|
||||
|
||||
bool isSameDay(DateTime d1, DateTime d2) {
|
||||
return d1.year == d2.year && d1.month == d2.month && d1.day == d2.day;
|
||||
}
|
Reference in New Issue
Block a user