diff --git a/assets/icons/close_settings_icon.svg b/assets/icons/close_settings_icon.svg
new file mode 100644
index 00000000..93e615d8
--- /dev/null
+++ b/assets/icons/close_settings_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/edit_name_icon_settings.svg b/assets/icons/edit_name_icon_settings.svg
new file mode 100644
index 00000000..54bee0af
--- /dev/null
+++ b/assets/icons/edit_name_icon_settings.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/settings_button.svg b/assets/icons/settings_button.svg
new file mode 100644
index 00000000..43cad368
--- /dev/null
+++ b/assets/icons/settings_button.svg
@@ -0,0 +1,24 @@
+
diff --git a/lib/pages/analytics/models/analytics_device.dart b/lib/pages/analytics/models/analytics_device.dart
index 88f18ec5..eaac8b2b 100644
--- a/lib/pages/analytics/models/analytics_device.dart
+++ b/lib/pages/analytics/models/analytics_device.dart
@@ -23,17 +23,18 @@ class AnalyticsDevice {
return AnalyticsDevice(
uuid: json['uuid'] as String,
name: json['name'] as String,
- createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt'] as String) : null,
- updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'] as String) : null,
+ createdAt: json['createdAt'] != null
+ ? DateTime.parse(json['createdAt'] as String)
+ : null,
+ updatedAt: json['updatedAt'] != null
+ ? DateTime.parse(json['updatedAt'] as String)
+ : null,
deviceTuyaUuid: json['deviceTuyaUuid'] as String?,
isActive: json['isActive'] as bool?,
- productDevice: json['productDevice'] != null
- ? ProductDevice.fromJson(json['productDevice'] as Map)
- : null,
- spaceUuid: (json['spaces'] as List?)
- ?.map((e) => e['uuid'])
- .firstOrNull
- ?.toString(),
+ productDevice: json['productDevice'] != null
+ ? ProductDevice.fromJson(json['productDevice'] as Map)
+ : null,
+ spaceUuid: json['spaceUuid'] as String?,
);
}
}
@@ -60,8 +61,12 @@ class ProductDevice {
factory ProductDevice.fromJson(Map json) {
return ProductDevice(
uuid: json['uuid'] as String?,
- createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt'] as String) : null,
- updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'] as String) : null,
+ createdAt: json['createdAt'] != null
+ ? DateTime.parse(json['createdAt'] as String)
+ : null,
+ updatedAt: json['updatedAt'] != null
+ ? DateTime.parse(json['updatedAt'] as String)
+ : null,
catName: json['catName'] as String?,
prodId: json['prodId'] as String?,
name: json['name'] as String?,
diff --git a/lib/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart b/lib/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart
index b1af85c8..2ed68e76 100644
--- a/lib/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart
+++ b/lib/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart
@@ -38,7 +38,7 @@ abstract final class EnergyManagementChartsHelper {
sideTitles: SideTitles(
showTitles: true,
maxIncluded: false,
- minIncluded: false,
+ minIncluded: true,
interval: leftTitlesInterval,
reservedSize: 110,
getTitlesWidget: (value, meta) => Padding(
diff --git a/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart b/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart
index a6fe4703..8de92098 100644
--- a/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart
+++ b/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart
@@ -16,7 +16,6 @@ import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_
abstract final class FetchEnergyManagementDataHelper {
const FetchEnergyManagementDataHelper._();
- // static const String _powerClampId = 'cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa';
static AnalyticsDevice? getSelectedDevice(BuildContext context) {
return context.read().state.selectedDevice;
}
@@ -48,7 +47,6 @@ abstract final class FetchEnergyManagementDataHelper {
loadTotalEnergyConsumption(
context,
selectedDate: selectedDate0,
- communityId: communityId,
spaceId: spaceId,
);
final selectedDevice = getSelectedDevice(context);
@@ -61,7 +59,6 @@ abstract final class FetchEnergyManagementDataHelper {
}
loadEnergyConsumptionPerDevice(
context,
- communityId: communityId,
spaceId: spaceId,
selectedDate: selectedDate0,
);
@@ -84,12 +81,10 @@ abstract final class FetchEnergyManagementDataHelper {
static void loadTotalEnergyConsumption(
BuildContext context, {
DateTime? selectedDate,
- required String communityId,
required String spaceId,
}) {
final param = GetTotalEnergyConsumptionParam(
spaceId: spaceId,
- communityId: communityId,
monthDate: selectedDate,
);
context.read().add(
@@ -100,12 +95,10 @@ abstract final class FetchEnergyManagementDataHelper {
static void loadEnergyConsumptionPerDevice(
BuildContext context, {
DateTime? selectedDate,
- required String communityId,
required String spaceId,
}) {
final param = GetEnergyConsumptionPerDeviceParam(
spaceId: spaceId,
- communityId: communityId,
monthDate: selectedDate,
);
context.read().add(
diff --git a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart
index f22517d5..be5faf57 100644
--- a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart
+++ b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart
@@ -23,7 +23,6 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
),
padding: const EdgeInsets.all(30),
child: Column(
- spacing: 20,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AnalyticsErrorWidget(state.errorMessage),
@@ -52,7 +51,9 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
),
],
),
+ const SizedBox(height: 20),
const Divider(height: 0),
+ const SizedBox(height: 20),
Expanded(
child: EnergyConsumptionPerDeviceChart(chartData: state.chartData),
),
diff --git a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart
index b7205424..f0cb5d64 100644
--- a/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart
+++ b/lib/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart
@@ -41,7 +41,7 @@ class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
.color;
return Tooltip(
- message: '${device.name}\n${device.productDevice?.uuid ?? ''}',
+ message: '${device.name}\n${device.spaceUuid ?? ''}',
child: ChartInformativeCell(title: Text(device.name), color: deviceColor),
);
}
diff --git a/lib/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart b/lib/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart
index 4d04a36b..f95ff7d1 100644
--- a/lib/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart
+++ b/lib/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart
@@ -41,7 +41,7 @@ class PowerClampEnergyDataWidget extends StatelessWidget {
AnalyticsErrorWidget(state.errorMessage),
AnalyticsSidebarHeader(
title: 'Smart Power Clamp',
- showSpaceUuid: true,
+ showSpaceUuidInDevicesDropdown: true,
onChanged: (device) {
FetchEnergyManagementDataHelper.loadEnergyConsumptionByPhases(
context,
diff --git a/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart b/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart
index 9e70e45e..e197c297 100644
--- a/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart
+++ b/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart
@@ -19,7 +19,6 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
),
padding: const EdgeInsets.all(30),
child: Column(
- spacing: 20,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AnalyticsErrorWidget(state.errorMessage),
@@ -39,7 +38,9 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
const Spacer(flex: 4),
],
),
+ const SizedBox(height: 20),
const Divider(),
+ const SizedBox(height: 20),
TotalEnergyConsumptionChart(chartData: state.chartData),
],
),
diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart
index 4ff85841..70087c46 100644
--- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart
+++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart
@@ -16,7 +16,7 @@ class OccupancyChart extends StatelessWidget {
Widget build(BuildContext context) {
return BarChart(
BarChartData(
- maxY: 100.0,
+ maxY: 100.001,
gridData: EnergyManagementChartsHelper.gridData().copyWith(
checkToShowHorizontalLine: (value) => true,
horizontalInterval: 20,
@@ -134,7 +134,7 @@ class OccupancyChart extends StatelessWidget {
alignment: AlignmentDirectional.bottomCenter,
fit: BoxFit.scaleDown,
child: Text(
- (value + 1).toString(),
+ chartData[value.toInt()].date.day.toString(),
style: context.textTheme.bodySmall?.copyWith(
color: ColorsManager.greyColor,
fontSize: 8,
diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart
index ab1d1699..08f7223f 100644
--- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart
+++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_chart_box.dart
@@ -22,7 +22,6 @@ class OccupancyChartBox extends StatelessWidget {
padding: const EdgeInsets.all(30),
decoration: containerWhiteDecoration,
child: Column(
- spacing: 20,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -65,7 +64,9 @@ class OccupancyChartBox extends StatelessWidget {
),
],
),
- const Divider(height: 0),
+ const SizedBox(height: 20),
+ const Divider(),
+ const SizedBox(height: 20),
Expanded(child: OccupancyChart(chartData: state.chartData)),
],
),
diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart
index cab9eab4..c3b537e0 100644
--- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart
+++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map_box.dart
@@ -22,7 +22,6 @@ class OccupancyHeatMapBox extends StatelessWidget {
padding: const EdgeInsets.all(30),
decoration: containerWhiteDecoration,
child: Column(
- spacing: 20,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -66,7 +65,9 @@ class OccupancyHeatMapBox extends StatelessWidget {
),
],
),
- const Divider(height: 0),
+ const SizedBox(height: 20),
+ const Divider(),
+ const SizedBox(height: 20),
Expanded(
child: OccupancyHeatMap(
heatMapData: state.heatMapData.asMap().map(
diff --git a/lib/pages/analytics/params/get_energy_consumption_per_device_param.dart b/lib/pages/analytics/params/get_energy_consumption_per_device_param.dart
index ba659ae7..79d0f2f4 100644
--- a/lib/pages/analytics/params/get_energy_consumption_per_device_param.dart
+++ b/lib/pages/analytics/params/get_energy_consumption_per_device_param.dart
@@ -2,18 +2,15 @@ class GetEnergyConsumptionPerDeviceParam {
const GetEnergyConsumptionPerDeviceParam({
this.monthDate,
this.spaceId,
- this.communityId,
});
final DateTime? monthDate;
final String? spaceId;
- final String? communityId;
Map toJson() => {
'monthDate':
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
if (spaceId == null || spaceId == null) 'spaceUuid': spaceId,
- 'communityUuid': communityId,
'groupByDevice': true,
};
}
diff --git a/lib/pages/analytics/params/get_total_energy_consumption_param.dart b/lib/pages/analytics/params/get_total_energy_consumption_param.dart
index c47e5bfe..6428fd30 100644
--- a/lib/pages/analytics/params/get_total_energy_consumption_param.dart
+++ b/lib/pages/analytics/params/get_total_energy_consumption_param.dart
@@ -1,12 +1,10 @@
class GetTotalEnergyConsumptionParam {
final DateTime? monthDate;
final String? spaceId;
- final String? communityId;
const GetTotalEnergyConsumptionParam({
this.monthDate,
this.spaceId,
- this.communityId,
});
Map toJson() {
@@ -14,7 +12,6 @@ class GetTotalEnergyConsumptionParam {
'monthDate':
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
if (spaceId == null || spaceId == null) 'spaceUuid': spaceId,
- 'communityUuid': communityId,
'groupByDevice': false,
};
}
diff --git a/lib/pages/analytics/widgets/analytics_error_widget.dart b/lib/pages/analytics/widgets/analytics_error_widget.dart
index 60167992..7c560da4 100644
--- a/lib/pages/analytics/widgets/analytics_error_widget.dart
+++ b/lib/pages/analytics/widgets/analytics_error_widget.dart
@@ -11,14 +11,17 @@ class AnalyticsErrorWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Visibility(
visible: errorMessage != null || (errorMessage?.isNotEmpty ?? false),
- child: Text(
- errorMessage ?? 'Something went wrong',
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: context.textTheme.bodySmall?.copyWith(
- color: ColorsManager.red,
- fontWeight: FontWeight.w400,
- fontSize: 8,
+ child: Padding(
+ padding: const EdgeInsetsDirectional.only(bottom: 10),
+ child: Text(
+ errorMessage ?? 'Something went wrong',
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ style: context.textTheme.bodySmall?.copyWith(
+ color: ColorsManager.red,
+ fontWeight: FontWeight.w400,
+ fontSize: 8,
+ ),
),
),
);
diff --git a/lib/pages/analytics/widgets/analytics_sidebar_header.dart b/lib/pages/analytics/widgets/analytics_sidebar_header.dart
index 5e454ea4..5ff1d042 100644
--- a/lib/pages/analytics/widgets/analytics_sidebar_header.dart
+++ b/lib/pages/analytics/widgets/analytics_sidebar_header.dart
@@ -10,13 +10,13 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
class AnalyticsSidebarHeader extends StatelessWidget {
const AnalyticsSidebarHeader({
required this.title,
- this.showSpaceUuid = false,
+ this.showSpaceUuidInDevicesDropdown = false,
this.onChanged,
super.key,
});
final String title;
- final bool showSpaceUuid;
+ final bool showSpaceUuidInDevicesDropdown;
final void Function(AnalyticsDevice device)? onChanged;
@override
@@ -49,6 +49,7 @@ class AnalyticsSidebarHeader extends StatelessWidget {
alignment: AlignmentDirectional.centerEnd,
fit: BoxFit.scaleDown,
child: AnalyticsDeviceDropdown(
+ showSpaceUuid: showSpaceUuidInDevicesDropdown,
onChanged: (value) {
context.read().add(
SelectAnalyticsDeviceEvent(value),
diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart
index 62760a16..f23daa45 100644
--- a/lib/pages/common/custom_table.dart
+++ b/lib/pages/common/custom_table.dart
@@ -162,31 +162,34 @@ class _DynamicTableState extends State {
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalBodyScrollController,
- child: SizedBox(
- width: widget.size.width,
- child: widget.isEmpty
- ? _buildEmptyState()
- : Column(
- children:
- List.generate(widget.data.length, (rowIndex) {
- final row = widget.data[rowIndex];
- return Row(
- children: [
- if (widget.withCheckBox)
- _buildRowCheckbox(
- rowIndex, widget.size.height * 0.08),
- ...row.asMap().entries.map((entry) {
- return _buildTableCell(
- entry.value.toString(),
- widget.size.height * 0.08,
- rowIndex: rowIndex,
- columnIndex: entry.key,
- );
- }).toList(),
- ],
- );
- }),
- ),
+ child: Container(
+ color: ColorsManager.whiteColors,
+ child: SizedBox(
+ width: widget.size.width,
+ child: widget.isEmpty
+ ? _buildEmptyState()
+ : Column(
+ children: List.generate(widget.data.length,
+ (rowIndex) {
+ final row = widget.data[rowIndex];
+ return Row(
+ children: [
+ if (widget.withCheckBox)
+ _buildRowCheckbox(rowIndex,
+ widget.size.height * 0.08),
+ ...row.asMap().entries.map((entry) {
+ return _buildTableCell(
+ entry.value.toString(),
+ widget.size.height * 0.08,
+ rowIndex: rowIndex,
+ columnIndex: entry.key,
+ );
+ }).toList(),
+ ],
+ );
+ }),
+ ),
+ ),
),
),
),
@@ -310,7 +313,12 @@ class _DynamicTableState extends State {
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
if (isSettingsColumn) {
- return _buildSettingsIcon(rowIndex, size);
+ return buildSettingsIcon(
+ width: 120,
+ height: 60,
+ iconSize: 40,
+ onTap: () => widget.onSettingsPressed?.call(rowIndex),
+ );
}
Color? statusColor;
@@ -364,22 +372,63 @@ class _DynamicTableState extends State {
);
}
- Widget _buildSettingsIcon(int rowIndex, double size) {
- return Container(
- height: size,
- width: 120,
- padding: const EdgeInsets.all(5.0),
- decoration: const BoxDecoration(
- border: Border(
- bottom: BorderSide(color: ColorsManager.boxDivider, width: 1.0),
+ Widget buildSettingsIcon(
+ {double width = 120,
+ double height = 60,
+ double iconSize = 40,
+ VoidCallback? onTap}) {
+ return Column(
+ children: [
+ Container(
+ padding: const EdgeInsets.only(top: 10, bottom: 15, left: 10),
+ margin: const EdgeInsets.only(right: 15),
+ decoration: const BoxDecoration(
+ color: ColorsManager.whiteColors,
+ border: Border(
+ bottom: BorderSide(
+ color: ColorsManager.boxDivider,
+ width: 1.0,
+ ),
+ ),
+ ),
+ width: width,
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: 16.0,
+ left: 17.0,
+ ),
+ child: Container(
+ width: 50,
+ decoration: BoxDecoration(
+ color: const Color(0xFFF7F8FA),
+ borderRadius: BorderRadius.circular(height / 2),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.black.withOpacity(0.17),
+ blurRadius: 14,
+ offset: const Offset(0, 4),
+ ),
+ ],
+ ),
+ child: InkWell(
+ onTap: onTap,
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Center(
+ child: SvgPicture.asset(
+ Assets.settings, // ضع المسار الصحيح هنا
+ width: 40,
+ height: 22,
+ color: ColorsManager
+ .primaryColor, // نفس لون الأيقونة في الصورة
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
),
- color: Colors.white,
- ),
- alignment: Alignment.center,
- child: IconButton(
- icon: SvgPicture.asset(Assets.settings),
- onPressed: () => widget.onSettingsPressed?.call(rowIndex),
- ),
+ ],
);
}
}
diff --git a/lib/pages/device_managment/all_devices/view/device_managment_page.dart b/lib/pages/device_managment/all_devices/view/device_managment_page.dart
index fd3a2574..755bc8b7 100644
--- a/lib/pages/device_managment/all_devices/view/device_managment_page.dart
+++ b/lib/pages/device_managment/all_devices/view/device_managment_page.dart
@@ -95,7 +95,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
return const RoutinesView();
}
if (state.createRoutineView) {
- return CreateNewRoutineView();
+ return const CreateNewRoutineView();
}
return BlocBuilder(
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 a3c975c1..f4baad0c 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
@@ -6,9 +6,11 @@ import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
+import 'package:syncrow_web/pages/device_managment/device_setting/device_settings_panel.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
+import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/format_date_time.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
import 'package:syncrow_web/utils/style.dart';
@@ -58,7 +60,8 @@ 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 Row(
children: [
@@ -105,18 +108,23 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
if (selectedDevices.length == 1) {
showDialog(
context: context,
- builder: (context) => DeviceControlDialog(
+ builder: (context) =>
+ DeviceControlDialog(
device: selectedDevices.first,
),
);
- } else if (selectedDevices.length > 1) {
- final productTypes = selectedDevices
- .map((device) => device.productType)
- .toSet();
+ } else if (selectedDevices.length >
+ 1) {
+ final productTypes =
+ selectedDevices
+ .map((device) =>
+ device.productType)
+ .toSet();
if (productTypes.length == 1) {
showDialog(
context: context,
- builder: (context) => DeviceBatchControlDialog(
+ builder: (context) =>
+ DeviceBatchControlDialog(
devices: selectedDevices,
),
);
@@ -130,7 +138,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,
),
),
),
@@ -166,29 +176,40 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Installation Date and Time',
'Status',
'Last Offline Date and Time',
+ 'Settings'
],
data: devicesToShow.map((device) {
final combinedSpaceNames = device.spaces != null
- ? device.spaces!.map((space) => space.spaceName).join(' > ') +
+ ? device.spaces!
+ .map((space) => space.spaceName)
+ .join(' > ') +
(device.community != null
? ' > ${device.community!.name}'
: '')
- : (device.community != null ? device.community!.name : '');
+ : (device.community != null
+ ? device.community!.name
+ : '');
return [
device.name ?? '',
device.productName ?? '',
device.uuid ?? '',
- (device.spaces != null && device.spaces!.isNotEmpty)
+ (device.spaces != null &&
+ device.spaces!.isNotEmpty)
? device.spaces![0].spaceName
: '',
combinedSpaceNames,
- device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
- formatDateTime(DateTime.fromMillisecondsSinceEpoch(
- (device.createTime ?? 0) * 1000)),
+ 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)),
+ 'Settings',
];
}).toList(),
onSelectionChanged: (selectedRows) {
@@ -202,6 +223,10 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
.map((device) => device.uuid!)
.toList(),
isEmpty: devicesToShow.isEmpty,
+ onSettingsPressed: (rowIndex) {
+ final device = devicesToShow[rowIndex];
+ showDeviceSettingsSidebar(context, device);
+ },
),
),
)
@@ -213,4 +238,37 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
},
);
}
+
+ void showDeviceSettingsSidebar(BuildContext context, AllDevicesModel device) {
+ showGeneralDialog(
+ context: context,
+ barrierDismissible: true,
+ barrierLabel: "Device Settings",
+ transitionDuration: const Duration(milliseconds: 300),
+ pageBuilder: (context, anim1, anim2) {
+ return Align(
+ alignment: Alignment.centerRight,
+ child: Material(
+ child: Container(
+ width: MediaQuery.of(context).size.width * 0.3,
+ color: ColorsManager.whiteColors,
+ child: DeviceSettingsPanel(
+ device: device,
+ onClose: () => Navigator.of(context).pop(),
+ ),
+ ),
+ ),
+ );
+ },
+ transitionBuilder: (context, anim1, anim2, child) {
+ return SlideTransition(
+ position: Tween(
+ begin: const Offset(1, 0),
+ end: Offset.zero,
+ ).animate(anim1),
+ child: child,
+ );
+ },
+ );
+ }
}
diff --git a/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart b/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart
new file mode 100644
index 00000000..c996cf72
--- /dev/null
+++ b/lib/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart
@@ -0,0 +1,165 @@
+import 'package:bloc/bloc.dart';
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
+import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart';
+import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart';
+import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart';
+import 'package:syncrow_web/services/devices_mang_api.dart';
+import 'package:syncrow_web/services/space_mana_api.dart';
+import 'package:syncrow_web/utils/snack_bar.dart';
+part 'setting_bloc_event.dart';
+
+class SettingDeviceBloc extends Bloc {
+ final String deviceId;
+ SettingDeviceBloc({
+ required this.deviceId,
+ }) : super(const DeviceSettingsInitial()) {
+ on(_fetchDeviceInfo);
+ on(_saveName);
+ on(_changeName);
+ on(_deleteDevice);
+ on(_fetchRooms);
+ on(_onAssignDevice);
+ }
+ final TextEditingController nameController = TextEditingController();
+ List roomsList = [];
+ bool isEditingName = false;
+
+ bool _validateInputs() {
+ final nameError = _fullNameValidator(nameController.text);
+ if (nameError != null) {
+ CustomSnackBar.displaySnackBar(nameError);
+ return true;
+ }
+ return false;
+ }
+
+ String? _fullNameValidator(String? value) {
+ if (value == null) return 'name is required';
+ final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
+ if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
+ return 'name must be between 2 and 30 characters long';
+ }
+ if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
+ return 'Only alphanumeric characters, space, dash and single quote are allowed';
+ }
+ return null;
+ }
+
+ Future _saveName(
+ SettingBlocSaveName event, Emitter emit) async {
+ if (_validateInputs()) return;
+ try {
+ emit(DeviceSettingsLoading());
+ await DevicesManagementApi.putDeviceName(
+ deviceId: deviceId, deviceName: nameController.text);
+ add(DeviceSettingInitialInfo());
+ CustomSnackBar.displaySnackBar('Save Successfully');
+ emit(DeviceSettingsUpdate(deviceName: nameController.text));
+ } catch (e) {
+ emit(DeviceSettingsError(message: e.toString()));
+ }
+ }
+
+ Future _fetchDeviceInfo(
+ DeviceSettingInitialInfo event, Emitter emit) async {
+ try {
+ emit(DeviceSettingsLoading());
+ var response = await DevicesManagementApi.getDeviceInfo(deviceId);
+ DeviceInfoModel deviceInfo = DeviceInfoModel.fromJson(response);
+ nameController.text = deviceInfo.name;
+ emit(DeviceSettingsUpdate(
+ deviceName: nameController.text,
+ deviceInfo: deviceInfo,
+ roomsList: roomsList,
+ ));
+ } catch (e) {
+ emit(DeviceSettingsError(message: e.toString()));
+ }
+ }
+
+ bool editName = false;
+ final FocusNode focusNode = FocusNode();
+
+ void _changeName(ChangeNameEvent event, Emitter emit) {
+ emit(DeviceSettingsInitial(
+ deviceName: nameController.text,
+ deviceId: deviceId,
+ isEditingName: event.value ?? false,
+ editingNameValue: event.value?.toString() ?? '',
+ deviceInfo: state.deviceInfo,
+ ));
+ editName = event.value!;
+ if (editName) {
+ Future.delayed(const Duration(milliseconds: 500), () {
+ focusNode.requestFocus();
+ });
+ } else {
+ add(const SettingBlocSaveName());
+ focusNode.unfocus();
+ }
+ emit(DeviceSettingsUpdate(
+ deviceName: nameController.text,
+ deviceInfo: state.deviceInfo,
+ roomsList: roomsList,
+ ));
+ }
+
+ void _deleteDevice(
+ SettingBlocDeleteDevice event, Emitter emit) async {
+ try {
+ emit(DeviceSettingsLoading());
+ await DevicesManagementApi.resetDevice(devicesUuid: deviceId);
+ CustomSnackBar.displaySnackBar('Reset Successfully');
+ emit(DeviceSettingsUpdate(
+ deviceName: nameController.text,
+ deviceInfo: state.deviceInfo,
+ roomsList: roomsList,
+ ));
+ } catch (e) {
+ emit(DeviceSettingsError(message: e.toString()));
+ return;
+ }
+ }
+
+ void _onAssignDevice(
+ SettingBlocAssignRoom event, Emitter emit) async {
+ try {
+ emit(DeviceSettingsLoading());
+ final projectUuid = await ProjectManager.getProjectUUID() ?? '';
+ await CommunitySpaceManagementApi.assignDeviceToRoom(
+ communityId: event.communityUuid,
+ spaceId: event.spaceUuid,
+ subSpaceId: event.subSpaceUuid,
+ deviceId: deviceId,
+ projectId: projectUuid);
+ add(DeviceSettingInitialInfo());
+ CustomSnackBar.displaySnackBar('Save Successfully');
+ emit(DeviceSettingsSaveSelectionSuccess());
+ } catch (e) {
+ emit(DeviceSettingsError(message: e.toString()));
+ return;
+ }
+ }
+
+ void _fetchRooms(
+ SettingBlocFetchRooms event, Emitter emit) async {
+ try {
+ emit(DeviceSettingsLoading());
+ final projectUuid = await ProjectManager.getProjectUUID() ?? '';
+ roomsList = await CommunitySpaceManagementApi.getSubSpaceBySpaceId(
+ communityId: event.communityUuid,
+ spaceId: event.spaceUuid,
+ projectId: projectUuid);
+ emit(DeviceSettingsUpdate(
+ deviceName: nameController.text,
+ deviceInfo: state.deviceInfo,
+ roomsList: roomsList,
+ ));
+ } catch (e) {
+ emit(DeviceSettingsError(message: e.toString()));
+ return;
+ }
+ }
+}
diff --git a/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart b/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart
new file mode 100644
index 00000000..7fb62ed9
--- /dev/null
+++ b/lib/pages/device_managment/device_setting/bloc/setting_bloc_event.dart
@@ -0,0 +1,69 @@
+part of 'setting_bloc_bloc.dart';
+
+abstract class DeviceSettingEvent extends Equatable {
+ const DeviceSettingEvent();
+ @override
+ List