diff --git a/assets/icons/frequency_icon.svg b/assets/icons/frequency_icon.svg new file mode 100644 index 0000000..d093af3 --- /dev/null +++ b/assets/icons/frequency_icon.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/power_active_icon.svg b/assets/icons/power_active_icon.svg new file mode 100644 index 0000000..28b1412 --- /dev/null +++ b/assets/icons/power_active_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/volt_meter_icon.svg b/assets/icons/volt_meter_icon.svg new file mode 100644 index 0000000..97b9037 --- /dev/null +++ b/assets/icons/volt_meter_icon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/features/devices/view/widgets/power_clamp/power_chart.dart b/lib/features/devices/view/widgets/power_clamp/power_chart.dart new file mode 100644 index 0000000..673ef1a --- /dev/null +++ b/lib/features/devices/view/widgets/power_clamp/power_chart.dart @@ -0,0 +1,192 @@ +import 'package:flutter/material.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class EnergyConsumptionPage extends StatefulWidget { + final List chartData; + final double totalConsumption; + final String date; + + EnergyConsumptionPage({ + required this.chartData, + required this.totalConsumption, + required this.date, + }); + + @override + _EnergyConsumptionPageState createState() => _EnergyConsumptionPageState(); +} + +class _EnergyConsumptionPageState extends State { + late List _chartData; + + @override + void initState() { + // Use the provided data + _chartData = widget.chartData; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(top: 19), + child: LineChart( + LineChartData( + lineTouchData: LineTouchData( + handleBuiltInTouches: true, + touchSpotThreshold: 2, + getTouchLineEnd: (barData, spotIndex) { + return 10.0; + }, + touchTooltipData: LineTouchTooltipData( + getTooltipColor: (touchTooltipItem) => Colors.white, + tooltipRoundedRadius: 10.0, + tooltipPadding: const EdgeInsets.all(8.0), + tooltipBorder: BorderSide(color: Colors.grey, width: 1), + getTooltipItems: (List touchedSpots) { + return touchedSpots.map((spot) { + return LineTooltipItem( + '${spot.x},\n ${spot.y.toStringAsFixed(2)} kWh', + const TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ); + }).toList(); + }, + )), + titlesData: FlTitlesData( + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + getTitlesWidget: (value, meta) { + int index = value.toInt(); + if (index >= 0 && index < _chartData.length) { + return Text(_chartData[index].time, + style: TextStyle(fontSize: 10)); + } + return const SizedBox.shrink(); + }, + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + ), + ), + rightTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: false, + reservedSize: 40, + getTitlesWidget: (value, meta) { + return Text(value.toStringAsFixed(1) + ' kWh', + style: TextStyle(fontSize: 10)); + }, + ), + ), + topTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 70, + getTitlesWidget: (value, meta) { + int index = value.toInt(); + if (index >= 0 && index < _chartData.length) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: RotatedBox( + quarterTurns: -1, + child: Text(_chartData[index].time, + style: TextStyle(fontSize: 10)), + ), + ); + } + return const SizedBox.shrink(); + }, + ), + ), + ), + gridData: FlGridData( + show: true, + drawVerticalLine: true, + horizontalInterval: 1, + verticalInterval: 1, + getDrawingVerticalLine: (value) { + return FlLine( + color: Colors.blue.withOpacity(0.2), + dashArray: [10, 10], + strokeWidth: 1, + ); + }, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Colors.grey.withOpacity(0.2), + dashArray: [5, 5], + strokeWidth: 1, + ); + }, + drawHorizontalLine: false, + ), + lineBarsData: [ + LineChartBarData( + + curveSmoothness: 0.5, + preventCurveOverShooting: true, + aboveBarData: BarAreaData(), + spots: _chartData + .asMap() + .entries + .map((entry) => FlSpot( + entry.key.toDouble(), entry.value.consumption)) + .toList(), + isCurved: true, + color: ColorsManager.chart.withOpacity(0.6), + show: true, + shadow: Shadow(color: Colors.black12), + belowBarData: BarAreaData( + show: true, + gradient: LinearGradient( + colors: [ + ColorsManager.chart.withOpacity(0.5), + Colors.blue.withOpacity(0.1), + ], + begin: Alignment.center, + end: Alignment.bottomCenter, + ), + ), + dotData: FlDotData( + show: false, + ), + isStrokeCapRound: true, + barWidth: 6, + + ), + ], + borderData: FlBorderData( + show: false, + border: Border.all( + color: Color(0xff023DFE).withOpacity(0.7), + width: 10, + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} + +class EnergyData { + EnergyData(this.time, this.consumption); + final String time; + final double consumption; +} +// \ No newline at end of file diff --git a/lib/features/devices/view/widgets/power_clamp/power_clamp_page.dart b/lib/features/devices/view/widgets/power_clamp/power_clamp_page.dart new file mode 100644 index 0000000..5fd0fc0 --- /dev/null +++ b/lib/features/devices/view/widgets/power_clamp/power_clamp_page.dart @@ -0,0 +1,235 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/door_sensor_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/power_clamp/power_chart.dart'; +import 'package:syncrow_app/features/devices/view/widgets/power_clamp/power_info_card.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class PowerClampPage extends StatefulWidget { + final DeviceModel? device; + + const PowerClampPage({super.key, this.device}); + + @override + _PowerClampPageState createState() => _PowerClampPageState(); +} + +class _PowerClampPageState extends State { + final PageController _pageController = PageController(); + int _currentPage = 0; + final int _pageCount = 5; + + @override + Widget build(BuildContext context) { + return DefaultScaffold( + title: 'Power Clamp', + child: BlocProvider( + create: (context) => DoorSensorBloc(DSId: widget.device?.uuid ?? '') + ..add(const DoorSensorInitial()), + child: BlocBuilder( + builder: (context, state) { + final doorSensorBloc = BlocProvider.of(context); + DoorSensorModel model = + DoorSensorModel(batteryPercentage: 0, doorContactState: false); + if (state is LoadingNewSate) { + model = state.doorSensor; + } else if (state is UpdateState) { + model = state.doorSensor; + } + return state is DoorSensorLoadingState + ? const Center( + child: DefaultContainer( + width: 50, + height: 50, + child: CircularProgressIndicator()), + ) + : Column( + children: [ + Expanded( + child: RefreshIndicator( + onRefresh: () async { + doorSensorBloc.add(const DoorSensorInitial()); + }, + child: PageView.builder( + controller: _pageController, + onPageChanged: (int page) { + setState(() { + _currentPage = page; + }); + }, + itemBuilder: (context, index) { + return DefaultContainer( + child: Padding( + padding: const EdgeInsets.only( + left: 10, right: 10, top: 25, bottom: 20), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text('Energy usage'), + Row( + crossAxisAlignment: + CrossAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + BodyLarge( + text: 'Total Energy \nConsumption', + fontSize: 20, + fontWeight: FontWeight.w700, + ), + Row( + children: [ + BodyLarge( + text: '8623.20 ', + fontSize: 20, + fontWeight: FontWeight.w700, + ), + BodySmall(text: 'kWh') + ], + ), + ], + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + PowerClampInfoCard( + iconPath: Assets.powerActiveIcon, + title: 'Active', + value: '700', + unit: ' w', + ), + PowerClampInfoCard( + iconPath: Assets.voltMeterIcon, + title: 'Current', + value: '3.06', + unit: ' A', + ), + PowerClampInfoCard( + iconPath: Assets.frequencyIcon, + title: 'Frequency', + value: '50', + unit: ' Hz', + ), + ], + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + BodyMedium( + text: 'Total consumption', + fontSize: 12, + fontWeight: FontWeight.w700, + ), + Text( + '10/08/2024', + style: TextStyle( + fontSize: 8, + fontWeight: + FontWeight.w400), + ), + ], + ), + Row( + children: [ + BodyMedium( + text: '1000.00 ', + fontSize: 12, + fontWeight: FontWeight.w700), + BodyMedium( + text: 'kWh', + fontSize: 8, + fontWeight: FontWeight.w700), + ], + ), + ], + ), + SizedBox( + height: 310, + child: EnergyConsumptionPage( + chartData: [ + EnergyData('12:00 AM', 4.0), + EnergyData('01:00 AM', 3.5), + EnergyData('02:00 AM', 3.8), + EnergyData('03:00 AM', 3.2), + EnergyData('04:00 AM', 4.0), + EnergyData('05:00 AM', 3.4), + EnergyData('06:00 AM', 3.2), + EnergyData('07:00 AM', 3.5), + EnergyData('08:00 AM', 3.8), + EnergyData('09:00 AM', 3.6), + EnergyData('10:00 AM', 3.9), + EnergyData('11:00 AM', 4.0), + ], + totalConsumption: 100.0, + date: '10/08/2024', + ), + ), + ], + ), + ), + ); + }, + itemCount: _pageCount, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(_pageCount, (index) { + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + margin: + const EdgeInsets.symmetric(horizontal: 4.0), + height: 10.0, + width: _currentPage == index ? 10.0 : 10.0, + decoration: BoxDecoration( + color: _currentPage == index + ? Colors.grey + : ColorsManager.greyColor, + borderRadius: BorderRadius.circular(5.0), + ), + child: Center( + child: _currentPage == index + ? Text( + '', + ) + : SizedBox.shrink(), + ), + ); + }), + ), + ), + ], + ); + }, + ), + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/power_clamp/power_info_card.dart b/lib/features/devices/view/widgets/power_clamp/power_info_card.dart new file mode 100644 index 0000000..a79adb0 --- /dev/null +++ b/lib/features/devices/view/widgets/power_clamp/power_info_card.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class PowerClampInfoCard extends StatelessWidget { + final String iconPath; + final String title; + final String value; + final String unit; + + const PowerClampInfoCard({ + Key? key, + required this.iconPath, + required this.title, + required this.value, + required this.unit, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: DefaultContainer( + height: 60, + color: ColorsManager.grayBox, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: SvgPicture.asset( + iconPath, + fit: BoxFit.fill, + ), + ), + Expanded( + flex: 3, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + BodyMedium( + fontWeight: FontWeight.w400, + fontSize: 8, + text: title, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + BodyMedium( + fontWeight: FontWeight.w700, + fontSize: 15, + text: value, + ), + BodyMedium( + fontWeight: FontWeight.w700, + fontSize: 8, + text: unit, + ), + ], + ), + ], + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 8e06f4d..bbe4bed 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -15,6 +15,7 @@ import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.d import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_screen.dart'; +import 'package:syncrow_app/features/devices/view/widgets/power_clamp/power_clamp_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_Interface.dart'; @@ -163,12 +164,20 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { PageRouteBuilder( pageBuilder: (context, animation1, animation2) => WaterHeaterPage(device: device))); - case DeviceType.DS: + // case DeviceType.DS: + // Navigator.push( + // context, + // PageRouteBuilder( + // pageBuilder: (context, animation1, animation2) => + // DoorSensorScreen(device: device))); + + + case DeviceType.DS: Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation1, animation2) => - DoorSensorScreen(device: device))); + PowerClampPage(device: device))); case DeviceType.OneTouch: Navigator.push( diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index acf46f7..2bdc191 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -1081,5 +1081,10 @@ class Assets { static const String gang1touch = "assets/icons/1gang_touch.svg"; static const String gang2touch = "assets/icons/2gang_touch.svg"; static const String gang3touch = "assets/icons/3gang_touch.svg"; + + static const String frequencyIcon = "assets/icons/frequency_icon.svg"; + static const String voltMeterIcon = "assets/icons/volt_meter_icon.svg"; + static const String powerActiveIcon = "assets/icons/power_active_icon.svg"; + //leakNormalIcon } diff --git a/lib/utils/resource_manager/color_manager.dart b/lib/utils/resource_manager/color_manager.dart index 78e9a50..c078eab 100644 --- a/lib/utils/resource_manager/color_manager.dart +++ b/lib/utils/resource_manager/color_manager.dart @@ -29,4 +29,7 @@ abstract class ColorsManager { static const Color graysColor = Color(0xffEBEBEB); static const Color textGray = Color(0xffD5D5D5); static const Color switchButton = Color(0xff023DFE); + static const Color grayBox = Color(0xffF5F5F5); + static const Color chart = Color(0xff023DFE); } +//background: #F5F5F5;023DFE diff --git a/pubspec.lock b/pubspec.lock index 935996a..4b11f46 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -317,10 +317,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: "00b74ae680df6b1135bdbea00a7d1fc072a9180b7c3f3702e4b19a9943f5ed7d" + sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef" url: "https://pub.dev" source: hosted - version: "0.66.2" + version: "0.69.0" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 4dff6df..a7270f2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,6 @@ dependencies: firebase_analytics: ^10.8.7 firebase_core: ^2.25.5 firebase_crashlytics: ^3.4.16 - fl_chart: ^0.66.2 flutter: sdk: flutter flutter_animated_dialog: ^2.0.1 @@ -45,8 +44,10 @@ dependencies: time_picker_spinner: ^1.0.0 image_picker: ^1.1.2 device_info_plus: ^10.1.0 + fl_chart: ^0.69.0 firebase_database: ^10.5.7 + dev_dependencies: flutter_lints: ^3.0.1 flutter_test: