bug fixes 2

This commit is contained in:
mohammad
2024-09-23 14:37:07 +03:00
parent 62e80c89a2
commit 429009aefa
11 changed files with 863 additions and 661 deletions

View File

@ -8,7 +8,6 @@ import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/authentication_api.dart'; import 'package:syncrow_app/services/api/authentication_api.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart'; import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';

View File

@ -16,7 +16,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
DoorSensorBloc({ DoorSensorBloc({
required this.DSId, required this.DSId,
}) : super(const DoorSensorState()) { }) : super(const DoorSensorState()) {
on<DoorSensorInitial>(_fetchWaterHeaterStatus); on<DoorSensorInitial>(_fetchStatus);
on<ReportLogsInitial>(fetchLogsForLastMonth); on<ReportLogsInitial>(fetchLogsForLastMonth);
on<ToggleLowBatteryEvent>(_toggleLowBattery); on<ToggleLowBatteryEvent>(_toggleLowBattery);
on<ToggleClosingReminderEvent>(_toggleClosingReminder); on<ToggleClosingReminderEvent>(_toggleClosingReminder);
@ -26,9 +26,11 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
bool lowBattery = false; bool lowBattery = false;
bool closingReminder = false; bool closingReminder = false;
bool doorAlarm = false; bool doorAlarm = false;
DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0); DoorSensorModel deviceStatus =
DoorSensorModel(doorContactState: false, batteryPercentage: 0);
void _fetchWaterHeaterStatus(DoorSensorInitial event, Emitter<DoorSensorState> emit) async { void _fetchStatus(
DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
emit(DoorSensorLoadingState()); emit(DoorSensorLoadingState());
try { try {
var response = await DevicesAPI.getDeviceStatus(DSId); var response = await DevicesAPI.getDeviceStatus(DSId);
@ -49,7 +51,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
// Toggle functions for each switch // Toggle functions for each switch
void _toggleLowBattery(ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async { void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
lowBattery = event.isLowBatteryEnabled; lowBattery = event.isLowBatteryEnabled;
@ -90,7 +93,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
} }
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async { void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
doorAlarm = event.isDoorAlarmEnabled; doorAlarm = event.isDoorAlarmEnabled;
@ -110,9 +114,11 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
} }
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []); DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(ReportLogsInitial event, Emitter<DoorSensorState> emit) async { Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
// Get the current date and time // Get the current date and time
DateTime now = DateTime.now(); DateTime now = DateTime.now();
@ -123,15 +129,18 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
int startTime = lastMonth.millisecondsSinceEpoch; int startTime = lastMonth.millisecondsSinceEpoch;
int endTime = now.millisecondsSinceEpoch; int endTime = now.millisecondsSinceEpoch;
try { try {
emit(DoorSensorLoadingState());
var response = await DevicesAPI.getReportLogs( var response = await DevicesAPI.getReportLogs(
startTime: startTime.toString(), // Convert to String if the API expects it startTime:
startTime.toString(), // Convert to String if the API expects it
endTime: endTime.toString(), // Convert to String if the API expects it endTime: endTime.toString(), // Convert to String if the API expects it
deviceUuid: DSId, deviceUuid: DSId,
code: 'doorcontact_state', code: 'doorcontact_state',
); );
print('response======${response}');
recordGroups = response; recordGroups = response;
// Process response here // Process response here
print(response); emit(UpdateState(doorSensor: deviceStatus));
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
String errorMessage = errorData['message']; String errorMessage = errorData['message'];
@ -142,14 +151,16 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
_listenToChanges() { _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$DSId'); DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$DSId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {

View File

@ -1,7 +1,7 @@
class DeviceReport { class DeviceReport {
final String? deviceUuid; final dynamic deviceUuid;
final String? startTime; final dynamic startTime;
final String? endTime; final dynamic endTime;
final List<DeviceEvent>? data; final List<DeviceEvent>? data;
DeviceReport({ DeviceReport({

View File

@ -4,27 +4,10 @@ import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
// // class DoorRecordsScreen extends StatelessWidget {
// final String DSId;
// const DoorRecordsScreen({super.key, required this.DSId});
// @override
// Widget build(BuildContext context) {
// return DefaultScaffold(
// title: 'Records',
// child: BlocProvider(
// create: (context) =>
// DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()),
// child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
// builder: (context, state) {
// final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);
// return SizedBox(
// child: ListView.builder(
// itemCount: doorSensorBloc.recordGroups!.data!.length,
// itemBuilder: (context, index) {
// final recordGroup = doorSensorBloc.recordGroups!.data![index];
class DoorRecordsScreen extends StatelessWidget { class DoorRecordsScreen extends StatelessWidget {
final String DSId; final String DSId;
@ -35,36 +18,43 @@ class DoorRecordsScreen extends StatelessWidget {
return DefaultScaffold( return DefaultScaffold(
title: 'Records', title: 'Records',
child: BlocProvider( child: BlocProvider(
create: (context) => DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), create: (context) =>
DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>( child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) { builder: (context, state) {
final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);
if (state is DoorSensorLoadingState) { if (state is DoorSensorLoadingState) {
return const Center(child: CircularProgressIndicator()); return const Center(
} child: DefaultContainer(
width: 50, height: 50, child: CircularProgressIndicator()),
if (state is DoorSensorFailedState) {
return Center(
child: Text('Failed to load data: ${state.errorMessage}'),
); );
} } else if (state is UpdateState) {
// Group records by formatted date
final Map<String, List<DeviceEvent>> groupedRecords = {};
if (state is UpdateState) { // Iterate over the data list in DeviceReport
final recordGroups = context.read<DoorSensorBloc>().recordGroups; for (var record in doorSensorBloc.recordGroups.data!) {
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedDate =
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
if (recordGroups.data == null || recordGroups.data!.isEmpty) { // Group by formatted date
return const Center(child: Text('No records available.')); if (groupedRecords.containsKey(formattedDate)) {
groupedRecords[formattedDate]!.add(record);
} else {
groupedRecords[formattedDate] = [record];
}
} }
// Build the ListView with grouped data
return ListView.builder( return ListView.builder(
itemCount: recordGroups.data!.length, itemCount: groupedRecords.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final record = recordGroups.data![index]; final String date = groupedRecords.keys.elementAt(index);
final List<DeviceEvent> recordsForDate =
// Convert eventTime to a human-readable format groupedRecords[date]!;
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedDate = DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
final String formattedTime = DateFormat('HH:mm:ss').format(eventDateTime);
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -73,30 +63,57 @@ class DoorRecordsScreen extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Text( child: Text(
formattedDate, date,
style: const TextStyle( style: const TextStyle(
fontSize: 18, color: ColorsManager.grayColor,
fontWeight: FontWeight.bold, fontSize: 13,
fontWeight: FontWeight.w700,
), ),
), ),
), ),
// Display the event details in DefaultContainer // List of records for the specific date
DefaultContainer( DefaultContainer(
child: ListTile( child: Column(
leading: Icon( children: [
record.value == 'true' ...recordsForDate.map((record) {
? Icons.radio_button_checked final DateTime eventDateTime =
: Icons.radio_button_unchecked, DateTime.fromMillisecondsSinceEpoch(
color: record.value == 'true' ? Colors.blue : Colors.grey, record.eventTime!);
), final String formattedTime =
title: Text( DateFormat('HH:mm:ss').format(eventDateTime);
'Status: ${record.value}',
style: const TextStyle( return Column(
fontWeight: FontWeight.bold, children: [
fontSize: 18, Container(
), child: ListTile(
), leading: Icon(
subtitle: Text('Time: $formattedTime'), record.value == 'true'
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: record.value == 'true'
? Colors.blue
: Colors.grey,
),
title: Text(
record.value == 'true'
? "Opened"
: "Closed",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
subtitle: Text('$formattedTime'),
),
),
const Divider(
color: ColorsManager.graysColor,
)
],
);
}).toList(),
],
), ),
), ),
], ],
@ -104,7 +121,6 @@ class DoorRecordsScreen extends StatelessWidget {
}, },
); );
} }
return const Center(child: Text('No data available.')); return const Center(child: Text('No data available.'));
}, },
), ),

View File

@ -63,17 +63,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( pageBuilder:
switchCode :"switch_1", (context, animation1, animation2) =>
device: device, TimerScheduleScreen(
deviceCode: 'countdown_1', switchCode: "switch_1",
))); device: device,
deviceCode: 'countdown_1',
)));
}, },
child: Container( child: Container(
padding: padding: const EdgeInsets.only(
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), left: 25, right: 15, top: 20, bottom: 20),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
BodySmall( BodySmall(
text: "Bedside Light", text: "Bedside Light",
@ -100,17 +103,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( pageBuilder:
switchCode :"switch_2", (context, animation1, animation2) =>
device: device, TimerScheduleScreen(
deviceCode: 'countdown_2', switchCode: "switch_2",
))); device: device,
deviceCode: 'countdown_2',
)));
}, },
child: Container( child: Container(
padding: padding: const EdgeInsets.only(
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), left: 25, right: 15, top: 20, bottom: 20),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
BodySmall( BodySmall(
text: "Ceiling Light", text: "Ceiling Light",
@ -137,17 +143,20 @@ class ScheduleScreen extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( pageBuilder:
switchCode :"switch_3", (context, animation1, animation2) =>
device: device, TimerScheduleScreen(
deviceCode: 'countdown_3', switchCode: "switch_3",
))); device: device,
deviceCode: 'countdown_3',
)));
}, },
child: Container( child: Container(
padding: padding: const EdgeInsets.only(
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), left: 25, right: 15, top: 20, bottom: 20),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
BodySmall( BodySmall(
text: "Spotlight", text: "Spotlight",

View File

@ -22,7 +22,10 @@ class TimerScheduleScreen extends StatelessWidget {
final String deviceCode; final String deviceCode;
final String switchCode; final String switchCode;
const TimerScheduleScreen( const TimerScheduleScreen(
{required this.device, required this.deviceCode, required this.switchCode, super.key}); {required this.device,
required this.deviceCode,
required this.switchCode,
super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -32,7 +35,8 @@ class TimerScheduleScreen extends StatelessWidget {
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
), ),
child: BlocProvider( child: BlocProvider(
create: (context) => ThreeGangBloc(switchCode: switchCode, threeGangId: device.uuid ?? '') create: (context) => ThreeGangBloc(
switchCode: switchCode, threeGangId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode)) ..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()), ..add(GetScheduleEvent()),
child: BlocBuilder<ThreeGangBloc, ThreeGangState>( child: BlocBuilder<ThreeGangBloc, ThreeGangState>(
@ -94,13 +98,15 @@ class TimerScheduleScreen extends StatelessWidget {
decoration: const ShapeDecoration( decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor, color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30)), borderRadius:
BorderRadius.all(Radius.circular(30)),
), ),
), ),
child: TabBar( child: TabBar(
onTap: (value) { onTap: (value) {
if (value == 0) { if (value == 0) {
if (threeGangBloc.createSchedule == true) { if (threeGangBloc.createSchedule ==
true) {
threeGangBloc.toggleCreateSchedule(); threeGangBloc.toggleCreateSchedule();
} }
threeGangBloc.toggleSelectedIndex(0); threeGangBloc.toggleSelectedIndex(0);
@ -108,19 +114,21 @@ class TimerScheduleScreen extends StatelessWidget {
threeGangBloc.toggleSelectedIndex(1); threeGangBloc.toggleSelectedIndex(1);
} }
}, },
indicatorColor: Colors.white, // Customize the indicator indicatorColor: Colors.white,
dividerHeight: 0, dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration( indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor, color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)), borderRadius: BorderRadius.all(
Radius.circular(20)),
), ),
), ),
tabs: [ tabs: [
Tab( Tab(
child: Container( child: Container(
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall( child: BodySmall(
text: 'Countdown', text: 'Countdown',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
@ -133,7 +141,8 @@ class TimerScheduleScreen extends StatelessWidget {
), ),
Tab( Tab(
child: Container( child: Container(
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text( child: Text(
'Schedule', 'Schedule',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
@ -153,84 +162,118 @@ class TimerScheduleScreen extends StatelessWidget {
Center( Center(
child: Container( child: Container(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
countNum > 0 countNum > 0
? BodyLarge( ? BodyLarge(
text: _formatDuration(countNum), text: _formatDuration(
fontColor: ColorsManager.slidingBlueColor, countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40, fontSize: 40,
) )
: CupertinoTimerPicker( : CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hm, mode:
CupertinoTimerPickerMode
.hm,
onTimerDurationChanged: onTimerDurationChanged:
(Duration newDuration) { (Duration
newDuration) {
duration = newDuration; duration = newDuration;
}, },
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
if (state is LoadingNewSate) { if (state
is LoadingNewSate) {
return; return;
} }
if (countNum > 0) { if (countNum > 0) {
threeGangBloc.add(SetCounterValue( threeGangBloc.add(
deviceCode: deviceCode, SetCounterValue(
duration: Duration.zero)); deviceCode:
} else if (duration != Duration.zero) { deviceCode,
threeGangBloc.add(SetCounterValue( duration: Duration
deviceCode: deviceCode, .zero));
duration: duration)); } else if (duration !=
Duration.zero) {
threeGangBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
} }
}, },
child: SvgPicture.asset(countNum > 0 child: SvgPicture.asset(
? Assets.pauseIcon countNum > 0
: Assets.playIcon)), ? Assets.pauseIcon
: Assets.playIcon)),
], ],
), ),
), ),
), ),
Column( SizedBox(
mainAxisAlignment: threeGangBloc.listSchedule.isNotEmpty child: threeGangBloc.createSchedule ==
? MainAxisAlignment.start true
: MainAxisAlignment.center, ? CreateSchedule(
children: [ onToggleChanged: (bool isOn) {
SizedBox( threeGangBloc.toggleSchedule =
child: threeGangBloc.createSchedule == true isOn;
? CreateSchedule( },
onToggleChanged: (bool isOn) { onDateTimeChanged:
threeGangBloc.toggleSchedule = isOn; (DateTime dateTime) {
}, threeGangBloc.selectedTime =
onDateTimeChanged: (DateTime dateTime) { dateTime;
threeGangBloc.selectedTime = dateTime; },
}, days: threeGangBloc.days,
days: threeGangBloc.days, selectDays: (List<String>
selectDays: (List<String> selectedDays) { selectedDays) {
threeGangBloc.selectedDays = selectedDays; threeGangBloc.selectedDays =
}, selectedDays;
) },
: Padding( )
padding: const EdgeInsets.only(top: 10), : Padding(
child: ScheduleListView( padding: const EdgeInsets.only(
listSchedule: threeGangBloc top: 10),
.listSchedule, // Pass the schedule list here child: Column(
onDismissed: (scheduleId) { mainAxisAlignment:
threeGangBloc.listSchedule.removeWhere( MainAxisAlignment.start,
(schedule) => crossAxisAlignment:
schedule.scheduleId == scheduleId); CrossAxisAlignment.start,
threeGangBloc.add( children: [
DeleteScheduleEvent(id: scheduleId)); Expanded(
}, child: ScheduleListView(
onToggleSchedule: (scheduleId, isEnabled) { listSchedule: threeGangBloc
threeGangBloc.add(ToggleScheduleEvent( .listSchedule, // Pass the schedule list here
id: scheduleId, onDismissed:
toggle: isEnabled, (scheduleId) {
)); threeGangBloc
}, .listSchedule
.removeWhere(
(schedule) =>
schedule
.scheduleId ==
scheduleId);
threeGangBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
threeGangBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
), ),
), ],
), ),
], ),
), ),
], ],
), ),

View File

@ -63,7 +63,7 @@ class TimerScheduleScreen extends StatelessWidget {
}, },
child: DefaultTabController( child: DefaultTabController(
length: 2, length: 2,
child: DefaultScaffold( child: DefaultScaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
centerTitle: true, centerTitle: true,
@ -73,177 +73,204 @@ class TimerScheduleScreen extends StatelessWidget {
fontWeight: FontsManager.bold, fontWeight: FontsManager.bold,
), ),
actions: [ actions: [
twoGangBloc.createSchedule == true ? twoGangBloc.createSchedule == true
TextButton( ? TextButton(
onPressed: () { onPressed: () {
twoGangBloc.add(TwoGangSave()); twoGangBloc.add(TwoGangSave());
}, },
child: const Text('Save') child: const Text('Save'))
) : : twoGangBloc.selectedTabIndex == 1
twoGangBloc.selectedTabIndex==1? IconButton( ? IconButton(
onPressed: () { onPressed: () {
twoGangBloc.toggleCreateSchedule(); twoGangBloc.toggleCreateSchedule();
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
):SizedBox(), )
: SizedBox(),
], ],
), ),
child: child: state is LoadingInitialState
state is LoadingInitialState? ? const Center(child: CircularProgressIndicator())
const Center(child: CircularProgressIndicator()): : Column(
Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30)),
),
),
child: TabBar(
onTap: (value) {
print(value);
if(value==0){
if(twoGangBloc.createSchedule == true){
twoGangBloc.toggleCreateSchedule();
}
twoGangBloc.toggleSelectedIndex(0);
}else{
twoGangBloc.toggleSelectedIndex(1);
}
},
indicatorColor: Colors.white, // Customize the indicator
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(20)),
),
),
tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
children: [ children: [
Center( Container(
child: Container( width: MediaQuery.of(context).size.width,
child: Column( decoration: const ShapeDecoration(
mainAxisAlignment: MainAxisAlignment.center, color: ColorsManager.onPrimaryColor,
children: [ shape: RoundedRectangleBorder(
countNum > 0 borderRadius:
? BodyLarge( BorderRadius.all(Radius.circular(30)),
text: _formatDuration(countNum),
fontColor:
ColorsManager.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode: CupertinoTimerPickerMode.hm,
onTimerDurationChanged:
(Duration newDuration) {
duration = newDuration;
},
),
GestureDetector(
onTap: () {
if (state is LoadingNewSate) {
return;
}
if (countNum > 0) {
twoGangBloc.add(SetCounterValue(
deviceCode: deviceCode,
duration: Duration.zero));
} else if (duration != Duration.zero) {
twoGangBloc.add(SetCounterValue(
deviceCode: deviceCode,
duration: duration));
}
},
child: SvgPicture.asset(countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
), ),
), ),
), child: TabBar(
Column( onTap: (value) {
mainAxisAlignment:twoGangBloc.listSchedule.isNotEmpty? print(value);
MainAxisAlignment.start:MainAxisAlignment.center, if (value == 0) {
children: [ if (twoGangBloc.createSchedule ==
SizedBox( true) {
child: twoGangBloc.createSchedule == true ? twoGangBloc.toggleCreateSchedule();
CreateSchedule( }
onToggleChanged: (bool isOn) { twoGangBloc.toggleSelectedIndex(0);
twoGangBloc.toggleSchedule = isOn; } else {
}, twoGangBloc.toggleSelectedIndex(1);
onDateTimeChanged: (DateTime dateTime) { }
twoGangBloc.selectedTime=dateTime; },
}, indicatorColor:
days: twoGangBloc.days, Colors.white, // Customize the indicator
selectDays: (List<String> selectedDays) { dividerHeight: 0,
twoGangBloc.selectedDays = selectedDays; indicatorSize: TabBarIndicatorSize.tab,
}, indicator: const ShapeDecoration(
) color: ColorsManager.slidingBlueColor,
: shape: RoundedRectangleBorder(
Padding( borderRadius: BorderRadius.all(
padding: const EdgeInsets.only(top: 10), Radius.circular(20)),
child: ScheduleListView(
listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here
onDismissed: (scheduleId) {
twoGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId);
twoGangBloc.add(DeleteScheduleEvent(id: scheduleId));
},
onToggleSchedule: (scheduleId, isEnabled) {
twoGangBloc.add(ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
), ),
), ),
], tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
children: [
Center(
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
countNum > 0
? BodyLarge(
text: _formatDuration(
countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode:
CupertinoTimerPickerMode
.hm,
onTimerDurationChanged:
(Duration
newDuration) {
duration = newDuration;
},
),
GestureDetector(
onTap: () {
if (state
is LoadingNewSate) {
return;
}
if (countNum > 0) {
twoGangBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
twoGangBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
SizedBox(
child: twoGangBloc.createSchedule ==
true
? CreateSchedule(
onToggleChanged: (bool isOn) {
twoGangBloc.toggleSchedule =
isOn;
},
onDateTimeChanged:
(DateTime dateTime) {
twoGangBloc.selectedTime =
dateTime;
},
days: twoGangBloc.days,
selectDays: (List<String>
selectedDays) {
twoGangBloc.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(
top: 10),
child: Column(
children: [
Expanded(
child: ScheduleListView(
listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here
onDismissed:(scheduleId) {
twoGangBloc .listSchedule
.removeWhere( (schedule) => schedule .scheduleId == scheduleId);
twoGangBloc.add(
DeleteScheduleEvent( id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
twoGangBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
],
),
),
),
],
),
), ),
], ],
), ),
), )));
],
),
))
);
}, },
), ),
), ),

View File

@ -1,8 +1,3 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -13,7 +8,6 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
class CirculateListView extends StatelessWidget { class CirculateListView extends StatelessWidget {
final List<ScheduleModel> listSchedule; final List<ScheduleModel> listSchedule;
final Function(String) onDismissed; final Function(String) onDismissed;
@ -30,96 +24,98 @@ class CirculateListView extends StatelessWidget {
return Center( return Center(
child: listSchedule.isNotEmpty child: listSchedule.isNotEmpty
? SizedBox( ? SizedBox(
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: listSchedule.length, itemCount: listSchedule.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Dismissible( return Dismissible(
key: Key(listSchedule[index].scheduleId), key: Key(listSchedule[index].scheduleId),
background: Container( background: Container(
padding: const EdgeInsets.only(right: 10), padding: const EdgeInsets.only(right: 10),
alignment: AlignmentDirectional.centerEnd, alignment: AlignmentDirectional.centerEnd,
decoration: const ShapeDecoration( decoration: const ShapeDecoration(
color: Color(0xFFFF0000), color: Color(0xFFFF0000),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)), borderRadius: BorderRadius.all(Radius.circular(20)),
), ),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only(bottom: 10, right: 10), padding: const EdgeInsets.only(bottom: 10, right: 10),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.assetsDeleteIcon, Assets.assetsDeleteIcon,
width: 20, width: 20,
height: 22, height: 22,
), ),
), ),
), ),
direction: DismissDirection.endToStart, direction: DismissDirection.endToStart,
onDismissed: (direction) { onDismissed: (direction) {
onDismissed(listSchedule[index].scheduleId);
onDismissed(listSchedule[index].scheduleId); ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Schedule removed')),
ScaffoldMessenger.of(context).showSnackBar( );
const SnackBar(content: Text('Schedule removed')), },
); child: InkWell(
}, onTap: () {},
child: InkWell( child: DefaultContainer(
onTap: () { padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.5,
}, child: Row(
child: DefaultContainer(
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.4,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
BodyLarge( Expanded(
text: '12:30 AM - 01:30 PM', flex: 2,
// text: listSchedule[index].time, child: Column(
fontWeight: FontWeight.w500, crossAxisAlignment: CrossAxisAlignment.start,
fontColor: Colors.black, children: [
fontSize: 22, Row(
children: [
BodyLarge(
text: '12:30 AM - 01:30 PM',
// text: listSchedule[index].time,
fontWeight: FontWeight.w500,
fontColor: Colors.black,
fontSize: 18,
),
],
),
Text(listSchedule[index].days.join(' ')),
// Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
Text(
'Start Duration: 0h 10m End Duration: 0h 15m'),
],
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
), ),
Text(listSchedule[index].days.join(' ')),
// Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
Text('Start Duration: 0h 10m End Duration: 0h 15m'),
], ],
), ),
), ),
Expanded( ),
child: ListTile( );
contentPadding: EdgeInsets.zero, },
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
),
],
),
),
), ),
); )
}, : const EmptySchedule());
),
)
: const EmptySchedule()
);
} }
} }

