mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
push living room status
This commit is contained in:
@ -0,0 +1,139 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
part 'device_managment_event.dart';
|
||||
part 'device_managment_state.dart';
|
||||
|
||||
class DeviceManagementBloc
|
||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
int _selectedIndex = 0;
|
||||
List<AllDevicesModel> _devices = [];
|
||||
int _onlineCount = 0;
|
||||
int _offlineCount = 0;
|
||||
int _lowBatteryCount = 0;
|
||||
AllDevicesModel? _selectedDevice;
|
||||
|
||||
DeviceManagementBloc() : super(DeviceManagementInitial()) {
|
||||
on<FetchDevices>(_onFetchDevices);
|
||||
on<FilterDevices>(_onFilterDevices);
|
||||
on<SelectedFilterChanged>(_onSelectedFilterChanged);
|
||||
on<SearchDevices>(_onSearchDevices);
|
||||
on<SelectDevice>(_onSelectDevice);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevices(
|
||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
emit(DeviceManagementLoading());
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
_devices = devices;
|
||||
_calculateDeviceCounts();
|
||||
emit(DeviceManagementLoaded(
|
||||
devices: devices,
|
||||
selectedIndex: _selectedIndex,
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(DeviceManagementInitial());
|
||||
}
|
||||
}
|
||||
|
||||
void _onFilterDevices(
|
||||
FilterDevices event, Emitter<DeviceManagementState> emit) {
|
||||
if (_devices.isNotEmpty) {
|
||||
final filteredDevices = _devices.where((device) {
|
||||
switch (event.filter) {
|
||||
case 'Online':
|
||||
return device.online == true;
|
||||
case 'Offline':
|
||||
return device.online == false;
|
||||
case 'Low Battery':
|
||||
return device.batteryLevel != null && device.batteryLevel! < 20;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}).toList();
|
||||
emit(DeviceManagementFiltered(
|
||||
filteredDevices: filteredDevices,
|
||||
selectedIndex: _selectedIndex,
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onSelectedFilterChanged(
|
||||
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedIndex = event.selectedIndex;
|
||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||
}
|
||||
|
||||
void _onSelectDevice(
|
||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedDevice = event.selectedDevice;
|
||||
}
|
||||
|
||||
void _calculateDeviceCounts() {
|
||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||
_lowBatteryCount = _devices
|
||||
.where((device) =>
|
||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
||||
.length;
|
||||
}
|
||||
|
||||
String _getFilterFromIndex(int index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
return 'Online';
|
||||
case 2:
|
||||
return 'Offline';
|
||||
case 3:
|
||||
return 'Low Battery';
|
||||
default:
|
||||
return 'All';
|
||||
}
|
||||
}
|
||||
|
||||
void _onSearchDevices(
|
||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
if (_devices.isNotEmpty) {
|
||||
final filteredDevices = _devices.where((device) {
|
||||
final matchesCommunity = event.community == null ||
|
||||
event.community!.isEmpty ||
|
||||
(device.room?.name
|
||||
?.toLowerCase()
|
||||
.contains(event.community!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesUnit = event.unitName == null ||
|
||||
event.unitName!.isEmpty ||
|
||||
(device.unit?.name
|
||||
?.toLowerCase()
|
||||
.contains(event.unitName!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesProductName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.name
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
return matchesCommunity && matchesUnit && matchesProductName;
|
||||
}).toList();
|
||||
|
||||
emit(DeviceManagementFiltered(
|
||||
filteredDevices: filteredDevices,
|
||||
selectedIndex: _selectedIndex,
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
AllDevicesModel? get selectedDevice => _selectedDevice;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
part of 'device_managment_bloc.dart';
|
||||
|
||||
abstract class DeviceManagementEvent extends Equatable {
|
||||
const DeviceManagementEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class FetchDevices extends DeviceManagementEvent {}
|
||||
|
||||
class FilterDevices extends DeviceManagementEvent {
|
||||
final String filter;
|
||||
|
||||
const FilterDevices(this.filter);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [filter];
|
||||
}
|
||||
|
||||
class SelectedFilterChanged extends DeviceManagementEvent {
|
||||
final int selectedIndex;
|
||||
|
||||
const SelectedFilterChanged(this.selectedIndex);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [selectedIndex];
|
||||
}
|
||||
|
||||
class SearchDevices extends DeviceManagementEvent {
|
||||
final String? community;
|
||||
final String? unitName;
|
||||
final String? productName;
|
||||
|
||||
const SearchDevices({
|
||||
this.community,
|
||||
this.unitName,
|
||||
this.productName,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [community, unitName, productName];
|
||||
}
|
||||
|
||||
class SelectDevice extends DeviceManagementEvent {
|
||||
final AllDevicesModel selectedDevice;
|
||||
|
||||
const SelectDevice(this.selectedDevice);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [selectedDevice];
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
part of 'device_managment_bloc.dart';
|
||||
|
||||
abstract class DeviceManagementState extends Equatable {
|
||||
const DeviceManagementState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class DeviceManagementInitial extends DeviceManagementState {}
|
||||
|
||||
class DeviceManagementLoading extends DeviceManagementState {}
|
||||
|
||||
class DeviceManagementLoaded extends DeviceManagementState {
|
||||
final List<AllDevicesModel> devices;
|
||||
final int selectedIndex;
|
||||
final int onlineCount;
|
||||
final int offlineCount;
|
||||
final int lowBatteryCount;
|
||||
final AllDevicesModel? selectedDevice;
|
||||
|
||||
const DeviceManagementLoaded({
|
||||
required this.devices,
|
||||
required this.selectedIndex,
|
||||
required this.onlineCount,
|
||||
required this.offlineCount,
|
||||
required this.lowBatteryCount,
|
||||
this.selectedDevice,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
devices,
|
||||
selectedIndex,
|
||||
onlineCount,
|
||||
offlineCount,
|
||||
lowBatteryCount,
|
||||
selectedDevice
|
||||
];
|
||||
}
|
||||
|
||||
class DeviceManagementFiltered extends DeviceManagementState {
|
||||
final List<AllDevicesModel> filteredDevices;
|
||||
final int selectedIndex;
|
||||
final int onlineCount;
|
||||
final int offlineCount;
|
||||
final int lowBatteryCount;
|
||||
final AllDevicesModel? selectedDevice;
|
||||
|
||||
const DeviceManagementFiltered({
|
||||
required this.filteredDevices,
|
||||
required this.selectedIndex,
|
||||
required this.onlineCount,
|
||||
required this.offlineCount,
|
||||
required this.lowBatteryCount,
|
||||
this.selectedDevice,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
filteredDevices,
|
||||
selectedIndex,
|
||||
onlineCount,
|
||||
offlineCount,
|
||||
lowBatteryCount,
|
||||
selectedDevice
|
||||
];
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
enum AcValuesEnums {
|
||||
Cooling,
|
||||
Heating,
|
||||
Ventilation,
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
enum OperationDialogType {
|
||||
countdown,
|
||||
delay,
|
||||
temperature,
|
||||
onOff,
|
||||
integerSteps,
|
||||
listOfOptions,
|
||||
none,
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/living_room_switch/view/living_room_device_control.dart';
|
||||
|
||||
mixin RouteControlsBasedCode {
|
||||
Widget routeControlsWidgets({required AllDevicesModel device}) {
|
||||
switch (device.categoryName) {
|
||||
case 'Switch':
|
||||
return LivingRoomDeviceControl(
|
||||
device: device,
|
||||
);
|
||||
case 'Gateway':
|
||||
return const SizedBox();
|
||||
case 'Residential Lock PRO':
|
||||
return const SizedBox();
|
||||
case 'Human Presence Sensor':
|
||||
return const SizedBox();
|
||||
case 'Thermostat':
|
||||
return const SizedBox();
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DeviceStatus {
|
||||
final String productUuid;
|
||||
final String productType;
|
||||
final List<Status> status;
|
||||
|
||||
DeviceStatus({
|
||||
required this.productUuid,
|
||||
required this.productType,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
factory DeviceStatus.fromMap(Map<String, dynamic> map) {
|
||||
return DeviceStatus(
|
||||
productUuid: map['productUuid'] ?? '',
|
||||
productType: map['productType'] ?? '',
|
||||
status: List<Status>.from(
|
||||
map['status']?.map((x) => Status.fromMap(x)) ?? const []),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'productUuid': productUuid,
|
||||
'productType': productType,
|
||||
'status': status.map((x) => x.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
factory DeviceStatus.fromJson(Map<String, dynamic> json) =>
|
||||
DeviceStatus.fromMap(json);
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
|
||||
class Status {
|
||||
final String code;
|
||||
final dynamic value;
|
||||
|
||||
Status({
|
||||
required this.code,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
factory Status.fromMap(Map<String, dynamic> map) {
|
||||
return Status(
|
||||
code: map['code'] ?? '',
|
||||
value: map['value'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'code': code,
|
||||
'value': value,
|
||||
};
|
||||
}
|
||||
|
||||
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
157
lib/pages/device_managment/all_devices/models/devices_model.dart
Normal file
157
lib/pages/device_managment/all_devices/models/devices_model.dart
Normal file
@ -0,0 +1,157 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
|
||||
class AllDevicesModel {
|
||||
/*
|
||||
{
|
||||
"room": {
|
||||
"uuid": "75ea7d60-5104-4726-b5f8-ea426c0c6a1b",
|
||||
"name": "Room 1"
|
||||
},
|
||||
"unit": {
|
||||
"uuid": "04fd1dcf-f24a-40db-970d-d0be884ed30f",
|
||||
"name": "unit 1"
|
||||
},
|
||||
"productUuid": "894aad5c-ce03-423a-9d61-2fd0c3f67ebf",
|
||||
"productType": "3G",
|
||||
"permissionType": "CONTROLLABLE",
|
||||
"activeTime": 1722173778,
|
||||
"category": "kg",
|
||||
"categoryName": "Switch",
|
||||
"createTime": 1722173778,
|
||||
"gatewayId": "bf0294123ed2c19067skrk",
|
||||
"icon": "smart/icon/bay1642572935385vcsA/2b1f5efbaa5bbf81c3164fa312cf2032.png",
|
||||
"ip": "",
|
||||
"lat": "31.97",
|
||||
"localKey": "T/39+<l/![iv>:9M",
|
||||
"lon": "35.89",
|
||||
"model": "S01ZLSWBSA3",
|
||||
"name": "3 Gang Button Switch L-L",
|
||||
"nodeId": "60a423fffed5a7f6",
|
||||
"online": true,
|
||||
"ownerId": "199200732",
|
||||
"sub": true,
|
||||
"timeZone": "+03:00",
|
||||
"updateTime": 1723626515,
|
||||
"uuid": "5b31dae4-ce9c-4c70-b52b-7e15011163bf"
|
||||
}
|
||||
*/
|
||||
|
||||
DevicesModelRoom? room;
|
||||
DevicesModelUnit? unit;
|
||||
String? productUuid;
|
||||
String? productType;
|
||||
String? permissionType;
|
||||
int? activeTime;
|
||||
String? category;
|
||||
String? categoryName;
|
||||
int? createTime;
|
||||
String? gatewayId;
|
||||
String? icon;
|
||||
String? ip;
|
||||
String? lat;
|
||||
String? localKey;
|
||||
String? lon;
|
||||
String? model;
|
||||
String? name;
|
||||
String? nodeId;
|
||||
bool? online;
|
||||
String? ownerId;
|
||||
bool? sub;
|
||||
String? timeZone;
|
||||
int? updateTime;
|
||||
String? uuid;
|
||||
int? batteryLevel;
|
||||
|
||||
AllDevicesModel({
|
||||
this.room,
|
||||
this.unit,
|
||||
this.productUuid,
|
||||
this.productType,
|
||||
this.permissionType,
|
||||
this.activeTime,
|
||||
this.category,
|
||||
this.categoryName,
|
||||
this.createTime,
|
||||
this.gatewayId,
|
||||
this.icon,
|
||||
this.ip,
|
||||
this.lat,
|
||||
this.localKey,
|
||||
this.lon,
|
||||
this.model,
|
||||
this.name,
|
||||
this.nodeId,
|
||||
this.online,
|
||||
this.ownerId,
|
||||
this.sub,
|
||||
this.timeZone,
|
||||
this.updateTime,
|
||||
this.uuid,
|
||||
this.batteryLevel,
|
||||
});
|
||||
AllDevicesModel.fromJson(Map<String, dynamic> json) {
|
||||
room = (json['room'] != null && (json['room'] is Map))
|
||||
? DevicesModelRoom.fromJson(json['room'])
|
||||
: null;
|
||||
unit = (json['unit'] != null && (json['unit'] is Map))
|
||||
? DevicesModelUnit.fromJson(json['unit'])
|
||||
: null;
|
||||
productUuid = json['productUuid']?.toString();
|
||||
productType = json['productType']?.toString();
|
||||
permissionType = json['permissionType']?.toString();
|
||||
activeTime = int.tryParse(json['activeTime']?.toString() ?? '');
|
||||
category = json['category']?.toString();
|
||||
categoryName = json['categoryName']?.toString();
|
||||
createTime = int.tryParse(json['createTime']?.toString() ?? '');
|
||||
gatewayId = json['gatewayId']?.toString();
|
||||
icon = json['icon']?.toString();
|
||||
ip = json['ip']?.toString();
|
||||
lat = json['lat']?.toString();
|
||||
localKey = json['localKey']?.toString();
|
||||
lon = json['lon']?.toString();
|
||||
model = json['model']?.toString();
|
||||
name = json['name']?.toString();
|
||||
nodeId = json['nodeId']?.toString();
|
||||
online = json['online'];
|
||||
ownerId = json['ownerId']?.toString();
|
||||
sub = json['sub'];
|
||||
timeZone = json['timeZone']?.toString();
|
||||
updateTime = int.tryParse(json['updateTime']?.toString() ?? '');
|
||||
uuid = json['uuid']?.toString();
|
||||
batteryLevel = int.tryParse(json['batteryLevel']?.toString() ?? '');
|
||||
}
|
||||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
if (room != null) {
|
||||
data['room'] = room!.toJson();
|
||||
}
|
||||
if (unit != null) {
|
||||
data['unit'] = unit!.toJson();
|
||||
}
|
||||
data['productUuid'] = productUuid;
|
||||
data['productType'] = productType;
|
||||
data['permissionType'] = permissionType;
|
||||
data['activeTime'] = activeTime;
|
||||
data['category'] = category;
|
||||
data['categoryName'] = categoryName;
|
||||
data['createTime'] = createTime;
|
||||
data['gatewayId'] = gatewayId;
|
||||
data['icon'] = icon;
|
||||
data['ip'] = ip;
|
||||
data['lat'] = lat;
|
||||
data['localKey'] = localKey;
|
||||
data['lon'] = lon;
|
||||
data['model'] = model;
|
||||
data['name'] = name;
|
||||
data['nodeId'] = nodeId;
|
||||
data['online'] = online;
|
||||
data['ownerId'] = ownerId;
|
||||
data['sub'] = sub;
|
||||
data['timeZone'] = timeZone;
|
||||
data['updateTime'] = updateTime;
|
||||
data['uuid'] = uuid;
|
||||
data['batteryLevel'] = batteryLevel;
|
||||
return data;
|
||||
}
|
||||
}
|
26
lib/pages/device_managment/all_devices/models/room.dart
Normal file
26
lib/pages/device_managment/all_devices/models/room.dart
Normal file
@ -0,0 +1,26 @@
|
||||
class DevicesModelRoom {
|
||||
/*
|
||||
{
|
||||
"uuid": "75ea7d60-5104-4726-b5f8-ea426c0c6a1b",
|
||||
"name": "Room 1"
|
||||
}
|
||||
*/
|
||||
|
||||
String? uuid;
|
||||
String? name;
|
||||
|
||||
DevicesModelRoom({
|
||||
this.uuid,
|
||||
this.name,
|
||||
});
|
||||
DevicesModelRoom.fromJson(Map<String, dynamic> json) {
|
||||
uuid = json['uuid']?.toString();
|
||||
name = json['name']?.toString();
|
||||
}
|
||||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
data['uuid'] = uuid;
|
||||
data['name'] = name;
|
||||
return data;
|
||||
}
|
||||
}
|
26
lib/pages/device_managment/all_devices/models/unit.dart
Normal file
26
lib/pages/device_managment/all_devices/models/unit.dart
Normal file
@ -0,0 +1,26 @@
|
||||
class DevicesModelUnit {
|
||||
/*
|
||||
{
|
||||
"uuid": "04fd1dcf-f24a-40db-970d-d0be884ed30f",
|
||||
"name": "unit 1"
|
||||
}
|
||||
*/
|
||||
|
||||
String? uuid;
|
||||
String? name;
|
||||
|
||||
DevicesModelUnit({
|
||||
this.uuid,
|
||||
this.name,
|
||||
});
|
||||
DevicesModelUnit.fromJson(Map<String, dynamic> json) {
|
||||
uuid = json['uuid']?.toString();
|
||||
name = json['name']?.toString();
|
||||
}
|
||||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
data['uuid'] = uuid;
|
||||
data['name'] = name;
|
||||
return data;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class DeviceManagementPage extends StatelessWidget {
|
||||
const DeviceManagementPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
||||
child: WebScaffold(
|
||||
appBarTitle: Text(
|
||||
'Device Management',
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
enableMenuSideba: true,
|
||||
scaffoldBody: BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
builder: (context, state) {
|
||||
if (state is DeviceManagementLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is DeviceManagementLoaded ||
|
||||
state is DeviceManagementFiltered) {
|
||||
final devices = state is DeviceManagementLoaded
|
||||
? state.devices
|
||||
: (state as DeviceManagementFiltered).filteredDevices;
|
||||
|
||||
return DeviceManagementBody(devices: devices);
|
||||
} else {
|
||||
return const Center(child: Text('No Devices Found'));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/core/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_table.dart';
|
||||
import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/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/shared/device_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.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';
|
||||
|
||||
class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
const DeviceManagementBody({super.key, required this.devices});
|
||||
|
||||
final List<AllDevicesModel> devices;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
builder: (context, state) {
|
||||
List<AllDevicesModel> devicesToShow = [];
|
||||
int selectedIndex = 0;
|
||||
int onlineCount = 0;
|
||||
int offlineCount = 0;
|
||||
int lowBatteryCount = 0;
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
devicesToShow = state.devices;
|
||||
selectedIndex = state.selectedIndex;
|
||||
onlineCount = state.onlineCount;
|
||||
offlineCount = state.offlineCount;
|
||||
lowBatteryCount = state.lowBatteryCount;
|
||||
} else if (state is DeviceManagementFiltered) {
|
||||
devicesToShow = state.filteredDevices;
|
||||
selectedIndex = state.selectedIndex;
|
||||
onlineCount = state.onlineCount;
|
||||
offlineCount = state.offlineCount;
|
||||
lowBatteryCount = state.lowBatteryCount;
|
||||
}
|
||||
|
||||
// Create tab labels with counts
|
||||
final tabs = [
|
||||
'All (${devices.length})',
|
||||
'Online ($onlineCount)',
|
||||
'Offline ($offlineCount)',
|
||||
'Low Battery ($lowBatteryCount)',
|
||||
];
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(30),
|
||||
height: context.screenHeight,
|
||||
width: context.screenWidth,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FilterWidget(
|
||||
size: MediaQuery.of(context).size,
|
||||
tabs: tabs,
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChanged: (index) {
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectedFilterChanged(index));
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
const DeviceSearchFilters(),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Container(
|
||||
height: 43,
|
||||
width: 100,
|
||||
decoration: containerDecoration,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
final selectedDevice =
|
||||
context.read<DeviceManagementBloc>().selectedDevice;
|
||||
if (selectedDevice != null) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
DeviceControlDialog(device: selectedDevice),
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: 9,
|
||||
child: const Text('Control'),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: DynamicTable(
|
||||
cellDecoration: containerDecoration,
|
||||
onRowSelected: (index, isSelected, row) {
|
||||
if (isSelected) {
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectDevice(devicesToShow[index]));
|
||||
}
|
||||
},
|
||||
withCheckBox: true,
|
||||
size: context.screenSize,
|
||||
headers: const [
|
||||
'Device Name',
|
||||
'Product Name',
|
||||
'Device ID',
|
||||
'Unit Name',
|
||||
'Room',
|
||||
'Battery Level',
|
||||
'Installation Date and Time',
|
||||
'Status',
|
||||
'Last Offline Date and Time',
|
||||
],
|
||||
data: devicesToShow.map((device) {
|
||||
return [
|
||||
device.categoryName ?? '',
|
||||
device.name ?? '',
|
||||
device.uuid ?? '',
|
||||
device.unit?.name ?? '',
|
||||
device.room?.name ?? '',
|
||||
device.batteryLevel != null
|
||||
? '${device.batteryLevel}%'
|
||||
: '',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.createTime ?? 0) * 1000)),
|
||||
device.online == true ? 'Online' : 'Offline',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.updateTime ?? 0) * 1000)),
|
||||
];
|
||||
}).toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class DeviceSearchFilters extends StatefulWidget {
|
||||
const DeviceSearchFilters({super.key});
|
||||
|
||||
@override
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
communityController.dispose();
|
||||
unitNameController.dispose();
|
||||
productNameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return isLargeScreenSize(context)
|
||||
? Row(
|
||||
children: [
|
||||
_buildSearchField("Community", communityController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Unit Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
)
|
||||
: Wrap(
|
||||
spacing: 20,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
_buildSearchField("Community", communityController, 200),
|
||||
_buildSearchField("Unit Name", unitNameController, 200),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(
|
||||
String title, TextEditingController controller, double width) {
|
||||
return StatefulTextField(
|
||||
title: title,
|
||||
width: width,
|
||||
elevation: 2,
|
||||
controller: controller,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchResetButtons() {
|
||||
return SearchResetButtons(
|
||||
onSearch: () {
|
||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
||||
community: communityController.text,
|
||||
unitName: unitNameController.text,
|
||||
productName: productNameController.text,
|
||||
));
|
||||
},
|
||||
onReset: () {
|
||||
communityController.clear();
|
||||
unitNameController.clear();
|
||||
productNameController.clear();
|
||||
context.read<DeviceManagementBloc>().add(FetchDevices());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user