feat: Refactor code structure and optimize performance across multiple modules

This commit is contained in:
Achintha Isuru
2025-11-17 23:29:28 -05:00
parent 831570f2e0
commit a64cbd9edf
1508 changed files with 105319 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
class CalendarButtonSectionWidget extends StatelessWidget {
const CalendarButtonSectionWidget({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const Gap(16),
BlocSelector<ScheduleBloc, ScheduleState, bool>(
selector: (state) =>
state.tempSchedules.firstOrNull?.isViableForSaving ?? false,
builder: (context, isEnabled) {
return KwButton.primary(
label: 'save_slots'.tr(),
disabled: !isEnabled,
onPressed: () {
BlocProvider.of<ScheduleBloc>(context)
.add(const ScheduleEventSave());
},
);
},
),
const Gap(12),
KwButton.outlinedPrimary(
label: 'cancel'.tr(),
onPressed: () {
BlocProvider.of<ScheduleBloc>(context)
.add(const ScheduleEventCancel());
},
)
],
);
}
}

View File

@@ -0,0 +1,191 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:intl/intl.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_popup_menu.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
class CalendarDataDetailSettingWidget extends StatefulWidget {
const CalendarDataDetailSettingWidget({
super.key,
required this.selectedDate,
});
final DateTime? selectedDate;
@override
State<CalendarDataDetailSettingWidget> createState() =>
_CalendarDataDetailSettingWidgetState();
}
class _CalendarDataDetailSettingWidgetState
extends State<CalendarDataDetailSettingWidget> {
var mode = SelectionMode.empty;
@override
Widget build(BuildContext context) {
final selectedDate = widget.selectedDate;
if (selectedDate == null) return const SizedBox.shrink();
return Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.graySecondaryFrame,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'selected_date_details'.tr(),
style: AppTextStyles.bodyMediumMed,
),
const Divider(
color: AppColors.grayTintStroke,
),
Row(
children: [
Expanded(
child: Text(
DateFormat('EEEE, MMMM d', context.locale.languageCode).format(selectedDate),
overflow: TextOverflow.ellipsis,
style: AppTextStyles.headingH3,
),
),
const Gap(8),
_buildKwPopupMenu(context, selectedDate),
],
),
const Gap(16),
Row(
children: [
Expanded(
child: KwButton.outlinedPrimary(
label: 'cancel'.tr(),
onPressed: () {
context.read<ScheduleBloc>().add(
const ScheduleEventChangeMode(
isInScheduleAddMode: false,
),
);
},
),
),
const Gap(8),
Expanded(
child: KwButton.primary(
disabled: mode == SelectionMode.empty,
label: 'choose_time'.tr(),
onPressed: () {
BlocProvider.of<ScheduleBloc>(context).add(
ScheduleEventChangeMode(
isInEditScheduleMode: true,
isWeekly: mode == SelectionMode.weekly,
),
);
},
),
),
],
),
],
),
);
}
KwPopupMenu _buildKwPopupMenu(BuildContext context, DateTime selectedDate) {
return KwPopupMenu(
customButtonBuilder: (_, isOpened) {
return _buildPopupButton(isOpened, selectedDate);
},
menuItems: [
KwPopupMenuItem(
icon: Assets.images.icons.calendarV2.svg(
height: 16,
width: 16,
),
title: 'date'.tr(),
onTap: () {
setState(() {
mode = SelectionMode.single;
});
},
),
KwPopupMenuItem(
icon: Assets.images.icons.calendar.svg(
height: 16,
width: 16,
),
title: '${'all'.tr()} ${DateFormat('EEEE', context.locale.languageCode).format(selectedDate)}',
onTap: () {
setState(() {
mode = SelectionMode.weekly;
});
},
)
],
);
}
Widget _buildPopupButton(bool isOpened, DateTime selectedDate) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 34,
padding: const EdgeInsets.only(left: 12, right: 10),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(17),
border: Border.all(
color: isOpened ? AppColors.bgColorDark : AppColors.grayTintStroke,
width: 1,
),
),
child: Row(
children: [
if (mode == SelectionMode.empty)
Text(
'modify'.tr(),
style: AppTextStyles.bodySmallMed,
)
else
RichText(
text: TextSpan(
children: [
TextSpan(
text: '${'modify'.tr()}: ',
style: AppTextStyles.bodyMediumMed.copyWith(
color: AppColors.blackGray,
),
),
TextSpan(
text: '${mode == SelectionMode.single ? 'one'.tr() : 'all'.tr()} '
'${DateFormat('EEEE', context.locale.languageCode).format(selectedDate)}',
style: AppTextStyles.bodyMediumMed,
),
],
),
),
const Gap(4),
AnimatedRotation(
duration: const Duration(milliseconds: 150),
turns: isOpened ? -0.5 : 0,
child: Assets.images.icons.caretDown.svg(
height: 16,
width: 16,
),
)
],
),
);
}
}
enum SelectionMode {empty, single, weekly}

