mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-16 10:06:19 +00:00
Compare commits
22 Commits
syncrow_an
...
SP-1591-FE
Author | SHA1 | Date | |
---|---|---|---|
5b13962d41 | |||
8c53d5322a | |||
af4d37939b | |||
d43c1847ff | |||
4c5b390887 | |||
5eeac01666 | |||
717d698378 | |||
9adbbb9a2d | |||
e792dbd72f | |||
9eaa367d32 | |||
d2eea33714 | |||
24372a0618 | |||
8988947694 | |||
ef875ef7dc | |||
5a61647fe4 | |||
568b6be354 | |||
c508d016c2 | |||
e0ad7855d3 | |||
ecf588cfcb | |||
c9d15d102b | |||
02b07cfdb6 | |||
0a94557eee |
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,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,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class OccupancyDataLoadingStrategy implements AnalyticsDataLoadingStrategy {
|
|||||||
CommunityModel community,
|
CommunityModel community,
|
||||||
SpaceModel child,
|
SpaceModel child,
|
||||||
) {
|
) {
|
||||||
onSpaceSelected(context, community, child);
|
if (child.children.isNotEmpty) return onSpaceSelected(context, community, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -17,7 +17,7 @@ import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_en
|
|||||||
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/remote_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';
|
||||||
@ -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),
|
||||||
|
@ -30,7 +30,6 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
|
|
||||||
loadOccupancyChartData(
|
loadOccupancyChartData(
|
||||||
context,
|
context,
|
||||||
communityUuid: communityId,
|
|
||||||
spaceUuid: spaceId,
|
spaceUuid: spaceId,
|
||||||
date: datePickerState.monthlyDate,
|
date: datePickerState.monthlyDate,
|
||||||
);
|
);
|
||||||
@ -59,16 +58,14 @@ abstract final class FetchOccupancyDataHelper {
|
|||||||
|
|
||||||
static void loadOccupancyChartData(
|
static void loadOccupancyChartData(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String communityUuid,
|
|
||||||
required String spaceUuid,
|
required String spaceUuid,
|
||||||
required DateTime date,
|
required DateTime date,
|
||||||
}) {
|
}) {
|
||||||
context.read<OccupancyBloc>().add(
|
context.read<OccupancyBloc>().add(
|
||||||
LoadOccupancyEvent(
|
LoadOccupancyEvent(
|
||||||
GetOccupancyParam(
|
GetOccupancyParam(
|
||||||
monthDate: '${date.year}-${date.month}',
|
monthDate: '${date.year}-${date.month.toString().padLeft(2, '0')}',
|
||||||
spaceUuid: spaceUuid,
|
spaceUuid: spaceUuid,
|
||||||
communityUuid: communityUuid,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -16,10 +16,10 @@ 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.2,
|
horizontalInterval: 20,
|
||||||
),
|
),
|
||||||
borderData: EnergyManagementChartsHelper.borderData(),
|
borderData: EnergyManagementChartsHelper.borderData(),
|
||||||
barTouchData: _barTouchData(context),
|
barTouchData: _barTouchData(context),
|
||||||
@ -33,20 +33,21 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
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),
|
||||||
@ -88,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,
|
||||||
@ -108,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.2,
|
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,
|
||||||
|
@ -50,9 +50,6 @@ class OccupancyChartBox extends StatelessWidget {
|
|||||||
if (spaceTreeState.selectedSpaces.isNotEmpty) {
|
if (spaceTreeState.selectedSpaces.isNotEmpty) {
|
||||||
FetchOccupancyDataHelper.loadOccupancyChartData(
|
FetchOccupancyDataHelper.loadOccupancyChartData(
|
||||||
context,
|
context,
|
||||||
communityUuid:
|
|
||||||
spaceTreeState.selectedCommunities.firstOrNull ??
|
|
||||||
'',
|
|
||||||
spaceUuid:
|
spaceUuid:
|
||||||
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
spaceTreeState.selectedSpaces.firstOrNull ?? '',
|
||||||
date: value,
|
date: value,
|
||||||
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -112,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,
|
||||||
|
@ -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";
|
||||||
|
@ -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: [
|
||||||
|
Reference in New Issue
Block a user