View File

@ -76,33 +76,36 @@ class WHTimerScheduleScreen extends StatelessWidget {
fontWeight: FontsManager.bold, fontWeight: FontsManager.bold,
), ),
actions: [ actions: [
waterHeaterBloc.createSchedule == true && waterHeaterBloc.selectedTabIndex == 1 ? waterHeaterBloc.createSchedule == true &&
TextButton( waterHeaterBloc.selectedTabIndex == 1
onPressed: () { ? TextButton(
waterHeaterBloc.add(ScheduleSave()); onPressed: () {
}, waterHeaterBloc.add(ScheduleSave());
child: const Text('Save')) : waterHeaterBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
waterHeaterBloc.createCirculate == true &&waterHeaterBloc.selectedTabIndex==2 ?
TextButton(
onPressed: () {
waterHeaterBloc.add(ScheduleSave());
},
child: const Text('Save'))
: waterHeaterBloc.selectedTabIndex == 2
? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateCirculate();
}, },
icon: const Icon(Icons.add), child: const Text('Save'))
) : waterHeaterBloc.selectedTabIndex == 1
: const SizedBox(), ? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateSchedule();
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
waterHeaterBloc.createCirculate == true &&
waterHeaterBloc.selectedTabIndex == 2
? TextButton(
onPressed: () {
waterHeaterBloc.add(ScheduleSave());
},
child: const Text('Save'))
: waterHeaterBloc.selectedTabIndex == 2
? IconButton(
onPressed: () {
waterHeaterBloc.toggleCreateCirculate();
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
], ],
), ),
child: state is WHLoadingState child: state is WHLoadingState
@ -124,20 +127,29 @@ class WHTimerScheduleScreen extends StatelessWidget {
labelPadding: EdgeInsets.zero, labelPadding: EdgeInsets.zero,
onTap: (value) { onTap: (value) {
if (value == 0) { if (value == 0) {
if (waterHeaterBloc.createSchedule == true) { if (waterHeaterBloc.createSchedule ==
waterHeaterBloc.toggleCreateSchedule(); true) {
waterHeaterBloc
.toggleCreateSchedule();
} }
waterHeaterBloc.toggleSelectedIndex(value); waterHeaterBloc
} else if (value == 2) { .toggleSelectedIndex(value);
if (waterHeaterBloc.createCirculate == true) { } else if (value == 2) {
waterHeaterBloc.toggleCreateCirculate(); if (waterHeaterBloc.createCirculate ==
true) {
waterHeaterBloc
.toggleCreateCirculate();
} }
waterHeaterBloc.toggleSelectedIndex(value); waterHeaterBloc
.toggleSelectedIndex(value);
} else { } else {
if (waterHeaterBloc.createSchedule == true) { if (waterHeaterBloc.createSchedule ==
waterHeaterBloc.toggleCreateSchedule(); true) {
waterHeaterBloc
.toggleCreateSchedule();
} }
waterHeaterBloc.toggleSelectedIndex(value); waterHeaterBloc
.toggleSelectedIndex(value);
} }
}, },
indicatorColor: Colors.white, indicatorColor: Colors.white,
@ -151,96 +163,128 @@ class WHTimerScheduleScreen extends StatelessWidget {
), ),
), ),
isScrollable: false, isScrollable: false,
labelColor: Colors.white, // Text color when selected labelColor: Colors
unselectedLabelColor: ColorsManager.blackColor, // Text color when not selected .white, // Text color when selected
unselectedLabelColor: ColorsManager
.blackColor, // Text color when not selected
tabs: [ tabs: [
Tab( Tab(
icon: SvgPicture.asset( icon: Padding(
Assets.scheduleTimeIcon, padding: const EdgeInsets.only(
color: waterHeaterBloc.selectedTabIndex == 0 top: 10.0),
? Colors.white child: SvgPicture.asset(
: ColorsManager.blackColor, // Change icon color based on selectedIndex Assets.scheduleTimeIcon,
color: waterHeaterBloc
.selectedTabIndex ==
0
? Colors.white
: ColorsManager
.blackColor, // Change icon color based on selectedIndex
),
), ),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 10), vertical: 5),
child: BodySmall( child: BodySmall(
text: 'Countdown', text: 'Countdown',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
color: waterHeaterBloc.selectedTabIndex == 0 color: waterHeaterBloc
.selectedTabIndex ==
0
? Colors.white ? Colors.white
: ColorsManager : ColorsManager
.blackColor, // Text color based on selectedTabIndex .blackColor, // Text color based on selectedTabIndex
fontSize: 8, fontSize: 10,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
), ),
), ),
Tab( Tab(
icon: SvgPicture.asset( icon: Padding(
Assets.scheduleCelenderIcon, padding:
color: waterHeaterBloc.selectedTabIndex == 1 const EdgeInsets.only(top: 10),
? Colors.white child: SvgPicture.asset(
: ColorsManager.blackColor, Assets.scheduleCelenderIcon,
color: waterHeaterBloc
.selectedTabIndex ==
1
? Colors.white
: ColorsManager.blackColor,
),
), ),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 10), vertical: 5),
child: Text( child: Text(
'Schedule', 'Schedule',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
color: waterHeaterBloc.selectedTabIndex == 1 color: waterHeaterBloc
.selectedTabIndex ==
1
? Colors.white ? Colors.white
: ColorsManager.blackColor, : ColorsManager.blackColor,
fontSize: 8, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
), ),
), ),
Tab( Tab(
icon: SvgPicture.asset( icon: Padding(
Assets.scheduleCirculateIcon, padding:
color: waterHeaterBloc.selectedTabIndex == 2 const EdgeInsets.only(top: 10),
? Colors.white child: SvgPicture.asset(
: ColorsManager.blackColor, Assets.scheduleCirculateIcon,
color: waterHeaterBloc
.selectedTabIndex ==
2
? Colors.white
: ColorsManager.blackColor,
),
), ),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 10), vertical: 5),
child: Text( child: Text(
'Circulate', 'Circulate',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
color: waterHeaterBloc color: waterHeaterBloc
.selectedTabIndex == 2 .selectedTabIndex ==
2
? Colors.white ? Colors.white
: ColorsManager.blackColor, : ColorsManager.blackColor,
fontSize: 8, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
), ),
), ),
Tab( Tab(
icon: SvgPicture.asset( icon: Padding(
Assets.scheduleInchingIcon, padding:
color: waterHeaterBloc const EdgeInsets.only(top: 10),
.selectedTabIndex == 3 child: SvgPicture.asset(
? Colors.white Assets.scheduleInchingIcon,
: ColorsManager.blackColor, color: waterHeaterBloc
.selectedTabIndex ==
3
? Colors.white
: ColorsManager.blackColor,
),
), ),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 10), vertical: 5),
child: Text( child: Text(
'Inching', 'Inching',
style: context.bodySmall.copyWith( style: context.bodySmall.copyWith(
color: waterHeaterBloc color: waterHeaterBloc
.selectedTabIndex == 3 .selectedTabIndex ==
3
? Colors.white ? Colors.white
: ColorsManager.blackColor, : ColorsManager.blackColor,
fontSize: 8, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
@ -308,93 +352,132 @@ class WHTimerScheduleScreen extends StatelessWidget {
), ),
), ),
), ),
Column( SizedBox(
mainAxisAlignment: waterHeaterBloc child: waterHeaterBloc.createSchedule ==
.listSchedule.isNotEmpty true
? MainAxisAlignment.start ? CreateSchedule(
: MainAxisAlignment.center, onToggleChanged: (bool isOn) {
children: [ waterHeaterBloc
SizedBox( .toggleSchedule = isOn;
child: waterHeaterBloc.createSchedule == true },
? CreateSchedule( onDateTimeChanged:
onToggleChanged: (bool isOn) { (DateTime dateTime) {
waterHeaterBloc.toggleSchedule = isOn; waterHeaterBloc.selectedTime =
}, dateTime;
onDateTimeChanged: (DateTime dateTime) { },
waterHeaterBloc.selectedTime = dateTime; days: waterHeaterBloc.days,
}, selectDays: (List<String>
days: waterHeaterBloc.days, selectedDays) {
selectDays: (List<String> waterHeaterBloc.selectedDays =
selectedDays) { selectedDays;
waterHeaterBloc },
.selectedDays = )
selectedDays; : Padding(
}, padding: const EdgeInsets.only(
) top: 10),
: Padding( child: Column(
padding: const EdgeInsets.only(top: 10), children: [
child: ScheduleListView( Expanded(
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here child: ScheduleListView(
onDismissed: listSchedule:
(scheduleId) { waterHeaterBloc
waterHeaterBloc.listSchedule.removeWhere( .listSchedule, // Pass the schedule list here
(schedule) => schedule.scheduleId == scheduleId); onDismissed:
waterHeaterBloc.add( (scheduleId) {
DeleteScheduleEvent(id: scheduleId)); waterHeaterBloc
}, .listSchedule
onToggleSchedule: (scheduleId, isEnabled) { .removeWhere(
(schedule) =>
waterHeaterBloc.add(ToggleScheduleEvent( schedule
id: scheduleId, toggle: isEnabled, .scheduleId ==
)); scheduleId);
}, waterHeaterBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
waterHeaterBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
), ),
), ],
), ),
], ),
), ),
Center( Center(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
waterHeaterBloc.createCirculate == true waterHeaterBloc.createCirculate ==
? true
CirculateWidget( ? CirculateWidget(
endDuration: () { endDuration: () {
waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false)); waterHeaterBloc.add(
}, SelectTimeEvent(
startDuration: () { context: context,
waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false)); isEffective:
false));
}, },
isStartEndTime: true, startDuration: () {
startTime: DateTime.now(), waterHeaterBloc.add(
endTime: DateTime.now(), SelectTimeEvent(
days: waterHeaterBloc.days, context: context,
selectedDays: [], isEffective:
onToggleStartEndTime: (c) {}, false));
onTimeChanged: (x, f) { },
}, isStartEndTime: true,
onDaySelected: (p0) {}, startTime: DateTime.now(),
):CirculateListView( endTime: DateTime.now(),
listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here days: waterHeaterBloc.days,
onDismissed: (scheduleId) { selectedDays: [],
waterHeaterBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId); onToggleStartEndTime:
waterHeaterBloc.add(DeleteScheduleEvent(id: scheduleId)); (c) {},
}, onTimeChanged: (x, f) {},
onToggleSchedule: (scheduleId, isEnabled) { onDaySelected: (p0) {},
waterHeaterBloc.add(ToggleScheduleEvent( )
id: scheduleId, toggle: isEnabled, : CirculateListView(
)); listSchedule: [], // Pass the schedule list here
}, onDismissed: (scheduleId) {
) waterHeaterBloc
.listSchedule
.removeWhere((schedule) =>
schedule
.scheduleId ==
scheduleId);
waterHeaterBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
waterHeaterBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
)
], ],
), ),
), ),
Column(children: [ Column(
SizedBox(height: 20), children: [
Container(child: InchingWidget(),),],) SizedBox(height: 20),
Container(
child: InchingWidget(),
),
],
)
], ],
), ),
), ),