View File

@@ -0,0 +1,152 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/kw_time_slot.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
import 'package:krow/features/profile/schedule/domain/entities/schedule_slot.dart';
class CalendarEditSlot extends StatelessWidget {
const CalendarEditSlot({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<ScheduleBloc, ScheduleState>(
buildWhen: (previous, current) {
return previous.scheduleErrorText != current.scheduleErrorText ||
previous.tempSchedules != current.tempSchedules;
},
builder: (context, state) {
final daySchedule = state.tempSchedules.first;
return Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: AppColors.graySecondaryFrame,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'what_hours_available'.tr(),
style: AppTextStyles.bodyMediumMed,
),
const Divider(
color: AppColors.grayTintStroke,
),
AnimatedSize(
duration: const Duration(milliseconds: 300),
alignment: Alignment.topCenter,
child: Column(
children: [
for (int i = 0; i < daySchedule.slots.length; i++)
_CalendarEditSlotItemWidget(
slot: daySchedule.slots[i],
slotIndex: i,
),
],
),
),
if (state.scheduleErrorText.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(
state.scheduleErrorText,
style: AppTextStyles.bodyTinyReg.copyWith(
color: AppColors.statusError,
),
),
),
const Gap(16),
KwButton.secondary(
label: 'add_slot'.tr(),
leftIcon: Assets.images.icons.add,
onPressed: () {
BlocProvider.of<ScheduleBloc>(context).add(
const ScheduleEventAddSlot(),
);
},
)
],
),
);
},
);
}
}
class _CalendarEditSlotItemWidget extends StatelessWidget {
const _CalendarEditSlotItemWidget({
required this.slot,
required this.slotIndex,
});
final ScheduleSlot slot;
final int slotIndex;
@override
Widget build(BuildContext context) {
return Column(
children: [
const Gap(8),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: KwTimeSlotInput(
label: 'start_time'.tr(),
initialValue: slot.startTime,
onChange: (DateTime start) {
BlocProvider.of<ScheduleBloc>(context).add(
ScheduleEventEditSlot(
start: start,
slot: slot,
slotIndex: slotIndex,
),
);
},
),
),
const Gap(8),
Expanded(
child: KwTimeSlotInput(
label: 'end_time'.tr(),
initialValue: slot.endTime,
onChange: (DateTime end) {
BlocProvider.of<ScheduleBloc>(context).add(
ScheduleEventEditSlot(
end: end,
slot: slot,
slotIndex: slotIndex,
),
);
},
),
),
const Gap(8),
KwButton.secondary(
onPressed: () {
BlocProvider.of<ScheduleBloc>(context).add(
ScheduleEventRemoveSlot(
slot: slot,
slotIndex: slotIndex,
),
);
},
leftIcon: Assets.images.icons.x,
fit: KwButtonFit.circular,
)
],
),
],
);
}
}

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/features/profile/schedule/domain/entities/day_shedule.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
import 'package:krow/features/profile/schedule/presentation/widgets/calendar_data_detail_setting_widget.dart';
import 'package:krow/features/profile/schedule/presentation/widgets/calendar_legend_widget.dart';
class CalendarFooterWidget extends StatelessWidget {
const CalendarFooterWidget({
super.key,
required this.selectedDates,
required this.existedSlots,
});
final List<DateTime> selectedDates;
final List<DaySchedule> existedSlots;
@override
Widget build(BuildContext context) {
return BlocSelector<ScheduleBloc, ScheduleState, bool>(
selector: (state) => state.isScheduleAddMode,
builder: (context, isInScheduleAddMode) {
return AnimatedCrossFade(
duration: Durations.short4,
crossFadeState: isInScheduleAddMode
? CrossFadeState.showSecond
: CrossFadeState.showFirst,
firstChild: CalendarLegendWidget(
selectedDates: selectedDates,
existedSlots: existedSlots,
),
secondChild: CalendarDataDetailSettingWidget(
selectedDate: selectedDates.firstOrNull,
),
);
},
);
}
}

