refactor effective period dialog

This commit is contained in:
ashrafzarkanisala
2024-07-27 22:45:59 +03:00
parent 0783f8dacd
commit b3b34eb4ce
6 changed files with 334 additions and 315 deletions

View File

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:time_picker_spinner/time_picker_spinner.dart';
class EffectPeriodHelper {
static Future<List<String>?> showCustomTimePicker(
BuildContext context) async {
String selectedStartTime = "00:00";
String selectedEndTime = "23:59";
PageController pageController = PageController(initialPage: 0);
DateTime startDateTime = DateTime(2022, 1, 1, 0, 0); // Fixed 00:00
DateTime endDateTime = DateTime(2022, 1, 1, 23, 59); // Fixed 23:59
context.customAlertDialog(
alertBody: SizedBox(
height: 250,
child: PageView(
controller: pageController,
physics: const NeverScrollableScrollPhysics(),
children: [
_buildTimePickerPage(
context: context,
pageController: pageController,
isStartTime: true,
time: startDateTime,
onTimeChange: (time) {
selectedStartTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
_buildTimePickerPage(
context: context,
pageController: pageController,
isStartTime: false,
time: endDateTime,
onTimeChange: (time) {
selectedEndTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
],
),
),
title: "Custom",
onConfirm: () {
context.read<EffectPeriodBloc>().add(
SetCustomTime(selectedStartTime, selectedEndTime),
);
context.read<EffectPeriodBloc>().add(
const SetPeriod('Custom'),
);
Navigator.of(context).pop();
},
);
return null;
}
static Widget _buildTimePickerPage({
required BuildContext context,
required PageController pageController,
required bool isStartTime,
required DateTime time,
required Function(DateTime) onTimeChange,
}) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (!isStartTime)
TextButton(
onPressed: () {
pageController.previousPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(text: "Start"),
),
TextButton(
onPressed: () {},
child: BodyMedium(
text: isStartTime ? "Start" : "End",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColor,
),
),
),
if (isStartTime)
TextButton(
onPressed: () {
pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(text: "End"),
),
],
),
),
TimePickerSpinner(
is24HourMode: false,
normalTextStyle: const TextStyle(
fontSize: 24,
color: Colors.grey,
),
highlightedTextStyle: const TextStyle(
fontSize: 24,
color: ColorsManager.primaryColor,
),
spacing: 20,
itemHeight: 50,
isForce2Digits: true,
time: time,
onTimeChange: onTimeChange,
),
const SizedBox(height: 16),
],
);
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/widgets/bottom_sheet/effective_period_bottom_sheet.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/effective_period_bottom_sheet.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';

View File

@ -1,314 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import 'package:time_picker_spinner/time_picker_spinner.dart';
class EffectPeriodBottomSheetContent extends StatefulWidget {
const EffectPeriodBottomSheetContent({super.key});
@override
State<EffectPeriodBottomSheetContent> createState() =>
_EffectPeriodBottomSheetContentState();
}
class _EffectPeriodBottomSheetContentState
extends State<EffectPeriodBottomSheetContent> {
Future<List<String>?> showCustomTimePicker(BuildContext context) async {
String selectedStartTime = "00:00";
String selectedEndTime = "23:59";
PageController pageController = PageController(initialPage: 0);
DateTime startDateTime = DateTime(2022, 1, 1, 0, 0); // Fixed 00:00
DateTime endDateTime = DateTime(2022, 1, 1, 23, 59); // Fixed 23:59
context.customAlertDialog(
alertBody: SizedBox(
height: 250,
child: PageView(
controller: pageController,
physics: const NeverScrollableScrollPhysics(),
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {},
child: BodyMedium(
text: "Start",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColor,
),
),
),
TextButton(
onPressed: () {
pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(
text: "End",
),
),
],
),
),
TimePickerSpinner(
is24HourMode: false,
normalTextStyle: const TextStyle(
fontSize: 24,
color: Colors.grey,
),
highlightedTextStyle: const TextStyle(
fontSize: 24,
color: ColorsManager.primaryColor,
),
spacing: 20,
itemHeight: 50,
isForce2Digits: true,
time: startDateTime,
onTimeChange: (time) {
selectedStartTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
const SizedBox(height: 16),
],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
pageController.previousPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(text: "Start"),
),
TextButton(
onPressed: () {},
child: BodyMedium(
text: "End",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColor,
),
),
),
],
),
),
TimePickerSpinner(
is24HourMode: false,
normalTextStyle: const TextStyle(
fontSize: 24,
color: Colors.grey,
),
highlightedTextStyle: const TextStyle(
fontSize: 24,
color: ColorsManager.primaryColor,
),
spacing: 20,
itemHeight: 50,
isForce2Digits: true,
time: endDateTime,
onTimeChange: (time) {
selectedEndTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
const SizedBox(height: 16),
],
),
],
),
),
title: "Custom",
onConfirm: () {
context.read<EffectPeriodBloc>().add(
SetCustomTime(selectedStartTime, selectedEndTime),
);
context.read<EffectPeriodBloc>().add(
const SetPeriod('Custom'),
);
Navigator.of(context).pop();
},
);
return null;
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => EffectPeriodBloc(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
BodyMedium(
text: 'Effective Period',
fontColor: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.bold,
),
const Divider(
color: ColorsManager.backgroundColor,
),
_buildPeriodOptions(context),
const SizedBox(height: 16),
_buildRepeatDays(context),
const SizedBox(height: 24),
],
),
),
);
}
Widget _buildPeriodOptions(BuildContext context) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Column(
children: [
_buildRadioOption(context, 'All Day', '24 Hours'),
_buildRadioOption(context, 'Daytime', 'Sunrise to Sunset'),
_buildRadioOption(context, 'Night', 'Sunset to Sunrise'),
ListTile(
contentPadding: EdgeInsets.zero,
onTap: () => showCustomTimePicker(context),
title: BodyMedium(
text: 'Custom',
fontColor: ColorsManager.primaryColorWithOpacity,
),
subtitle:
state.customStartTime != null && state.customEndTime != null
? BodySmall(
text:
'${"${state.customStartTime} AM"} - ${"${state.customEndTime} PM"}',
style: context.bodySmall.copyWith(fontSize: 10),
)
: BodySmall(
text: '00:00 AM - 11:59 PM',
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<String>(
value: 'Custom',
groupValue: state.selectedPeriod,
onChanged: (value) async {},
),
),
],
);
},
);
}
Widget _buildRadioOption(
BuildContext context, String value, String subtitle) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return ListTile(
contentPadding: EdgeInsets.zero,
onTap: () {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
},
title: BodyMedium(text: value),
subtitle: BodySmall(
text: subtitle,
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<String>(
value: value,
groupValue: state.selectedPeriod,
onChanged: (value) {
if (value != null) {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
}
},
),
);
},
);
}
Widget _buildRepeatDays(BuildContext context) {
final daysMap = {
'Mon': 'M',
'Tue': 'T',
'Wed': 'W',
'Thu': 'T',
'Fri': 'F',
'Sat': 'S',
'Sun': 'S',
};
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const BodyMedium(text: 'Repeat'),
const SizedBox(width: 8),
BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final isSelected = state.selectedDays.contains(day);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
isSelected ? Colors.grey : Colors.grey.shade300,
width: 1,
),
),
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Text(
abbreviation,
style: TextStyle(
fontSize: 20,
color:
isSelected ? Colors.grey : Colors.grey.shade300,
),
),
),
),
),
);
}).toList(),
);
},
),
],
);
}
}

