mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-08-26 04:29:40 +00:00
door sensor
This commit is contained in:
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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'],
|
||||
|
51
lib/features/devices/model/device_report_model.dart
Normal file
51
lib/features/devices/model/device_report_model.dart
Normal 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,
|
||||
};
|
||||
}
|
@ -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);
|
||||
|
@ -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.'));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
},
|
||||
);
|
||||
|
Reference in New Issue
Block a user