View File

@@ -0,0 +1,117 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/features/profile/schedule/domain/entities/day_shedule.dart';
import 'package:krow/features/profile/schedule/presentation/widgets/shared_functions.dart';
class CalendarLegendWidget extends StatelessWidget {
const CalendarLegendWidget({
super.key,
required this.selectedDates,
required this.existedSlots,
});
final List<DateTime> selectedDates;
final List<DaySchedule> existedSlots;
@override
Widget build(BuildContext context) {
final selectedDatesOption = _getSelectedDatesOption();
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: const BoxDecoration(
color: AppColors.grayPrimaryFrame,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Divider(
color: AppColors.grayTintStroke,
),
const Gap(8),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 16,
width: 16,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: AppColors.bgColorDark,
),
),
const Gap(8),
Text(
'available'.tr(),
style: AppTextStyles.bodyMediumReg,
),
const Gap(32),
Container(
height: 16,
width: 16,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: AppColors.blackCaptionText,
),
),
const Gap(8),
Text(
'not_available'.tr(),
style: AppTextStyles.bodyMediumReg,
),
const Spacer(),
if (selectedDates.isEmpty)
const SizedBox(
height: 34,
)
else
Container(
decoration: BoxDecoration(
border: Border.all(
color: AppColors.grayTintStroke,
),
borderRadius: BorderRadius.circular(16),
),
child: KwButton.secondary(
height: 32,
label: switch (selectedDatesOption) {
SelectedDatesOption.add => 'add'.tr(),
SelectedDatesOption.edit => 'edit'.tr(),
SelectedDatesOption.editAll => 'edit_all'.tr(),
},
onPressed: () => onEditButtonPress(
context,
selectedDatesOption: selectedDatesOption,
isWeeklySchedule: existedSlots.length == 1 &&
existedSlots.first.isWeekly,
),
rightIcon: existedSlots.isNotEmpty
? Assets.images.icons.edit
: Assets.images.icons.add,
),
),
],
),
const Gap(24),
],
),
);
}
SelectedDatesOption _getSelectedDatesOption() {
if (existedSlots.isEmpty) return SelectedDatesOption.add;
return existedSlots.length > 1 || selectedDates.length > 1
? SelectedDatesOption.editAll
: SelectedDatesOption.edit;
}
}

View File