View File

@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/period_options.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/repeat_days.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import '../../helper/effect_period_helper.dart';
class EffectPeriodBottomSheetContent extends StatelessWidget {
const EffectPeriodBottomSheetContent({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => EffectPeriodBloc(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
BodyMedium(
text: 'Effective Period',
fontColor: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.bold,
),
const Divider(
color: ColorsManager.backgroundColor,
),
const PeriodOptions(
showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker,
),
const SizedBox(height: 16),
const RepeatDays(),
const SizedBox(height: 24),
],
),
),
);
}
}

View File

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class PeriodOptions extends StatelessWidget {
final Future<List<String>?> Function(BuildContext) showCustomTimePicker;
const PeriodOptions({
required this.showCustomTimePicker,
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Column(
children: [
_buildRadioOption(context, 'All Day', '24 Hours'),
_buildRadioOption(context, 'Daytime', 'Sunrise to Sunset'),
_buildRadioOption(context, 'Night', 'Sunset to Sunrise'),
ListTile(
contentPadding: EdgeInsets.zero,
onTap: () => showCustomTimePicker(context),
title: BodyMedium(
text: 'Custom',
fontColor: ColorsManager.primaryColorWithOpacity,
),
subtitle:
state.customStartTime != null && state.customEndTime != null
? BodySmall(
text:
'${"${state.customStartTime} AM"} - ${"${state.customEndTime} PM"}',
style: context.bodySmall.copyWith(fontSize: 10),
)
: BodySmall(
text: '00:00 AM - 11:59 PM',
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<String>(
value: 'Custom',
groupValue: state.selectedPeriod,
onChanged: (value) async {},
),
),
],
);
},
);
}
Widget _buildRadioOption(
BuildContext context, String value, String subtitle) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return ListTile(
contentPadding: EdgeInsets.zero,
onTap: () {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
},
title: BodyMedium(text: value),
subtitle: BodySmall(
text: subtitle,
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<String>(
value: value,
groupValue: state.selectedPeriod,
onChanged: (value) {
if (value != null) {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
}
},
),
);
},
);
}
}

View File

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
class RepeatDays extends StatelessWidget {
const RepeatDays({super.key});
@override
Widget build(BuildContext context) {
final daysMap = {
'Mon': 'M',
'Tue': 'T',
'Wed': 'W',
'Thu': 'T',
'Fri': 'F',
'Sat': 'S',
'Sun': 'S',
};
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const BodyMedium(text: 'Repeat'),
const SizedBox(width: 8),
BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final isSelected = state.selectedDays.contains(day);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
isSelected ? Colors.grey : Colors.grey.shade300,
width: 1,
),
),
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Text(
abbreviation,
style: TextStyle(
fontSize: 16,
color:
isSelected ? Colors.grey : Colors.grey.shade300,
),
),
),
),
),
);
}).toList(),
);
},
),
],
);
}
}