View File

@ -21,94 +21,98 @@ class ScheduleListView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return listSchedule.isNotEmpty
child: listSchedule.isNotEmpty ? SizedBox(
? SizedBox( child: ListView.builder(
child: ListView.builder( shrinkWrap: true,
shrinkWrap: true, itemCount: listSchedule.length,
itemCount: listSchedule.length, itemBuilder: (context, index) {
itemBuilder: (context, index) { return Dismissible(
return Dismissible( key: Key(listSchedule[index].scheduleId),
key: Key(listSchedule[index].scheduleId), background: Container(
background: Container( padding: const EdgeInsets.only(right: 10),
padding: const EdgeInsets.only(right: 10), alignment: AlignmentDirectional.centerEnd,
alignment: AlignmentDirectional.centerEnd, decoration: const ShapeDecoration(
decoration: const ShapeDecoration( color: Color(0xFFFF0000),
color: Color(0xFFFF0000), shape: RoundedRectangleBorder(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(20)),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 10, right: 10),
child: SvgPicture.asset(
Assets.assetsDeleteIcon,
width: 20,
height: 22,
),
),
), ),
direction: DismissDirection.endToStart, ),
onDismissed: (direction) { child: Padding(
onDismissed(listSchedule[index].scheduleId); padding: const EdgeInsets.only(bottom: 10, right: 10),
child: SvgPicture.asset(
Assets.assetsDeleteIcon,
width: 20,
height: 22,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
onDismissed(listSchedule[index].scheduleId);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Schedule removed')), const SnackBar(content: Text('Schedule removed')),
);
},
child: InkWell(
onTap: () {},
child: DefaultContainer(
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.4,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BodyLarge(
text: listSchedule[index].time,
fontWeight: FontWeight.w500,
fontColor: Colors.black,
fontSize: 22,
),
Text(listSchedule[index].days.join(' ')),
Text(
'Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
],
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
),
],
),
),
),
); );
}, },
), child: InkWell(
) onTap: () {},
: const EmptySchedule()); child: DefaultContainer(
padding: const EdgeInsets.all(20),
height: MediaQuery.of(context).size.height / 6.4,
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
BodyLarge(
text: listSchedule[index].time,
fontWeight: FontWeight.w500,
fontColor: Colors.black,
fontSize: 22,
),
Text(listSchedule[index].days.join(' ')),
Text(
'Function ${listSchedule[index].function.value ? "ON" : "OFF"}'),
],
),
),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: '',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: listSchedule[index].enable,
onChanged: (value) {
onToggleSchedule(
listSchedule[index].scheduleId,
value,
);
},
applyTheme: true,
),
),
),
),
],
),
),
),
);
},
),
)
: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(child: EmptySchedule()),
],
);
} }
} }