@@ -0,0 +1,184 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:intl/intl.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_box_decorations.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/dialogs/kw_dialog.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_popup_menu.dart';
import 'package:krow/features/profile/schedule/domain/entities/day_shedule.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
import 'package:krow/features/profile/schedule/domain/entities/schedule_slot.dart';
import 'package:krow/features/profile/schedule/presentation/widgets/shared_functions.dart';
import '../../../../../app.dart';
class CalendarSlotListWidget extends StatelessWidget {
const CalendarSlotListWidget({
super.key,
required this.selectedSchedules,
});
final List<DaySchedule> selectedSchedules;
static final timeFormat = DateFormat('h:mma', 'en');
Future<void> _onDeleteButtonPress(
BuildContext context,
DaySchedule schedule,
) async {
final scheduleBloc = context.read<ScheduleBloc>();
if (!schedule.isWeekly) {
scheduleBloc.add(
ScheduleEventDeleteSchedule(schedule: schedule),
);
return;
}
await KwDialog.show(
context: context,
state: KwDialogState.warning,
icon: Assets.images.icons.alertTriangle,
title: 'delete_schedule'.tr(),
message: 'delete_schedule_message'.tr(args: [(DateFormat('EEEE', context.locale.languageCode).format(schedule.date))]),
primaryButtonLabel: 'confirm'.tr(),
secondaryButtonLabel: 'cancel'.tr(),
onPrimaryButtonPressed: (dialogContext) {
scheduleBloc.add(
ScheduleEventDeleteSchedule(schedule: schedule),
);
Navigator.of(dialogContext).pop();
},
);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ScheduleBloc, ScheduleState>(
buildWhen: (previous, current) =>
previous.selectedDates != current.selectedDates,
builder: (context, state) {
if (state.selectedDates.isEmpty) return const SizedBox.shrink();
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Gap(12),
Text(
'slot_details'.tr(),
style: AppTextStyles.bodySmallMed,
),
const Gap(12),
for (var schedule in selectedSchedules)
_buildInfoWidget(context, schedule),
],
);
},
);
}
Widget _buildInfoWidget(context, DaySchedule schedule) {
return Container(
margin: const EdgeInsets.only(top: 12),
padding: const EdgeInsets.all(12),
decoration: KwBoxDecorations.primaryLight8,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Container(
height: 36,
width: 36,
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: AppColors.grayStroke,
width: 1,
),
),
child: Center(
child: Assets.images.icons.calendar.svg(),
),
),
const Gap(12),
Text(
DateFormat('MMMM d', appContext!.locale.languageCode).format(schedule.date),
style: AppTextStyles.headingH3,
),
const Spacer(),
KwPopupMenu(
horizontalMargin: 24,
menuItems: [
KwPopupMenuItem(
title: 'edit'.tr(),
icon: Assets.images.icons.edit.svg(),
onTap: () => onEditButtonPress(
context,
editedDate: schedule.date,
isWeeklySchedule: schedule.isWeekly,
),
),
KwPopupMenuItem(
title: 'delete'.tr(),
textStyle: AppTextStyles.bodyMediumReg.copyWith(
color: AppColors.statusError,
),
icon: Assets.images.icons.trash.svg(),
onTap: () => _onDeleteButtonPress(context, schedule),
),
],
),
],
),
const Gap(12),
Text(
'time_slots'.tr(),
style: AppTextStyles.bodySmallMed.copyWith(
color: AppColors.blackGray,
),
),
for (var i = 0; i < schedule.slots.length / 2; i++)
Row(
children: [
_buildSlotWidget(context, schedule.slots[i * 2]),
const Gap(12),
schedule.slots.length > (i * 2 + 1)
? _buildSlotWidget(context, schedule.slots[i * 2 + 1])
: const Spacer(),
],
),
],
),
);
}
_buildSlotWidget(BuildContext context, ScheduleSlot slot) {
return Expanded(
child: Container(
margin: const EdgeInsets.only(top: 12),
height: 36,
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: AppColors.grayTintStroke,
width: 1,
),
),
child: Center(
child: Text(
'${timeFormat.format(slot.startTime)} - '
'${timeFormat.format(slot.endTime)}',
style: AppTextStyles.bodyMediumReg,
),
),
),
);
}
}

View File

