From 03b5c49df017d20a34d8519b6f9fe064e9fd1b39 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Mon, 21 Oct 2024 21:54:22 +0400 Subject: [PATCH 1/5] added device spaces model --- .../models/device_space_model.dart | 18 +++++++++++ .../all_devices/models/devices_model.dart | 11 +++++++ .../widgets/device_managment_body.dart | 4 +-- lib/services/devices_mang_api.dart | 31 +++++++++++++------ 4 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 lib/pages/device_managment/all_devices/models/device_space_model.dart diff --git a/lib/pages/device_managment/all_devices/models/device_space_model.dart b/lib/pages/device_managment/all_devices/models/device_space_model.dart new file mode 100644 index 00000000..29f80142 --- /dev/null +++ b/lib/pages/device_managment/all_devices/models/device_space_model.dart @@ -0,0 +1,18 @@ +class DeviceSpaceModel { + String? uuid; + String? spaceName; + + DeviceSpaceModel({this.uuid, this.spaceName}); + + DeviceSpaceModel.fromJson(Map json) { + uuid = json['uuid']?.toString(); + spaceName = json['spaceName']?.toString(); + } + + Map toJson() { + final data = {}; + data['uuid'] = uuid; + data['spaceName'] = spaceName; + return data; + } +} diff --git a/lib/pages/device_managment/all_devices/models/devices_model.dart b/lib/pages/device_managment/all_devices/models/devices_model.dart index b706dad3..f62c4cff 100644 --- a/lib/pages/device_managment/all_devices/models/devices_model.dart +++ b/lib/pages/device_managment/all_devices/models/devices_model.dart @@ -1,3 +1,4 @@ +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; @@ -64,6 +65,7 @@ class AllDevicesModel { String? uuid; int? batteryLevel; String? productName; + List? spaces; AllDevicesModel({ this.room, @@ -92,6 +94,7 @@ class AllDevicesModel { this.uuid, this.batteryLevel, this.productName, + this.spaces, }); AllDevicesModel.fromJson(Map json) { room = (json['room'] != null && (json['room'] is Map)) @@ -124,6 +127,11 @@ class AllDevicesModel { uuid = json['uuid']?.toString(); batteryLevel = int.tryParse(json['battery']?.toString() ?? ''); productName = json['productName']?.toString(); + if (json['spaces'] != null && json['spaces'] is List) { + spaces = (json['spaces'] as List) + .map((space) => DeviceSpaceModel.fromJson(space)) + .toList(); + } } String _getDefaultIcon(String? productType) { @@ -186,6 +194,9 @@ class AllDevicesModel { data['uuid'] = uuid; data['battery'] = batteryLevel; data['productName'] = productName; + if (spaces != null) { + data['spaces'] = spaces!.map((space) => space.toJson()).toList(); + } return data; } diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 2787c7b9..148d085f 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -138,8 +138,8 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { 'Device Name', 'Product Name', 'Device ID', - 'Unit Name', - 'Room', + 'Space Name', + 'location', 'Battery Level', 'Installation Date and Time', 'Status', diff --git a/lib/services/devices_mang_api.dart b/lib/services/devices_mang_api.dart index bb591b0d..c8f680d2 100644 --- a/lib/services/devices_mang_api.dart +++ b/lib/services/devices_mang_api.dart @@ -68,7 +68,8 @@ class DevicesManagementApi { } } - Future deviceBatchControl(List uuids, String code, dynamic value) async { + Future deviceBatchControl( + List uuids, String code, dynamic value) async { try { final body = { 'devicesUuid': uuids, @@ -92,7 +93,8 @@ class DevicesManagementApi { } } - static Future> getDevicesByGatewayId(String gatewayId) async { + static Future> getDevicesByGatewayId( + String gatewayId) async { final response = await HTTPService().get( path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), showServerMessage: false, @@ -126,7 +128,9 @@ class DevicesManagementApi { String code, ) async { final response = await HTTPService().get( - path: ApiEndpoints.getDeviceLogs.replaceAll('{uuid}', uuid).replaceAll('{code}', code), + path: ApiEndpoints.getDeviceLogs + .replaceAll('{uuid}', uuid) + .replaceAll('{code}', code), showServerMessage: false, expectedResponseModel: (json) { return DeviceReport.fromJson(json); @@ -135,7 +139,8 @@ class DevicesManagementApi { return response; } - static Future getDeviceReportsByDate(String uuid, String code, [String? from, String? to]) async { + static Future getDeviceReportsByDate(String uuid, String code, + [String? from, String? to]) async { final response = await HTTPService().get( path: ApiEndpoints.getDeviceLogsByDate .replaceAll('{uuid}', uuid) @@ -174,7 +179,8 @@ class DevicesManagementApi { } } - Future addScheduleRecord(ScheduleEntry sendSchedule, String uuid) async { + Future addScheduleRecord( + ScheduleEntry sendSchedule, String uuid) async { try { final response = await HTTPService().post( path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid), @@ -191,10 +197,13 @@ class DevicesManagementApi { } } - Future> getDeviceSchedules(String uuid, String category) async { + Future> getDeviceSchedules( + String uuid, String category) async { try { final response = await HTTPService().get( - path: ApiEndpoints.getScheduleByDeviceId.replaceAll('{deviceUuid}', uuid).replaceAll('{category}', category), + path: ApiEndpoints.getScheduleByDeviceId + .replaceAll('{deviceUuid}', uuid) + .replaceAll('{category}', category), showServerMessage: true, expectedResponseModel: (json) { List schedules = []; @@ -211,7 +220,10 @@ class DevicesManagementApi { } } - Future updateScheduleRecord({required bool enable, required String uuid, required String scheduleId}) async { + Future updateScheduleRecord( + {required bool enable, + required String uuid, + required String scheduleId}) async { try { final response = await HTTPService().put( path: ApiEndpoints.updateScheduleByDeviceId @@ -232,7 +244,8 @@ class DevicesManagementApi { } } - Future editScheduleRecord(String uuid, ScheduleEntry newSchedule) async { + Future editScheduleRecord( + String uuid, ScheduleEntry newSchedule) async { try { final response = await HTTPService().put( path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid), From c297e02a846a10850153f6cc561c4595223ecdfe Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 22 Oct 2024 10:12:08 +0400 Subject: [PATCH 2/5] added community to all device --- .../models/device_community.model.dart | 18 ++++++++++++++++++ .../all_devices/models/devices_model.dart | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 lib/pages/device_managment/all_devices/models/device_community.model.dart diff --git a/lib/pages/device_managment/all_devices/models/device_community.model.dart b/lib/pages/device_managment/all_devices/models/device_community.model.dart new file mode 100644 index 00000000..6f91cab6 --- /dev/null +++ b/lib/pages/device_managment/all_devices/models/device_community.model.dart @@ -0,0 +1,18 @@ +class DeviceCommunityModel { + String? uuid; + String? name; + + DeviceCommunityModel({this.uuid, this.name}); + + DeviceCommunityModel.fromJson(Map json) { + uuid = json['uuid']?.toString(); + name = json['name']?.toString(); + } + + Map toJson() { + final data = {}; + data['uuid'] = uuid; + data['name'] = name; + return data; + } +} diff --git a/lib/pages/device_managment/all_devices/models/devices_model.dart b/lib/pages/device_managment/all_devices/models/devices_model.dart index f62c4cff..df80c3e7 100644 --- a/lib/pages/device_managment/all_devices/models/devices_model.dart +++ b/lib/pages/device_managment/all_devices/models/devices_model.dart @@ -1,3 +1,4 @@ +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart'; @@ -41,6 +42,7 @@ class AllDevicesModel { DevicesModelRoom? room; DevicesModelUnit? unit; + DeviceCommunityModel? community; String? productUuid; String? productType; String? permissionType; @@ -70,6 +72,7 @@ class AllDevicesModel { AllDevicesModel({ this.room, this.unit, + this.community, this.productUuid, this.productType, this.permissionType, @@ -103,6 +106,9 @@ class AllDevicesModel { unit = (json['unit'] != null && (json['unit'] is Map)) ? DevicesModelUnit.fromJson(json['unit']) : null; + community = (json['community'] != null && (json['community'] is Map)) + ? DeviceCommunityModel.fromJson(json['community']) + : null; productUuid = json['productUuid']?.toString(); productType = json['productType']?.toString(); permissionType = json['permissionType']?.toString(); @@ -170,6 +176,9 @@ class AllDevicesModel { if (unit != null) { data['unit'] = unit!.toJson(); } + if (community != null) { + data['community'] = community!.toJson(); + } data['productUuid'] = productUuid; data['productType'] = productType; data['permissionType'] = permissionType; From 76f48aad6f042d7f361a0b3cbd955ac68ca40362 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 22 Oct 2024 10:22:39 +0400 Subject: [PATCH 3/5] added community --- .../widgets/device_managment_body.dart | 68 ++++++++++++++----- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 148d085f..397909a8 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -58,12 +58,15 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { 'Low Battery ($lowBatteryCount)', ]; - final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control'; + final buttonLabel = + (selectedDevices.length > 1) ? 'Batch Control' : 'Control'; return Column( children: [ Container( - padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15), + padding: isLargeScreenSize(context) + ? const EdgeInsets.all(30) + : const EdgeInsets.all(15), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -72,7 +75,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { tabs: tabs, selectedIndex: selectedIndex, onTabChanged: (index) { - context.read().add(SelectedFilterChanged(index)); + context + .read() + .add(SelectedFilterChanged(index)); }, ), const SizedBox(height: 20), @@ -94,11 +99,14 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { ), ); } else if (selectedDevices.length > 1) { - final productTypes = selectedDevices.map((device) => device.productType).toSet(); + final productTypes = selectedDevices + .map((device) => device.productType) + .toSet(); if (productTypes.length == 1) { showDialog( context: context, - builder: (context) => DeviceBatchControlDialog( + builder: (context) => + DeviceBatchControlDialog( devices: selectedDevices, ), ); @@ -112,7 +120,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { textAlign: TextAlign.center, style: TextStyle( fontSize: 12, - color: isControlButtonEnabled ? Colors.white : Colors.grey, + color: isControlButtonEnabled + ? Colors.white + : Colors.grey, ), ), ), @@ -123,13 +133,17 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { ), Expanded( child: Padding( - padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15), + padding: isLargeScreenSize(context) + ? const EdgeInsets.all(30) + : const EdgeInsets.all(15), child: DynamicTable( withSelectAll: true, cellDecoration: containerDecoration, onRowSelected: (index, isSelected, row) { final selectedDevice = devicesToShow[index]; - context.read().add(SelectDevice(selectedDevice)); + context + .read() + .add(SelectDevice(selectedDevice)); }, withCheckBox: true, size: context.screenSize, @@ -146,23 +160,45 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { 'Last Offline Date and Time', ], data: devicesToShow.map((device) { + final combinedSpaceNames = device.spaces != null + ? device.spaces! + .map((space) => space.spaceName) + .join(' > ') + + (device.community != null + ? ' > ${device.community!.name}' + : '') + : (device.community != null + ? device.community!.name + : ''); + return [ device.name ?? '', device.productName ?? '', device.uuid ?? '', - device.unit?.name ?? '', - device.room?.name ?? '', - device.batteryLevel != null ? '${device.batteryLevel}%' : '-', - formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)), + (device.spaces != null && device.spaces!.isNotEmpty) + ? device.spaces![0].spaceName + : '', + combinedSpaceNames, + device.batteryLevel != null + ? '${device.batteryLevel}%' + : '-', + formatDateTime(DateTime.fromMillisecondsSinceEpoch( + (device.createTime ?? 0) * 1000)), device.online == true ? 'Online' : 'Offline', - formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)), + formatDateTime(DateTime.fromMillisecondsSinceEpoch( + (device.updateTime ?? 0) * 1000)), ]; }).toList(), onSelectionChanged: (selectedRows) { - context.read().add(UpdateSelection(selectedRows)); + context + .read() + .add(UpdateSelection(selectedRows)); }, - initialSelectedIds: - context.read().selectedDevices.map((device) => device.uuid!).toList(), + initialSelectedIds: context + .read() + .selectedDevices + .map((device) => device.uuid!) + .toList(), isEmpty: devicesToShow.isEmpty, ), ), From 0b0fee2e260824c7b26fb2963e257a64de975d51 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 22 Oct 2024 10:47:14 +0400 Subject: [PATCH 4/5] added community filtering --- .../bloc/device_managment_bloc.dart | 68 +++++++++++++------ .../widgets/device_search_filters.dart | 4 +- .../shared/device_control_dialog.dart | 2 +- .../view/add_device_dialog.dart | 4 +- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart index cb5b427f..628e2d5f 100644 --- a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart +++ b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart @@ -6,7 +6,8 @@ import 'package:syncrow_web/services/devices_mang_api.dart'; part 'device_managment_event.dart'; part 'device_managment_state.dart'; -class DeviceManagementBloc extends Bloc { +class DeviceManagementBloc + extends Bloc { int _selectedIndex = 0; List _devices = []; int _onlineCount = 0; @@ -29,7 +30,8 @@ class DeviceManagementBloc extends Bloc(_onUpdateSelection); } - Future _onFetchDevices(FetchDevices event, Emitter emit) async { + Future _onFetchDevices( + FetchDevices event, Emitter emit) async { emit(DeviceManagementLoading()); try { final devices = await DevicesManagementApi().fetchDevices(); @@ -51,7 +53,8 @@ class DeviceManagementBloc extends Bloc emit) async { + void _onFilterDevices( + FilterDevices event, Emitter emit) async { if (_devices.isNotEmpty) { _filteredDevices = List.from(_devices.where((device) { switch (event.filter) { @@ -82,7 +85,8 @@ class DeviceManagementBloc extends Bloc _onResetFilters(ResetFilters event, Emitter emit) async { + Future _onResetFilters( + ResetFilters event, Emitter emit) async { currentProductName = ''; _selectedDevices.clear(); _filteredDevices = List.from(_devices); @@ -98,7 +102,8 @@ class DeviceManagementBloc extends Bloc emit) { + void _onResetSelectedDevices( + ResetSelectedDevices event, Emitter emit) { _selectedDevices.clear(); if (state is DeviceManagementLoaded) { @@ -124,12 +129,14 @@ class DeviceManagementBloc extends Bloc emit) { + void _onSelectedFilterChanged( + SelectedFilterChanged event, Emitter emit) { _selectedIndex = event.selectedIndex; add(FilterDevices(_getFilterFromIndex(_selectedIndex))); } - void _onSelectDevice(SelectDevice event, Emitter emit) { + void _onSelectDevice( + SelectDevice event, Emitter emit) { final selectedUuid = event.selectedDevice.uuid; if (_selectedDevices.any((device) => device.uuid == selectedUuid)) { @@ -140,7 +147,8 @@ class DeviceManagementBloc extends Bloc clonedSelectedDevices = List.from(_selectedDevices); - bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices); + bool isControlButtonEnabled = + _checkIfControlButtonEnabled(clonedSelectedDevices); if (state is DeviceManagementLoaded) { emit(DeviceManagementLoaded( @@ -149,7 +157,8 @@ class DeviceManagementBloc extends Bloc emit) { + void _onUpdateSelection( + UpdateSelection event, Emitter emit) { List selectedDevices = []; List devicesToSelectFrom = []; @@ -208,7 +219,8 @@ class DeviceManagementBloc extends Bloc selectedDevices) { if (selectedDevices.length > 1) { - final productTypes = selectedDevices.map((device) => device.productType).toSet(); + final productTypes = + selectedDevices.map((device) => device.productType).toSet(); return productTypes.length == 1; } else if (selectedDevices.length == 1) { return true; @@ -219,8 +231,10 @@ class DeviceManagementBloc extends Bloc device.online == true).length; _offlineCount = _devices.where((device) => device.online == false).length; - _lowBatteryCount = - _devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length; + _lowBatteryCount = _devices + .where((device) => + device.batteryLevel != null && device.batteryLevel! < 20) + .length; } String _getFilterFromIndex(int index) { @@ -236,7 +250,8 @@ class DeviceManagementBloc extends Bloc emit) { + void _onSearchDevices( + SearchDevices event, Emitter emit) { if ((event.community == null || event.community!.isEmpty) && (event.unitName == null || event.unitName!.isEmpty) && (event.productName == null || event.productName!.isEmpty)) { @@ -265,19 +280,32 @@ class DeviceManagementBloc extends Bloc with HelperRe children: [ _buildSearchField("Community", communityController, 200), const SizedBox(width: 20), - _buildSearchField("Unit Name", unitNameController, 200), + _buildSearchField("Space Name", unitNameController, 200), const SizedBox(width: 20), _buildSearchField("Device Name / Product Name", productNameController, 300), const SizedBox(width: 20), @@ -48,7 +48,7 @@ class _DeviceSearchFiltersState extends State with HelperRe communityController, 200, ), - _buildSearchField("Unit Name", unitNameController, 200), + _buildSearchField("Space Name", unitNameController, 200), _buildSearchField( "Device Name / Product Name", productNameController, diff --git a/lib/pages/device_managment/shared/device_control_dialog.dart b/lib/pages/device_managment/shared/device_control_dialog.dart index 14878a46..660e654b 100644 --- a/lib/pages/device_managment/shared/device_control_dialog.dart +++ b/lib/pages/device_managment/shared/device_control_dialog.dart @@ -94,7 +94,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode { ]), TableRow( children: [ - _buildInfoRow('Unit Name:', device.unit?.name ?? 'N/A'), + _buildInfoRow('Space Name:', device.unit?.name ?? 'N/A'), _buildInfoRow('Room:', device.room?.name ?? 'N/A'), ], ), diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 5a4a4785..ebc41292 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -111,7 +111,7 @@ class AddDeviceDialog extends StatelessWidget { child: CustomWebTextField( controller: visitorBloc.unitNameController, isRequired: false, - textFieldName: 'Unit Name', + textFieldName: 'Space Name', description: '', ), ), @@ -185,7 +185,7 @@ class AddDeviceDialog extends StatelessWidget { 'Device Name', 'Device ID', 'Access Type', - 'Unit Name', + 'Space Name', 'Status' ], data: state.data.map((item) { From 64b84fed825e1ec6d22ed2a00b97766f721fdfb0 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 22 Oct 2024 11:31:49 +0400 Subject: [PATCH 5/5] filter by space --- .../all_devices/bloc/device_managment_bloc.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart index 628e2d5f..8f6d085d 100644 --- a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart +++ b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart @@ -286,10 +286,11 @@ class DeviceManagementBloc false); final matchesUnit = event.unitName == null || event.unitName!.isEmpty || - (device.unit?.name - ?.toLowerCase() - .contains(event.unitName!.toLowerCase()) ?? - false); + (device.spaces != null && + device.spaces!.isNotEmpty && + device.spaces![0].spaceName + !.toLowerCase() + .contains(event.unitName!.toLowerCase())); final matchesProductName = event.productName == null || event.productName!.isEmpty || (device.name