door sensor

This commit is contained in:
mohammad
2024-09-22 17:27:29 +03:00
parent 58e13da887
commit d97efe229d
10 changed files with 202 additions and 116 deletions

View File

@ -6,19 +6,18 @@ import 'package:flutter_bloc/flutter_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_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/door_sensor_model.dart';
import 'package:syncrow_app/features/devices/model/report_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
final String DSId;
final String switchCode;
DoorSensorBloc({required this.DSId, required this.switchCode})
: super(const DoorSensorState()) {
DoorSensorBloc({
required this.DSId,
}) : super(const DoorSensorState()) {
on<DoorSensorInitial>(_fetchWaterHeaterStatus);
on<ReportLogsInitial>(fetchLogsForLastMonth);
on<DoorSensorSwitch>(_changeFirstSwitch);
on<ToggleLowBatteryEvent>(_toggleLowBattery);
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ToggleDoorAlarmEvent>(_toggleDoorAlarm);
@ -29,6 +28,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
bool doorAlarm = false;
DoorSensorModel deviceStatus =
DoorSensorModel(doorContactState: false, batteryPercentage: 0);
void _fetchWaterHeaterStatus(
DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
emit(DoorSensorLoadingState());
@ -43,34 +43,13 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
);
emit(UpdateState(doorSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
_listenToChanges();
} catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString()));
return;
}
}
void _changeFirstSwitch(
DoorSensorSwitch event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus));
try {
deviceStatus.doorContactState = !event.switchD;
emit(UpdateState(doorSensor: deviceStatus));
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: DSId,
code: 'doorcontact_state',
value: deviceStatus.doorContactState),
DSId);
if (!response['success']) {
// add(InitialEvent(groupScreen: oneGangGroup));
}
} catch (_) {
emit(DoorSensorFailedState(errorMessage: _.toString()));
}
}
// Toggle functions for each switch
void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
@ -135,31 +114,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
}
}
final List<RecordGroup> recordGroups = [
RecordGroup(
date: DateTime(2024, 8, 31),
records: [
Record(status: 'Opened', time: '15:10:25', isOpen: false),
Record(status: 'Closed', time: '12:24:45', isOpen: false),
Record(status: 'Opened', time: '12:20:05', isOpen: true),
],
),
RecordGroup(
date: DateTime(2024, 8, 30),
records: [
Record(status: 'Opened', time: '14:15:30', isOpen: true),
Record(status: 'Closed', time: '10:22:45', isOpen: false),
],
),
RecordGroup(
date: DateTime(2024, 8, 29),
records: [
Record(status: 'Opened', time: '13:45:00', isOpen: true),
Record(status: 'Closed', time: '11:30:15', isOpen: false),
Record(status: 'Opened', time: '09:20:10', isOpen: true),
],
),
];
DeviceReport recordGroups = DeviceReport(startTime: 0, endTime: 0, data: []);
Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
@ -174,11 +130,13 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
int endTime = now.millisecondsSinceEpoch;
try {
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
deviceUuid: DSId,
code: 'doorcontact_state',
);
recordGroups = response;
// Process response here
print(response);
} on DioException catch (e) {
@ -204,8 +162,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
statusList.add(StatusModel(code: element['code'], value: true));
});
deviceStatus = DoorSensorModel.fromJson(statusList);

View File