@@ -0,0 +1,235 @@
import 'package:calendar_date_picker2/calendar_date_picker2.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
class ScheduleCalendar extends StatefulWidget {
const ScheduleCalendar({
super.key,
required this.selectedDates,
required this.onDateSelected,
required this.containsScheduleForDate,
required this.disabled,
});
// static const _monthNames = [
// 'Jan',
// 'Feb',
// 'Mar',
// 'Apr',
// 'May',
// 'Jun',
// 'Jul',
// 'Aug',
// 'Sep',
// 'Oct',
// 'Nov',
// 'Dec',
// ];
final List<DateTime> selectedDates;
final void Function(List<DateTime> value) onDateSelected;
final bool Function(DateTime date) containsScheduleForDate;
final bool disabled;
@override
State<ScheduleCalendar> createState() => _ScheduleCalendarState();
}
class _ScheduleCalendarState extends State<ScheduleCalendar> {
final currentDate = DateTime.now();
final selectedTextStyle = AppTextStyles.bodyMediumSmb.copyWith(
color: AppColors.grayWhite,
);
final dayTextStyle = AppTextStyles.bodyMediumReg.copyWith(
color: AppColors.bgColorDark,
);
late List<DateTime> _selectedDates =
_getStateSelectedDates(widget.selectedDates);
List<DateTime> _getStateSelectedDates(List<DateTime> selectedDates) {
if (selectedDates.isEmpty) return [];
return [
selectedDates.first,
if (selectedDates.length > 1) selectedDates.last,
];
}
@override
void didUpdateWidget(covariant ScheduleCalendar oldWidget) {
_selectedDates = _getStateSelectedDates(widget.selectedDates);
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return IgnorePointer(
ignoring: widget.disabled,
child: CalendarDatePicker2(
value: _selectedDates,
config: CalendarDatePicker2Config(
calendarType: CalendarDatePicker2Type.range,
selectedRangeHighlightColor: AppColors.tintGray,
selectedDayTextStyle: selectedTextStyle,
dayTextStyle: dayTextStyle,
selectedMonthTextStyle: selectedTextStyle,
selectedYearTextStyle: selectedTextStyle,
selectedDayHighlightColor: AppColors.bgColorDark,
centerAlignModePicker: true,
monthTextStyle: dayTextStyle,
weekdayLabelBuilder: _dayWeekBuilder,
dayBuilder: _dayBuilder,
monthBuilder: _monthBuilder,
yearBuilder: _yearBuilder,
controlsTextStyle: AppTextStyles.headingH3,
nextMonthIcon: Assets.images.icons.caretRight.svg(),
lastMonthIcon: Assets.images.icons.caretLeft.svg(),
customModePickerIcon: Padding(
padding: const EdgeInsets.only(left: 4),
child: Assets.images.icons.caretDown.svg(),
),
// modePickerBuilder: _controlBuilder,
),
onValueChanged: widget.onDateSelected,
),
);
}
Widget? _monthBuilder({
required int month,
TextStyle? textStyle,
BoxDecoration? decoration,
bool? isSelected,
bool? isDisabled,
bool? isCurrentMonth,
}) {
return Center(
child: Container(
margin: const EdgeInsets.only(top: 12),
height: 46,
decoration: BoxDecoration(
color: isSelected == true ? AppColors.blackDarkBgBody : null,
borderRadius: BorderRadius.circular(23),
border: Border.all(
color: AppColors.grayStroke,
width: isSelected == true ? 0 : 1,
),
),
child: Center(
child: Text(
DateFormat.MMM(context.locale.toLanguageTag()).format(
DateFormat('M').parse(month.toString()),
),
style: isSelected == true
? AppTextStyles.bodyMediumMed
.copyWith(color: AppColors.grayWhite)
: AppTextStyles.bodyMediumReg
.copyWith(color: AppColors.blackGray),
textAlign: TextAlign.center,
),
),
),
);
}
Widget? _yearBuilder({
required int year,
TextStyle? textStyle,
BoxDecoration? decoration,
bool? isSelected,
bool? isDisabled,
bool? isCurrentYear,
}) {
return Center(
child: Text(
year.toString(),
style: dayTextStyle,
textAlign: TextAlign.center,
),
);
}
Widget? _dayBuilder({
required DateTime date,
TextStyle? textStyle,
BoxDecoration? decoration,
bool? isSelected,
bool? isDisabled,
bool? isToday,
}) {
final eventExist = widget.containsScheduleForDate(date);
return Center(
child: Container(
margin: const EdgeInsets.only(left: 2, right: 2),
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected == true ? AppColors.bgColorDark : null,
borderRadius: BorderRadius.circular(20),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (eventExist) const Gap(5),
Text(
date.day.toString(),
style: isSelected == true
? selectedTextStyle
: AppTextStyles.bodyMediumReg.copyWith(
color: _isPast(date)
? AppColors.blackCaptionText
: AppColors.bgColorDark,
),
textAlign: TextAlign.center,
),
if (eventExist) ...[
const Gap(1),
DecoratedBox(
decoration: BoxDecoration(
color: isSelected == true
? AppColors.grayWhite
: AppColors.bgColorDark,
borderRadius: BorderRadius.circular(2),
),
child: const SizedBox(
height: 4,
width: 4,
),
),
],
const Gap(2),
],
),
),
);
}
bool _isPast(DateTime date) {
return date.isBefore(
DateTime(currentDate.year, currentDate.month, currentDate.day),
);
}
Widget? _dayWeekBuilder({
required int weekday,
bool? isScrollViewTopHeader,
}) {
print(DateFormat('d', 'en').parse((weekday).toString()));
return Text(
DateFormat.E(context.locale.toLanguageTag()).format(
DateTime(2020, 1, (5 + weekday)) // 5 is Monday, so we start from there),
),
style: AppTextStyles.bodyMediumSmb.copyWith(
color: AppColors.bgColorDark,
),
textAlign: TextAlign.center,
);
}
}

