mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 17:47:53 +00:00
Compare commits
59 Commits
bugfix/cha
...
SP-1513-re
Author | SHA1 | Date | |
---|---|---|---|
12deceb7d3 | |||
0f9227a6f5 | |||
5b13962d41 | |||
8c53d5322a | |||
af4d37939b | |||
d43c1847ff | |||
4c5b390887 | |||
5eeac01666 | |||
717d698378 | |||
9adbbb9a2d | |||
e792dbd72f | |||
9eaa367d32 | |||
d2eea33714 | |||
24372a0618 | |||
8988947694 | |||
ef875ef7dc | |||
5a61647fe4 | |||
568b6be354 | |||
94e4fbd5db | |||
302ef36b17 | |||
c508d016c2 | |||
e0ad7855d3 | |||
ecf588cfcb | |||
c9d15d102b | |||
64a29681de | |||
02b07cfdb6 | |||
0a94557eee | |||
4f8d1c4ffd | |||
06b320a75d | |||
000fe70663 | |||
4257f7f0f3 | |||
b2bf3866a9 | |||
a15b5439f0 | |||
fd2a09cada | |||
4c2802acfc | |||
15343be258 | |||
c21842cc6d | |||
4326559e14 | |||
4ded7d5202 | |||
0d45a155e3 | |||
625f737791 | |||
494ae1c941 | |||
f67d0e2912 | |||
17aad13b2a | |||
a849c1dafb | |||
3e3e17019a | |||
b1bae3cb15 | |||
051bf657ed | |||
5191c1e456 | |||
7a073f10aa | |||
900d47faae | |||
e35a7fdc70 | |||
baaf5111b1 | |||
745205063e | |||
c07b53107e | |||
39d125ac7e | |||
ad15d0e138 | |||
e6d272a60d | |||
8dfe8d10d4 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,6 +30,7 @@ migrate_working_dir/
|
|||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
pubspec.lock
|
||||||
|
|
||||||
# Symbolication related
|
# Symbolication related
|
||||||
app.*.symbols
|
app.*.symbols
|
||||||
|
@ -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:
|
||||||
|
BIN
assets/images/web_Background.png
Normal file
BIN
assets/images/web_Background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -1,13 +1,71 @@
|
|||||||
class AnalyticsDevice {
|
class AnalyticsDevice {
|
||||||
const AnalyticsDevice({required this.name, required this.uuid});
|
const AnalyticsDevice({
|
||||||
|
required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
|
this.deviceTuyaUuid,
|
||||||
|
this.isActive,
|
||||||
|
this.productDevice,
|
||||||
|
this.spaceUuid,
|
||||||
|
});
|
||||||
|
|
||||||
final String uuid;
|
final String uuid;
|
||||||
final String name;
|
final String name;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String? deviceTuyaUuid;
|
||||||
|
final bool? isActive;
|
||||||
|
final ProductDevice? productDevice;
|
||||||
|
final String? spaceUuid;
|
||||||
|
|
||||||
factory AnalyticsDevice.fromJson(Map<String, dynamic> json) {
|
factory AnalyticsDevice.fromJson(Map<String, dynamic> json) {
|
||||||
return AnalyticsDevice(
|
return AnalyticsDevice(
|
||||||
uuid: json['uuid'] as String? ?? '',
|
uuid: json['uuid'] as String,
|
||||||
name: json['name'] as String? ?? '',
|
name: json['name'] as String,
|
||||||
|
createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt'] as String) : null,
|
||||||
|
updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'] as String) : null,
|
||||||
|
deviceTuyaUuid: json['deviceTuyaUuid'] as String?,
|
||||||
|
isActive: json['isActive'] as bool?,
|
||||||
|
productDevice: json['productDevice'] != null
|
||||||
|
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
|
||||||
|
: null,
|
||||||
|
spaceUuid: (json['spaces'] as List<dynamic>?)
|
||||||
|
?.map((e) => e['uuid'])
|
||||||
|
.firstOrNull
|
||||||
|
?.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductDevice {
|
||||||
|
const ProductDevice({
|
||||||
|
this.uuid,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
|
this.catName,
|
||||||
|
this.prodId,
|
||||||
|
this.name,
|
||||||
|
this.prodType,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String? uuid;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String? catName;
|
||||||
|
final String? prodId;
|
||||||
|
final String? name;
|
||||||
|
final String? prodType;
|
||||||
|
|
||||||
|
factory ProductDevice.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ProductDevice(
|
||||||
|
uuid: json['uuid'] as String?,
|
||||||
|
createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt'] as String) : null,
|
||||||
|
updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'] as String) : null,
|
||||||
|
catName: json['catName'] as String?,
|
||||||
|
prodId: json['prodId'] as String?,
|
||||||
|
name: json['name'] as String?,
|
||||||
|
prodType: json['prodType'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,32 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
class Occupacy extends Equatable {
|
class Occupacy extends Equatable {
|
||||||
final String date;
|
final DateTime date;
|
||||||
final String occupancy;
|
final String occupancy;
|
||||||
|
final String spaceUuid;
|
||||||
|
final int occupiedSeconds;
|
||||||
|
|
||||||
const Occupacy({required this.date, required this.occupancy});
|
const Occupacy({
|
||||||
|
required this.date,
|
||||||
|
required this.occupancy,
|
||||||
|
required this.spaceUuid,
|
||||||
|
required this.occupiedSeconds,
|
||||||
|
});
|
||||||
|
|
||||||
factory Occupacy.fromJson(Map<String, dynamic> json) {
|
factory Occupacy.fromJson(Map<String, dynamic> json) {
|
||||||
return Occupacy(
|
return Occupacy(
|
||||||
date: json['date'] as String,
|
date: DateTime.parse(json['event_date'] as String? ?? '${DateTime.now()}'),
|
||||||
occupancy: json['occupancy'] as String,
|
occupancy: (json['occupancy_percentage'] ?? 0).toString(),
|
||||||
|
spaceUuid: json['space_uuid'] as String? ?? '',
|
||||||
|
occupiedSeconds: json['occupied_seconds'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [date, occupancy];
|
List<Object?> get props => [
|
||||||
|
date,
|
||||||
|
occupancy,
|
||||||
|
spaceUuid,
|
||||||
|
occupiedSeconds,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,66 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
class PhasesEnergyConsumption extends Equatable {
|
class PhasesEnergyConsumption extends Equatable {
|
||||||
final int month;
|
final String uuid;
|
||||||
final double phaseA;
|
final DateTime createdAt;
|
||||||
final double phaseB;
|
final DateTime updatedAt;
|
||||||
final double phaseC;
|
final String deviceUuid;
|
||||||
|
final DateTime date;
|
||||||
|
final double energyConsumedKw;
|
||||||
|
final double energyConsumedA;
|
||||||
|
final double energyConsumedB;
|
||||||
|
final double energyConsumedC;
|
||||||
|
|
||||||
const PhasesEnergyConsumption({
|
const PhasesEnergyConsumption({
|
||||||
required this.month,
|
required this.uuid,
|
||||||
required this.phaseA,
|
required this.createdAt,
|
||||||
required this.phaseB,
|
required this.updatedAt,
|
||||||
required this.phaseC,
|
required this.deviceUuid,
|
||||||
|
required this.date,
|
||||||
|
required this.energyConsumedKw,
|
||||||
|
required this.energyConsumedA,
|
||||||
|
required this.energyConsumedB,
|
||||||
|
required this.energyConsumedC,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [month, phaseA, phaseB, phaseC];
|
List<Object?> get props => [
|
||||||
|
uuid,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
deviceUuid,
|
||||||
|
date,
|
||||||
|
energyConsumedKw,
|
||||||
|
energyConsumedA,
|
||||||
|
energyConsumedB,
|
||||||
|
energyConsumedC,
|
||||||
|
];
|
||||||
|
|
||||||
factory PhasesEnergyConsumption.fromJson(Map<String, dynamic> json) {
|
factory PhasesEnergyConsumption.fromJson(Map<String, dynamic> json) {
|
||||||
return PhasesEnergyConsumption(
|
return PhasesEnergyConsumption(
|
||||||
month: json['month'] as int,
|
uuid: json['uuid'] as String,
|
||||||
phaseA: (json['phaseA'] as num).toDouble(),
|
createdAt: DateTime.parse(json['createdAt'] as String),
|
||||||
phaseB: (json['phaseB'] as num).toDouble(),
|
updatedAt: DateTime.parse(json['updatedAt'] as String),
|
||||||
phaseC: (json['phaseC'] as num).toDouble(),
|
deviceUuid: json['deviceUuid'] as String,
|
||||||
|
date: DateTime.parse(json['date'] as String),
|
||||||
|
energyConsumedKw: double.parse(json['energyConsumedKw']),
|
||||||
|
energyConsumedA: double.parse(json['energyConsumedA']),
|
||||||
|
energyConsumedB: double.parse(json['energyConsumedB']),
|
||||||
|
energyConsumedC: double.parse(json['energyConsumedC']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'uuid': uuid,
|
||||||
|
'createdAt': createdAt.toIso8601String(),
|
||||||
|
'updatedAt': updatedAt.toIso8601String(),
|
||||||
|
'deviceUuid': deviceUuid,
|
||||||
|
'date': date.toIso8601String().split('T')[0],
|
||||||
|
'energyConsumedKw': energyConsumedKw.toString(),
|
||||||
|
'energyConsumedA': energyConsumedA.toString(),
|
||||||
|
'energyConsumedB': energyConsumedB.toString(),
|
||||||
|
'energyConsumedC': energyConsumedC.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_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/params/get_analytics_devices_param.dart';
|
||||||
|
|
||||||
|
abstract final class FetchAirQualityDataHelper {
|
||||||
|
const FetchAirQualityDataHelper._();
|
||||||
|
|
||||||
|
static void loadAirQualityData(
|
||||||
|
BuildContext context, {
|
||||||
|
required String communityUuid,
|
||||||
|
required String spaceUuid,
|
||||||
|
}) {
|
||||||
|
loadAnalyticsDevices(
|
||||||
|
context,
|
||||||
|
communityUuid: communityUuid,
|
||||||
|
spaceUuid: spaceUuid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearAllData(BuildContext context) {
|
||||||
|
context.read<AnalyticsDevicesBloc>().add(
|
||||||
|
const ClearAnalyticsDeviceEvent(),
|
||||||
|
);
|
||||||
|
context.read<RealtimeDeviceChangesBloc>().add(
|
||||||
|
const RealtimeDeviceChangesClosed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadAnalyticsDevices(
|
||||||
|
BuildContext context, {
|
||||||
|
required String communityUuid,
|
||||||
|
required String spaceUuid,
|
||||||
|
}) {
|
||||||
|
context.read<AnalyticsDevicesBloc>().add(
|
||||||
|
LoadAnalyticsDevicesEvent(
|
||||||
|
param: GetAnalyticsDevicesParam(
|
||||||
|
communityUuid: communityUuid,
|
||||||
|
spaceUuid: spaceUuid,
|
||||||
|
deviceTypes: ['AQI'],
|
||||||
|
requestType: AnalyticsDeviceRequestType.energyManagement,
|
||||||
|
),
|
||||||
|
onSuccess: (device) {
|
||||||
|
context.read<RealtimeDeviceChangesBloc>()
|
||||||
|
..add(const RealtimeDeviceChangesClosed())
|
||||||
|
..add(RealtimeDeviceChangesStarted(device.uuid));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/air_quality_end_side_widget.dart';
|
||||||
|
|
||||||
|
class AirQualityView extends StatelessWidget {
|
||||||
|
const AirQualityView({super.key});
|
||||||
|
|
||||||
|
static const _padding = EdgeInsetsDirectional.all(32);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final isMediumOrLess = constraints.maxWidth <= 900;
|
||||||
|
final height = MediaQuery.sizeOf(context).height;
|
||||||
|
if (isMediumOrLess) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
padding: _padding,
|
||||||
|
child: Column(
|
||||||
|
spacing: 32,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: height * 1.2,
|
||||||
|
child: const AirQualityEndSideWidget(),
|
||||||
|
),
|
||||||
|
SizedBox(height: height * 0.5, child: const Placeholder()),
|
||||||
|
SizedBox(height: height * 0.5, child: const Placeholder()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
padding: _padding,
|
||||||
|
height: height,
|
||||||
|
child: const Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
spacing: 32,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Column(
|
||||||
|
spacing: 20,
|
||||||
|
children: [
|
||||||
|
Expanded(child: Placeholder()),
|
||||||
|
Expanded(child: Placeholder()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: AirQualityEndSideWidget()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_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/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/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
|
class AirQualityEndSideWidget extends StatelessWidget {
|
||||||
|
const AirQualityEndSideWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: subSectionContainerDecoration.copyWith(
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsetsDirectional.all(32),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildHeader(context),
|
||||||
|
Text(
|
||||||
|
'Device ID:',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.textPrimaryColor,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
SelectableText(
|
||||||
|
context.watch<AnalyticsDevicesBloc>().state.selectedDevice?.uuid ??
|
||||||
|
'N/A',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeader(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: SelectableText(
|
||||||
|
'AQI Sensor',
|
||||||
|
style: context.textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: ColorsManager.vividBlue.withValues(alpha: 0.6),
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
|
child: AnalyticsDeviceDropdown(
|
||||||
|
onChanged: (value) {
|
||||||
|
context.read<AnalyticsDevicesBloc>().add(
|
||||||
|
SelectAnalyticsDeviceEvent(value),
|
||||||
|
);
|
||||||
|
FetchEnergyManagementDataHelper.loadRealtimeDeviceChanges(
|
||||||
|
context,
|
||||||
|
deviceUuid: value.uuid,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/views/air_quality_view.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/views/analytics_occupancy_view.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/views/analytics_occupancy_view.dart';
|
||||||
|
|
||||||
@ -10,6 +11,10 @@ enum AnalyticsPageTab {
|
|||||||
occupancy(
|
occupancy(
|
||||||
title: 'Occupancy',
|
title: 'Occupancy',
|
||||||
child: AnalyticsOccupancyView(),
|
child: AnalyticsOccupancyView(),
|
||||||
|
),
|
||||||
|
airQuality(
|
||||||
|
title: 'Air Quality',
|
||||||
|
child: AirQualityView(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const AnalyticsPageTab({
|
const AnalyticsPageTab({
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/helpers/fetch_air_quality_data_helper.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/analytics_data_loading_strategy.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
|
||||||
|
final class AirQualityDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
||||||
|
@override
|
||||||
|
void onCommunitySelected(
|
||||||
|
BuildContext context,
|
||||||
|
CommunityModel community,
|
||||||
|
List<SpaceModel> spaces,
|
||||||
|
) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onSpaceSelected(
|
||||||
|
BuildContext context,
|
||||||
|
CommunityModel community,
|
||||||
|
SpaceModel space,
|
||||||
|
) {
|
||||||
|
final spaceTreeBloc = context.read<SpaceTreeBloc>();
|
||||||
|
final isSpaceSelected = spaceTreeBloc.state.selectedSpaces.contains(space.uuid);
|
||||||
|
|
||||||
|
if (isSpaceSelected) {
|
||||||
|
clearData(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spaceTreeBloc
|
||||||
|
..add(const SpaceTreeClearSelectionEvent())
|
||||||
|
..add(OnSpaceSelected(community, space.uuid ?? '', []));
|
||||||
|
|
||||||
|
FetchAirQualityDataHelper.loadAirQualityData(
|
||||||
|
context,
|
||||||
|
communityUuid: community.uuid,
|
||||||
|
spaceUuid: space.uuid ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onChildSpaceSelected(
|
||||||
|
BuildContext context,
|
||||||
|
CommunityModel community,
|
||||||
|
SpaceModel child,
|
||||||
|
) {
|
||||||
|
if (child.children.isNotEmpty) return onSpaceSelected(context, community, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clearData(BuildContext context) {
|
||||||
|
context.read<SpaceTreeBloc>().add(const SpaceTreeClearSelectionEvent());
|
||||||
|
FetchAirQualityDataHelper.clearAllData(context);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/enums/analytics_page_tab.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/enums/analytics_page_tab.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/air_quality_data_loading_strategy.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/analytics_data_loading_strategy.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/analytics_data_loading_strategy.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/energy_management_data_loading_strategy.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/energy_management_data_loading_strategy.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/occupancy_data_loading_strategy.dart';
|
import 'package:syncrow_web/pages/analytics/modules/analytics/strategies/occupancy_data_loading_strategy.dart';
|
||||||
@ -9,6 +10,7 @@ abstract final class AnalyticsDataLoadingStrategyFactory {
|
|||||||
return switch (tab) {
|
return switch (tab) {
|
||||||
AnalyticsPageTab.energyManagement => EnergyManagementDataLoadingStrategy(),
|
AnalyticsPageTab.energyManagement => EnergyManagementDataLoadingStrategy(),
|
||||||
AnalyticsPageTab.occupancy => OccupancyDataLoadingStrategy(),
|
AnalyticsPageTab.occupancy => OccupancyDataLoadingStrategy(),
|
||||||
|
AnalyticsPageTab.airQuality => AirQualityDataLoadingStrategy(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ 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,
|
||||||
@ -69,7 +68,9 @@ class EnergyManagementDataLoadingStrategy implements AnalyticsDataLoadingStrateg
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
SpaceModel child,
|
SpaceModel child,
|
||||||
) {
|
) {
|
||||||
// Do nothing else as per original implementation
|
if (child.children.isNotEmpty) {
|
||||||
|
return onSpaceSelected(context, community, child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -14,23 +14,7 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
List<SpaceModel> spaces,
|
List<SpaceModel> spaces,
|
||||||
) {
|
) {
|
||||||
context.read<SpaceTreeBloc>().add(
|
// Do Nothing
|
||||||
OnCommunitySelected(
|
|
||||||
community.uuid,
|
|
||||||
spaces.isNotEmpty ? [spaces.first] : [],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid)) {
|
|
||||||
clearData(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
|
||||||
context,
|
|
||||||
communityId: community.uuid,
|
|
||||||
spaceId: spaces.isNotEmpty ? spaces.first.uuid ?? '' : '',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -40,26 +24,17 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
SpaceModel space,
|
SpaceModel space,
|
||||||
) {
|
) {
|
||||||
final spaceTreeBloc = context.read<SpaceTreeBloc>();
|
final spaceTreeBloc = context.read<SpaceTreeBloc>();
|
||||||
final selectedSpacesIds = spaceTreeBloc.state.selectedSpaces;
|
final isSpaceSelected = spaceTreeBloc.state.selectedSpaces.contains(space.uuid);
|
||||||
final isSpaceSelected = selectedSpacesIds.contains(space.uuid);
|
|
||||||
|
|
||||||
if (selectedSpacesIds.isEmpty) {
|
if (isSpaceSelected) {
|
||||||
spaceTreeBloc.add(OnCommunitySelected(community.uuid, [space]));
|
|
||||||
} else if (isSpaceSelected) {
|
|
||||||
spaceTreeBloc.add(const SpaceTreeClearSelectionEvent());
|
|
||||||
} else {
|
|
||||||
spaceTreeBloc
|
|
||||||
..add(const SpaceTreeClearSelectionEvent())
|
|
||||||
..add(OnSpaceSelected(community, space.uuid ?? '', []));
|
|
||||||
}
|
|
||||||
|
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
if (spaceTreeState.selectedCommunities.contains(community.uuid) ||
|
|
||||||
spaceTreeState.selectedSpaces.contains(space.uuid)) {
|
|
||||||
clearData(context);
|
clearData(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spaceTreeBloc
|
||||||
|
..add(const SpaceTreeClearSelectionEvent())
|
||||||
|
..add(OnSpaceSelected(community, space.uuid ?? '', []));
|
||||||
|
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
FetchOccupancyDataHelper.loadOccupancyData(
|
||||||
context,
|
context,
|
||||||
communityId: community.uuid,
|
communityId: community.uuid,
|
||||||
@ -73,7 +48,7 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
SpaceModel child,
|
SpaceModel child,
|
||||||
) {
|
) {
|
||||||
// Do nothing
|
if (child.children.isNotEmpty) return onSpaceSelected(context, community, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -15,9 +15,9 @@ import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_he
|
|||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service_delagate.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_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/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/remote_energy_consumption_by_phases_service.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/remote_energy_consumption_per_device_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/remote_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/remote_occupancy_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/remote_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';
|
||||||
@ -57,7 +57,7 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
|||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => EnergyConsumptionByPhasesBloc(
|
create: (context) => EnergyConsumptionByPhasesBloc(
|
||||||
FakeEnergyConsumptionByPhasesService(),
|
RemoteEnergyConsumptionByPhasesService(_httpService),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
@ -75,7 +75,11 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
|
|||||||
FirebaseRealtimeDeviceService(),
|
FirebaseRealtimeDeviceService(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => OccupancyBloc(FakeOccupacyService())),
|
BlocProvider(
|
||||||
|
create: (context) => OccupancyBloc(
|
||||||
|
RemoteOccupancyService(_httpService),
|
||||||
|
),
|
||||||
|
),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => OccupancyHeatMapBloc(
|
create: (context) => OccupancyHeatMapBloc(
|
||||||
RemoteOccupancyHeatMapService(_httpService),
|
RemoteOccupancyHeatMapService(_httpService),
|
||||||
|
@ -14,7 +14,6 @@ class AnalyticsPageTabsAndChildren extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
|
||||||
return BlocBuilder<AnalyticsTabBloc, AnalyticsPageTab>(
|
return BlocBuilder<AnalyticsTabBloc, AnalyticsPageTab>(
|
||||||
buildWhen: (previous, current) => previous != current,
|
buildWhen: (previous, current) => previous != current,
|
||||||
builder: (context, selectedTab) => Column(
|
builder: (context, selectedTab) => Column(
|
||||||
@ -68,8 +67,14 @@ class AnalyticsPageTabsAndChildren extends StatelessWidget {
|
|||||||
context.read<AnalyticsDatePickerBloc>().add(
|
context.read<AnalyticsDatePickerBloc>().add(
|
||||||
UpdateAnalyticsDatePickerEvent(montlyDate: value),
|
UpdateAnalyticsDatePickerEvent(montlyDate: value),
|
||||||
);
|
);
|
||||||
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
|
||||||
|
final spaceTreeState =
|
||||||
|
context.read<SpaceTreeBloc>().state;
|
||||||
|
if (spaceTreeState.selectedSpaces.isNotEmpty) {
|
||||||
|
FetchEnergyManagementDataHelper
|
||||||
|
.loadEnergyManagementData(
|
||||||
context,
|
context,
|
||||||
|
shouldFetchAnalyticsDevices: false,
|
||||||
selectedDate: value,
|
selectedDate: value,
|
||||||
communityId:
|
communityId:
|
||||||
spaceTreeState.selectedCommunities.firstOrNull ??
|
spaceTreeState.selectedCommunities.firstOrNull ??
|
||||||
@ -77,6 +82,7 @@ class AnalyticsPageTabsAndChildren extends StatelessWidget {
|
|||||||
spaceId:
|
spaceId:
|
||||||
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectedDate: context
|
selectedDate: context
|
||||||
.watch<AnalyticsDatePickerBloc>()
|
.watch<AnalyticsDatePickerBloc>()
|
||||||
|
@ -45,7 +45,7 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Dialog(
|
return Dialog(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsetsDirectional.all(20),
|
padding: const EdgeInsetsDirectional.all(20),
|
||||||
width: 320,
|
width: 320,
|
||||||
@ -121,6 +121,7 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Row _buildYearSelector() {
|
Row _buildYearSelector() {
|
||||||
|
final currentYear = DateTime.now().year;
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -134,17 +135,35 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => setState(() => _currentYear = _currentYear - 1),
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_currentYear = _currentYear - 1;
|
||||||
|
});
|
||||||
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.chevron_left,
|
Icons.chevron_left,
|
||||||
color: ColorsManager.grey700,
|
color: ColorsManager.grey700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => setState(() => _currentYear = _currentYear + 1),
|
onPressed: _currentYear < currentYear
|
||||||
icon: const Icon(
|
? () {
|
||||||
|
setState(() {
|
||||||
|
_currentYear = _currentYear + 1;
|
||||||
|
// Clear selected month if it becomes invalid in the new year
|
||||||
|
if (_currentYear == currentYear &&
|
||||||
|
_selectedMonth != null &&
|
||||||
|
_selectedMonth! > DateTime.now().month - 1) {
|
||||||
|
_selectedMonth = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
icon: Icon(
|
||||||
Icons.chevron_right,
|
Icons.chevron_right,
|
||||||
color: ColorsManager.grey700,
|
color: _currentYear < currentYear
|
||||||
|
? ColorsManager.grey700
|
||||||
|
: ColorsManager.grey700.withValues(alpha: 0.3),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -152,11 +171,13 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMonthsGrid() {
|
Widget _buildMonthsGrid() {
|
||||||
|
final currentDate = DateTime.now();
|
||||||
|
final isCurrentYear = _currentYear == currentDate.year;
|
||||||
|
|
||||||
return GridView.builder(
|
return GridView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: 12,
|
itemCount: 12,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
childAspectRatio: 2.5,
|
childAspectRatio: 2.5,
|
||||||
@ -165,13 +186,28 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final isSelected = _selectedMonth == index;
|
final isSelected = _selectedMonth == index;
|
||||||
|
final isFutureMonth = isCurrentYear && index > currentDate.month - 1;
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => setState(() => _selectedMonth = index),
|
onTap: isFutureMonth ? null : () => setState(() => _selectedMonth = index),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFEDF2F7),
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: index % 3 == 0 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
bottomLeft: index % 3 == 0 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
topRight: index % 3 == 2 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
bottomRight:
|
||||||
|
index % 3 == 2 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.vividBlue.withValues(alpha: 0.7)
|
? ColorsManager.vividBlue.withValues(alpha: 0.7)
|
||||||
|
: isFutureMonth
|
||||||
|
? ColorsManager.grey700.withValues(alpha: 0.1)
|
||||||
: const Color(0xFFEDF2F7),
|
: const Color(0xFFEDF2F7),
|
||||||
borderRadius:
|
borderRadius:
|
||||||
isSelected ? BorderRadius.circular(15) : BorderRadius.zero,
|
isSelected ? BorderRadius.circular(15) : BorderRadius.zero,
|
||||||
@ -182,11 +218,14 @@ class _MonthPickerWidgetState extends State<MonthPickerWidget> {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.whiteColors
|
? ColorsManager.whiteColors
|
||||||
|
: isFutureMonth
|
||||||
|
? ColorsManager.blackColor.withValues(alpha: 0.3)
|
||||||
: ColorsManager.blackColor.withValues(alpha: 0.8),
|
: ColorsManager.blackColor.withValues(alpha: 0.8),
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -20,9 +20,9 @@ class _YearPickerWidgetState extends State<YearPickerWidget> {
|
|||||||
late int _currentYear;
|
late int _currentYear;
|
||||||
|
|
||||||
static final years = List.generate(
|
static final years = List.generate(
|
||||||
DateTime.now().year - 2020 + 1,
|
DateTime.now().year - (DateTime.now().year - 5) + 1,
|
||||||
(index) => (2020 + index),
|
(index) => (2020 + index),
|
||||||
);
|
).where((year) => year <= DateTime.now().year).toList();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -33,7 +33,7 @@ class _YearPickerWidgetState extends State<YearPickerWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Dialog(
|
return Dialog(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsetsDirectional.all(20),
|
padding: const EdgeInsetsDirectional.all(20),
|
||||||
width: 320,
|
width: 320,
|
||||||
@ -109,7 +109,6 @@ class _YearPickerWidgetState extends State<YearPickerWidget> {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: years.length,
|
itemCount: years.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
childAspectRatio: 2.5,
|
childAspectRatio: 2.5,
|
||||||
@ -120,6 +119,17 @@ class _YearPickerWidgetState extends State<YearPickerWidget> {
|
|||||||
final isSelected = _currentYear == years[index];
|
final isSelected = _currentYear == years[index];
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => setState(() => _currentYear = years[index]),
|
onTap: () => setState(() => _currentYear = years[index]),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFEDF2F7),
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: index % 3 == 0 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
bottomLeft: index % 3 == 0 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
topRight: index % 3 == 2 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
bottomRight:
|
||||||
|
index % 3 == 2 ? const Radius.circular(16) : Radius.zero,
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -140,6 +150,7 @@ class _YearPickerWidgetState extends State<YearPickerWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
|
||||||
|
|
||||||
abstract final class EnergyConsumptionByPhasesChartHelper {
|
|
||||||
const EnergyConsumptionByPhasesChartHelper._();
|
|
||||||
|
|
||||||
static const fakeData = <PhasesEnergyConsumption>[
|
|
||||||
PhasesEnergyConsumption(month: 1, phaseA: 200, phaseB: 300, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 2, phaseA: 300, phaseB: 400, phaseC: 500),
|
|
||||||
PhasesEnergyConsumption(month: 3, phaseA: 400, phaseB: 500, phaseC: 600),
|
|
||||||
PhasesEnergyConsumption(month: 4, phaseA: 100, phaseB: 100, phaseC: 100),
|
|
||||||
PhasesEnergyConsumption(month: 5, phaseA: 300, phaseB: 400, phaseC: 500),
|
|
||||||
PhasesEnergyConsumption(month: 6, phaseA: 300, phaseB: 100, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 7, phaseA: 300, phaseB: 100, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 8, phaseA: 500, phaseB: 100, phaseC: 100),
|
|
||||||
PhasesEnergyConsumption(month: 9, phaseA: 500, phaseB: 100, phaseC: 200),
|
|
||||||
PhasesEnergyConsumption(month: 10, phaseA: 100, phaseB: 50, phaseC: 50),
|
|
||||||
PhasesEnergyConsumption(month: 11, phaseA: 600, phaseB: 750, phaseC: 130),
|
|
||||||
PhasesEnergyConsumption(month: 12, phaseA: 100, phaseB: 80, phaseC: 100),
|
|
||||||
];
|
|
||||||
}
|
|
@ -21,12 +21,13 @@ abstract final class EnergyManagementChartsHelper {
|
|||||||
reservedSize: 32,
|
reservedSize: 32,
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
maxIncluded: true,
|
maxIncluded: true,
|
||||||
|
minIncluded: true,
|
||||||
getTitlesWidget: (value, meta) => Padding(
|
getTitlesWidget: (value, meta) => Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(top: 20.0),
|
padding: const EdgeInsetsDirectional.only(top: 20.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
(value + 1).toString(),
|
value.toString(),
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.lightGreyColor,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -36,7 +37,8 @@ abstract final class EnergyManagementChartsHelper {
|
|||||||
leftTitles: AxisTitles(
|
leftTitles: AxisTitles(
|
||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
maxIncluded: true,
|
maxIncluded: false,
|
||||||
|
minIncluded: true,
|
||||||
interval: leftTitlesInterval,
|
interval: leftTitlesInterval,
|
||||||
reservedSize: 110,
|
reservedSize: 110,
|
||||||
getTitlesWidget: (value, meta) => Padding(
|
getTitlesWidget: (value, meta) => Padding(
|
||||||
@ -70,7 +72,7 @@ abstract final class EnergyManagementChartsHelper {
|
|||||||
static List<LineTooltipItem?> getTooltipItems(List<LineBarSpot> touchedSpots) {
|
static List<LineTooltipItem?> getTooltipItems(List<LineBarSpot> touchedSpots) {
|
||||||
return touchedSpots.map((spot) {
|
return touchedSpots.map((spot) {
|
||||||
return LineTooltipItem(
|
return LineTooltipItem(
|
||||||
getToolTipLabel(spot.x + 1, spot.y),
|
getToolTipLabel(spot.x, spot.y),
|
||||||
const TextStyle(
|
const TextStyle(
|
||||||
color: ColorsManager.textPrimaryColor,
|
color: ColorsManager.textPrimaryColor,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -91,31 +93,38 @@ abstract final class EnergyManagementChartsHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FlBorderData borderData() {
|
|
||||||
return FlBorderData(
|
|
||||||
show: true,
|
|
||||||
border: const Border.symmetric(
|
|
||||||
horizontal: BorderSide(
|
|
||||||
color: ColorsManager.greyColor,
|
|
||||||
style: BorderStyle.solid,
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlGridData gridData() {
|
static FlGridData gridData() {
|
||||||
return const FlGridData(
|
return FlGridData(
|
||||||
show: true,
|
show: true,
|
||||||
drawVerticalLine: false,
|
drawVerticalLine: false,
|
||||||
drawHorizontalLine: true,
|
drawHorizontalLine: true,
|
||||||
|
horizontalInterval: 250,
|
||||||
|
getDrawingHorizontalLine: (value) {
|
||||||
|
return FlLine(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
strokeWidth: 1,
|
||||||
|
dashArray: value == 0 ? null : [5, 5],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FlBorderData borderData() {
|
||||||
|
return FlBorderData(
|
||||||
|
border: const Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
style: BorderStyle.solid,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
show: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LineTouchData lineTouchData() {
|
static LineTouchData lineTouchData() {
|
||||||
return LineTouchData(
|
return LineTouchData(
|
||||||
handleBuiltInTouches: true,
|
handleBuiltInTouches: true,
|
||||||
touchSpotThreshold: 2,
|
touchSpotThreshold: 16,
|
||||||
touchTooltipData: EnergyManagementChartsHelper.lineTouchTooltipData(),
|
touchTooltipData: EnergyManagementChartsHelper.lineTouchTooltipData(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
required String communityId,
|
required String communityId,
|
||||||
required String spaceId,
|
required String spaceId,
|
||||||
DateTime? selectedDate,
|
DateTime? selectedDate,
|
||||||
|
bool shouldFetchAnalyticsDevices = true,
|
||||||
}) {
|
}) {
|
||||||
if (communityId.isEmpty && spaceId.isEmpty) {
|
if (communityId.isEmpty && spaceId.isEmpty) {
|
||||||
clearAllData(context);
|
clearAllData(context);
|
||||||
@ -34,31 +35,46 @@ 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);
|
if (shouldFetchAnalyticsDevices) {
|
||||||
|
loadAnalyticsDevices(
|
||||||
|
context,
|
||||||
|
communityUuid: communityId,
|
||||||
|
spaceUuid: spaceId,
|
||||||
|
selectedDate: selectedDate0,
|
||||||
|
);
|
||||||
|
loadRealtimeDeviceChanges(context);
|
||||||
|
loadPowerClampInfo(context);
|
||||||
|
}
|
||||||
loadTotalEnergyConsumption(
|
loadTotalEnergyConsumption(
|
||||||
context,
|
context,
|
||||||
selectedDate: selectedDate0,
|
selectedDate: selectedDate0,
|
||||||
communityId: communityId,
|
communityId: communityId,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
);
|
);
|
||||||
loadEnergyConsumptionByPhases(context, selectedDate: selectedDate);
|
final selectedDevice = getSelectedDevice(context);
|
||||||
|
if (selectedDevice case final AnalyticsDevice device) {
|
||||||
|
loadEnergyConsumptionByPhases(
|
||||||
|
context,
|
||||||
|
powerClampUuid: device.uuid,
|
||||||
|
selectedDate: selectedDate0,
|
||||||
|
);
|
||||||
|
}
|
||||||
loadEnergyConsumptionPerDevice(
|
loadEnergyConsumptionPerDevice(
|
||||||
context,
|
context,
|
||||||
communityId: communityId,
|
communityId: communityId,
|
||||||
spaceId: spaceId,
|
spaceId: spaceId,
|
||||||
selectedDate: selectedDate0,
|
selectedDate: selectedDate0,
|
||||||
);
|
);
|
||||||
loadRealtimeDeviceChanges(context);
|
|
||||||
loadPowerClampInfo(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadEnergyConsumptionByPhases(
|
static void loadEnergyConsumptionByPhases(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
|
required String powerClampUuid,
|
||||||
DateTime? selectedDate,
|
DateTime? selectedDate,
|
||||||
}) {
|
}) {
|
||||||
final param = GetEnergyConsumptionByPhasesParam(
|
final param = GetEnergyConsumptionByPhasesParam(
|
||||||
startDate: selectedDate,
|
date: selectedDate,
|
||||||
spaceId: '',
|
powerClampUuid: powerClampUuid,
|
||||||
);
|
);
|
||||||
context.read<EnergyConsumptionByPhasesBloc>().add(
|
context.read<EnergyConsumptionByPhasesBloc>().add(
|
||||||
LoadEnergyConsumptionByPhasesEvent(param: param),
|
LoadEnergyConsumptionByPhasesEvent(param: param),
|
||||||
@ -121,6 +137,7 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String communityUuid,
|
required String communityUuid,
|
||||||
required String spaceUuid,
|
required String spaceUuid,
|
||||||
|
required DateTime selectedDate,
|
||||||
}) {
|
}) {
|
||||||
context.read<AnalyticsDevicesBloc>().add(
|
context.read<AnalyticsDevicesBloc>().add(
|
||||||
LoadAnalyticsDevicesEvent(
|
LoadAnalyticsDevicesEvent(
|
||||||
@ -128,6 +145,11 @@ abstract final class FetchEnergyManagementDataHelper {
|
|||||||
context.read<PowerClampInfoBloc>().add(
|
context.read<PowerClampInfoBloc>().add(
|
||||||
LoadPowerClampInfoEvent(device.uuid),
|
LoadPowerClampInfoEvent(device.uuid),
|
||||||
);
|
);
|
||||||
|
loadEnergyConsumptionByPhases(
|
||||||
|
context,
|
||||||
|
powerClampUuid: device.uuid,
|
||||||
|
selectedDate: selectedDate,
|
||||||
|
);
|
||||||
context.read<RealtimeDeviceChangesBloc>().add(
|
context.read<RealtimeDeviceChangesBloc>().add(
|
||||||
RealtimeDeviceChangesStarted(device.uuid),
|
RealtimeDeviceChangesStarted(device.uuid),
|
||||||
);
|
);
|
||||||
|
@ -48,6 +48,7 @@ class AnalyticsDeviceDropdown extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDevicesDropdown(BuildContext context, AnalyticsDevicesState state) {
|
Widget _buildDevicesDropdown(BuildContext context, AnalyticsDevicesState state) {
|
||||||
|
final spaceUuid = state.selectedDevice?.spaceUuid;
|
||||||
return DropdownButton<AnalyticsDevice?>(
|
return DropdownButton<AnalyticsDevice?>(
|
||||||
value: state.selectedDevice,
|
value: state.selectedDevice,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
@ -60,10 +61,30 @@ class AnalyticsDeviceDropdown extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
style: _getTextStyle(context),
|
style: _getTextStyle(context),
|
||||||
padding: _defaultPadding,
|
padding: _defaultPadding,
|
||||||
|
selectedItemBuilder: (context) {
|
||||||
|
return state.devices.map((e) => Text(e.name)).toList();
|
||||||
|
},
|
||||||
items: state.devices.map((e) {
|
items: state.devices.map((e) {
|
||||||
return DropdownMenuItem(
|
return DropdownMenuItem(
|
||||||
value: e,
|
value: e,
|
||||||
child: Text(e.name),
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(e.name),
|
||||||
|
if (spaceUuid != null)
|
||||||
|
FittedBox(
|
||||||
|
fit: BoxFit.scaleDown,
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: Text(
|
||||||
|
spaceUuid,
|
||||||
|
style: _getTextStyle(context)?.copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/helpers/get_month_name_from_int.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/energy_management_charts_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -34,25 +34,29 @@ class EnergyConsumptionByPhasesChart extends StatelessWidget {
|
|||||||
barRods: [
|
barRods: [
|
||||||
BarChartRodData(
|
BarChartRodData(
|
||||||
color: ColorsManager.vividBlue.withValues(alpha: 0.1),
|
color: ColorsManager.vividBlue.withValues(alpha: 0.1),
|
||||||
toY: data.phaseA + data.phaseB + data.phaseC,
|
toY: data.energyConsumedA +
|
||||||
|
data.energyConsumedB +
|
||||||
|
data.energyConsumedC,
|
||||||
rodStackItems: [
|
rodStackItems: [
|
||||||
BarChartRodStackItem(
|
BarChartRodStackItem(
|
||||||
0,
|
0,
|
||||||
data.phaseA,
|
data.energyConsumedA,
|
||||||
ColorsManager.vividBlue.withValues(alpha: 0.8),
|
ColorsManager.vividBlue.withValues(alpha: 0.8),
|
||||||
),
|
),
|
||||||
BarChartRodStackItem(
|
BarChartRodStackItem(
|
||||||
data.phaseA,
|
data.energyConsumedA,
|
||||||
data.phaseA + data.phaseB,
|
data.energyConsumedA + data.energyConsumedB,
|
||||||
ColorsManager.vividBlue.withValues(alpha: 0.4),
|
ColorsManager.vividBlue.withValues(alpha: 0.4),
|
||||||
),
|
),
|
||||||
BarChartRodStackItem(
|
BarChartRodStackItem(
|
||||||
data.phaseA + data.phaseB,
|
data.energyConsumedA + data.energyConsumedB,
|
||||||
data.phaseA + data.phaseB + data.phaseC,
|
data.energyConsumedA +
|
||||||
|
data.energyConsumedB +
|
||||||
|
data.energyConsumedC,
|
||||||
ColorsManager.vividBlue.withValues(alpha: 0.15),
|
ColorsManager.vividBlue.withValues(alpha: 0.15),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
width: 16,
|
width: 8,
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(8),
|
topLeft: Radius.circular(8),
|
||||||
topRight: Radius.circular(8),
|
topRight: Radius.circular(8),
|
||||||
@ -62,6 +66,7 @@ class EnergyConsumptionByPhasesChart extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
duration: Duration.zero,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,18 +99,27 @@ class EnergyConsumptionByPhasesChart extends StatelessWidget {
|
|||||||
}) {
|
}) {
|
||||||
final data = energyData;
|
final data = energyData;
|
||||||
|
|
||||||
final month = data[group.x.toInt()].month.getMonthName;
|
final date = DateFormat('dd/MM/yyyy').format(data[group.x.toInt()].date);
|
||||||
final phaseA = data[group.x.toInt()].phaseA;
|
final phaseA = data[group.x.toInt()].energyConsumedA;
|
||||||
final phaseB = data[group.x.toInt()].phaseB;
|
final phaseB = data[group.x.toInt()].energyConsumedB;
|
||||||
final phaseC = data[group.x.toInt()].phaseC;
|
final phaseC = data[group.x.toInt()].energyConsumedC;
|
||||||
|
final total = data[group.x.toInt()].energyConsumedKw;
|
||||||
|
|
||||||
return BarTooltipItem(
|
return BarTooltipItem(
|
||||||
'$month\n',
|
'$date\n',
|
||||||
context.textTheme.bodyMedium!.copyWith(
|
context.textTheme.bodyMedium!.copyWith(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
|
textAlign: TextAlign.start,
|
||||||
children: [
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: 'Total: $total\n',
|
||||||
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Phase A: $phaseA\n',
|
text: 'Phase A: $phaseA\n',
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
@ -147,9 +161,9 @@ class EnergyConsumptionByPhasesChart extends StatelessWidget {
|
|||||||
sideTitles: SideTitles(
|
sideTitles: SideTitles(
|
||||||
showTitles: true,
|
showTitles: true,
|
||||||
getTitlesWidget: (value, _) {
|
getTitlesWidget: (value, _) {
|
||||||
final month = energyData[value.toInt()].month.getMonthName;
|
final month = DateFormat('d').format(energyData[value.toInt()].date);
|
||||||
return FittedBox(
|
return FittedBox(
|
||||||
alignment: AlignmentDirectional.bottomCenter,
|
alignment: AlignmentDirectional.center,
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: RotatedBox(
|
child: RotatedBox(
|
||||||
quarterTurns: 3,
|
quarterTurns: 3,
|
||||||
@ -163,7 +177,7 @@ class EnergyConsumptionByPhasesChart extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
reservedSize: 36,
|
reservedSize: 18,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ class EnergyConsumptionPerDeviceChart extends StatelessWidget {
|
|||||||
context,
|
context,
|
||||||
leftTitlesInterval: 250,
|
leftTitlesInterval: 250,
|
||||||
),
|
),
|
||||||
|
|
||||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||||
checkToShowHorizontalLine: (value) => true,
|
checkToShowHorizontalLine: (value) => true,
|
||||||
horizontalInterval: 250,
|
horizontalInterval: 250,
|
||||||
@ -36,7 +37,7 @@ class EnergyConsumptionPerDeviceChart extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
duration: Durations.extralong1,
|
duration: Duration.zero,
|
||||||
curve: Curves.easeIn,
|
curve: Curves.easeIn,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +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_devices/analytics_devices_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/widgets/chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart';
|
||||||
@ -46,6 +47,7 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
child: EnergyConsumptionPerDeviceDevicesList(
|
child: EnergyConsumptionPerDeviceDevicesList(
|
||||||
chartData: state.chartData,
|
chartData: state.chartData,
|
||||||
|
devices: context.watch<AnalyticsDevicesBloc>().state.devices,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
|
class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
|
||||||
const EnergyConsumptionPerDeviceDevicesList({required this.chartData, super.key});
|
const EnergyConsumptionPerDeviceDevicesList({
|
||||||
|
required this.chartData,
|
||||||
|
required this.devices,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<AnalyticsDevice> devices;
|
||||||
final List<DeviceEnergyDataModel> chartData;
|
final List<DeviceEnergyDataModel> chartData;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -16,13 +22,27 @@ class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: chartData.map((e) => _buildDeviceCell(context, e)).toList(),
|
children: devices.map((e) => _buildDeviceCell(context, e)).toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDeviceCell(BuildContext context, DeviceEnergyDataModel device) {
|
Widget _buildDeviceCell(BuildContext context, AnalyticsDevice device) {
|
||||||
return Container(
|
final deviceColor = chartData
|
||||||
|
.firstWhere(
|
||||||
|
(element) => element.deviceId == device.uuid,
|
||||||
|
orElse: () => const DeviceEnergyDataModel(
|
||||||
|
energy: [],
|
||||||
|
deviceName: '',
|
||||||
|
deviceId: '',
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.color;
|
||||||
|
|
||||||
|
return Tooltip(
|
||||||
|
message: '${device.name}\n${device.productDevice?.uuid ?? ''}',
|
||||||
|
child: Container(
|
||||||
height: MediaQuery.sizeOf(context).height * 0.0365,
|
height: MediaQuery.sizeOf(context).height * 0.0365,
|
||||||
padding: const EdgeInsetsDirectional.symmetric(
|
padding: const EdgeInsetsDirectional.symmetric(
|
||||||
vertical: 8,
|
vertical: 8,
|
||||||
@ -43,10 +63,10 @@ class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 4,
|
radius: 4,
|
||||||
backgroundColor: device.color,
|
backgroundColor: deviceColor,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
device.deviceName,
|
device.name,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
@ -57,6 +77,7 @@ class EnergyConsumptionPerDeviceDevicesList extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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_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_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';
|
||||||
@ -132,6 +133,12 @@ class PowerClampEnergyDataWidget extends StatelessWidget {
|
|||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: AnalyticsDeviceDropdown(
|
child: AnalyticsDeviceDropdown(
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
FetchEnergyManagementDataHelper.loadEnergyConsumptionByPhases(
|
||||||
|
context,
|
||||||
|
powerClampUuid: value.uuid,
|
||||||
|
selectedDate:
|
||||||
|
context.read<AnalyticsDatePickerBloc>().state.monthlyDate,
|
||||||
|
);
|
||||||
FetchEnergyManagementDataHelper.loadRealtimeDeviceChanges(
|
FetchEnergyManagementDataHelper.loadRealtimeDeviceChanges(
|
||||||
context,
|
context,
|
||||||
deviceUuid: value.uuid,
|
deviceUuid: value.uuid,
|
||||||
|
@ -48,6 +48,9 @@ class PowerClampEnergyStatusWidget extends StatelessWidget {
|
|||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
|
softWrap: true,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
trailing: Text.rich(
|
trailing: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
|
@ -125,7 +125,48 @@ class PowerClampPhasesDataWidget extends StatelessWidget {
|
|||||||
(e) => e.code == code,
|
(e) => e.code == code,
|
||||||
orElse: () => DataPoint(value: '--'),
|
orElse: () => DataPoint(value: '--'),
|
||||||
);
|
);
|
||||||
|
final value = element?.value;
|
||||||
|
if (code.contains('Current')) {
|
||||||
|
return _formatCurrentValue(value?.toString());
|
||||||
|
}
|
||||||
|
if (code.contains('PowerFactor')) {
|
||||||
|
return _formatPowerFactor(value?.toString());
|
||||||
|
}
|
||||||
|
if (code.contains('Voltage')) {
|
||||||
|
return _formatVoltage(value?.toString());
|
||||||
|
}
|
||||||
|
return value?.toString() ?? '--';
|
||||||
|
}
|
||||||
|
|
||||||
return element?.value.toString() ?? '--';
|
String _formatCurrentValue(String? value) {
|
||||||
|
if (value == null) return '--';
|
||||||
|
String str = value;
|
||||||
|
if (str.isEmpty || str == '--') return '--';
|
||||||
|
str = str.replaceAll(RegExp(r'[^0-9]'), '');
|
||||||
|
if (str.isEmpty) return '--';
|
||||||
|
if (str.length == 1) return '${str[0]}.0';
|
||||||
|
return '${str[0]}.${str.substring(1)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatPowerFactor(String? value) {
|
||||||
|
if (value == null) return '--';
|
||||||
|
String str = value;
|
||||||
|
if (str.isEmpty || str == '--') return '--';
|
||||||
|
str = str.replaceAll(RegExp(r'[^0-9]'), '');
|
||||||
|
if (str.isEmpty) return '--';
|
||||||
|
final intValue = int.tryParse(str);
|
||||||
|
if (intValue == null) return '--';
|
||||||
|
final doubleValue = intValue / 100;
|
||||||
|
return doubleValue.toStringAsFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatVoltage(String? value) {
|
||||||
|
if (value == null) return '--';
|
||||||
|
String str = value;
|
||||||
|
if (str.isEmpty || str == '--') return '--';
|
||||||
|
str = str.replaceAll(RegExp(r'[^0-9]'), '');
|
||||||
|
if (str.isEmpty) return '--';
|
||||||
|
if (str.length == 1) return '0.${str[0]}';
|
||||||
|
return '${str.substring(0, str.length - 1)}.${str.substring(str.length - 1)}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ class TotalEnergyConsumptionChart extends StatelessWidget {
|
|||||||
lineTouchData: EnergyManagementChartsHelper.lineTouchData(),
|
lineTouchData: EnergyManagementChartsHelper.lineTouchData(),
|
||||||
lineBarsData: _lineBarsData,
|
lineBarsData: _lineBarsData,
|
||||||
),
|
),
|
||||||
duration: Durations.extralong1,
|
duration: Duration.zero,
|
||||||
curve: Curves.easeIn,
|
curve: Curves.easeIn,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -43,7 +43,7 @@ class TotalEnergyConsumptionChart extends StatelessWidget {
|
|||||||
.entries
|
.entries
|
||||||
.map(
|
.map(
|
||||||
(entry) => FlSpot(
|
(entry) => FlSpot(
|
||||||
entry.key.toDouble(),
|
entry.value.date.day.toDouble(),
|
||||||
entry.value.value,
|
entry.value.value,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -28,25 +28,12 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
loadAnalyticsDevices(context, communityUuid: communityId, spaceUuid: spaceId);
|
loadAnalyticsDevices(context, communityUuid: communityId, spaceUuid: spaceId);
|
||||||
final selectedDevice = context.read<AnalyticsDevicesBloc>().state.selectedDevice;
|
final selectedDevice = context.read<AnalyticsDevicesBloc>().state.selectedDevice;
|
||||||
|
|
||||||
context.read<OccupancyBloc>().add(
|
loadOccupancyChartData(
|
||||||
LoadOccupancyEvent(
|
context,
|
||||||
GetOccupancyParam(
|
|
||||||
monthDate:
|
|
||||||
'${datePickerState.monthlyDate.year}-${datePickerState.monthlyDate.month}',
|
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceId,
|
||||||
communityUuid: communityId,
|
date: datePickerState.monthlyDate,
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
context.read<OccupancyHeatMapBloc>().add(
|
|
||||||
LoadOccupancyHeatMapEvent(
|
|
||||||
GetOccupancyHeatMapParam(
|
|
||||||
spaceUuid: spaceId,
|
|
||||||
year: datePickerState.yearlyDate,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
loadHeatMapData(context, spaceUuid: spaceId, year: datePickerState.yearlyDate);
|
||||||
|
|
||||||
if (selectedDevice case final AnalyticsDevice device) {
|
if (selectedDevice case final AnalyticsDevice device) {
|
||||||
context.read<RealtimeDeviceChangesBloc>()
|
context.read<RealtimeDeviceChangesBloc>()
|
||||||
@ -57,6 +44,33 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loadHeatMapData(
|
||||||
|
BuildContext context, {
|
||||||
|
required String spaceUuid,
|
||||||
|
required DateTime year,
|
||||||
|
}) {
|
||||||
|
context.read<OccupancyHeatMapBloc>().add(
|
||||||
|
LoadOccupancyHeatMapEvent(
|
||||||
|
GetOccupancyHeatMapParam(spaceUuid: spaceUuid, year: year),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadOccupancyChartData(
|
||||||
|
BuildContext context, {
|
||||||
|
required String spaceUuid,
|
||||||
|
required DateTime date,
|
||||||
|
}) {
|
||||||
|
context.read<OccupancyBloc>().add(
|
||||||
|
LoadOccupancyEvent(
|
||||||
|
GetOccupancyParam(
|
||||||
|
monthDate: '${date.year}-${date.month.toString().padLeft(2, '0')}',
|
||||||
|
spaceUuid: spaceUuid,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static void loadAnalyticsDevices(
|
static void loadAnalyticsDevices(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String communityUuid,
|
required String communityUuid,
|
||||||
|
@ -20,9 +20,9 @@ class AnalyticsOccupancyView extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
spacing: 32,
|
spacing: 32,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: height * 0.45, child: const OccupancyEndSideBar()),
|
SizedBox(height: height * 0.46, child: const OccupancyEndSideBar()),
|
||||||
SizedBox(height: height * 0.5, child: const OccupancyChartBox()),
|
SizedBox(height: height * 0.5, child: const OccupancyChartBox()),
|
||||||
SizedBox(height: height * 0.5, child: const Placeholder()),
|
SizedBox(height: height * 0.5, child: const OccupancyHeatMapBox()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -16,30 +16,38 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BarChart(
|
return BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
maxY: 1.0,
|
maxY: 100.0,
|
||||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||||
checkToShowHorizontalLine: (value) => true,
|
checkToShowHorizontalLine: (value) => true,
|
||||||
horizontalInterval: 0.25,
|
horizontalInterval: 20,
|
||||||
),
|
),
|
||||||
borderData: EnergyManagementChartsHelper.borderData(),
|
borderData: EnergyManagementChartsHelper.borderData(),
|
||||||
barTouchData: _barTouchData(context),
|
barTouchData: _barTouchData(context),
|
||||||
titlesData: _titlesData(context),
|
titlesData: _titlesData(context).copyWith(
|
||||||
|
leftTitles: _titlesData(context).leftTitles.copyWith(
|
||||||
|
sideTitles: _titlesData(context).leftTitles.sideTitles.copyWith(
|
||||||
|
maxIncluded: true,
|
||||||
|
minIncluded: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
barGroups: List.generate(chartData.length, (index) {
|
barGroups: List.generate(chartData.length, (index) {
|
||||||
final actual = chartData[index];
|
final actual = chartData[index];
|
||||||
|
final occupancyValue = double.parse(actual.occupancy);
|
||||||
return BarChartGroupData(
|
return BarChartGroupData(
|
||||||
x: index,
|
x: index,
|
||||||
barsSpace: 0,
|
barsSpace: 0,
|
||||||
groupVertically: true,
|
groupVertically: true,
|
||||||
barRods: [
|
barRods: [
|
||||||
BarChartRodData(
|
BarChartRodData(
|
||||||
toY: 1.0,
|
toY: 100.0,
|
||||||
fromY: double.parse(actual.occupancy) + 0.025,
|
fromY: occupancyValue == 0 ? occupancyValue : occupancyValue + 2.5,
|
||||||
color: ColorsManager.graysColor,
|
color: ColorsManager.graysColor,
|
||||||
width: _chartWidth,
|
width: _chartWidth,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
BarChartRodData(
|
BarChartRodData(
|
||||||
toY: double.parse(actual.occupancy),
|
toY: occupancyValue,
|
||||||
color: ColorsManager.vividBlue.withValues(alpha: 0.8),
|
color: ColorsManager.vividBlue.withValues(alpha: 0.8),
|
||||||
width: _chartWidth,
|
width: _chartWidth,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
@ -81,7 +89,7 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
final data = chartData;
|
final data = chartData;
|
||||||
|
|
||||||
final occupancyValue = double.parse(data[group.x.toInt()].occupancy);
|
final occupancyValue = double.parse(data[group.x.toInt()].occupancy);
|
||||||
final percentage = '${(occupancyValue * 100).toStringAsFixed(0)}%';
|
final percentage = '${(occupancyValue).toStringAsFixed(0)}%';
|
||||||
|
|
||||||
return BarTooltipItem(
|
return BarTooltipItem(
|
||||||
percentage,
|
percentage,
|
||||||
@ -101,14 +109,14 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
final leftTitles = titlesData.leftTitles.copyWith(
|
final leftTitles = titlesData.leftTitles.copyWith(
|
||||||
sideTitles: titlesData.leftTitles.sideTitles.copyWith(
|
sideTitles: titlesData.leftTitles.sideTitles.copyWith(
|
||||||
reservedSize: 70,
|
reservedSize: 70,
|
||||||
interval: 0.25,
|
interval: 20,
|
||||||
getTitlesWidget: (value, meta) => Padding(
|
getTitlesWidget: (value, meta) => Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(end: 12),
|
padding: const EdgeInsetsDirectional.only(end: 12),
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: Text(
|
child: Text(
|
||||||
'${(value * 100).toStringAsFixed(0)}%',
|
'${(value).toStringAsFixed(0)}%',
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.greyColor,
|
||||||
|
@ -47,11 +47,14 @@ class OccupancyChartBox extends StatelessWidget {
|
|||||||
context.read<AnalyticsDatePickerBloc>().add(
|
context.read<AnalyticsDatePickerBloc>().add(
|
||||||
UpdateAnalyticsDatePickerEvent(montlyDate: value),
|
UpdateAnalyticsDatePickerEvent(montlyDate: value),
|
||||||
);
|
);
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
if (spaceTreeState.selectedSpaces.isNotEmpty) {
|
||||||
|
FetchOccupancyDataHelper.loadOccupancyChartData(
|
||||||
context,
|
context,
|
||||||
communityId: spaceTreeState.selectedCommunities.firstOrNull ?? '',
|
spaceUuid:
|
||||||
spaceId: spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
||||||
|
date: value,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectedDate: context
|
selectedDate: context
|
||||||
.watch<AnalyticsDatePickerBloc>()
|
.watch<AnalyticsDatePickerBloc>()
|
||||||
|
@ -47,12 +47,14 @@ class OccupancyHeatMapBox extends StatelessWidget {
|
|||||||
context.read<AnalyticsDatePickerBloc>().add(
|
context.read<AnalyticsDatePickerBloc>().add(
|
||||||
UpdateAnalyticsDatePickerEvent(yearlyDate: value),
|
UpdateAnalyticsDatePickerEvent(yearlyDate: value),
|
||||||
);
|
);
|
||||||
FetchOccupancyDataHelper.loadOccupancyData(
|
if (spaceTreeState.selectedSpaces.isNotEmpty) {
|
||||||
|
FetchOccupancyDataHelper.loadHeatMapData(
|
||||||
context,
|
context,
|
||||||
communityId:
|
spaceUuid:
|
||||||
spaceTreeState.selectedCommunities.firstOrNull ?? '',
|
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
||||||
spaceId: spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
year: value,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
datePickerType: DatePickerType.year,
|
datePickerType: DatePickerType.year,
|
||||||
selectedDate: context
|
selectedDate: context
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
class GetEnergyConsumptionByPhasesParam extends Equatable {
|
class GetEnergyConsumptionByPhasesParam extends Equatable {
|
||||||
final DateTime? startDate;
|
final String powerClampUuid;
|
||||||
final DateTime? endDate;
|
final DateTime? date;
|
||||||
final String? spaceId;
|
|
||||||
|
|
||||||
const GetEnergyConsumptionByPhasesParam({
|
const GetEnergyConsumptionByPhasesParam({
|
||||||
this.startDate,
|
required this.powerClampUuid,
|
||||||
this.endDate,
|
this.date,
|
||||||
this.spaceId,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'startDate': startDate?.toIso8601String(),
|
'monthDate': '${date?.year}-${date?.month.toString().padLeft(2, '0')}',
|
||||||
'endDate': endDate?.toIso8601String(),
|
|
||||||
'spaceId': spaceId,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [startDate, endDate, spaceId];
|
List<Object?> get props => [powerClampUuid, date];
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
class GetOccupancyParam {
|
class GetOccupancyParam {
|
||||||
final String monthDate;
|
final String monthDate;
|
||||||
final String? spaceUuid;
|
final String? spaceUuid;
|
||||||
final String communityUuid;
|
|
||||||
|
|
||||||
GetOccupancyParam({
|
GetOccupancyParam({
|
||||||
required this.monthDate,
|
required this.monthDate,
|
||||||
required this.spaceUuid,
|
required this.spaceUuid,
|
||||||
required this.communityUuid,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() => {'monthDate': monthDate};
|
||||||
return {
|
|
||||||
'monthDate': monthDate,
|
|
||||||
'spaceUuid': spaceUuid,
|
|
||||||
'communityUuid': communityUuid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService
|
|||||||
path:
|
path:
|
||||||
'/projects/$projectUuid/communities/${param.communityUuid}/spaces/${param.spaceUuid}/devices',
|
'/projects/$projectUuid/communities/${param.communityUuid}/spaces/${param.spaceUuid}/devices',
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'requestType': param.requestType.name,
|
|
||||||
'communityUuid': param.communityUuid,
|
'communityUuid': param.communityUuid,
|
||||||
'spaceUuid': param.spaceUuid,
|
'spaceUuid': param.spaceUuid,
|
||||||
'productType': param.deviceTypes.first,
|
'productType': param.deviceTypes.first,
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/energy_consumption_by_phases_service.dart';
|
|
||||||
|
|
||||||
class FakeEnergyConsumptionByPhasesService
|
|
||||||
implements EnergyConsumptionByPhasesService {
|
|
||||||
@override
|
|
||||||
Future<List<PhasesEnergyConsumption>> load(
|
|
||||||
GetEnergyConsumptionByPhasesParam param,
|
|
||||||
) {
|
|
||||||
return Future.delayed(
|
|
||||||
const Duration(milliseconds: 500),
|
|
||||||
() => const [
|
|
||||||
PhasesEnergyConsumption(month: 1, phaseA: 200, phaseB: 300, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 2, phaseA: 300, phaseB: 400, phaseC: 500),
|
|
||||||
PhasesEnergyConsumption(month: 3, phaseA: 400, phaseB: 500, phaseC: 600),
|
|
||||||
PhasesEnergyConsumption(month: 4, phaseA: 100, phaseB: 100, phaseC: 100),
|
|
||||||
PhasesEnergyConsumption(month: 5, phaseA: 300, phaseB: 400, phaseC: 500),
|
|
||||||
PhasesEnergyConsumption(month: 6, phaseA: 300, phaseB: 100, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 7, phaseA: 300, phaseB: 100, phaseC: 400),
|
|
||||||
PhasesEnergyConsumption(month: 8, phaseA: 500, phaseB: 100, phaseC: 100),
|
|
||||||
PhasesEnergyConsumption(month: 9, phaseA: 500, phaseB: 100, phaseC: 200),
|
|
||||||
PhasesEnergyConsumption(month: 10, phaseA: 100, phaseB: 50, phaseC: 50),
|
|
||||||
PhasesEnergyConsumption(month: 11, phaseA: 600, phaseB: 750, phaseC: 130),
|
|
||||||
PhasesEnergyConsumption(month: 12, phaseA: 100, phaseB: 100, phaseC: 100),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,8 +15,9 @@ final class RemoteEnergyConsumptionByPhasesService
|
|||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
path: 'endpoint',
|
path: '/power-clamp/${param.powerClampUuid}/historical',
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
|
queryParameters: param.toJson(),
|
||||||
expectedResponseModel: (data) {
|
expectedResponseModel: (data) {
|
||||||
final json = data as Map<String, dynamic>? ?? {};
|
final json = data as Map<String, dynamic>? ?? {};
|
||||||
final mappedData = json['data'] as List<dynamic>? ?? [];
|
final mappedData = json['data'] as List<dynamic>? ?? [];
|
||||||
@ -28,7 +29,7 @@ final class RemoteEnergyConsumptionByPhasesService
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load energy consumption per device: $e');
|
throw Exception('Failed to load energy consumption per phase: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import 'dart:math' as math show Random;
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/energy_consumption_per_device_service.dart';
|
|
||||||
|
|
||||||
class FakeEnergyConsumptionPerDeviceService
|
|
||||||
implements EnergyConsumptionPerDeviceService {
|
|
||||||
@override
|
|
||||||
Future<List<DeviceEnergyDataModel>> load(
|
|
||||||
GetEnergyConsumptionPerDeviceParam param,
|
|
||||||
) {
|
|
||||||
final random = math.Random();
|
|
||||||
return Future.delayed(const Duration(milliseconds: 500), () {
|
|
||||||
return [
|
|
||||||
(Colors.redAccent, 1),
|
|
||||||
(Colors.lightBlueAccent, 2),
|
|
||||||
(Colors.purpleAccent, 3),
|
|
||||||
].map((e) {
|
|
||||||
final (color, index) = e;
|
|
||||||
return DeviceEnergyDataModel(
|
|
||||||
color: color,
|
|
||||||
energy: List.generate(30, (i) => i)
|
|
||||||
.map(
|
|
||||||
(index) => EnergyDataModel(
|
|
||||||
date: DateTime(2025, 1, index + 1),
|
|
||||||
value: random.nextInt(100) + (index * 100),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
deviceName: 'Device $index',
|
|
||||||
deviceId: 'device_$index',
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -34,10 +34,7 @@ abstract final class _EnergyConsumptionPerDeviceMapper {
|
|||||||
static List<DeviceEnergyDataModel> map(dynamic data) {
|
static List<DeviceEnergyDataModel> map(dynamic data) {
|
||||||
final json = data as Map<String, dynamic>? ?? {};
|
final json = data as Map<String, dynamic>? ?? {};
|
||||||
final mappedData = json['data'] as List<dynamic>? ?? [];
|
final mappedData = json['data'] as List<dynamic>? ?? [];
|
||||||
return mappedData.where((e) {
|
return mappedData.map((e) {
|
||||||
final deviceData = (e as Map<String, dynamic>)['data'] as List<dynamic>? ?? [];
|
|
||||||
return deviceData.isNotEmpty;
|
|
||||||
}).map((e) {
|
|
||||||
final deviceData = e as Map<String, dynamic>;
|
final deviceData = e as Map<String, dynamic>;
|
||||||
final energyData = deviceData['data'] as List<dynamic>;
|
final energyData = deviceData['data'] as List<dynamic>;
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
|
||||||
|
|
||||||
class FakeOccupacyService implements OccupacyService {
|
|
||||||
@override
|
|
||||||
Future<List<Occupacy>> load(GetOccupancyParam param) async {
|
|
||||||
return await Future.delayed(
|
|
||||||
const Duration(seconds: 1),
|
|
||||||
() => List.generate(
|
|
||||||
30,
|
|
||||||
(index) => Occupacy(
|
|
||||||
date: DateTime.now().subtract(Duration(days: index)).toString(),
|
|
||||||
occupancy: ((index / 100)).toString(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,32 @@
|
|||||||
|
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
|
final class RemoteOccupancyService implements OccupacyService {
|
||||||
|
const RemoteOccupancyService(this._httpService);
|
||||||
|
|
||||||
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<Occupacy>> load(GetOccupancyParam param) async {
|
||||||
|
try {
|
||||||
|
final response = await _httpService.get(
|
||||||
|
path: '/occupancy/duration/space/${param.spaceUuid}',
|
||||||
|
showServerMessage: true,
|
||||||
|
queryParameters: param.toJson(),
|
||||||
|
expectedResponseModel: (data) {
|
||||||
|
final json = data as Map<String, dynamic>? ?? {};
|
||||||
|
final mappedData = json['data'] as List<dynamic>? ?? [];
|
||||||
|
return mappedData.map((e) {
|
||||||
|
final jsonData = e as Map<String, dynamic>;
|
||||||
|
return Occupacy.fromJson(jsonData);
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to load energy consumption per phase: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -63,7 +63,8 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _compareListOfLists(List<List<dynamic>> oldList, List<List<dynamic>> newList) {
|
bool _compareListOfLists(
|
||||||
|
List<List<dynamic>> oldList, List<List<dynamic>> newList) {
|
||||||
// Check if the old and new lists are the same
|
// Check if the old and new lists are the same
|
||||||
if (oldList.length != newList.length) return false;
|
if (oldList.length != newList.length) return false;
|
||||||
|
|
||||||
@ -111,8 +112,8 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
trackVisibility: true,
|
trackVisibility: true,
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
controller: _horizontalScrollController,
|
controller: _horizontalScrollController,
|
||||||
thumbVisibility: false,
|
thumbVisibility: true,
|
||||||
trackVisibility: false,
|
trackVisibility: true,
|
||||||
notificationPredicate: (notif) => notif.depth == 1,
|
notificationPredicate: (notif) => notif.depth == 1,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _verticalScrollController,
|
controller: _verticalScrollController,
|
||||||
@ -132,14 +133,18 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||||
...List.generate(widget.headers.length, (index) {
|
...List.generate(widget.headers.length, (index) {
|
||||||
return _buildTableHeaderCell(widget.headers[index], index);
|
return _buildTableHeaderCell(
|
||||||
|
widget.headers[index], index);
|
||||||
})
|
})
|
||||||
//...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
//...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
widget.isEmpty
|
widget.isEmpty
|
||||||
? Column(
|
? SizedBox(
|
||||||
|
height: widget.size.height * 0.5,
|
||||||
|
width: widget.size.width,
|
||||||
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@ -153,25 +158,35 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
height: 15,
|
height: 15,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
|
widget.tableName == 'AccessManagement'
|
||||||
|
? 'No Password '
|
||||||
|
: 'No Devices',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(color: ColorsManager.grayColor),
|
.copyWith(
|
||||||
|
color:
|
||||||
|
ColorsManager.grayColor),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
children: List.generate(widget.data.length, (index) {
|
children:
|
||||||
|
List.generate(widget.data.length, (index) {
|
||||||
final row = widget.data[index];
|
final row = widget.data[index];
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.08),
|
if (widget.withCheckBox)
|
||||||
...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.08)),
|
_buildRowCheckbox(
|
||||||
|
index, widget.size.height * 0.08),
|
||||||
|
...row.map((cell) => _buildTableCell(
|
||||||
|
cell.toString(),
|
||||||
|
widget.size.height * 0.08)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
@ -196,7 +211,9 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
),
|
),
|
||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
value: _selectAll,
|
value: _selectAll,
|
||||||
onChanged: widget.withSelectAll && widget.data.isNotEmpty ? _toggleSelectAll : null,
|
onChanged: widget.withSelectAll && widget.data.isNotEmpty
|
||||||
|
? _toggleSelectAll
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -238,7 +255,9 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
constraints: const BoxConstraints.expand(height: 40),
|
constraints: const BoxConstraints.expand(height: 40),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: index == widget.headers.length - 1 ? 12 : 8.0, vertical: 4),
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: index == widget.headers.length - 1 ? 12 : 8.0,
|
||||||
|
vertical: 4),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: context.textTheme.titleSmall!.copyWith(
|
style: context.textTheme.titleSmall!.copyWith(
|
||||||
|
@ -97,7 +97,8 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
|||||||
children: [
|
children: [
|
||||||
_buildInfoRow('Space Name:',
|
_buildInfoRow('Space Name:',
|
||||||
device.spaces?.firstOrNull?.spaceName ?? 'N/A'),
|
device.spaces?.firstOrNull?.spaceName ?? 'N/A'),
|
||||||
_buildInfoRow('Room:', device.subspace?.subspaceName ?? 'N/A'),
|
_buildInfoRow(
|
||||||
|
'Sub space:', device.subspace?.subspaceName ?? 'N/A'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TableRow(
|
TableRow(
|
||||||
|
@ -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,7 +77,8 @@ 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,
|
||||||
@ -88,12 +90,7 @@ class ACHelper {
|
|||||||
'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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,14 @@ class CpsFunctionsList extends StatelessWidget {
|
|||||||
return RoutineDialogFunctionListTile(
|
return RoutineDialogFunctionListTile(
|
||||||
iconPath: function.icon,
|
iconPath: function.icon,
|
||||||
operationName: function.operationName,
|
operationName: function.operationName,
|
||||||
onTap: () => RoutineTapFunctionHelper.onTapFunction(
|
onTap: () {
|
||||||
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
context,
|
context,
|
||||||
|
step: function.step,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
functionOperationName: function.operationName,
|
functionOperationName: function.operationName,
|
||||||
functionValueDescription: selectedFunctionData?.valueDescription,
|
functionValueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
deviceUuid: device?.uuid,
|
deviceUuid: device?.uuid,
|
||||||
codesToAddIntoFunctionsWithDefaultValue: [
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
'static_max_dis',
|
'static_max_dis',
|
||||||
@ -56,8 +59,8 @@ class CpsFunctionsList extends StatelessWidget {
|
|||||||
'presence_range',
|
'presence_range',
|
||||||
if (dialogType == "IF") 'sensitivity',
|
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';
|
||||||
|
|
||||||
@ -24,19 +25,17 @@ class FlushOperationalValuesList extends StatelessWidget {
|
|||||||
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',
|
||||||
@ -110,12 +111,14 @@ class OneGangSwitchHelper {
|
|||||||
child: _buildValueSelector(
|
child: _buildValueSelector(
|
||||||
context: context,
|
context: context,
|
||||||
selectedFunction: selectedFunction,
|
selectedFunction: selectedFunction,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData:
|
||||||
|
selectedFunctionData,
|
||||||
acFunctions: oneGangFunctions,
|
acFunctions: oneGangFunctions,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: selectedOperationName ?? '',
|
operationName:
|
||||||
|
selectedOperationName ?? '',
|
||||||
removeComparetors: removeComparetors,
|
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]
|
||||||
],
|
: [],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -111,12 +112,14 @@ class ThreeGangSwitchHelper {
|
|||||||
child: _buildValueSelector(
|
child: _buildValueSelector(
|
||||||
context: context,
|
context: context,
|
||||||
selectedFunction: selectedFunction,
|
selectedFunction: selectedFunction,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData:
|
||||||
|
selectedFunctionData,
|
||||||
switchFunctions: switchFunctions,
|
switchFunctions: switchFunctions,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: selectedOperationName ?? '',
|
operationName:
|
||||||
|
selectedOperationName ?? '',
|
||||||
removeComparetors: removeComparetors,
|
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,6 +168,7 @@ 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' ||
|
||||||
@ -187,10 +183,11 @@ class ThreeGangSwitchHelper {
|
|||||||
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,8 +175,10 @@ 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,
|
||||||
@ -184,10 +189,11 @@ class TwoGangSwitchHelper {
|
|||||||
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(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty)
|
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('Failed Devises'),
|
const Text('Failed Devices'),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 50,
|
height: 50,
|
||||||
@ -63,7 +63,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty)
|
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('Success Devises'),
|
const Text('Success Devices'),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 50,
|
height: 50,
|
||||||
|
@ -2,6 +2,7 @@ class Assets {
|
|||||||
Assets._();
|
Assets._();
|
||||||
static const String background = "assets/images/Background.png";
|
static const String background = "assets/images/Background.png";
|
||||||
static const String webBackground = "assets/images/web_Background.svg";
|
static const String webBackground = "assets/images/web_Background.svg";
|
||||||
|
static const String webBackgroundPng = "assets/images/web_Background.png";
|
||||||
static const String blackLogo = "assets/images/black-logo.png";
|
static const String blackLogo = "assets/images/black-logo.png";
|
||||||
static const String logo = "assets/images/Logo.svg";
|
static const String logo = "assets/images/Logo.svg";
|
||||||
static const String logoHorizontal = "assets/images/logo_horizontal.png";
|
static const String logoHorizontal = "assets/images/logo_horizontal.png";
|
||||||
|
@ -41,7 +41,16 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
|||||||
_isDropdownOpen = false;
|
_isDropdownOpen = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Transform.rotate(
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
if (widget.user != null)
|
||||||
|
Text(
|
||||||
|
'${widget.user!.firstName} ${widget.user!.lastName}',
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Transform.rotate(
|
||||||
angle: _isDropdownOpen ? -1.5708 : 1.5708,
|
angle: _isDropdownOpen ? -1.5708 : 1.5708,
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.arrow_forward_ios,
|
Icons.arrow_forward_ios,
|
||||||
@ -49,6 +58,8 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
|||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -92,13 +92,6 @@ class DesktopAppBar extends StatelessWidget {
|
|||||||
if (rightBody != null) rightBody!,
|
if (rightBody != null) rightBody!,
|
||||||
const SizedBox(width: 24),
|
const SizedBox(width: 24),
|
||||||
_UserAvatar(),
|
_UserAvatar(),
|
||||||
const SizedBox(width: 12),
|
|
||||||
if (user != null)
|
|
||||||
Text(
|
|
||||||
'${user.firstName} ${user.lastName}',
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
UserDropdownMenu(user: user),
|
UserDropdownMenu(user: user),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -146,14 +139,6 @@ class TabletAppBar extends StatelessWidget {
|
|||||||
if (rightBody != null) rightBody!,
|
if (rightBody != null) rightBody!,
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
_UserAvatar(),
|
_UserAvatar(),
|
||||||
if (user != null) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
'${user.firstName} ${user.lastName}',
|
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 14),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
UserDropdownMenu(user: user),
|
UserDropdownMenu(user: user),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -215,14 +200,6 @@ class MobileAppBar extends StatelessWidget {
|
|||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
_UserAvatar(),
|
_UserAvatar(),
|
||||||
if (user != null) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
'${user.firstName} ${user.lastName}',
|
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 14),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
UserDropdownMenu(user: user),
|
UserDropdownMenu(user: user),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_app_bar.dart';
|
import 'package:syncrow_web/web_layout/web_app_bar.dart';
|
||||||
|
|
||||||
import 'menu_sidebar.dart';
|
import 'menu_sidebar.dart';
|
||||||
|
|
||||||
class WebScaffold extends StatelessWidget with HelperResponsiveLayout {
|
class WebScaffold extends StatelessWidget with HelperResponsiveLayout {
|
||||||
@ -28,14 +28,11 @@ class WebScaffold extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.sizeOf(context).width,
|
width: MediaQuery.sizeOf(context).width,
|
||||||
height: MediaQuery.sizeOf(context).height,
|
height: MediaQuery.sizeOf(context).height,
|
||||||
child: SvgPicture.asset(
|
child: Image.asset(
|
||||||
Assets.webBackground,
|
Assets.webBackgroundPng,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
|
||||||
color: Colors.white.withOpacity(0.7),
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
|
906
pubspec.lock
906
pubspec.lock
@ -1,906 +0,0 @@
|
|||||||
# Generated by pub
|
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
||||||
packages:
|
|
||||||
_flutterfire_internals:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: _flutterfire_internals
|
|
||||||
sha256: e051259913915ea5bc8fe18664596bea08592fd123930605d562969cd7315fcd
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.51"
|
|
||||||
args:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: args
|
|
||||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: async
|
|
||||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.11.0"
|
|
||||||
bloc:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: bloc
|
|
||||||
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "8.1.4"
|
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.1"
|
|
||||||
characters:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: characters
|
|
||||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0"
|
|
||||||
clock:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: clock
|
|
||||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: collection
|
|
||||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.19.0"
|
|
||||||
crypto:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: crypto
|
|
||||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.6"
|
|
||||||
csslib:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: csslib
|
|
||||||
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.17.3"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.8"
|
|
||||||
data_table_2:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: data_table_2
|
|
||||||
sha256: f02ec9b24f44420816a87370ff4f4e533e15b274f6267e4c9a88a585ad1a0473
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.15"
|
|
||||||
dio:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: dio
|
|
||||||
sha256: e17f6b3097b8c51b72c74c9f071a605c47bcc8893839bd66732457a5ebe73714
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.5.0+1"
|
|
||||||
dio_web_adapter:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: dio_web_adapter
|
|
||||||
sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1"
|
|
||||||
dropdown_button2:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: dropdown_button2
|
|
||||||
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.9"
|
|
||||||
dropdown_search:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: dropdown_search
|
|
||||||
sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.0.6"
|
|
||||||
equatable:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: equatable
|
|
||||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.5"
|
|
||||||
fake_async:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fake_async
|
|
||||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.1"
|
|
||||||
ffi:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: ffi
|
|
||||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.2"
|
|
||||||
file:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: file
|
|
||||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "7.0.0"
|
|
||||||
firebase_analytics:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: firebase_analytics
|
|
||||||
sha256: "47428047a0778f72af53a3c7cb5d556e1cb25e2327cc8aa40d544971dc6245b2"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "11.4.2"
|
|
||||||
firebase_analytics_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_analytics_platform_interface
|
|
||||||
sha256: "1076f4b041f76143e14878c70f0758f17fe5910c0cd992db9e93bd3c3584512b"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.3.2"
|
|
||||||
firebase_analytics_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_analytics_web
|
|
||||||
sha256: "8f6dd64ea6d28b7f5b9e739d183a9e1c7f17027794a3e9aba1879621d42426ef"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.5.10+8"
|
|
||||||
firebase_core:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: firebase_core
|
|
||||||
sha256: "93dc4dd12f9b02c5767f235307f609e61ed9211047132d07f9e02c668f0bfc33"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.11.0"
|
|
||||||
firebase_core_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_core_platform_interface
|
|
||||||
sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.4.0"
|
|
||||||
firebase_core_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_core_web
|
|
||||||
sha256: "0e13c80f0de8acaa5d0519cbe23c8b4cc138a2d5d508b5755c861bdfc9762678"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.20.0"
|
|
||||||
firebase_crashlytics:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: firebase_crashlytics
|
|
||||||
sha256: "6273ed71bcd8a6fb4d0ca13d3abddbb3301796807efaad8782b5f90156f26f03"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.3.2"
|
|
||||||
firebase_crashlytics_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_crashlytics_platform_interface
|
|
||||||
sha256: "94f3986e1a10e5a883f2ad5e3d719aef98a8a0f9a49357f6e45b7d3696ea6a97"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.8.2"
|
|
||||||
firebase_database:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: firebase_database
|
|
||||||
sha256: cd2354dfef68e52c0713b5efbb7f4e10dfc2aff2f945c7bc8db34d1934170627
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "11.3.2"
|
|
||||||
firebase_database_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_database_platform_interface
|
|
||||||
sha256: d430983f4d877c9f72f88b3d715cca9a50021dd7ccd8e3ae6fb79603853317de
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.6+2"
|
|
||||||
firebase_database_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: firebase_database_web
|
|
||||||
sha256: f64edae62c5beaa08e9e611a0736d64ab11a812983a0aa132695d2d191311ea7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.6+8"
|
|
||||||
fixnum:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fixnum
|
|
||||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
fl_chart:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: fl_chart
|
|
||||||
sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.69.0"
|
|
||||||
flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_bloc:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_bloc
|
|
||||||
sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "8.1.5"
|
|
||||||
flutter_dotenv:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_dotenv
|
|
||||||
sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.1.0"
|
|
||||||
flutter_html:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_html
|
|
||||||
sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.0-beta.2"
|
|
||||||
flutter_lints:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: flutter_lints
|
|
||||||
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.2"
|
|
||||||
flutter_secure_storage:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage
|
|
||||||
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "9.2.2"
|
|
||||||
flutter_secure_storage_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_linux
|
|
||||||
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
flutter_secure_storage_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_macos
|
|
||||||
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.2"
|
|
||||||
flutter_secure_storage_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_platform_interface
|
|
||||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.2"
|
|
||||||
flutter_secure_storage_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_web
|
|
||||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
flutter_secure_storage_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_windows
|
|
||||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.2"
|
|
||||||
flutter_svg:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_svg
|
|
||||||
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.10+1"
|
|
||||||
flutter_test:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_web_plugins:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
get_it:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: get_it
|
|
||||||
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "7.7.0"
|
|
||||||
go_router:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: go_router
|
|
||||||
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "14.2.7"
|
|
||||||
graphview:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: graphview
|
|
||||||
sha256: bdba183583b23c30c71edea09ad5f0beef612572d3e39e855467a925bd08392f
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
html:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: html
|
|
||||||
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.15.4"
|
|
||||||
http:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http
|
|
||||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.2"
|
|
||||||
http_parser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http_parser
|
|
||||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.0.2"
|
|
||||||
intl:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: intl
|
|
||||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.19.0"
|
|
||||||
intl_phone_field:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: intl_phone_field
|
|
||||||
sha256: "73819d3dfcb68d2c85663606f6842597c3ddf6688ac777f051b17814fe767bbf"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.0"
|
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.7"
|
|
||||||
leak_tracker:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker
|
|
||||||
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "10.0.7"
|
|
||||||
leak_tracker_flutter_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_flutter_testing
|
|
||||||
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.8"
|
|
||||||
leak_tracker_testing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: leak_tracker_testing
|
|
||||||
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.1"
|
|
||||||
lints:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: lints
|
|
||||||
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.0.0"
|
|
||||||
list_counter:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: list_counter
|
|
||||||
sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.2"
|
|
||||||
logging:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: logging
|
|
||||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
matcher:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: matcher
|
|
||||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.12.16+1"
|
|
||||||
material_color_utilities:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: material_color_utilities
|
|
||||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.11.1"
|
|
||||||
meta:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: meta
|
|
||||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.15.0"
|
|
||||||
nested:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nested
|
|
||||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
number_pagination:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: number_pagination
|
|
||||||
sha256: "75d3a28616196e7c8df431d0fb7c48e811e462155f4cf3b5b4167b3408421327"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.6"
|
|
||||||
path:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path
|
|
||||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.9.0"
|
|
||||||
path_parsing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_parsing
|
|
||||||
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1"
|
|
||||||
path_provider:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider
|
|
||||||
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.3"
|
|
||||||
path_provider_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_android
|
|
||||||
sha256: e84c8a53fe1510ef4582f118c7b4bdf15b03002b51d7c2b66983c65843d61193
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.8"
|
|
||||||
path_provider_foundation:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_foundation
|
|
||||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
path_provider_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_linux
|
|
||||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.1"
|
|
||||||
path_provider_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_platform_interface
|
|
||||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.2"
|
|
||||||
path_provider_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_provider_windows
|
|
||||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.0"
|
|
||||||
petitparser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: petitparser
|
|
||||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.0.2"
|
|
||||||
platform:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: platform
|
|
||||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.5"
|
|
||||||
plugin_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: plugin_platform_interface
|
|
||||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.8"
|
|
||||||
provider:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: provider
|
|
||||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.1.2"
|
|
||||||
shared_preferences:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: shared_preferences
|
|
||||||
sha256: c3f888ba2d659f3e75f4686112cc1e71f46177f74452d40d8307edc332296ead
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.0"
|
|
||||||
shared_preferences_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_android
|
|
||||||
sha256: "041be4d9d2dc6079cf342bc8b761b03787e3b71192d658220a56cac9c04a0294"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.0"
|
|
||||||
shared_preferences_foundation:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_foundation
|
|
||||||
sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
shared_preferences_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_linux
|
|
||||||
sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
shared_preferences_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_platform_interface
|
|
||||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.1"
|
|
||||||
shared_preferences_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_web
|
|
||||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.2"
|
|
||||||
shared_preferences_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shared_preferences_windows
|
|
||||||
sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
sky_engine:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
source_span:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_span
|
|
||||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.10.0"
|
|
||||||
sprintf:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: sprintf
|
|
||||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "7.0.0"
|
|
||||||
stack_trace:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stack_trace
|
|
||||||
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.12.0"
|
|
||||||
stream_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_channel
|
|
||||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.2"
|
|
||||||
string_scanner:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: string_scanner
|
|
||||||
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0"
|
|
||||||
term_glyph:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: term_glyph
|
|
||||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.3"
|
|
||||||
time_picker_spinner:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: time_picker_spinner
|
|
||||||
sha256: "53d824801d108890d22756501e7ade9db48b53dac1ec41580499dd4ebd128e3c"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
typed_data:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: typed_data
|
|
||||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.2"
|
|
||||||
url_launcher:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: url_launcher
|
|
||||||
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.3.1"
|
|
||||||
url_launcher_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_android
|
|
||||||
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.3.14"
|
|
||||||
url_launcher_ios:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_ios
|
|
||||||
sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.3.2"
|
|
||||||
url_launcher_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_linux
|
|
||||||
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.1"
|
|
||||||
url_launcher_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_macos
|
|
||||||
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.2"
|
|
||||||
url_launcher_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_platform_interface
|
|
||||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.2"
|
|
||||||
url_launcher_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_web
|
|
||||||
sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.4.0"
|
|
||||||
url_launcher_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: url_launcher_windows
|
|
||||||
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.4"
|
|
||||||
uuid:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: uuid
|
|
||||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.5.1"
|
|
||||||
vector_graphics:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics
|
|
||||||
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_graphics_codec:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_codec
|
|
||||||
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_graphics_compiler:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_compiler
|
|
||||||
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_math:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_math
|
|
||||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.4"
|
|
||||||
vm_service:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vm_service
|
|
||||||
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "14.3.0"
|
|
||||||
web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: web
|
|
||||||
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
win32:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: win32
|
|
||||||
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.5.1"
|
|
||||||
xdg_directories:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xdg_directories
|
|
||||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.4"
|
|
||||||
xml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xml
|
|
||||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.5.0"
|
|
||||||
sdks:
|
|
||||||
dart: ">=3.6.0 <4.0.0"
|
|
||||||
flutter: ">=3.27.0"
|
|
Reference in New Issue
Block a user