mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-11 07:38:05 +00:00
Compare commits
1 Commits
SP-1509-FE
...
SP-1448-FE
Author | SHA1 | Date | |
---|---|---|---|
0d45a155e3 |
@ -10,6 +10,7 @@
|
|||||||
analyzer:
|
analyzer:
|
||||||
errors:
|
errors:
|
||||||
constant_identifier_names: ignore
|
constant_identifier_names: ignore
|
||||||
|
overridden_fields: ignore
|
||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
class AnalyticsDevice {
|
|
||||||
const AnalyticsDevice({required this.name, required this.uuid});
|
|
||||||
|
|
||||||
final String uuid;
|
|
||||||
final String name;
|
|
||||||
|
|
||||||
factory AnalyticsDevice.fromJson(Map<String, dynamic> json) {
|
|
||||||
return AnalyticsDevice(
|
|
||||||
uuid: json['uuid'] as String? ?? '',
|
|
||||||
name: json['name'] as String? ?? '',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +1,22 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
class OccupancyHeatMapModel extends Equatable {
|
class OccupancyHeatMapModel extends Equatable {
|
||||||
final String uuid;
|
final DateTime date;
|
||||||
|
|
||||||
final DateTime eventDate;
|
final int occupancy;
|
||||||
|
|
||||||
final int countTotalPresenceDetected;
|
|
||||||
|
|
||||||
const OccupancyHeatMapModel({
|
const OccupancyHeatMapModel({
|
||||||
required this.uuid,
|
required this.date,
|
||||||
required this.eventDate,
|
required this.occupancy,
|
||||||
required this.countTotalPresenceDetected,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory OccupancyHeatMapModel.fromJson(Map<String, dynamic> json) {
|
factory OccupancyHeatMapModel.fromJson(Map<String, dynamic> json) {
|
||||||
return OccupancyHeatMapModel(
|
return OccupancyHeatMapModel(
|
||||||
uuid: json['uuid'] as String? ?? '',
|
date: DateTime.parse(json['date'] as String),
|
||||||
eventDate: DateTime.parse(
|
occupancy: json['occupancy'] as int,
|
||||||
json['event_date'] as String? ?? '${DateTime.now()}',
|
|
||||||
),
|
|
||||||
countTotalPresenceDetected: json['count_total_presence_detected'] as int? ?? 0,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, eventDate, countTotalPresenceDetected];
|
List<Object?> get props => [date, occupancy];
|
||||||
}
|
}
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
|
||||||
|
|
||||||
part 'analytics_devices_event.dart';
|
|
||||||
part 'analytics_devices_state.dart';
|
|
||||||
|
|
||||||
class AnalyticsDevicesBloc
|
|
||||||
extends Bloc<AnalyticsDevicesEvent, AnalyticsDevicesState> {
|
|
||||||
AnalyticsDevicesBloc(
|
|
||||||
this._analyticsDevicesService,
|
|
||||||
) : super(const AnalyticsDevicesState()) {
|
|
||||||
on<LoadAnalyticsDevicesEvent>(_onLoadAnalyticsDevices);
|
|
||||||
on<SelectAnalyticsDeviceEvent>(_onSelectAnalyticsDevice);
|
|
||||||
on<ClearAnalyticsDeviceEvent>(_onClearAnalyticsDevice);
|
|
||||||
}
|
|
||||||
final AnalyticsDevicesService _analyticsDevicesService;
|
|
||||||
|
|
||||||
Future<void> _onLoadAnalyticsDevices(
|
|
||||||
LoadAnalyticsDevicesEvent event,
|
|
||||||
Emitter<AnalyticsDevicesState> emit,
|
|
||||||
) async {
|
|
||||||
emit(const AnalyticsDevicesState(status: AnalyticsDevicesStatus.loading));
|
|
||||||
|
|
||||||
try {
|
|
||||||
final devices = await _analyticsDevicesService.getDevices(event.param);
|
|
||||||
emit(
|
|
||||||
AnalyticsDevicesState(
|
|
||||||
status: AnalyticsDevicesStatus.loaded,
|
|
||||||
devices: devices,
|
|
||||||
selectedDevice: devices.firstOrNull,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (devices.isNotEmpty) {
|
|
||||||
event.onSuccess(devices.first);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
emit(
|
|
||||||
AnalyticsDevicesState(
|
|
||||||
status: AnalyticsDevicesStatus.failure,
|
|
||||||
errorMessage: e.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onSelectAnalyticsDevice(
|
|
||||||
SelectAnalyticsDeviceEvent event,
|
|
||||||
Emitter<AnalyticsDevicesState> emit,
|
|
||||||
) {
|
|
||||||
emit(
|
|
||||||
AnalyticsDevicesState(
|
|
||||||
selectedDevice: event.device,
|
|
||||||
devices: state.devices,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
status: state.status,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onClearAnalyticsDevice(
|
|
||||||
ClearAnalyticsDeviceEvent event,
|
|
||||||
Emitter<AnalyticsDevicesState> emit,
|
|
||||||
) {
|
|
||||||
emit(const AnalyticsDevicesState());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
part of 'analytics_devices_bloc.dart';
|
|
||||||
|
|
||||||
sealed class AnalyticsDevicesEvent extends Equatable {
|
|
||||||
const AnalyticsDevicesEvent();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class LoadAnalyticsDevicesEvent extends AnalyticsDevicesEvent {
|
|
||||||
const LoadAnalyticsDevicesEvent({required this.param, required this.onSuccess});
|
|
||||||
|
|
||||||
final GetAnalyticsDevicesParam param;
|
|
||||||
final void Function(AnalyticsDevice device) onSuccess;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [param];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class SelectAnalyticsDeviceEvent extends AnalyticsDevicesEvent {
|
|
||||||
const SelectAnalyticsDeviceEvent(this.device);
|
|
||||||
|
|
||||||
final AnalyticsDevice device;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object> get props => [device];
|
|
||||||
}
|
|
||||||
|
|
||||||
final class ClearAnalyticsDeviceEvent extends AnalyticsDevicesEvent {
|
|
||||||
const ClearAnalyticsDeviceEvent();
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
part of 'analytics_devices_bloc.dart';
|
|
||||||
|
|
||||||
enum AnalyticsDevicesStatus { initial, loading, loaded, failure }
|
|
||||||
|
|
||||||
final class AnalyticsDevicesState extends Equatable {
|
|
||||||
const AnalyticsDevicesState({
|
|
||||||
this.status = AnalyticsDevicesStatus.initial,
|
|
||||||
this.devices = const [],
|
|
||||||
this.errorMessage,
|
|
||||||
this.selectedDevice,
|
|
||||||
});
|
|
||||||
|
|
||||||
final AnalyticsDevicesStatus status;
|
|
||||||
final List<AnalyticsDevice> devices;
|
|
||||||
final AnalyticsDevice? selectedDevice;
|
|
||||||
final String? errorMessage;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [status, devices, errorMessage, selectedDevice];
|
|
||||||
}
|
|
@ -14,20 +14,12 @@ class EnergyManagementDataLoadingStrategy implements AnalyticsDataLoadingStrateg
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
List<SpaceModel> spaces,
|
List<SpaceModel> spaces,
|
||||||
) {
|
) {
|
||||||
// Add to space tree bloc first
|
|
||||||
context.read<SpaceTreeBloc>().add(
|
context.read<SpaceTreeBloc>().add(
|
||||||
OnCommunitySelected(
|
OnCommunitySelected(
|
||||||
community.uuid,
|
community.uuid,
|
||||||
spaces,
|
spaces,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid)) {
|
|
||||||
clearData(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
||||||
context,
|
context,
|
||||||
communityId: community.uuid,
|
communityId: community.uuid,
|
||||||
@ -49,13 +41,6 @@ class EnergyManagementDataLoadingStrategy implements AnalyticsDataLoadingStrateg
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid) ||
|
|
||||||
spaceTreeState.selectedSpaces.contains(space.uuid)) {
|
|
||||||
clearData(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
||||||
context,
|
context,
|
||||||
communityId: community.uuid,
|
communityId: community.uuid,
|
||||||
@ -69,7 +54,7 @@ class EnergyManagementDataLoadingStrategy implements AnalyticsDataLoadingStrateg
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
SpaceModel child,
|
SpaceModel child,
|
||||||
) {
|
) {
|
||||||
// Do nothing else as per original implementation
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -20,12 +20,6 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
spaces.isNotEmpty ? [spaces.first] : [],
|
spaces.isNotEmpty ? [spaces.first] : [],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid)) {
|
|
||||||
clearData(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
FetchOccupancyDataHelper.loadOccupancyData(
|
||||||
context,
|
context,
|
||||||
communityId: community.uuid,
|
communityId: community.uuid,
|
||||||
@ -53,13 +47,6 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
..add(OnSpaceSelected(community, space.uuid ?? '', []));
|
..add(OnSpaceSelected(community, space.uuid ?? '', []));
|
||||||
}
|
}
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid) ||
|
|
||||||
spaceTreeState.selectedSpaces.contains(space.uuid)) {
|
|
||||||
clearData(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
FetchOccupancyDataHelper.loadOccupancyData(
|
||||||
context,
|
context,
|
||||||
communityId: community.uuid,
|
communityId: community.uuid,
|
||||||
@ -79,6 +66,6 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
@override
|
@override
|
||||||
void clearData(BuildContext context) {
|
void clearData(BuildContext context) {
|
||||||
context.read<SpaceTreeBloc>().add(const SpaceTreeClearSelectionEvent());
|
context.read<SpaceTreeBloc>().add(const SpaceTreeClearSelectionEvent());
|
||||||
FetchOccupancyDataHelper.clearAllData(context);
|
// FetchOccupancyDataHelper.clearAllData(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_tab/analytics_tab_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_tab/analytics_tab_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/widgets/analytics_page_tabs_and_children.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/widgets/analytics_page_tabs_and_children.dart';
|
||||||
@ -12,13 +11,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/real
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service_delagate.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_energy_management_analytics_devices_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_occupancy_analytics_devices_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/fake_energy_consumption_by_phases_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/fake_energy_consumption_by_phases_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/fake_energy_consumption_per_device_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/fake_energy_consumption_per_device_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupacy/fake_occupacy_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupacy/fake_occupacy_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/remote_occupancy_heat_map_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/fake_occupancy_heat_map_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/remote_power_clamp_info_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/remote_power_clamp_info_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/realtime_device_service/firebase_realtime_device_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/realtime_device_service/firebase_realtime_device_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/remote_total_energy_consumption_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/remote_total_energy_consumption_service.dart';
|
||||||
@ -27,22 +23,9 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
|||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class AnalyticsPage extends StatefulWidget {
|
class AnalyticsPage extends StatelessWidget {
|
||||||
const AnalyticsPage({super.key});
|
const AnalyticsPage({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<AnalyticsPage> createState() => _AnalyticsPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AnalyticsPageState extends State<AnalyticsPage> {
|
|
||||||
late final HTTPService _httpService;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_httpService = HTTPService();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
@ -52,7 +35,7 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
|||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => TotalEnergyConsumptionBloc(
|
create: (context) => TotalEnergyConsumptionBloc(
|
||||||
RemoteTotalEnergyConsumptionService(_httpService),
|
RemoteTotalEnergyConsumptionService(HTTPService()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
@ -67,7 +50,7 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
|||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => PowerClampInfoBloc(
|
create: (context) => PowerClampInfoBloc(
|
||||||
RemotePowerClampInfoService(_httpService),
|
RemotePowerClampInfoService(HTTPService()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
BlocProvider<RealtimeDeviceChangesBloc>(
|
BlocProvider<RealtimeDeviceChangesBloc>(
|
||||||
@ -77,19 +60,9 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
|||||||
),
|
),
|
||||||
BlocProvider(create: (context) => OccupancyBloc(FakeOccupacyService())),
|
BlocProvider(create: (context) => OccupancyBloc(FakeOccupacyService())),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => OccupancyHeatMapBloc(
|
create: (context) => OccupancyHeatMapBloc(FakeOccupancyHeatMapService()),
|
||||||
RemoteOccupancyHeatMapService(_httpService),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => AnalyticsDatePickerBloc()),
|
BlocProvider(create: (context) => AnalyticsDatePickerBloc()),
|
||||||
BlocProvider(
|
|
||||||
create: (context) => AnalyticsDevicesBloc(
|
|
||||||
AnalyticsDevicesServiceDelegate(
|
|
||||||
RemoteOccupancyAnalyticsDevicesService(_httpService),
|
|
||||||
RemoteEnergyManagementAnalyticsDevicesService(_httpService),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: const AnalyticsPageForm(),
|
child: const AnalyticsPageForm(),
|
||||||
);
|
);
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
||||||
@ -16,10 +13,7 @@ import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_
|
|||||||
abstract final class FetchEnergyManagementDataHelper {
|
abstract final class FetchEnergyManagementDataHelper {
|
||||||
const FetchEnergyManagementDataHelper._();
|
const FetchEnergyManagementDataHelper._();
|
||||||
|
|
||||||
// static const String _powerClampId = 'cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa';
|
static const String _powerClampId = 'cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa';
|
||||||
static AnalyticsDevice? getSelectedDevice(BuildContext context) {
|
|
||||||
return context.read<AnalyticsDevicesBloc>().state.selectedDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadEnergyManagementData(
|
static void loadEnergyManagementData(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
@ -34,14 +28,16 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
|
|
||||||
final datePickerState = context.read<AnalyticsDatePickerBloc>().state;
|
final datePickerState = context.read<AnalyticsDatePickerBloc>().state;
|
||||||
final selectedDate0 = selectedDate ?? datePickerState.monthlyDate;
|
final selectedDate0 = selectedDate ?? datePickerState.monthlyDate;
|
||||||
loadAnalyticsDevices(context, communityUuid: communityId, spaceUuid: spaceId);
|
|
||||||
loadTotalEnergyConsumption(
|
loadTotalEnergyConsumption(
|
||||||
context,
|
context,
|
||||||
selectedDate: selectedDate0,
|
selectedDate: selectedDate0,
|
||||||
communityId: communityId,
|
communityId: communityId,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
loadEnergyConsumptionByPhases(context, selectedDate: selectedDate);
|
loadEnergyConsumptionByPhases(context, selectedDate: selectedDate);
|
||||||
|
|
||||||
loadEnergyConsumptionPerDevice(context);
|
loadEnergyConsumptionPerDevice(context);
|
||||||
loadRealtimeDeviceChanges(context);
|
loadRealtimeDeviceChanges(context);
|
||||||
loadPowerClampInfo(context);
|
loadPowerClampInfo(context);
|
||||||
@ -84,58 +80,26 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void loadPowerClampInfo(BuildContext context) {
|
static void loadPowerClampInfo(BuildContext context) {
|
||||||
final selectedDevice = getSelectedDevice(context);
|
context.read<PowerClampInfoBloc>().add(
|
||||||
if (selectedDevice case final AnalyticsDevice device) {
|
const LoadPowerClampInfoEvent(_powerClampId),
|
||||||
context.read<PowerClampInfoBloc>().add(
|
|
||||||
LoadPowerClampInfoEvent(device.uuid),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadRealtimeDeviceChanges(
|
|
||||||
BuildContext context, {
|
|
||||||
String? deviceUuid,
|
|
||||||
}) {
|
|
||||||
final selectedDevice = getSelectedDevice(context);
|
|
||||||
|
|
||||||
context.read<RealtimeDeviceChangesBloc>().add(
|
|
||||||
RealtimeDeviceChangesStarted(deviceUuid ?? selectedDevice?.uuid ?? ''),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadAnalyticsDevices(
|
static void loadRealtimeDeviceChanges(BuildContext context) {
|
||||||
BuildContext context, {
|
context.read<RealtimeDeviceChangesBloc>().add(
|
||||||
required String communityUuid,
|
const RealtimeDeviceChangesStarted(_powerClampId),
|
||||||
required String spaceUuid,
|
|
||||||
}) {
|
|
||||||
context.read<AnalyticsDevicesBloc>().add(
|
|
||||||
LoadAnalyticsDevicesEvent(
|
|
||||||
onSuccess: (device) {
|
|
||||||
context.read<PowerClampInfoBloc>().add(
|
|
||||||
LoadPowerClampInfoEvent(device.uuid),
|
|
||||||
);
|
|
||||||
context.read<RealtimeDeviceChangesBloc>().add(
|
|
||||||
RealtimeDeviceChangesStarted(device.uuid),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
param: GetAnalyticsDevicesParam(
|
|
||||||
communityUuid: communityUuid,
|
|
||||||
spaceUuid: spaceUuid,
|
|
||||||
deviceTypes: ['PC'],
|
|
||||||
requestType: AnalyticsDeviceRequestType.energyManagement,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearAllData(BuildContext context) {
|
static void clearAllData(BuildContext context) {
|
||||||
context.read<PowerClampInfoBloc>().add(
|
|
||||||
const ClearPowerClampInfoEvent(),
|
|
||||||
);
|
|
||||||
context.read<RealtimeDeviceChangesBloc>().add(
|
context.read<RealtimeDeviceChangesBloc>().add(
|
||||||
const RealtimeDeviceChangesClosed(),
|
const RealtimeDeviceChangesClosed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
context.read<PowerClampInfoBloc>().add(
|
||||||
|
const ClearPowerClampInfoEvent(),
|
||||||
|
);
|
||||||
|
|
||||||
context.read<EnergyConsumptionPerDeviceBloc>().add(
|
context.read<EnergyConsumptionPerDeviceBloc>().add(
|
||||||
const ClearEnergyConsumptionPerDeviceEvent(),
|
const ClearEnergyConsumptionPerDeviceEvent(),
|
||||||
);
|
);
|
||||||
@ -147,6 +111,5 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
context.read<EnergyConsumptionByPhasesBloc>().add(
|
context.read<EnergyConsumptionByPhasesBloc>().add(
|
||||||
const ClearEnergyConsumptionByPhasesEvent(),
|
const ClearEnergyConsumptionByPhasesEvent(),
|
||||||
);
|
);
|
||||||
context.read<AnalyticsDevicesBloc>().add(const ClearAnalyticsDeviceEvent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class AnalyticsDeviceDropdown extends StatelessWidget {
|
|
||||||
const AnalyticsDeviceDropdown({required this.onChanged, super.key});
|
|
||||||
|
|
||||||
final ValueChanged<AnalyticsDevice> onChanged;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BlocBuilder<AnalyticsDevicesBloc, AnalyticsDevicesState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.greyColor,
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Visibility(
|
|
||||||
visible: state.devices.isNotEmpty,
|
|
||||||
replacement: _buildNoDevicesFound(context),
|
|
||||||
child: _buildDevicesDropdown(context, state),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const _defaultPadding = EdgeInsetsDirectional.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
vertical: 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildNoDevicesFound(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: _defaultPadding,
|
|
||||||
child: Text(
|
|
||||||
'no devices found',
|
|
||||||
style: _getTextStyle(context),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDevicesDropdown(BuildContext context, AnalyticsDevicesState state) {
|
|
||||||
return DropdownButton<AnalyticsDevice?>(
|
|
||||||
value: state.selectedDevice,
|
|
||||||
isDense: true,
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
dropdownColor: ColorsManager.whiteColors,
|
|
||||||
underline: const SizedBox.shrink(),
|
|
||||||
icon: const RotatedBox(
|
|
||||||
quarterTurns: 1,
|
|
||||||
child: Icon(Icons.chevron_right, size: 16),
|
|
||||||
),
|
|
||||||
style: _getTextStyle(context),
|
|
||||||
padding: _defaultPadding,
|
|
||||||
items: state.devices.map((e) {
|
|
||||||
return DropdownMenuItem(
|
|
||||||
value: e,
|
|
||||||
child: Text(e.name),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (value) {
|
|
||||||
if (value case final AnalyticsDevice device) {
|
|
||||||
context.read<AnalyticsDevicesBloc>().add(
|
|
||||||
SelectAnalyticsDeviceEvent(device),
|
|
||||||
);
|
|
||||||
onChanged.call(device);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextStyle? _getTextStyle(BuildContext context) {
|
|
||||||
return context.textTheme.labelSmall?.copyWith(
|
|
||||||
color: ColorsManager.textPrimaryColor,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
fontSize: 14,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,55 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
class PowerClampEnergyDataDeviceDropdown extends StatelessWidget {
|
||||||
|
const PowerClampEnergyDataDeviceDropdown({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: DropdownButton<String>(
|
||||||
|
value: 'Device 1',
|
||||||
|
isDense: true,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
dropdownColor: ColorsManager.whiteColors,
|
||||||
|
underline: const SizedBox.shrink(),
|
||||||
|
icon: const RotatedBox(
|
||||||
|
quarterTurns: 1,
|
||||||
|
child: Icon(Icons.chevron_right, size: 16),
|
||||||
|
),
|
||||||
|
style: context.textTheme.labelSmall?.copyWith(
|
||||||
|
color: ColorsManager.textPrimaryColor,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsetsDirectional.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 2,
|
||||||
|
),
|
||||||
|
items: [
|
||||||
|
for (var i = 1; i < 10; i++)
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: 'Device $i',
|
||||||
|
child: Text(
|
||||||
|
'Device $i',
|
||||||
|
style: context.textTheme.labelSmall?.copyWith(
|
||||||
|
color: ColorsManager.textPrimaryColor,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onChanged: (value) {},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/power_clamp_energy_status.dart';
|
import 'package:syncrow_web/pages/analytics/models/power_clamp_energy_status.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_by_phases_chart_box.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_by_phases_chart_box.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_device_dropdown.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_status_widget.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_status_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_phases_data_widget.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_phases_data_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
@ -52,8 +50,7 @@ class PowerClampEnergyDataWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
SelectableText(
|
SelectableText(
|
||||||
context.watch<AnalyticsDevicesBloc>().state.selectedDevice?.uuid ??
|
state.powerClampModel?.productUuid ?? 'N/A',
|
||||||
'N/A',
|
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -110,7 +107,7 @@ class PowerClampEnergyDataWidget extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 2,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
@ -125,19 +122,11 @@ class PowerClampEnergyDataWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Expanded(
|
const Expanded(
|
||||||
flex: 2,
|
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: AnalyticsDeviceDropdown(
|
child: PowerClampEnergyDataDeviceDropdown(),
|
||||||
onChanged: (value) {
|
|
||||||
FetchEnergyManagementDataHelper.loadRealtimeDeviceChanges(
|
|
||||||
context,
|
|
||||||
deviceUuid: value.uuid,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_date_picker_bloc/analytics_date_picker_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
||||||
|
|
||||||
@ -20,14 +17,10 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
}) {
|
}) {
|
||||||
if (communityId.isEmpty && spaceId.isEmpty) {
|
if (communityId.isEmpty && spaceId.isEmpty) {
|
||||||
clearAllData(context);
|
clearAllData(context);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final datePickerState = context.read<AnalyticsDatePickerBloc>().state;
|
final datePickerState = context.read<AnalyticsDatePickerBloc>().state;
|
||||||
|
|
||||||
loadAnalyticsDevices(context, communityUuid: communityId, spaceUuid: spaceId);
|
|
||||||
final selectedDevice = context.read<AnalyticsDevicesBloc>().state.selectedDevice;
|
|
||||||
|
|
||||||
context.read<OccupancyBloc>().add(
|
context.read<OccupancyBloc>().add(
|
||||||
LoadOccupancyEvent(
|
LoadOccupancyEvent(
|
||||||
GetOccupancyParam(
|
GetOccupancyParam(
|
||||||
@ -42,41 +35,18 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
context.read<OccupancyHeatMapBloc>().add(
|
context.read<OccupancyHeatMapBloc>().add(
|
||||||
LoadOccupancyHeatMapEvent(
|
LoadOccupancyHeatMapEvent(
|
||||||
GetOccupancyHeatMapParam(
|
GetOccupancyHeatMapParam(
|
||||||
spaceUuid: spaceId,
|
spaceId: spaceId,
|
||||||
|
communityId: communityId,
|
||||||
year: datePickerState.yearlyDate,
|
year: datePickerState.yearlyDate,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedDevice case final AnalyticsDevice device) {
|
context.read<RealtimeDeviceChangesBloc>()
|
||||||
context.read<RealtimeDeviceChangesBloc>()
|
..add(const RealtimeDeviceChangesClosed())
|
||||||
..add(const RealtimeDeviceChangesClosed())
|
..add(
|
||||||
..add(
|
const RealtimeDeviceChangesStarted('14fe6e7e-47af-4a07-ae0a-7c4a26ef8135'),
|
||||||
RealtimeDeviceChangesStarted(device.uuid),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadAnalyticsDevices(
|
|
||||||
BuildContext context, {
|
|
||||||
required String communityUuid,
|
|
||||||
required String spaceUuid,
|
|
||||||
}) {
|
|
||||||
context.read<AnalyticsDevicesBloc>().add(
|
|
||||||
LoadAnalyticsDevicesEvent(
|
|
||||||
param: GetAnalyticsDevicesParam(
|
|
||||||
communityUuid: communityUuid,
|
|
||||||
spaceUuid: spaceUuid,
|
|
||||||
deviceTypes: ['WPS', 'CPS'],
|
|
||||||
requestType: AnalyticsDeviceRequestType.occupancy,
|
|
||||||
),
|
|
||||||
onSuccess: (device) {
|
|
||||||
context.read<RealtimeDeviceChangesBloc>()
|
|
||||||
..add(const RealtimeDeviceChangesClosed())
|
|
||||||
..add(RealtimeDeviceChangesStarted(device.uuid));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearAllData(BuildContext context) {
|
static void clearAllData(BuildContext context) {
|
||||||
@ -89,9 +59,5 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
context.read<RealtimeDeviceChangesBloc>().add(
|
context.read<RealtimeDeviceChangesBloc>().add(
|
||||||
const RealtimeDeviceChangesClosed(),
|
const RealtimeDeviceChangesClosed(),
|
||||||
);
|
);
|
||||||
|
|
||||||
context.read<AnalyticsDevicesBloc>().add(
|
|
||||||
const ClearAnalyticsDeviceEvent(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/power_clamp_energy_status.dart';
|
import 'package:syncrow_web/pages/analytics/models/power_clamp_energy_status.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/blocs/analytics_devices/analytics_devices_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_device_dropdown.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_status_widget.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_status_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class OccupancyEndSideBar extends StatelessWidget {
|
class OccupancyEndSideBar extends StatelessWidget {
|
||||||
const OccupancyEndSideBar({super.key});
|
const OccupancyEndSideBar({super.key});
|
||||||
@ -38,8 +37,7 @@ class OccupancyEndSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
SelectableText(
|
SelectableText(
|
||||||
context.watch<AnalyticsDevicesBloc>().state.selectedDevice?.uuid ??
|
(const Uuid().v4()),
|
||||||
'N/A',
|
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -107,7 +105,7 @@ class OccupancyEndSideBar extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 2,
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
@ -122,18 +120,11 @@ class OccupancyEndSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Expanded(
|
const Expanded(
|
||||||
flex: 2,
|
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: AnalyticsDeviceDropdown(
|
child: PowerClampEnergyDataDeviceDropdown(),
|
||||||
onChanged: (value) =>
|
|
||||||
FetchEnergyManagementDataHelper.loadRealtimeDeviceChanges(
|
|
||||||
context,
|
|
||||||
deviceUuid: value.uuid,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -15,7 +15,7 @@ class OccupancyHeatMap extends StatelessWidget {
|
|||||||
static const _totalWeeks = 53;
|
static const _totalWeeks = 53;
|
||||||
|
|
||||||
int get _maxValue => heatMapData.isNotEmpty
|
int get _maxValue => heatMapData.isNotEmpty
|
||||||
? heatMapData.keys.map((key) => heatMapData[key] ?? 0).reduce(math.max)
|
? heatMapData.keys.map((key) => heatMapData[key]!).reduce(math.max)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
DateTime _getStartingDate() {
|
DateTime _getStartingDate() {
|
||||||
|
@ -68,10 +68,7 @@ class OccupancyHeatMapBox extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: OccupancyHeatMap(
|
child: OccupancyHeatMap(
|
||||||
heatMapData: state.heatMapData.asMap().map(
|
heatMapData: state.heatMapData.asMap().map(
|
||||||
(_, value) => MapEntry(
|
(_, value) => MapEntry(value.date, value.occupancy),
|
||||||
value.eventDate,
|
|
||||||
value.countTotalPresenceDetected,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
enum AnalyticsDeviceRequestType { energyManagement, occupancy }
|
|
||||||
|
|
||||||
class GetAnalyticsDevicesParam {
|
|
||||||
final String? spaceUuid;
|
|
||||||
final List<String> deviceTypes;
|
|
||||||
final String? communityUuid;
|
|
||||||
final AnalyticsDeviceRequestType requestType;
|
|
||||||
|
|
||||||
const GetAnalyticsDevicesParam({
|
|
||||||
required this.requestType,
|
|
||||||
required this.spaceUuid,
|
|
||||||
required this.deviceTypes,
|
|
||||||
required this.communityUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return <String, dynamic>{
|
|
||||||
if (spaceUuid != null) 'spaceUuid': spaceUuid,
|
|
||||||
if (communityUuid != null) 'communityUuid': communityUuid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +1,19 @@
|
|||||||
class GetOccupancyHeatMapParam {
|
class GetOccupancyHeatMapParam {
|
||||||
final DateTime year;
|
final DateTime year;
|
||||||
final String spaceUuid;
|
final String communityId;
|
||||||
|
final String spaceId;
|
||||||
|
|
||||||
const GetOccupancyHeatMapParam({
|
const GetOccupancyHeatMapParam({
|
||||||
required this.year,
|
required this.year,
|
||||||
required this.spaceUuid,
|
required this.communityId,
|
||||||
|
required this.spaceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {'year': year.year};
|
return {
|
||||||
|
'year': year.toIso8601String(),
|
||||||
|
'communityId': communityId,
|
||||||
|
'spaceId': spaceId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
|
|
||||||
abstract interface class AnalyticsDevicesService {
|
|
||||||
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param);
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
|
||||||
|
|
||||||
class AnalyticsDevicesServiceDelegate implements AnalyticsDevicesService {
|
|
||||||
const AnalyticsDevicesServiceDelegate(
|
|
||||||
this._occupancyService,
|
|
||||||
this._energyManagementService,
|
|
||||||
);
|
|
||||||
|
|
||||||
final AnalyticsDevicesService _occupancyService;
|
|
||||||
final AnalyticsDevicesService _energyManagementService;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<AnalyticsDevice>> getDevices(
|
|
||||||
GetAnalyticsDevicesParam param,
|
|
||||||
) {
|
|
||||||
return switch (param.requestType) {
|
|
||||||
AnalyticsDeviceRequestType.occupancy => _occupancyService.getDevices(param),
|
|
||||||
AnalyticsDeviceRequestType.energyManagement =>
|
|
||||||
_energyManagementService.getDevices(param),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
|
||||||
|
|
||||||
final class RemoteEnergyManagementAnalyticsDevicesService
|
|
||||||
implements AnalyticsDevicesService {
|
|
||||||
const RemoteEnergyManagementAnalyticsDevicesService(this._httpService);
|
|
||||||
|
|
||||||
final HTTPService _httpService;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
|
||||||
try {
|
|
||||||
final response = await _httpService.get(
|
|
||||||
path: '/devices-space-community/recursive-child',
|
|
||||||
queryParameters: param.toJson()
|
|
||||||
..addAll({'productType': param.deviceTypes.first}),
|
|
||||||
expectedResponseModel: (response) {
|
|
||||||
final json = response as Map<String, dynamic>;
|
|
||||||
final dailyData = json['data'] as List<dynamic>? ?? <dynamic>[];
|
|
||||||
|
|
||||||
final result = dailyData.map(
|
|
||||||
(json) => AnalyticsDevice.fromJson(json as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result.toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (e) {
|
|
||||||
throw Exception('Failed to load total energy consumption: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
|
||||||
|
|
||||||
class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService {
|
|
||||||
const RemoteOccupancyAnalyticsDevicesService(this._httpService);
|
|
||||||
|
|
||||||
final HTTPService _httpService;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
|
||||||
try {
|
|
||||||
final requests = await Future.wait<List<AnalyticsDevice>>(
|
|
||||||
param.deviceTypes.map((e) {
|
|
||||||
final mappedParam = GetAnalyticsDevicesParam(
|
|
||||||
requestType: AnalyticsDeviceRequestType.occupancy,
|
|
||||||
spaceUuid: param.spaceUuid,
|
|
||||||
deviceTypes: [e],
|
|
||||||
communityUuid: param.communityUuid,
|
|
||||||
);
|
|
||||||
return _makeRequest(mappedParam);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
final result = requests.map((e) => e.first).toList();
|
|
||||||
return result;
|
|
||||||
} catch (e) {
|
|
||||||
throw Exception('Failed to load total energy consumption: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<AnalyticsDevice>> _makeRequest(GetAnalyticsDevicesParam param) async {
|
|
||||||
try {
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID();
|
|
||||||
|
|
||||||
final response = await _httpService.get(
|
|
||||||
path:
|
|
||||||
'/projects/$projectUuid/communities/${param.communityUuid}/spaces/${param.spaceUuid}/devices',
|
|
||||||
queryParameters: {
|
|
||||||
'requestType': param.requestType.name,
|
|
||||||
'communityUuid': param.communityUuid,
|
|
||||||
'spaceUuid': param.spaceUuid,
|
|
||||||
'productType': param.deviceTypes.first,
|
|
||||||
},
|
|
||||||
expectedResponseModel: (response) {
|
|
||||||
final json = response as Map<String, dynamic>;
|
|
||||||
final dailyData = json['data'] as List<dynamic>? ?? <dynamic>[];
|
|
||||||
|
|
||||||
final result = dailyData.map(
|
|
||||||
(json) => AnalyticsDevice.fromJson(json as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
return result.toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return response;
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,25 @@
|
|||||||
|
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
||||||
|
|
||||||
|
class FakeOccupancyHeatMapService implements OccupancyHeatMapService {
|
||||||
|
@override
|
||||||
|
Future<List<OccupancyHeatMapModel>> load(GetOccupancyHeatMapParam param) {
|
||||||
|
return Future.delayed(const Duration(milliseconds: 200), () {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final startOfYear = DateTime(now.year, 1, 1);
|
||||||
|
final endOfYear = DateTime(now.year, 12, 31);
|
||||||
|
final daysInYear = endOfYear.difference(startOfYear).inDays + 1;
|
||||||
|
|
||||||
|
final List<OccupancyHeatMapModel> data = List.generate(
|
||||||
|
daysInYear,
|
||||||
|
(index) => OccupancyHeatMapModel(
|
||||||
|
date: startOfYear.add(Duration(days: index)),
|
||||||
|
occupancy: ((index + 1) * 10) % 100,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
|
||||||
|
|
||||||
final class RemoteOccupancyHeatMapService implements OccupancyHeatMapService {
|
|
||||||
const RemoteOccupancyHeatMapService(this._httpService);
|
|
||||||
|
|
||||||
final HTTPService _httpService;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<OccupancyHeatMapModel>> load(GetOccupancyHeatMapParam param) async {
|
|
||||||
try {
|
|
||||||
final response = await _httpService.get(
|
|
||||||
path: '/occupancy/heat-map/space/${param.spaceUuid}',
|
|
||||||
showServerMessage: true,
|
|
||||||
queryParameters: param.toJson(),
|
|
||||||
expectedResponseModel: (response) {
|
|
||||||
final json = response as Map<String, dynamic>;
|
|
||||||
final dailyData = json['data'] as List<dynamic>? ?? <dynamic>[];
|
|
||||||
|
|
||||||
final result = dailyData.map(
|
|
||||||
(json) => OccupancyHeatMapModel.fromJson(json as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result.toList();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (e) {
|
|
||||||
throw Exception('Failed to load total energy consumption:');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,7 +12,7 @@ class AnalyticsErrorWidget extends StatelessWidget {
|
|||||||
return Visibility(
|
return Visibility(
|
||||||
visible: errorMessage != null || (errorMessage?.isNotEmpty ?? false),
|
visible: errorMessage != null || (errorMessage?.isNotEmpty ?? false),
|
||||||
child: Text(
|
child: Text(
|
||||||
errorMessage ?? 'Something went wrong',
|
'$errorMessage ?? "Something went wrong"',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
@ -26,8 +26,10 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
|||||||
functionCode: event.functionData.functionCode,
|
functionCode: event.functionData.functionCode,
|
||||||
operationName: event.functionData.operationName,
|
operationName: event.functionData.operationName,
|
||||||
value: event.functionData.value ?? existingData.value,
|
value: event.functionData.value ?? existingData.value,
|
||||||
valueDescription: event.functionData.valueDescription ?? existingData.valueDescription,
|
valueDescription: event.functionData.valueDescription ??
|
||||||
|
existingData.valueDescription,
|
||||||
condition: event.functionData.condition ?? existingData.condition,
|
condition: event.functionData.condition ?? existingData.condition,
|
||||||
|
step: event.functionData.step ?? existingData.step,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
functions.clear();
|
functions.clear();
|
||||||
@ -59,8 +61,10 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSelectFunction(SelectFunction event, Emitter<FunctionBlocState> emit) {
|
FutureOr<void> _onSelectFunction(
|
||||||
|
SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
selectedFunction: event.functionCode, selectedOperationName: event.operationName));
|
selectedFunction: event.functionCode,
|
||||||
|
selectedOperationName: event.operationName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ abstract class ACFunction extends DeviceFunction<AcStatusModel> {
|
|||||||
required super.operationName,
|
required super.operationName,
|
||||||
required super.icon,
|
required super.icon,
|
||||||
required this.type,
|
required this.type,
|
||||||
|
super.step,
|
||||||
|
super.unit,
|
||||||
|
super.max,
|
||||||
|
super.min,
|
||||||
});
|
});
|
||||||
|
|
||||||
List<ACOperationalValue> getOperationalValues();
|
List<ACOperationalValue> getOperationalValues();
|
||||||
@ -75,26 +79,24 @@ class ModeFunction extends ACFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TempSetFunction extends ACFunction {
|
class TempSetFunction extends ACFunction {
|
||||||
final int min;
|
TempSetFunction({
|
||||||
final int max;
|
required super.deviceId,
|
||||||
final int step;
|
required super.deviceName,
|
||||||
|
required super.type,
|
||||||
TempSetFunction(
|
}) : super(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
|
||||||
: min = 160,
|
|
||||||
max = 300,
|
|
||||||
step = 1,
|
|
||||||
super(
|
|
||||||
code: 'temp_set',
|
code: 'temp_set',
|
||||||
operationName: 'Set Temperature',
|
operationName: 'Set Temperature',
|
||||||
icon: Assets.assetsTempreture,
|
icon: Assets.assetsTempreture,
|
||||||
type: type,
|
min: 200,
|
||||||
|
max: 300,
|
||||||
|
step: 1,
|
||||||
|
unit: "°C",
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ACOperationalValue> getOperationalValues() {
|
List<ACOperationalValue> getOperationalValues() {
|
||||||
List<ACOperationalValue> values = [];
|
List<ACOperationalValue> values = [];
|
||||||
for (int temp = min; temp <= max; temp += step) {
|
for (int temp = min!.toInt(); temp <= max!; temp += step!.toInt()) {
|
||||||
values.add(ACOperationalValue(
|
values.add(ACOperationalValue(
|
||||||
icon: Assets.assetsTempreture,
|
icon: Assets.assetsTempreture,
|
||||||
description: "${temp / 10}°C",
|
description: "${temp / 10}°C",
|
||||||
@ -104,7 +106,6 @@ class TempSetFunction extends ACFunction {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LevelFunction extends ACFunction {
|
class LevelFunction extends ACFunction {
|
||||||
LevelFunction(
|
LevelFunction(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
@ -166,9 +167,10 @@ class ChildLockFunction extends ACFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CurrentTempFunction extends ACFunction {
|
class CurrentTempFunction extends ACFunction {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
final String unit = "°C";
|
||||||
|
|
||||||
CurrentTempFunction(
|
CurrentTempFunction(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
@ -185,7 +187,7 @@ class CurrentTempFunction extends ACFunction {
|
|||||||
@override
|
@override
|
||||||
List<ACOperationalValue> getOperationalValues() {
|
List<ACOperationalValue> getOperationalValues() {
|
||||||
List<ACOperationalValue> values = [];
|
List<ACOperationalValue> values = [];
|
||||||
for (int temp = min; temp <= max; temp += step) {
|
for (int temp = min.toInt(); temp <= max; temp += step.toInt()) {
|
||||||
values.add(ACOperationalValue(
|
values.add(ACOperationalValue(
|
||||||
icon: Assets.currentTemp,
|
icon: Assets.currentTemp,
|
||||||
description: "${temp / 10}°C",
|
description: "${temp / 10}°C",
|
||||||
|
@ -6,10 +6,12 @@ class CpsOperationalValue {
|
|||||||
final String description;
|
final String description;
|
||||||
final dynamic value;
|
final dynamic value;
|
||||||
|
|
||||||
|
|
||||||
CpsOperationalValue({
|
CpsOperationalValue({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.value,
|
required this.value,
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,9 +96,9 @@ final class CpsSensitivityFunction extends CpsFunctions {
|
|||||||
icon: Assets.sensitivity,
|
icon: Assets.sensitivity,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
static const _images = <String>[
|
static const _images = <String>[
|
||||||
Assets.sensitivityFeature1,
|
Assets.sensitivityFeature1,
|
||||||
@ -115,10 +117,10 @@ final class CpsSensitivityFunction extends CpsFunctions {
|
|||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
final values = <CpsOperationalValue>[];
|
final values = <CpsOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min; value <= max; value += step.toInt()) {
|
||||||
values.add(
|
values.add(
|
||||||
CpsOperationalValue(
|
CpsOperationalValue(
|
||||||
icon: _images[value],
|
icon: _images[value.toInt()],
|
||||||
description: '$value',
|
description: '$value',
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
@ -142,9 +144,9 @@ final class CpsMovingSpeedFunction extends CpsFunctions {
|
|||||||
icon: Assets.speedoMeter,
|
icon: Assets.speedoMeter,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
@ -173,9 +175,9 @@ final class CpsSpatialStaticValueFunction extends CpsFunctions {
|
|||||||
icon: Assets.spatialStaticValue,
|
icon: Assets.spatialStaticValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
@ -204,9 +206,9 @@ final class CpsSpatialMotionValueFunction extends CpsFunctions {
|
|||||||
icon: Assets.spatialMotionValue,
|
icon: Assets.spatialMotionValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
@ -375,9 +377,9 @@ final class CpsPresenceJudgementThrsholdFunction extends CpsFunctions {
|
|||||||
icon: Assets.presenceJudgementThrshold,
|
icon: Assets.presenceJudgementThrshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
@ -406,9 +408,9 @@ final class CpsMotionAmplitudeTriggerThresholdFunction extends CpsFunctions {
|
|||||||
icon: Assets.presenceJudgementThrshold,
|
icon: Assets.presenceJudgementThrshold,
|
||||||
);
|
);
|
||||||
|
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<CpsOperationalValue> getOperationalValues() {
|
List<CpsOperationalValue> getOperationalValues() {
|
||||||
|
@ -4,6 +4,11 @@ abstract class DeviceFunction<T> {
|
|||||||
final String code;
|
final String code;
|
||||||
final String operationName;
|
final String operationName;
|
||||||
final String icon;
|
final String icon;
|
||||||
|
final double? step;
|
||||||
|
final String? unit;
|
||||||
|
final double? max;
|
||||||
|
final double? min;
|
||||||
|
|
||||||
|
|
||||||
DeviceFunction({
|
DeviceFunction({
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
@ -11,6 +16,10 @@ abstract class DeviceFunction<T> {
|
|||||||
required this.code,
|
required this.code,
|
||||||
required this.operationName,
|
required this.operationName,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
|
this.step,
|
||||||
|
this.unit,
|
||||||
|
this.max,
|
||||||
|
this.min,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +31,10 @@ class DeviceFunctionData {
|
|||||||
final dynamic value;
|
final dynamic value;
|
||||||
final String? condition;
|
final String? condition;
|
||||||
final String? valueDescription;
|
final String? valueDescription;
|
||||||
|
final double? step;
|
||||||
|
final String? unit;
|
||||||
|
final double? max;
|
||||||
|
final double? min;
|
||||||
|
|
||||||
DeviceFunctionData({
|
DeviceFunctionData({
|
||||||
required this.entityId,
|
required this.entityId,
|
||||||
@ -31,6 +44,10 @@ class DeviceFunctionData {
|
|||||||
required this.value,
|
required this.value,
|
||||||
this.condition,
|
this.condition,
|
||||||
this.valueDescription,
|
this.valueDescription,
|
||||||
|
this.step,
|
||||||
|
this.unit,
|
||||||
|
this.max,
|
||||||
|
this.min,
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@ -42,6 +59,10 @@ class DeviceFunctionData {
|
|||||||
'value': value,
|
'value': value,
|
||||||
if (condition != null) 'condition': condition,
|
if (condition != null) 'condition': condition,
|
||||||
if (valueDescription != null) 'valueDescription': valueDescription,
|
if (valueDescription != null) 'valueDescription': valueDescription,
|
||||||
|
if (step != null) 'step': step,
|
||||||
|
if (unit != null) 'unit': unit,
|
||||||
|
if (max != null) 'max': max,
|
||||||
|
if (min != null) 'min': min,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +75,10 @@ class DeviceFunctionData {
|
|||||||
value: json['value'],
|
value: json['value'],
|
||||||
condition: json['condition'],
|
condition: json['condition'],
|
||||||
valueDescription: json['valueDescription'],
|
valueDescription: json['valueDescription'],
|
||||||
|
step: json['step']?.toDouble(),
|
||||||
|
unit: json['unit'],
|
||||||
|
max: json['max']?.toDouble(),
|
||||||
|
min: json['min']?.toDouble(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +93,11 @@ class DeviceFunctionData {
|
|||||||
other.operationName == operationName &&
|
other.operationName == operationName &&
|
||||||
other.value == value &&
|
other.value == value &&
|
||||||
other.condition == condition &&
|
other.condition == condition &&
|
||||||
other.valueDescription == valueDescription;
|
other.valueDescription == valueDescription &&
|
||||||
|
other.step == step &&
|
||||||
|
other.unit == unit &&
|
||||||
|
other.max == max &&
|
||||||
|
other.min == min;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -79,6 +108,10 @@ class DeviceFunctionData {
|
|||||||
operationName.hashCode ^
|
operationName.hashCode ^
|
||||||
value.hashCode ^
|
value.hashCode ^
|
||||||
condition.hashCode ^
|
condition.hashCode ^
|
||||||
valueDescription.hashCode;
|
valueDescription.hashCode ^
|
||||||
|
step.hashCode ^
|
||||||
|
unit.hashCode ^
|
||||||
|
max.hashCode ^
|
||||||
|
min.hashCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,11 @@ abstract class FlushFunctions
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushPresenceDelayFunction extends FlushFunctions {
|
class FlushPresenceDelayFunction extends FlushFunctions {
|
||||||
final int min;
|
|
||||||
FlushPresenceDelayFunction({
|
FlushPresenceDelayFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
required super.deviceName,
|
required super.deviceName,
|
||||||
required super.type,
|
required super.type,
|
||||||
}) : min = 0,
|
}) :
|
||||||
super(
|
super(
|
||||||
code: FlushMountedPresenceSensorModel.codePresenceState,
|
code: FlushMountedPresenceSensorModel.codePresenceState,
|
||||||
operationName: 'Presence State',
|
operationName: 'Presence State',
|
||||||
@ -50,9 +49,9 @@ class FlushPresenceDelayFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushSensiReduceFunction extends FlushFunctions {
|
class FlushSensiReduceFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
FlushSensiReduceFunction({
|
FlushSensiReduceFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
@ -80,8 +79,8 @@ class FlushSensiReduceFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushNoneDelayFunction extends FlushFunctions {
|
class FlushNoneDelayFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushNoneDelayFunction({
|
FlushNoneDelayFunction({
|
||||||
@ -110,9 +109,9 @@ class FlushNoneDelayFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushIlluminanceFunction extends FlushFunctions {
|
class FlushIlluminanceFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
FlushIlluminanceFunction({
|
FlushIlluminanceFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
@ -130,7 +129,7 @@ class FlushIlluminanceFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
List<FlushOperationalValue> values = [];
|
List<FlushOperationalValue> values = [];
|
||||||
for (int lux = min; lux <= max; lux += step) {
|
for (int lux = min.toInt(); lux <= max; lux += step.toInt()) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.IlluminanceIcon,
|
icon: Assets.IlluminanceIcon,
|
||||||
description: "$lux Lux",
|
description: "$lux Lux",
|
||||||
@ -142,9 +141,9 @@ class FlushIlluminanceFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushOccurDistReduceFunction extends FlushFunctions {
|
class FlushOccurDistReduceFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
FlushOccurDistReduceFunction({
|
FlushOccurDistReduceFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
@ -173,9 +172,9 @@ class FlushOccurDistReduceFunction extends FlushFunctions {
|
|||||||
|
|
||||||
// ==== then functions ====
|
// ==== then functions ====
|
||||||
class FlushSensitivityFunction extends FlushFunctions {
|
class FlushSensitivityFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
FlushSensitivityFunction({
|
FlushSensitivityFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
@ -203,9 +202,9 @@ class FlushSensitivityFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushNearDetectionFunction extends FlushFunctions {
|
class FlushNearDetectionFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final double max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushNearDetectionFunction({
|
FlushNearDetectionFunction({
|
||||||
@ -225,7 +224,7 @@ class FlushNearDetectionFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min.toDouble(); value <= max; value += step) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -237,9 +236,9 @@ class FlushNearDetectionFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushMaxDetectDistFunction extends FlushFunctions {
|
class FlushMaxDetectDistFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushMaxDetectDistFunction({
|
FlushMaxDetectDistFunction({
|
||||||
@ -259,7 +258,7 @@ class FlushMaxDetectDistFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min; value <= max; value += step.toInt()) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -271,9 +270,9 @@ class FlushMaxDetectDistFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushTargetConfirmTimeFunction extends FlushFunctions {
|
class FlushTargetConfirmTimeFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushTargetConfirmTimeFunction({
|
FlushTargetConfirmTimeFunction({
|
||||||
@ -293,7 +292,7 @@ class FlushTargetConfirmTimeFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min.toDouble(); value <= max; value += step) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -305,9 +304,9 @@ class FlushTargetConfirmTimeFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushDisappeDelayFunction extends FlushFunctions {
|
class FlushDisappeDelayFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushDisappeDelayFunction({
|
FlushDisappeDelayFunction({
|
||||||
@ -327,7 +326,7 @@ class FlushDisappeDelayFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min.toDouble(); value <= max; value += step) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -339,9 +338,9 @@ class FlushDisappeDelayFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushIndentLevelFunction extends FlushFunctions {
|
class FlushIndentLevelFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushIndentLevelFunction({
|
FlushIndentLevelFunction({
|
||||||
@ -361,7 +360,7 @@ class FlushIndentLevelFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min.toDouble(); value <= max; value += step) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -373,9 +372,9 @@ class FlushIndentLevelFunction extends FlushFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlushTriggerLevelFunction extends FlushFunctions {
|
class FlushTriggerLevelFunction extends FlushFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FlushTriggerLevelFunction({
|
FlushTriggerLevelFunction({
|
||||||
@ -395,7 +394,7 @@ class FlushTriggerLevelFunction extends FlushFunctions {
|
|||||||
@override
|
@override
|
||||||
List<FlushOperationalValue> getOperationalValues() {
|
List<FlushOperationalValue> getOperationalValues() {
|
||||||
final values = <FlushOperationalValue>[];
|
final values = <FlushOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min.toDouble(); value <= max; value += step) {
|
||||||
values.add(FlushOperationalValue(
|
values.add(FlushOperationalValue(
|
||||||
icon: Assets.nobodyTime,
|
icon: Assets.nobodyTime,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
|
@ -20,18 +20,17 @@ abstract class WaterHeaterFunctions
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WHRestartStatusFunction extends WaterHeaterFunctions {
|
class WHRestartStatusFunction extends WaterHeaterFunctions {
|
||||||
final int min;
|
|
||||||
WHRestartStatusFunction({
|
WHRestartStatusFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
required super.deviceName,
|
required super.deviceName,
|
||||||
required super.type,
|
required super.type,
|
||||||
}) : min = 0,
|
}) : super(
|
||||||
super(
|
|
||||||
code: 'relay_status',
|
code: 'relay_status',
|
||||||
operationName: 'Restart Status',
|
operationName: 'Restart Status',
|
||||||
icon: Assets.refreshStatusIcon,
|
icon: Assets.refreshStatusIcon,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<WaterHeaterOperationalValue> getOperationalValues() {
|
List<WaterHeaterOperationalValue> getOperationalValues() {
|
||||||
return [
|
return [
|
||||||
@ -55,13 +54,11 @@ class WHRestartStatusFunction extends WaterHeaterFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class WHSwitchFunction extends WaterHeaterFunctions {
|
class WHSwitchFunction extends WaterHeaterFunctions {
|
||||||
final int min;
|
|
||||||
WHSwitchFunction({
|
WHSwitchFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
required super.deviceName,
|
required super.deviceName,
|
||||||
required super.type,
|
required super.type,
|
||||||
}) : min = 0,
|
}) : super(
|
||||||
super(
|
|
||||||
code: 'switch_1',
|
code: 'switch_1',
|
||||||
operationName: 'Switch',
|
operationName: 'Switch',
|
||||||
icon: Assets.assetsAcPower,
|
icon: Assets.assetsAcPower,
|
||||||
@ -104,12 +101,11 @@ class TimerConfirmTimeFunction extends WaterHeaterFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BacklightFunction extends WaterHeaterFunctions {
|
class BacklightFunction extends WaterHeaterFunctions {
|
||||||
final int min;
|
|
||||||
BacklightFunction({
|
BacklightFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
required super.deviceName,
|
required super.deviceName,
|
||||||
required super.type,
|
required super.type,
|
||||||
}) : min = 0,
|
}) :
|
||||||
super(
|
super(
|
||||||
code: 'switch_backlight',
|
code: 'switch_backlight',
|
||||||
operationName: 'Backlight',
|
operationName: 'Backlight',
|
||||||
|
@ -13,6 +13,10 @@ abstract class WpsFunctions extends DeviceFunction<WallSensorModel> {
|
|||||||
required super.operationName,
|
required super.operationName,
|
||||||
required super.icon,
|
required super.icon,
|
||||||
required this.type,
|
required this.type,
|
||||||
|
super.step,
|
||||||
|
super.unit,
|
||||||
|
super.max,
|
||||||
|
super.min,
|
||||||
});
|
});
|
||||||
|
|
||||||
List<WpsOperationalValue> getOperationalValues();
|
List<WpsOperationalValue> getOperationalValues();
|
||||||
@ -20,9 +24,13 @@ abstract class WpsFunctions extends DeviceFunction<WallSensorModel> {
|
|||||||
|
|
||||||
// For far_detection (75-600cm in 75cm steps)
|
// For far_detection (75-600cm in 75cm steps)
|
||||||
class FarDetectionFunction extends WpsFunctions {
|
class FarDetectionFunction extends WpsFunctions {
|
||||||
final int min;
|
|
||||||
final int max;
|
final double min;
|
||||||
final int step;
|
@override
|
||||||
|
final double max;
|
||||||
|
@override
|
||||||
|
final double step;
|
||||||
|
@override
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
FarDetectionFunction(
|
FarDetectionFunction(
|
||||||
@ -41,7 +49,7 @@ class FarDetectionFunction extends WpsFunctions {
|
|||||||
@override
|
@override
|
||||||
List<WpsOperationalValue> getOperationalValues() {
|
List<WpsOperationalValue> getOperationalValues() {
|
||||||
final values = <WpsOperationalValue>[];
|
final values = <WpsOperationalValue>[];
|
||||||
for (var value = min; value <= max; value += step) {
|
for (var value = min; value <= max; value += step.toInt()) {
|
||||||
values.add(WpsOperationalValue(
|
values.add(WpsOperationalValue(
|
||||||
icon: Assets.currentDistanceIcon,
|
icon: Assets.currentDistanceIcon,
|
||||||
description: '$value $unit',
|
description: '$value $unit',
|
||||||
@ -54,9 +62,9 @@ class FarDetectionFunction extends WpsFunctions {
|
|||||||
|
|
||||||
// For presence_time (0-65535 minutes)
|
// For presence_time (0-65535 minutes)
|
||||||
class PresenceTimeFunction extends WpsFunctions {
|
class PresenceTimeFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
PresenceTimeFunction(
|
PresenceTimeFunction(
|
||||||
@ -86,9 +94,9 @@ class PresenceTimeFunction extends WpsFunctions {
|
|||||||
|
|
||||||
// For motion_sensitivity_value (1-5 levels)
|
// For motion_sensitivity_value (1-5 levels)
|
||||||
class MotionSensitivityFunction extends WpsFunctions {
|
class MotionSensitivityFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
MotionSensitivityFunction(
|
MotionSensitivityFunction(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
@ -116,9 +124,9 @@ class MotionSensitivityFunction extends WpsFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MotionLessSensitivityFunction extends WpsFunctions {
|
class MotionLessSensitivityFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
MotionLessSensitivityFunction(
|
MotionLessSensitivityFunction(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
@ -171,8 +179,8 @@ class IndicatorFunction extends WpsFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NoOneTimeFunction extends WpsFunctions {
|
class NoOneTimeFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final String unit;
|
final String unit;
|
||||||
|
|
||||||
NoOneTimeFunction(
|
NoOneTimeFunction(
|
||||||
@ -225,9 +233,9 @@ class PresenceStateFunction extends WpsFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CurrentDistanceFunction extends WpsFunctions {
|
class CurrentDistanceFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
CurrentDistanceFunction(
|
CurrentDistanceFunction(
|
||||||
{required super.deviceId, required super.deviceName, required type})
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
@ -244,11 +252,10 @@ class CurrentDistanceFunction extends WpsFunctions {
|
|||||||
@override
|
@override
|
||||||
List<WpsOperationalValue> getOperationalValues() {
|
List<WpsOperationalValue> getOperationalValues() {
|
||||||
List<WpsOperationalValue> values = [];
|
List<WpsOperationalValue> values = [];
|
||||||
for (int cm = min; cm <= max; cm += step) {
|
for (int cm = min.toInt(); cm <= max; cm += step.toInt()) {
|
||||||
values.add(WpsOperationalValue(
|
values.add(WpsOperationalValue(
|
||||||
icon: Assets.assetsTempreture,
|
icon: Assets.assetsTempreture,
|
||||||
description: "${cm}CM",
|
description: "${cm}CM",
|
||||||
|
|
||||||
value: cm,
|
value: cm,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -257,9 +264,9 @@ class CurrentDistanceFunction extends WpsFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IlluminanceValueFunction extends WpsFunctions {
|
class IlluminanceValueFunction extends WpsFunctions {
|
||||||
final int min;
|
final double min;
|
||||||
final int max;
|
final double max;
|
||||||
final int step;
|
final double step;
|
||||||
|
|
||||||
IlluminanceValueFunction({
|
IlluminanceValueFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
@ -277,7 +284,7 @@ class IlluminanceValueFunction extends WpsFunctions {
|
|||||||
@override
|
@override
|
||||||
List<WpsOperationalValue> getOperationalValues() {
|
List<WpsOperationalValue> getOperationalValues() {
|
||||||
List<WpsOperationalValue> values = [];
|
List<WpsOperationalValue> values = [];
|
||||||
for (int lux = min; lux <= max; lux += step) {
|
for (int lux = min.toInt(); lux <= max; lux += step.toInt()) {
|
||||||
values.add(WpsOperationalValue(
|
values.add(WpsOperationalValue(
|
||||||
icon: Assets.IlluminanceIcon,
|
icon: Assets.IlluminanceIcon,
|
||||||
description: "$lux Lux",
|
description: "$lux Lux",
|
||||||
|
297
lib/pages/routines/widgets/custom_routines_textbox.dart
Normal file
297
lib/pages/routines/widgets/custom_routines_textbox.dart
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/condition_toggle.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
class CustomRoutinesTextbox extends StatefulWidget {
|
||||||
|
final String? currentCondition;
|
||||||
|
final String dialogType;
|
||||||
|
final (double, double) sliderRange;
|
||||||
|
final dynamic displayedValue;
|
||||||
|
final dynamic initialValue;
|
||||||
|
final void Function(String condition) onConditionChanged;
|
||||||
|
final void Function(double value) onTextChanged;
|
||||||
|
final String unit;
|
||||||
|
final double dividendOfRange;
|
||||||
|
final double stepIncreaseAmount;
|
||||||
|
final bool withSpecialChar;
|
||||||
|
|
||||||
|
const CustomRoutinesTextbox({
|
||||||
|
required this.dialogType,
|
||||||
|
required this.sliderRange,
|
||||||
|
required this.displayedValue,
|
||||||
|
required this.initialValue,
|
||||||
|
required this.onConditionChanged,
|
||||||
|
required this.onTextChanged,
|
||||||
|
required this.currentCondition,
|
||||||
|
required this.unit,
|
||||||
|
required this.dividendOfRange,
|
||||||
|
required this.stepIncreaseAmount,
|
||||||
|
required this.withSpecialChar,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CustomRoutinesTextbox> createState() => _CustomRoutinesTextboxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomRoutinesTextboxState extends State<CustomRoutinesTextbox> {
|
||||||
|
late final TextEditingController _controller;
|
||||||
|
bool hasError = false;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
int getDecimalPlaces(double step) {
|
||||||
|
String stepStr = step.toString();
|
||||||
|
if (stepStr.contains('.')) {
|
||||||
|
List<String> parts = stepStr.split('.');
|
||||||
|
String decimalPart = parts[1];
|
||||||
|
decimalPart = decimalPart.replaceAll(RegExp(r'0+$'), '');
|
||||||
|
return decimalPart.isEmpty ? 0 : decimalPart.length;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
int decimalPlaces = getDecimalPlaces(widget.stepIncreaseAmount);
|
||||||
|
double initialValue;
|
||||||
|
if (widget.initialValue != null &&
|
||||||
|
widget.initialValue is num &&
|
||||||
|
(widget.initialValue as num) == 0) {
|
||||||
|
initialValue = 0.0;
|
||||||
|
} else {
|
||||||
|
initialValue = double.tryParse(widget.displayedValue) ?? 0.0;
|
||||||
|
}
|
||||||
|
_controller = TextEditingController(
|
||||||
|
text: initialValue.toStringAsFixed(decimalPlaces),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _validateInput(String value) {
|
||||||
|
final doubleValue = double.tryParse(value);
|
||||||
|
if (doubleValue == null) {
|
||||||
|
setState(() {
|
||||||
|
errorMessage = "Invalid number";
|
||||||
|
hasError = true;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final min = widget.sliderRange.$1;
|
||||||
|
final max = widget.sliderRange.$2;
|
||||||
|
|
||||||
|
if (doubleValue < min) {
|
||||||
|
setState(() {
|
||||||
|
errorMessage = "Value must be at least $min";
|
||||||
|
hasError = true;
|
||||||
|
});
|
||||||
|
} else if (doubleValue > max) {
|
||||||
|
setState(() {
|
||||||
|
errorMessage = "Value must be at most $max";
|
||||||
|
hasError = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
int decimalPlaces = getDecimalPlaces(widget.stepIncreaseAmount);
|
||||||
|
int factor = pow(10, decimalPlaces).toInt();
|
||||||
|
int scaledStep = (widget.stepIncreaseAmount * factor).round();
|
||||||
|
int scaledValue = (doubleValue * factor).round();
|
||||||
|
|
||||||
|
if (scaledValue % scaledStep != 0) {
|
||||||
|
setState(() {
|
||||||
|
errorMessage = "must be a multiple of ${widget.stepIncreaseAmount}";
|
||||||
|
hasError = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
errorMessage = null;
|
||||||
|
hasError = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(CustomRoutinesTextbox oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (widget.initialValue != oldWidget.initialValue) {
|
||||||
|
if (widget.initialValue != null &&
|
||||||
|
widget.initialValue is num &&
|
||||||
|
(widget.initialValue as num) == 0) {
|
||||||
|
int decimalPlaces = getDecimalPlaces(widget.stepIncreaseAmount);
|
||||||
|
_controller.text = 0.0.toStringAsFixed(decimalPlaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _correctAndUpdateValue(String value) {
|
||||||
|
final doubleValue = double.tryParse(value) ?? 0.0;
|
||||||
|
int decimalPlaces = getDecimalPlaces(widget.stepIncreaseAmount);
|
||||||
|
double rounded = (doubleValue / widget.stepIncreaseAmount).round() *
|
||||||
|
widget.stepIncreaseAmount;
|
||||||
|
rounded = rounded.clamp(widget.sliderRange.$1, widget.sliderRange.$2);
|
||||||
|
rounded = double.parse(rounded.toStringAsFixed(decimalPlaces));
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
hasError = false;
|
||||||
|
errorMessage = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
_controller.text = rounded.toStringAsFixed(decimalPlaces);
|
||||||
|
_controller.selection = TextSelection.fromPosition(
|
||||||
|
TextPosition(offset: _controller.text.length),
|
||||||
|
);
|
||||||
|
widget.onTextChanged(rounded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
int decimalPlaces = getDecimalPlaces(widget.stepIncreaseAmount);
|
||||||
|
|
||||||
|
List<TextInputFormatter> formatters = [];
|
||||||
|
if (decimalPlaces == 0) {
|
||||||
|
formatters.add(FilteringTextInputFormatter.digitsOnly);
|
||||||
|
} else {
|
||||||
|
formatters.add(FilteringTextInputFormatter.allow(
|
||||||
|
RegExp(r'^\d*\.?\d{0,' + decimalPlaces.toString() + r'}$'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
formatters.add(RangeInputFormatter(
|
||||||
|
min: widget.sliderRange.$1,
|
||||||
|
max: widget.sliderRange.$2,
|
||||||
|
));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (widget.dialogType == 'IF')
|
||||||
|
ConditionToggle(
|
||||||
|
currentCondition: widget.currentCondition,
|
||||||
|
onChanged: widget.onConditionChanged,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 35, vertical: 2),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Step: ${widget.stepIncreaseAmount}',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
width: 170,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF8F8F8),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: hasError
|
||||||
|
? Border.all(color: Colors.red, width: 1)
|
||||||
|
: Border.all(
|
||||||
|
color: ColorsManager.lightGrayBorderColor, width: 1),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: ColorsManager.blackColor.withOpacity(0.05),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _controller,
|
||||||
|
style: context.textTheme.bodyLarge?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: widget.withSpecialChar == true
|
||||||
|
? [FilteringTextInputFormatter.digitsOnly]
|
||||||
|
: null,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
onChanged: _validateInput,
|
||||||
|
onFieldSubmitted: _correctAndUpdateValue,
|
||||||
|
onTapOutside: (_) =>
|
||||||
|
_correctAndUpdateValue(_controller.text),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
widget.unit,
|
||||||
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorsManager.vividBlue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (errorMessage != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 2.0),
|
||||||
|
child: Text(
|
||||||
|
errorMessage!,
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: Colors.red,
|
||||||
|
fontSize: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Min. ${widget.sliderRange.$1.toInt()}${widget.unit}',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Max. ${widget.sliderRange.$2.toInt()}${widget.unit}',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
@ -76,24 +77,20 @@ class ACHelper {
|
|||||||
context: context,
|
context: context,
|
||||||
acFunctions: acFunctions,
|
acFunctions: acFunctions,
|
||||||
device: device,
|
device: device,
|
||||||
onFunctionSelected: (functionCode, operationName) {
|
onFunctionSelected:
|
||||||
|
(functionCode, operationName) {
|
||||||
RoutineTapFunctionHelper.onTapFunction(
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
context,
|
context,
|
||||||
functionCode: functionCode,
|
functionCode: functionCode,
|
||||||
functionOperationName: operationName,
|
functionOperationName: operationName,
|
||||||
functionValueDescription:
|
functionValueDescription:
|
||||||
selectedFunctionData.valueDescription,
|
selectedFunctionData.valueDescription,
|
||||||
deviceUuid: device?.uuid,
|
deviceUuid: device?.uuid,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
'temp_set',
|
'temp_set',
|
||||||
'temp_current',
|
'temp_current',
|
||||||
],
|
],
|
||||||
defaultValue: functionCode == 'temp_set'
|
defaultValue: 0);
|
||||||
? 200
|
|
||||||
: functionCode == 'temp_current'
|
|
||||||
? -100
|
|
||||||
: 0,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -206,27 +203,61 @@ class ACHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
bool? removeComparators,
|
bool? removeComparators,
|
||||||
}) {
|
}) {
|
||||||
final initialVal = selectedFunction == 'temp_set' ? 200 : -100;
|
final selectedFn =
|
||||||
|
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
|
|
||||||
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
if (selectedFunction == 'temp_set' || selectedFunction == 'temp_current') {
|
||||||
final initialValue = selectedFunctionData?.value ?? initialVal;
|
// Convert stored integer value to display value
|
||||||
return _buildTemperatureSelector(
|
final displayValue =
|
||||||
context: context,
|
(selectedFunctionData?.value ?? selectedFn.min ?? 0) / 10;
|
||||||
initialValue: initialValue,
|
final minValue = selectedFn.min! / 10;
|
||||||
selectCode: selectedFunction,
|
final maxValue = selectedFn.max! / 10;
|
||||||
|
return CustomRoutinesTextbox(
|
||||||
|
withSpecialChar: true,
|
||||||
|
dividendOfRange: maxValue,
|
||||||
currentCondition: selectedFunctionData?.condition,
|
currentCondition: selectedFunctionData?.condition,
|
||||||
device: device,
|
dialogType: selectedFn.type,
|
||||||
operationName: operationName,
|
sliderRange: (minValue, maxValue),
|
||||||
selectedFunctionData: selectedFunctionData,
|
displayedValue: displayValue.toStringAsFixed(1),
|
||||||
removeComparators: removeComparators,
|
initialValue: displayValue.toDouble(),
|
||||||
|
unit: selectedFn.unit!,
|
||||||
|
onConditionChanged: (condition) => context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectedFunction,
|
||||||
|
operationName: selectedFn.operationName,
|
||||||
|
condition: condition,
|
||||||
|
value: 0,
|
||||||
|
step: selectedFn.step,
|
||||||
|
unit: selectedFn.unit,
|
||||||
|
max: selectedFn.max,
|
||||||
|
min: selectedFn.min,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTextChanged: (value) => context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectedFunction,
|
||||||
|
operationName: selectedFn.operationName,
|
||||||
|
value: (value * 10).round(), // Store as integer
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
step: selectedFn.step,
|
||||||
|
unit: selectedFn.unit,
|
||||||
|
max: selectedFn.max,
|
||||||
|
min: selectedFn.min,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
stepIncreaseAmount: selectedFn.step! / 10, // Convert step for display
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
context: context,
|
context: context,
|
||||||
values: values,
|
values: selectedFn.getOperationalValues(),
|
||||||
selectedValue: selectedFunctionData?.value,
|
selectedValue: selectedFunctionData?.value,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
@ -235,150 +266,151 @@ class ACHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build temperature selector for AC functions dialog
|
// /// Build temperature selector for AC functions dialog
|
||||||
static Widget _buildTemperatureSelector({
|
// static Widget _buildTemperatureSelector({
|
||||||
required BuildContext context,
|
// required BuildContext context,
|
||||||
required dynamic initialValue,
|
// required dynamic initialValue,
|
||||||
required String? currentCondition,
|
// required String? currentCondition,
|
||||||
required String selectCode,
|
// required String selectCode,
|
||||||
AllDevicesModel? device,
|
// AllDevicesModel? device,
|
||||||
required String operationName,
|
// required String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
// DeviceFunctionData? selectedFunctionData,
|
||||||
bool? removeComparators,
|
// bool? removeComparators,
|
||||||
}) {
|
// }) {
|
||||||
return Column(
|
// return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
// children: [
|
||||||
if (removeComparators != true)
|
// if (removeComparators != true)
|
||||||
_buildConditionToggle(
|
// _buildConditionToggle(
|
||||||
context,
|
// context,
|
||||||
currentCondition,
|
// currentCondition,
|
||||||
selectCode,
|
// selectCode,
|
||||||
device,
|
// device,
|
||||||
operationName,
|
// operationName,
|
||||||
selectedFunctionData,
|
// selectedFunctionData,
|
||||||
),
|
// ),
|
||||||
const SizedBox(height: 20),
|
// const SizedBox(height: 20),
|
||||||
_buildTemperatureDisplay(
|
// _buildTemperatureDisplay(
|
||||||
context,
|
// context,
|
||||||
initialValue,
|
// initialValue,
|
||||||
device,
|
// device,
|
||||||
operationName,
|
// operationName,
|
||||||
selectedFunctionData,
|
// selectedFunctionData,
|
||||||
selectCode,
|
// selectCode,
|
||||||
),
|
// ),
|
||||||
const SizedBox(height: 20),
|
// const SizedBox(height: 20),
|
||||||
_buildTemperatureSlider(
|
// _buildTemperatureSlider(
|
||||||
context,
|
// context,
|
||||||
initialValue,
|
// initialValue,
|
||||||
device,
|
// device,
|
||||||
operationName,
|
// operationName,
|
||||||
selectedFunctionData,
|
// selectedFunctionData,
|
||||||
selectCode,
|
// selectCode,
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Build condition toggle for AC functions dialog
|
// /// Build condition toggle for AC functions dialog
|
||||||
static Widget _buildConditionToggle(
|
// static Widget _buildConditionToggle(
|
||||||
BuildContext context,
|
// BuildContext context,
|
||||||
String? currentCondition,
|
// String? currentCondition,
|
||||||
String selectCode,
|
// String selectCode,
|
||||||
AllDevicesModel? device,
|
// AllDevicesModel? device,
|
||||||
String operationName,
|
// String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
// DeviceFunctionData? selectedFunctionData,
|
||||||
|
|
||||||
// Function(String) onConditionChanged,
|
// // Function(String) onConditionChanged,
|
||||||
) {
|
// ) {
|
||||||
final conditions = ["<", "==", ">"];
|
// final conditions = ["<", "==", ">"];
|
||||||
|
|
||||||
return ToggleButtons(
|
// return ToggleButtons(
|
||||||
onPressed: (int index) {
|
// onPressed: (int index) {
|
||||||
context.read<FunctionBloc>().add(
|
// context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
// AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
// functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
// entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
// functionCode: selectCode,
|
||||||
operationName: operationName,
|
// operationName: operationName,
|
||||||
condition: conditions[index],
|
// condition: conditions[index],
|
||||||
value: selectedFunctionData?.value ?? selectCode == 'temp_set'
|
// value: selectedFunctionData?.value ?? selectCode == 'temp_set'
|
||||||
? 200
|
// ? 200
|
||||||
: -100,
|
// : -100,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
// valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
// borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
// selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
||||||
selectedColor: Colors.white,
|
// selectedColor: Colors.white,
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
// fillColor: ColorsManager.primaryColorWithOpacity,
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
// color: ColorsManager.primaryColorWithOpacity,
|
||||||
constraints: const BoxConstraints(
|
// constraints: const BoxConstraints(
|
||||||
minHeight: 40.0,
|
// minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
// minWidth: 40.0,
|
||||||
),
|
// ),
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
// isSelected:
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
// conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
);
|
// children: conditions.map((c) => Text(c)).toList(),
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
/// Build temperature display for AC functions dialog
|
// /// Build temperature display for AC functions dialog
|
||||||
static Widget _buildTemperatureDisplay(
|
// static Widget _buildTemperatureDisplay(
|
||||||
BuildContext context,
|
// BuildContext context,
|
||||||
dynamic initialValue,
|
// dynamic initialValue,
|
||||||
AllDevicesModel? device,
|
// AllDevicesModel? device,
|
||||||
String operationName,
|
// String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
// DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
// String selectCode,
|
||||||
) {
|
// ) {
|
||||||
final initialVal = selectCode == 'temp_set' ? 200 : -100;
|
// final initialVal = selectCode == 'temp_set' ? 200 : -100;
|
||||||
return Container(
|
// return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
// padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
// color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(10),
|
// borderRadius: BorderRadius.circular(10),
|
||||||
),
|
// ),
|
||||||
child: Text(
|
// child: Text(
|
||||||
'${(initialValue ?? initialVal) / 10}°C',
|
// '${(initialValue ?? initialVal) / 10}°C',
|
||||||
style: context.textTheme.headlineMedium!.copyWith(
|
// style: context.textTheme.headlineMedium!.copyWith(
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
// color: ColorsManager.primaryColorWithOpacity,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
static Widget _buildTemperatureSlider(
|
// static Widget _buildTemperatureSlider(
|
||||||
BuildContext context,
|
// BuildContext context,
|
||||||
dynamic initialValue,
|
// dynamic initialValue,
|
||||||
AllDevicesModel? device,
|
// AllDevicesModel? device,
|
||||||
String operationName,
|
// String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
// DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
// String selectCode,
|
||||||
) {
|
// ) {
|
||||||
return Slider(
|
// return Slider(
|
||||||
value: initialValue is int ? initialValue.toDouble() : 200.0,
|
// value: initialValue is int ? initialValue.toDouble() : 200.0,
|
||||||
min: selectCode == 'temp_current' ? -100 : 200,
|
// min: selectCode == 'temp_current' ? -100 : 200,
|
||||||
max: selectCode == 'temp_current' ? 900 : 300,
|
// max: selectCode == 'temp_current' ? 900 : 300,
|
||||||
divisions: 10,
|
// divisions: 10,
|
||||||
label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
// label: '${((initialValue ?? 160) / 10).toInt()}°C',
|
||||||
onChanged: (value) {
|
// onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
// context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
// AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
// functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
// entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
// functionCode: selectCode,
|
||||||
operationName: operationName,
|
// operationName: operationName,
|
||||||
value: value,
|
// value: value,
|
||||||
condition: selectedFunctionData?.condition,
|
// condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
// valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
static Widget _buildOperationalValuesList({
|
static Widget _buildOperationalValuesList({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
@ -414,7 +446,9 @@ class ACHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@ -430,7 +464,8 @@ class ACHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -41,7 +41,8 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_cpsFunctions = widget.functions.whereType<CpsFunctions>().where((function) {
|
_cpsFunctions =
|
||||||
|
widget.functions.whereType<CpsFunctions>().where((function) {
|
||||||
if (widget.dialogType == 'THEN') {
|
if (widget.dialogType == 'THEN') {
|
||||||
return function.type == 'THEN' || function.type == 'BOTH';
|
return function.type == 'THEN' || function.type == 'BOTH';
|
||||||
}
|
}
|
||||||
@ -149,6 +150,7 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
|||||||
device: widget.device,
|
device: widget.device,
|
||||||
)
|
)
|
||||||
: CpsDialogSliderSelector(
|
: CpsDialogSliderSelector(
|
||||||
|
step: selectedCpsFunctions.step!,
|
||||||
operations: operations,
|
operations: operations,
|
||||||
selectedFunction: selectedFunction ?? '',
|
selectedFunction: selectedFunction ?? '',
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_slider_helpers.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_slider_helpers.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
|||||||
required this.device,
|
required this.device,
|
||||||
required this.operationName,
|
required this.operationName,
|
||||||
required this.dialogType,
|
required this.dialogType,
|
||||||
|
required this.step,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -26,13 +28,16 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
|||||||
final AllDevicesModel? device;
|
final AllDevicesModel? device;
|
||||||
final String operationName;
|
final String operationName;
|
||||||
final String dialogType;
|
final String dialogType;
|
||||||
|
final double step;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliderValueSelector(
|
return CustomRoutinesTextbox(
|
||||||
|
withSpecialChar: false,
|
||||||
currentCondition: selectedFunctionData.condition,
|
currentCondition: selectedFunctionData.condition,
|
||||||
dialogType: dialogType,
|
dialogType: dialogType,
|
||||||
sliderRange: CpsSliderHelpers.sliderRange(selectedFunctionData.functionCode),
|
sliderRange:
|
||||||
|
CpsSliderHelpers.sliderRange(selectedFunctionData.functionCode),
|
||||||
displayedValue: CpsSliderHelpers.displayText(
|
displayedValue: CpsSliderHelpers.displayText(
|
||||||
value: selectedFunctionData.value,
|
value: selectedFunctionData.value,
|
||||||
functionCode: selectedFunctionData.functionCode,
|
functionCode: selectedFunctionData.functionCode,
|
||||||
@ -50,7 +55,7 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSliderChanged: (value) => context.read<FunctionBloc>().add(
|
onTextChanged: (value) => context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
@ -64,6 +69,7 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
|||||||
dividendOfRange: CpsSliderHelpers.dividendOfRange(
|
dividendOfRange: CpsSliderHelpers.dividendOfRange(
|
||||||
selectedFunctionData.functionCode,
|
selectedFunctionData.functionCode,
|
||||||
),
|
),
|
||||||
|
stepIncreaseAmount: step,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,30 +34,33 @@ class CpsFunctionsList extends StatelessWidget {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final function = cpsFunctions[index];
|
final function = cpsFunctions[index];
|
||||||
return RoutineDialogFunctionListTile(
|
return RoutineDialogFunctionListTile(
|
||||||
iconPath: function.icon,
|
iconPath: function.icon,
|
||||||
operationName: function.operationName,
|
operationName: function.operationName,
|
||||||
onTap: () => RoutineTapFunctionHelper.onTapFunction(
|
onTap: () {
|
||||||
context,
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
functionCode: function.code,
|
context,
|
||||||
functionOperationName: function.operationName,
|
step: function.step,
|
||||||
functionValueDescription: selectedFunctionData?.valueDescription,
|
functionCode: function.code,
|
||||||
deviceUuid: device?.uuid,
|
functionOperationName: function.operationName,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
functionValueDescription:
|
||||||
'static_max_dis',
|
selectedFunctionData?.valueDescription,
|
||||||
'presence_reference',
|
deviceUuid: device?.uuid,
|
||||||
'moving_reference',
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
'perceptual_boundary',
|
'static_max_dis',
|
||||||
'moving_boundary',
|
'presence_reference',
|
||||||
'moving_rigger_time',
|
'moving_reference',
|
||||||
'moving_static_time',
|
'perceptual_boundary',
|
||||||
'none_body_time',
|
'moving_boundary',
|
||||||
'moving_max_dis',
|
'moving_rigger_time',
|
||||||
'moving_range',
|
'moving_static_time',
|
||||||
'presence_range',
|
'none_body_time',
|
||||||
if (dialogType == "IF") 'sensitivity',
|
'moving_max_dis',
|
||||||
],
|
'moving_range',
|
||||||
),
|
'presence_range',
|
||||||
);
|
if (dialogType == "IF") 'sensitivity',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/flush/flush_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/flush/flush_operational_value.dart';
|
||||||
|
|
||||||
@ -21,22 +22,20 @@ class FlushOperationalValuesList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
itemCount: values.length,
|
itemCount: values.length,
|
||||||
itemBuilder: (context, index) =>
|
itemBuilder: (context, index) => _buildValueItem(context, values[index]),
|
||||||
_buildValueItem(context, values[index]),
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildValueItem(BuildContext context, FlushOperationalValue value) {
|
Widget _buildValueItem(BuildContext context, FlushOperationalValue value) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
SvgPicture.asset(value.icon, width: 25, height: 25),
|
||||||
Expanded(child: _buildValueDescription(value)),
|
Expanded(child: _buildValueDescription(value)),
|
||||||
_buildValueRadio(context, value),
|
_buildValueRadio(context, value),
|
||||||
],
|
],
|
||||||
@ -44,9 +43,6 @@ class FlushOperationalValuesList extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildValueDescription(FlushOperationalValue value) {
|
Widget _buildValueDescription(FlushOperationalValue value) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
@ -60,6 +56,4 @@ class FlushOperationalValuesList extends StatelessWidget {
|
|||||||
groupValue: selectedValue,
|
groupValue: selectedValue,
|
||||||
onChanged: (_) => onSelect(value));
|
onChanged: (_) => onSelect(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/flush/flush_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/flush/flush_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/flush_presence_sensor/flush_operational_values_list.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/flush_presence_sensor/flush_operational_values_list.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||||
|
|
||||||
@ -66,7 +67,8 @@ class FlushValueSelectorWidget extends StatelessWidget {
|
|||||||
if (isDistanceDetection) {
|
if (isDistanceDetection) {
|
||||||
initialValue = initialValue / 100;
|
initialValue = initialValue / 100;
|
||||||
}
|
}
|
||||||
return SliderValueSelector(
|
return CustomRoutinesTextbox(
|
||||||
|
withSpecialChar: true,
|
||||||
currentCondition: functionData.condition,
|
currentCondition: functionData.condition,
|
||||||
dialogType: dialogType,
|
dialogType: dialogType,
|
||||||
sliderRange: sliderRange,
|
sliderRange: sliderRange,
|
||||||
@ -83,7 +85,7 @@ class FlushValueSelectorWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSliderChanged: (value) {
|
onTextChanged: (value) {
|
||||||
final roundedValue = _roundToStep(value, stepSize);
|
final roundedValue = _roundToStep(value, stepSize);
|
||||||
final finalValue =
|
final finalValue =
|
||||||
isDistanceDetection ? (roundedValue * 100).toInt() : roundedValue;
|
isDistanceDetection ? (roundedValue * 100).toInt() : roundedValue;
|
||||||
@ -102,6 +104,7 @@ class FlushValueSelectorWidget extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
unit: _unit,
|
unit: _unit,
|
||||||
dividendOfRange: stepSize,
|
dividendOfRange: stepSize,
|
||||||
|
stepIncreaseAmount: stepSize,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ abstract final class RoutineTapFunctionHelper {
|
|||||||
|
|
||||||
static void onTapFunction(
|
static void onTapFunction(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
|
double? step,
|
||||||
required String functionCode,
|
required String functionCode,
|
||||||
required String functionOperationName,
|
required String functionOperationName,
|
||||||
required String? functionValueDescription,
|
required String? functionValueDescription,
|
||||||
|
@ -4,11 +4,11 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
@ -87,14 +87,15 @@ class OneGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () =>
|
onTap: () => RoutineTapFunctionHelper
|
||||||
RoutineTapFunctionHelper.onTapFunction(
|
.onTapFunction(
|
||||||
context,
|
context,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
functionOperationName:
|
functionOperationName:
|
||||||
function.operationName,
|
function.operationName,
|
||||||
functionValueDescription:
|
functionValueDescription:
|
||||||
selectedFunctionData.valueDescription,
|
selectedFunctionData
|
||||||
|
.valueDescription,
|
||||||
deviceUuid: device?.uuid,
|
deviceUuid: device?.uuid,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
'countdown_1',
|
'countdown_1',
|
||||||
@ -108,14 +109,16 @@ class OneGangSwitchHelper {
|
|||||||
if (selectedFunction != null)
|
if (selectedFunction != null)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildValueSelector(
|
child: _buildValueSelector(
|
||||||
context: context,
|
context: context,
|
||||||
selectedFunction: selectedFunction,
|
selectedFunction: selectedFunction,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData:
|
||||||
acFunctions: oneGangFunctions,
|
selectedFunctionData,
|
||||||
device: device,
|
acFunctions: oneGangFunctions,
|
||||||
operationName: selectedOperationName ?? '',
|
device: device,
|
||||||
removeComparetors: removeComparetors,
|
operationName:
|
||||||
),
|
selectedOperationName ?? '',
|
||||||
|
removeComparetors: removeComparetors,
|
||||||
|
dialogType: dialogType),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -172,6 +175,7 @@ class OneGangSwitchHelper {
|
|||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
|
required String dialogType,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1') {
|
if (selectedFunction == 'countdown_1') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 0;
|
final initialValue = selectedFunctionData?.value ?? 0;
|
||||||
@ -184,6 +188,7 @@ class OneGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData: selectedFunctionData,
|
||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
|
dialogType: dialogType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final selectedFn = acFunctions.firstWhere(
|
final selectedFn = acFunctions.firstWhere(
|
||||||
@ -216,93 +221,18 @@ class OneGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
|
String? dialogType,
|
||||||
}) {
|
}) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (removeComparetors != true)
|
|
||||||
_buildConditionToggle(
|
|
||||||
context,
|
|
||||||
currentCondition,
|
|
||||||
selectCode,
|
|
||||||
device,
|
|
||||||
operationName,
|
|
||||||
selectedFunctionData,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
|
||||||
selectedFunctionData, selectCode),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode, dialogType!),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build condition toggle for AC functions dialog
|
|
||||||
static Widget _buildConditionToggle(
|
|
||||||
BuildContext context,
|
|
||||||
String? currentCondition,
|
|
||||||
String selectCode,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
// Function(String) onConditionChanged,
|
|
||||||
) {
|
|
||||||
final conditions = ["<", "==", ">"];
|
|
||||||
|
|
||||||
return ToggleButtons(
|
|
||||||
onPressed: (int index) {
|
|
||||||
context.read<FunctionBloc>().add(
|
|
||||||
AddFunction(
|
|
||||||
functionData: DeviceFunctionData(
|
|
||||||
entityId: device?.uuid ?? '',
|
|
||||||
functionCode: selectCode,
|
|
||||||
operationName: operationName,
|
|
||||||
condition: conditions[index],
|
|
||||||
value: selectedFunctionData?.value ?? 0,
|
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
selectedColor: Colors.white,
|
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minHeight: 40.0,
|
|
||||||
minWidth: 40.0,
|
|
||||||
),
|
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build temperature display for AC functions dialog
|
|
||||||
static Widget _buildCountDownDisplay(
|
|
||||||
BuildContext context,
|
|
||||||
dynamic initialValue,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
String selectCode) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
DurationFormatMixin.formatDuration(initialValue?.toInt() ?? 0),
|
|
||||||
style: context.textTheme.headlineMedium!.copyWith(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget _buildCountDownSlider(
|
static Widget _buildCountDownSlider(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
@ -310,38 +240,47 @@ class OneGangSwitchHelper {
|
|||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
String selectCode,
|
||||||
|
String dialogType,
|
||||||
) {
|
) {
|
||||||
const twelveHoursInSeconds = 43200.0;
|
return CustomRoutinesTextbox(
|
||||||
final operationalValues = SwitchOperationalValue(
|
withSpecialChar: false,
|
||||||
icon: '',
|
currentCondition: selectedFunctionData?.condition,
|
||||||
description: "sec",
|
dialogType: dialogType,
|
||||||
value: 0.0,
|
sliderRange: (0, 43200),
|
||||||
minValue: 0,
|
displayedValue: (initialValue ?? 0).toString(),
|
||||||
maxValue: twelveHoursInSeconds,
|
initialValue: (initialValue ?? 0).toString(),
|
||||||
stepValue: 1,
|
onConditionChanged: (condition) {
|
||||||
);
|
|
||||||
return Slider(
|
|
||||||
value: (initialValue ?? 0).toDouble(),
|
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
|
||||||
divisions:
|
|
||||||
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
|
||||||
.round(),
|
|
||||||
onChanged: (value) {
|
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
functionCode: selectCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value,
|
condition: condition,
|
||||||
|
value: selectedFunctionData?.value ?? 0,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTextChanged: (value) {
|
||||||
|
final roundedValue = value.round();
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: roundedValue,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
unit: 'sec',
|
||||||
|
dividendOfRange: 1,
|
||||||
|
stepIncreaseAmount: 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +316,9 @@ class OneGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@ -393,7 +334,8 @@ class OneGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,10 +4,10 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
@ -86,20 +86,21 @@ class ThreeGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () =>
|
onTap: () => RoutineTapFunctionHelper
|
||||||
RoutineTapFunctionHelper.onTapFunction(
|
.onTapFunction(
|
||||||
context,
|
context,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
functionOperationName:
|
functionOperationName:
|
||||||
function.operationName,
|
function.operationName,
|
||||||
functionValueDescription:
|
functionValueDescription:
|
||||||
selectedFunctionData.valueDescription,
|
selectedFunctionData
|
||||||
|
.valueDescription,
|
||||||
deviceUuid: device?.uuid,
|
deviceUuid: device?.uuid,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
codesToAddIntoFunctionsWithDefaultValue:
|
||||||
'countdown_1',
|
function.code
|
||||||
'countdown_2',
|
.startsWith('countdown')
|
||||||
'countdown_3',
|
? [function.code]
|
||||||
],
|
: [],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -109,14 +110,16 @@ class ThreeGangSwitchHelper {
|
|||||||
if (selectedFunction != null)
|
if (selectedFunction != null)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildValueSelector(
|
child: _buildValueSelector(
|
||||||
context: context,
|
context: context,
|
||||||
selectedFunction: selectedFunction,
|
selectedFunction: selectedFunction,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData:
|
||||||
switchFunctions: switchFunctions,
|
selectedFunctionData,
|
||||||
device: device,
|
switchFunctions: switchFunctions,
|
||||||
operationName: selectedOperationName ?? '',
|
device: device,
|
||||||
removeComparetors: removeComparetors,
|
operationName:
|
||||||
),
|
selectedOperationName ?? '',
|
||||||
|
removeComparetors: removeComparetors,
|
||||||
|
dialogType: dialogType),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -133,14 +136,6 @@ class ThreeGangSwitchHelper {
|
|||||||
onConfirm: state.addedFunctions.isNotEmpty
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
? () {
|
? () {
|
||||||
/// add the functions to the routine bloc
|
/// add the functions to the routine bloc
|
||||||
// for (var function in state.addedFunctions) {
|
|
||||||
// context.read<RoutineBloc>().add(
|
|
||||||
// AddFunctionToRoutine(
|
|
||||||
// function,
|
|
||||||
// uniqueCustomId,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
context.read<RoutineBloc>().add(
|
context.read<RoutineBloc>().add(
|
||||||
AddFunctionToRoutine(
|
AddFunctionToRoutine(
|
||||||
state.addedFunctions,
|
state.addedFunctions,
|
||||||
@ -173,24 +168,26 @@ class ThreeGangSwitchHelper {
|
|||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
|
required String dialogType,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1' ||
|
if (selectedFunction == 'countdown_1' ||
|
||||||
selectedFunction == 'countdown_2' ||
|
selectedFunction == 'countdown_2' ||
|
||||||
selectedFunction == 'countdown_3') {
|
selectedFunction == 'countdown_3') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 0;
|
final initialValue = selectedFunctionData?.value ?? 0;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
initialValue: initialValue,
|
initialValue: initialValue,
|
||||||
selectCode: selectedFunction,
|
selectCode: selectedFunction,
|
||||||
currentCondition: selectedFunctionData?.condition,
|
currentCondition: selectedFunctionData?.condition,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData: selectedFunctionData,
|
||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
);
|
dialogType: dialogType);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
final selectedFn =
|
||||||
|
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -213,93 +210,18 @@ class ThreeGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
bool? removeComparetors,
|
bool? removeComparetors,
|
||||||
|
required String dialogType,
|
||||||
}) {
|
}) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (removeComparetors != true)
|
|
||||||
_buildConditionToggle(
|
|
||||||
context,
|
|
||||||
currentCondition,
|
|
||||||
selectCode,
|
|
||||||
device,
|
|
||||||
operationName,
|
|
||||||
selectedFunctionData,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
|
||||||
selectedFunctionData, selectCode),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode, dialogType),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build condition toggle for AC functions dialog
|
|
||||||
static Widget _buildConditionToggle(
|
|
||||||
BuildContext context,
|
|
||||||
String? currentCondition,
|
|
||||||
String selectCode,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
// Function(String) onConditionChanged,
|
|
||||||
) {
|
|
||||||
final conditions = ["<", "==", ">"];
|
|
||||||
|
|
||||||
return ToggleButtons(
|
|
||||||
onPressed: (int index) {
|
|
||||||
context.read<FunctionBloc>().add(
|
|
||||||
AddFunction(
|
|
||||||
functionData: DeviceFunctionData(
|
|
||||||
entityId: device?.uuid ?? '',
|
|
||||||
functionCode: selectCode,
|
|
||||||
operationName: operationName,
|
|
||||||
condition: conditions[index],
|
|
||||||
value: selectedFunctionData?.value ?? 0,
|
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
selectedColor: Colors.white,
|
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minHeight: 40.0,
|
|
||||||
minWidth: 40.0,
|
|
||||||
),
|
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build temperature display for AC functions dialog
|
|
||||||
static Widget _buildCountDownDisplay(
|
|
||||||
BuildContext context,
|
|
||||||
dynamic initialValue,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
String selectCode) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
DurationFormatMixin.formatDuration(initialValue?.toInt() ?? 0),
|
|
||||||
style: context.textTheme.headlineMedium!.copyWith(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget _buildCountDownSlider(
|
static Widget _buildCountDownSlider(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
@ -307,38 +229,47 @@ class ThreeGangSwitchHelper {
|
|||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
String selectCode,
|
||||||
|
String dialogType,
|
||||||
) {
|
) {
|
||||||
const twelveHoursInSeconds = 43200.0;
|
return CustomRoutinesTextbox(
|
||||||
final operationalValues = SwitchOperationalValue(
|
withSpecialChar: true,
|
||||||
icon: '',
|
currentCondition: selectedFunctionData?.condition,
|
||||||
description: "sec",
|
dialogType: dialogType,
|
||||||
value: 0.0,
|
sliderRange: (0, 43200),
|
||||||
minValue: 0,
|
displayedValue: (initialValue ?? 0).toString(),
|
||||||
maxValue: twelveHoursInSeconds,
|
initialValue: (initialValue ?? 0).toString(),
|
||||||
stepValue: 1,
|
onConditionChanged: (condition) {
|
||||||
);
|
|
||||||
return Slider(
|
|
||||||
value: (initialValue ?? 0).toDouble(),
|
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
|
||||||
divisions:
|
|
||||||
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
|
||||||
.round(),
|
|
||||||
onChanged: (value) {
|
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
functionCode: selectCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value,
|
condition: condition,
|
||||||
|
value: selectedFunctionData?.value ?? 0,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTextChanged: (value) {
|
||||||
|
final roundedValue = value.round();
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: roundedValue,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
unit: 'sec',
|
||||||
|
dividendOfRange: 1,
|
||||||
|
stepIncreaseAmount: 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +305,9 @@ class ThreeGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@ -390,7 +323,8 @@ class ThreeGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
@ -86,14 +87,15 @@ class TwoGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () =>
|
onTap: () => RoutineTapFunctionHelper
|
||||||
RoutineTapFunctionHelper.onTapFunction(
|
.onTapFunction(
|
||||||
context,
|
context,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
functionOperationName:
|
functionOperationName:
|
||||||
function.operationName,
|
function.operationName,
|
||||||
functionValueDescription:
|
functionValueDescription:
|
||||||
selectedFunctionData.valueDescription,
|
selectedFunctionData
|
||||||
|
.valueDescription,
|
||||||
deviceUuid: device?.uuid,
|
deviceUuid: device?.uuid,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
'countdown_1',
|
'countdown_1',
|
||||||
@ -115,6 +117,7 @@ class TwoGangSwitchHelper {
|
|||||||
device: device,
|
device: device,
|
||||||
operationName: selectedOperationName ?? '',
|
operationName: selectedOperationName ?? '',
|
||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
|
dialogType: dialogType,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -172,22 +175,25 @@ class TwoGangSwitchHelper {
|
|||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
|
required String dialogType,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
|
if (selectedFunction == 'countdown_1' ||
|
||||||
|
selectedFunction == 'countdown_2') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 0;
|
final initialValue = selectedFunctionData?.value ?? 0;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
initialValue: initialValue,
|
initialValue: initialValue,
|
||||||
selectCode: selectedFunction,
|
selectCode: selectedFunction,
|
||||||
currentCondition: selectedFunctionData?.condition,
|
currentCondition: selectedFunctionData?.condition,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData: selectedFunctionData,
|
||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
);
|
dialogType: dialogType);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
final selectedFn =
|
||||||
|
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -210,25 +216,13 @@ class TwoGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
bool? removeComparetors,
|
bool? removeComparetors,
|
||||||
|
String? dialogType,
|
||||||
}) {
|
}) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if (removeComparetors != true)
|
|
||||||
_buildConditionToggle(
|
|
||||||
context,
|
|
||||||
currentCondition,
|
|
||||||
selectCode,
|
|
||||||
device,
|
|
||||||
operationName,
|
|
||||||
selectedFunctionData,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
|
||||||
selectedFunctionData, selectCode),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode, dialogType!),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -269,7 +263,8 @@ class TwoGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
isSelected:
|
||||||
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -304,38 +299,48 @@ class TwoGangSwitchHelper {
|
|||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
String selectCode,
|
||||||
|
String dialogType,
|
||||||
) {
|
) {
|
||||||
const twelveHoursInSeconds = 43200.0;
|
return CustomRoutinesTextbox(
|
||||||
final operationalValues = SwitchOperationalValue(
|
withSpecialChar: true,
|
||||||
icon: '',
|
currentCondition: selectedFunctionData?.condition,
|
||||||
description: "sec",
|
dialogType: dialogType,
|
||||||
value: 0.0,
|
sliderRange: (0, 43200),
|
||||||
minValue: 0,
|
displayedValue: (initialValue ?? 0).toString(),
|
||||||
maxValue: twelveHoursInSeconds,
|
initialValue: (initialValue ?? 0).toString(),
|
||||||
stepValue: 1,
|
onConditionChanged: (condition) {
|
||||||
);
|
|
||||||
return Slider(
|
|
||||||
value: (initialValue ?? 0).toDouble(),
|
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
|
||||||
divisions:
|
|
||||||
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
|
||||||
.round(),
|
|
||||||
onChanged: (value) {
|
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
functionCode: selectCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value,
|
condition: condition,
|
||||||
|
value: selectedFunctionData?.value ?? 0,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTextChanged: (value) {
|
||||||
|
final roundedValue =
|
||||||
|
value.round(); // Round to nearest integer (stepSize 1)
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: roundedValue,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
unit: 'sec',
|
||||||
|
dividendOfRange: 1,
|
||||||
|
stepIncreaseAmount: 1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +376,9 @@ class TwoGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@ -387,7 +394,8 @@ class TwoGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,8 +4,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_operational_values_list.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_operational_values_list.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
|
||||||
|
|
||||||
class WpsValueSelectorWidget extends StatelessWidget {
|
class WpsValueSelectorWidget extends StatelessWidget {
|
||||||
final String selectedFunction;
|
final String selectedFunction;
|
||||||
@ -27,11 +27,13 @@ class WpsValueSelectorWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final selectedFn = wpsFunctions.firstWhere((f) => f.code == selectedFunction);
|
final selectedFn =
|
||||||
|
wpsFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
if (_isSliderFunction(selectedFunction)) {
|
if (_isSliderFunction(selectedFunction)) {
|
||||||
return SliderValueSelector(
|
return CustomRoutinesTextbox(
|
||||||
|
withSpecialChar: false,
|
||||||
currentCondition: functionData.condition,
|
currentCondition: functionData.condition,
|
||||||
dialogType: dialogType,
|
dialogType: dialogType,
|
||||||
sliderRange: sliderRange,
|
sliderRange: sliderRange,
|
||||||
@ -48,7 +50,7 @@ class WpsValueSelectorWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSliderChanged: (value) => context.read<FunctionBloc>().add(
|
onTextChanged: (value) => context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
@ -61,6 +63,7 @@ class WpsValueSelectorWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
unit: _unit,
|
unit: _unit,
|
||||||
dividendOfRange: 1,
|
dividendOfRange: 1,
|
||||||
|
stepIncreaseAmount: _steps,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,4 +102,10 @@ class WpsValueSelectorWidget extends StatelessWidget {
|
|||||||
'illuminance_value' => 'Lux',
|
'illuminance_value' => 'Lux',
|
||||||
_ => '',
|
_ => '',
|
||||||
};
|
};
|
||||||
|
double get _steps => switch (functionData.functionCode) {
|
||||||
|
'presence_time' => 1,
|
||||||
|
'dis_current' => 1,
|
||||||
|
'illuminance_value' => 1,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,7 @@ class _WaterHeaterDialogRoutinesState extends State<WaterHeaterDialogRoutines> {
|
|||||||
functionData: functionData,
|
functionData: functionData,
|
||||||
whFunctions: _waterHeaterFunctions,
|
whFunctions: _waterHeaterFunctions,
|
||||||
device: widget.device,
|
device: widget.device,
|
||||||
|
dialogType: widget.dialogType,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,25 +2,24 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/models/water_heater/water_heater_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/water_heater/water_heater_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/custom_routines_textbox.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/water_heater/water_heater_operational_values_list.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/water_heater/water_heater_operational_values_list.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
||||||
final String selectedFunction;
|
final String selectedFunction;
|
||||||
final DeviceFunctionData functionData;
|
final DeviceFunctionData functionData;
|
||||||
final List<WaterHeaterFunctions> whFunctions;
|
final List<WaterHeaterFunctions> whFunctions;
|
||||||
final AllDevicesModel? device;
|
final AllDevicesModel? device;
|
||||||
|
final String dialogType;
|
||||||
|
|
||||||
const WaterHeaterValueSelectorWidget({
|
const WaterHeaterValueSelectorWidget({
|
||||||
required this.selectedFunction,
|
required this.selectedFunction,
|
||||||
required this.functionData,
|
required this.functionData,
|
||||||
required this.whFunctions,
|
required this.whFunctions,
|
||||||
required this.device,
|
required this.device,
|
||||||
|
required this.dialogType,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,22 +38,6 @@ class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_buildConditionToggle(
|
|
||||||
context,
|
|
||||||
functionData.condition,
|
|
||||||
selectedFunction,
|
|
||||||
device,
|
|
||||||
selectedFn.operationName,
|
|
||||||
functionData,
|
|
||||||
),
|
|
||||||
_buildCountDownDisplay(
|
|
||||||
context,
|
|
||||||
functionData.value,
|
|
||||||
device,
|
|
||||||
selectedFn.operationName,
|
|
||||||
functionData,
|
|
||||||
selectedFunction,
|
|
||||||
),
|
|
||||||
_buildCountDownSlider(
|
_buildCountDownSlider(
|
||||||
context,
|
context,
|
||||||
functionData.value,
|
functionData.value,
|
||||||
@ -62,6 +45,7 @@ class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
|||||||
selectedFn.operationName,
|
selectedFn.operationName,
|
||||||
functionData,
|
functionData,
|
||||||
selectedFunction,
|
selectedFunction,
|
||||||
|
dialogType
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
],
|
],
|
||||||
@ -90,28 +74,6 @@ class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _buildCountDownDisplay(
|
|
||||||
BuildContext context,
|
|
||||||
dynamic initialValue,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
String selectCode) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
DurationFormatMixin.formatDuration(initialValue?.toInt() ?? 0),
|
|
||||||
style: context.textTheme.headlineMedium!.copyWith(
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget _buildCountDownSlider(
|
static Widget _buildCountDownSlider(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
@ -119,78 +81,47 @@ class WaterHeaterValueSelectorWidget extends StatelessWidget {
|
|||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
String selectCode,
|
||||||
|
String dialogType,
|
||||||
) {
|
) {
|
||||||
const twelveHoursInSeconds = 43200.0;
|
return CustomRoutinesTextbox(
|
||||||
final operationalValues = SwitchOperationalValue(
|
withSpecialChar: false,
|
||||||
icon: '',
|
currentCondition: selectedFunctionData?.condition,
|
||||||
description: "sec",
|
dialogType: dialogType,
|
||||||
value: 0.0,
|
sliderRange: (0, 43200),
|
||||||
minValue: 0,
|
displayedValue: (initialValue ?? 0).toString(),
|
||||||
maxValue: twelveHoursInSeconds,
|
initialValue: (initialValue ?? 0).toString(),
|
||||||
stepValue: 1,
|
onConditionChanged: (condition) {
|
||||||
);
|
|
||||||
return Slider(
|
|
||||||
value: (initialValue ?? 0).toDouble(),
|
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
|
||||||
(operationalValues.minValue ?? 0)) /
|
|
||||||
(operationalValues.stepValue ?? 1))
|
|
||||||
.round(),
|
|
||||||
onChanged: (value) {
|
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
functionData: DeviceFunctionData(
|
functionData: DeviceFunctionData(
|
||||||
entityId: device?.uuid ?? '',
|
entityId: device?.uuid ?? '',
|
||||||
functionCode: selectCode,
|
functionCode: selectCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value,
|
value: condition,
|
||||||
|
condition: condition,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onTextChanged: (value) {
|
||||||
|
final roundedValue = value.round();
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: roundedValue,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
unit: 'sec',
|
||||||
}
|
dividendOfRange: 1,
|
||||||
|
stepIncreaseAmount: 1,
|
||||||
static Widget _buildConditionToggle(
|
|
||||||
BuildContext context,
|
|
||||||
String? currentCondition,
|
|
||||||
String selectCode,
|
|
||||||
AllDevicesModel? device,
|
|
||||||
String operationName,
|
|
||||||
DeviceFunctionData? selectedFunctionData,
|
|
||||||
) {
|
|
||||||
final conditions = ["<", "==", ">"];
|
|
||||||
|
|
||||||
return ToggleButtons(
|
|
||||||
onPressed: (int index) {
|
|
||||||
context.read<FunctionBloc>().add(
|
|
||||||
AddFunction(
|
|
||||||
functionData: DeviceFunctionData(
|
|
||||||
entityId: device?.uuid ?? '',
|
|
||||||
functionCode: selectCode,
|
|
||||||
operationName: operationName,
|
|
||||||
condition: conditions[index],
|
|
||||||
value: selectedFunctionData?.value ?? 0,
|
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
selectedColor: Colors.white,
|
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minHeight: 40.0,
|
|
||||||
minWidth: 40.0,
|
|
||||||
),
|
|
||||||
isSelected:
|
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user