View File

@@ -0,0 +1,63 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/widgets/ui_kit/dialogs/kw_dialog.dart';
import 'package:krow/features/profile/schedule/domain/bloc/schedule_bloc.dart';
import 'package:krow/features/profile/schedule/presentation/widgets/weekly_option_selector.dart';
enum SelectedDatesOption { add, edit, editAll }
Future<void> onEditButtonPress(
BuildContext context, {
required bool isWeeklySchedule,
SelectedDatesOption selectedDatesOption = SelectedDatesOption.edit,
DateTime? editedDate,
}) async {
if (selectedDatesOption != SelectedDatesOption.edit) {
context.read<ScheduleBloc>().add(
const ScheduleEventChangeMode(
isInScheduleAddMode: true,
isInEditScheduleMode: true,
),
);
return;
}
if (!isWeeklySchedule) {
context.read<ScheduleBloc>().add(
ScheduleEventChangeMode(
isWeekly: false,
isInEditScheduleMode: true,
editedDate: editedDate,
),
);
return;
}
var isWeeklySelected = false;
await KwDialog.show(
context: context,
icon: Assets.images.icons.menuBoard,
title: 'update_schedule'.tr(),
message: 'update_schedule_message'.tr(),
primaryButtonLabel: 'submit_update'.tr(),
secondaryButtonLabel: 'cancel'.tr(),
onPrimaryButtonPressed: (dialogContext) {
context.read<ScheduleBloc>().add(
ScheduleEventChangeMode(
isWeekly: isWeeklySelected,
isInEditScheduleMode: true,
editedDate: editedDate,
),
);
Navigator.of(dialogContext).pop();
},
child: WeeklyOptionSelector(
onWeeklyToggle: (isWeekly) {
isWeeklySelected = isWeekly;
},
),
);
}

View File

@@ -0,0 +1,36 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_option_selector.dart';
class WeeklyOptionSelector extends StatefulWidget {
const WeeklyOptionSelector({
super.key,
required this.onWeeklyToggle,
});
final void Function(bool) onWeeklyToggle;
@override
State<WeeklyOptionSelector> createState() => _WeeklyOptionSelectorState();
}
class _WeeklyOptionSelectorState extends State<WeeklyOptionSelector> {
int selectedOption = 0;
@override
Widget build(BuildContext context) {
return KwOptionSelector(
selectedIndex: selectedOption,
selectedColor: AppColors.blackDarkBgBody,
itemBorder: const Border.fromBorderSide(
BorderSide(color: AppColors.grayStroke),
),
onChanged: (index) => setState(() {
selectedOption = index;
widget.onWeeklyToggle(selectedOption != 0);
}),
items: ['this_day_only'.tr(), 'entire_schedule'.tr()],
);
}
}