@ -42,7 +42,9 @@ class DevicesCategoryModel {
: name = json['groupName'],
// id = json['groupId'],
type = devicesTypesMap[json['groupName']] ?? DeviceType.Other,
icon = deviceTypeIconMap[devicesTypesMap[json['groupName']] ?? DeviceType.Other] ?? '',
icon = deviceTypeIconMap[
devicesTypesMap[json['groupName']] ?? DeviceType.Other] ??
'',
devices = [],
isSelected = false;
@ -60,5 +62,9 @@ Map<DeviceType, String> deviceTypeIconMap = {
DeviceType.CeilingSensor: Assets.assetsIconsSensors,
DeviceType.WallSensor: Assets.assetsIconsSensors,
DeviceType.ThreeGang: Assets.assetsIconsGang,
DeviceType.OneGang: Assets.oneGang,
DeviceType.TwoGang: Assets.twoGang,
DeviceType.WH: Assets.waterHeaterIcon,
DeviceType.DS: Assets.doorSensorIcon,
DeviceType.Other: Assets.assetsIconsAC,
};

View File

@ -62,11 +62,14 @@ class DeviceModel {
tempIcon = Assets.oneGang;
} else if (type == DeviceType.TwoGang) {
tempIcon = Assets.twoGang;
}else if (type == DeviceType.WH) {
} else if (type == DeviceType.WH) {
tempIcon = Assets.waterHeaterIcon;
} else if (type == DeviceType.DS) {
tempIcon = Assets.doorSensorIcon;
} else {
tempIcon = Assets.assetsIconsLogo;
}
return DeviceModel(
icon: tempIcon,
activeTime: json['activeTime'],

View File

@ -0,0 +1,51 @@
class DeviceReport {
final String? deviceUuid;
final int? startTime;
final int? endTime;
final List<DeviceEvent>? data;
DeviceReport({
this.deviceUuid,
this.startTime,
this.endTime,
this.data,
});
DeviceReport.fromJson(Map<String, dynamic> json)
: deviceUuid = json['deviceUuid'] as String?,
startTime = json['startTime'] as int?,
endTime = json['endTime'] as int?,
data = (json['data'] as List<dynamic>?)
?.map((e) => DeviceEvent.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> toJson() => {
'deviceUuid': deviceUuid,
'startTime': startTime,
'endTime': endTime,
'data': data?.map((e) => e.toJson()).toList(),
};
}
class DeviceEvent {
final String? code;
final int? eventTime;
final String? value;
DeviceEvent({
this.code,
this.eventTime,
this.value,
});
DeviceEvent.fromJson(Map<String, dynamic> json)
: code = json['code'] as String?,
eventTime = json['eventTime'] as int?,
value = json['value'] as String?;
Map<String, dynamic> toJson() => {
'code': code,
'eventTime': eventTime,
'value': value,
};
}

View File

@ -16,8 +16,8 @@ class NotificationSettingsPage extends StatelessWidget {
return DefaultScaffold(
title: 'Notification Settings',
child: BlocProvider(
create: (context) => DoorSensorBloc(switchCode: 'switch_1', DSId: '')
..add(const DoorSensorInitial()),
create: (context) =>
DoorSensorBloc(DSId: '')..add(const DoorSensorInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {
final doorSensorBloc = BlocProvider.of<DoorSensorBloc>(context);

View File

@ -7,71 +7,115 @@ import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_s
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.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 {
final String DSId;
const DoorRecordsScreen({super.key,required this.DSId});
final String DSId;
const DoorRecordsScreen({super.key, required this.DSId});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Records',
child: BlocProvider(
create: (context) =>
DoorSensorBloc(switchCode: 'switch_1', 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.length,
itemBuilder: (context, index) {
final recordGroup = doorSensorBloc.recordGroups[index];
title: 'Records',
child: BlocProvider(
create: (context) =>
DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {
if (state is DoorSensorLoadingState) {
return const Center(child: CircularProgressIndicator());
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Date header
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
DateFormat('EEEE, dd/MM/yyyy')
.format(recordGroup.date),
if (state is DoorSensorFailedState) {
return Center(
child: Text('Failed to load data: ${state.errorMessage}'),
);
}
if (state is UpdateState && state.doorSensor != null) {
final recordGroups = context.read<DoorSensorBloc>().recordGroups;
if (recordGroups == null ||
recordGroups.data == null ||
recordGroups.data!.isEmpty) {
return const Center(child: Text('No records available.'));
}
return ListView.builder(
itemCount: recordGroups.data!.length,
itemBuilder: (context, index) {
final record = recordGroups.data![index];
// Convert eventTime to a human-readable format
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(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Date header
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
formattedDate,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
// Display the event details in DefaultContainer
DefaultContainer(
child: ListTile(
leading: Icon(
record.value == 'true'
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: record.value == 'true'
? Colors.blue
: Colors.grey,
),
title: Text(
'Status: ${record.value}',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
subtitle: Text('Time: $formattedTime'),
),
// Display each record for the date
DefaultContainer(
child: Column(
children: recordGroup.records.map((record) {
return ListTile(
leading: Icon(
record.isOpen
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color:
record.isOpen ? Colors.blue : Colors.grey,
),
title: Text(
record.status,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
subtitle: Text(record.time),
);
}).toList(),
),
),
],
);
},
),
),
],
);
},
);
})));
}
return const Center(child: Text('No data available.'));
},
),
),
);
}
}

View File

@ -25,7 +25,7 @@ class DoorSensorScreen extends StatelessWidget {
title: 'Door Sensor',
child: BlocProvider(
create: (context) =>
DoorSensorBloc(switchCode: 'switch_1', DSId: device?.uuid ?? '')
DoorSensorBloc( DSId: device?.uuid ?? '')
..add(const DoorSensorInitial()),
child: BlocBuilder<DoorSensorBloc, DoorSensorState>(
builder: (context, state) {

View File

@ -1058,4 +1058,5 @@ class Assets {
static const String doorNotificationSetting =
"assets/icons/door_notification_setting_icon.svg";
static const String doorRecordsIcon = "assets/icons/door_records_icon.svg";
static const String doorSensorIcon = "assets/icons/door_sensor_icon.svg";
}

View File

@ -3,6 +3,7 @@ import 'dart:convert';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
@ -358,7 +359,7 @@ class DevicesAPI {
return response;
}
static Future getReportLogs({
static Future<DeviceReport> getReportLogs({
required String deviceUuid,
required String code,
required String startTime,
@ -373,7 +374,7 @@ class DevicesAPI {
.replaceAll('{startTime}', startTime)
.replaceAll('{endTime}', endTime),
expectedResponseModel: (json) {
print('====---------${json}');
return DeviceReport.fromJson(json);
return json;
},
);