View File

@ -72,7 +72,8 @@ class DevicesAPI {
static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async { static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId), path: ApiEndpoints.deviceFunctionsStatus
.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -82,7 +83,9 @@ class DevicesAPI {
} }
static Future<Map<String, dynamic>> renamePass( static Future<Map<String, dynamic>> renamePass(
{required String name, required String doorLockUuid, required String passwordId}) async { {required String name,
required String doorLockUuid,
required String passwordId}) async {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.renamePassword path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid) .replaceAll('{doorLockUuid}', doorLockUuid)
@ -107,7 +110,8 @@ class DevicesAPI {
return response; return response;
} }
static Future<List<DeviceModel>> getDeviceByGroupName(String unitId, String groupName) async { static Future<List<DeviceModel>> getDeviceByGroupName(
String unitId, String groupName) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.devicesByGroupName path: ApiEndpoints.devicesByGroupName
.replaceAll('{unitUuid}', unitId) .replaceAll('{unitUuid}', unitId)
@ -146,7 +150,8 @@ class DevicesAPI {
return response; return response;
} }
static Future<List<DeviceModel>> getDevicesByGatewayId(String gatewayId) async { static Future<List<DeviceModel>> getDevicesByGatewayId(
String gatewayId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
showServerMessage: false, showServerMessage: false,
@ -168,7 +173,8 @@ class DevicesAPI {
String deviceId, String deviceId,
) async { ) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -179,7 +185,8 @@ class DevicesAPI {
static Future getOneTimePasswords(String deviceId) async { static Future getOneTimePasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getOneTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -190,7 +197,8 @@ class DevicesAPI {
static Future getTimeLimitPasswords(String deviceId) async { static Future getTimeLimitPasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.getMultipleTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -215,10 +223,12 @@ class DevicesAPI {
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
if (scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); body["scheduleList"] =
scheduleList.map((schedule) => schedule.toJson()).toList();
} }
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
body: body, body: body,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => json, expectedResponseModel: (json) => json,
@ -229,7 +239,8 @@ class DevicesAPI {
static Future generateOneTimePassword({deviceId}) async { static Future generateOneTimePassword({deviceId}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addOneTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -241,10 +252,12 @@ class DevicesAPI {
} }
} }
static Future generateMultiTimePassword({deviceId, effectiveTime, invalidTime}) async { static Future generateMultiTimePassword(
{deviceId, effectiveTime, invalidTime}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), path: ApiEndpoints.addMultipleTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: true, showServerMessage: true,
body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime}, body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime},
expectedResponseModel: (json) { expectedResponseModel: (json) {
@ -361,6 +374,7 @@ class DevicesAPI {
.replaceAll('{startTime}', startTime) .replaceAll('{startTime}', startTime)
.replaceAll('{endTime}', endTime), .replaceAll('{endTime}', endTime),
expectedResponseModel: (json) { expectedResponseModel: (json) {
print('json-=-=-=-=-=-=-=${json}');
return DeviceReport.fromJson(json); return DeviceReport.fromJson(json);
}, },
); );