import 'dart:async'; import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; import '../../product/shared/shared_component_loading_animation.dart'; import '../../product/utils/app_logger_utils.dart'; import 'shared/alert_card.dart'; import 'shared/warning_card.dart'; import '../../product/utils/device_utils.dart'; import 'device_alias_model.dart'; import 'shared/overview_card.dart'; import '../settings/device_notification_settings/device_notification_settings_model.dart'; import '../../product/extension/context_extension.dart'; import '../../product/services/api_services.dart'; import '../../product/services/language_services.dart'; import '../../bloc/home_bloc.dart'; import '../../product/base/bloc/base_bloc.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key, required this.persistentTabController}); final PersistentTabController persistentTabController; @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { late HomeBloc homeBloc; APIServices apiServices = APIServices(); Map> allDevicesAliasMap = {}; List devices = []; bool isFunctionCall = false; Timer? getAllDevicesTimer; int notificationCount = 0; Map> ownerDevicesStatus = {}; List ownerDevicesState = []; @override void initState() { super.initState(); homeBloc = BlocProvider.of(context); getAllDevicesTimer?.cancel(); AppLoggerUtils.debug("Init State HomeScreen"); getOwnerAndJoinedDevices(); const duration = Duration(seconds: 10); getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices()); } @override void dispose() { getAllDevicesTimer?.cancel(); homeBloc.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: context.paddingLow, child: SingleChildScrollView( child: Column( children: [ Row( children: [ Text( appLocalization(context).notification, style: context.titleMediumTextStyle, ), SizedBox(width: context.lowValue), StreamBuilder( stream: homeBloc.streamCountNotification, builder: (context, countSnapshot) { return Text( "(${countSnapshot.data ?? 0})", style: context.titleMediumTextStyle, ); }, ) ], ), SizedBox( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: StreamBuilder>>( stream: homeBloc.streamOwnerDevicesStatus, builder: (context, snapshot) { return AnimatedSwitcher( duration: context.lowDuration, transitionBuilder: (Widget child, Animation animation) { final offsetAnimation = Tween( begin: const Offset(0.0, 0.2), end: Offset.zero, ).animate(CurvedAnimation( parent: animation, curve: Curves.easeInOut, )); return FadeTransition( opacity: animation, child: SlideTransition( position: offsetAnimation, child: child, ), ); }, child: snapshot.data?['state'] != null || snapshot.data?['battery'] != null ? ConstrainedBox( key: const ValueKey('data'), constraints: BoxConstraints( minWidth: MediaQuery.of(context).size.width), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ if (snapshot.data?['state'] != null) ...snapshot.data!['state']! .map( (item) => SizedBox( width: context.dynamicWidth(0.95), child: FutureBuilder( future: warningCard( context, apiServices, item), builder: (context, warningCardSnapshot) { if (warningCardSnapshot .hasData) { return warningCardSnapshot .data!; } else { return const SizedBox .shrink(); } }, ), ), ) .toList(), if (snapshot.data?['battery'] != null) ...snapshot.data!['battery']! .map( (batteryItem) => SizedBox( width: context.dynamicWidth(0.95), child: FutureBuilder( future: notificationCard( context, "lowBattery", appLocalization(context) .low_battery_message, batteryItem, ), builder: (context, warningCardSnapshot) { if (warningCardSnapshot .hasData) { return warningCardSnapshot .data!; } else { return const SizedBox .shrink(); } }, ), ), ) .toList(), ], ), ) : Padding( key: const ValueKey('no_data'), padding: context.paddingMedium, child: Center( child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.check_circle_outline_rounded, size: 40, color: Colors.green, ), SizedBox(width: context.lowValue), Text( appLocalization(context) .notification_description, maxLines: 2, overflow: TextOverflow.ellipsis, softWrap: true, textAlign: TextAlign.start, ), ], ), ), ), ); }, ), ), ), StreamBuilder>>( stream: homeBloc.streamAllDevicesAliasMap, builder: (context, allDevicesAliasMapSnapshot) { if(allDevicesAliasMapSnapshot.data == null){ return const SharedComponentLoadingAnimation(); }else{ final data = allDevicesAliasMapSnapshot.data!; return OverviewCard( isOwner: true, total: data['all']?.length ?? 0, active: data['online']?.length ?? 0, inactive: data['offline']?.length ?? 0, warning: data['warn']?.length ?? 0, unused: data['not-use']?.length ?? 0, showUnused: false, ); } }, ), ], ), ), ), ); } void getOwnerAndJoinedDevices() async { await apiServices.execute(context, () async { devices = await apiServices.getDashBoardDevices().handleApiError(); List publicDevices = []; for (var device in devices) { if (device.visibility == "PUBLIC") { publicDevices.add(device); } } getOwnerDeviceState(publicDevices); checkSettingDevice(publicDevices); getDeviceStatusAliasMap(publicDevices); }); } void getOwnerDeviceState(List allDevices) async { ownerDevicesState.clear(); ownerDevicesStatus.clear(); if (!mounted) return; homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); int count = 0; for (var device in allDevices) { // if (device.isOwner != true) continue; if (!mounted) return; Map sensorMap = DeviceUtils.instance .getDeviceSensors(context, device.status?.sensors ?? []); if (device.state == 1 || device.state == 3) { ownerDevicesStatus["state"] ??= []; ownerDevicesStatus["state"]!.add(device); if (!mounted) return; homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); count++; } final noDataMessage = appLocalization(context).no_data_message; if (sensorMap['sensorBattery'] != noDataMessage) { if (double.parse(sensorMap['sensorBattery']) <= 20) { ownerDevicesStatus['battery'] ??= []; ownerDevicesStatus['battery']!.add(device); if (!mounted) return; homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); count++; } } } notificationCount = count; if (!mounted) return; homeBloc.sinkCountNotification.add(notificationCount); } void getDeviceStatusAliasMap(List devices) { allDevicesAliasMap.clear(); for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) { allDevicesAliasMap[key] = []; } for (DeviceWithAlias device in devices) { allDevicesAliasMap['all']!.add(device); if (device.state == 0 || device.state == 1) { allDevicesAliasMap['online']!.add(device); } if (device.state == -1) { allDevicesAliasMap['offline']!.add(device); } if (device.state == 1) { allDevicesAliasMap['warning']!.add(device); } if (device.state == -2) { allDevicesAliasMap['not-use']!.add(device); } } homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap); } void checkSettingDevice(List devices) async { if (isFunctionCall) { log("Ham check setting da duoc goi"); } else { await apiServices.execute(context, () async { List list = await apiServices.getAllSettingsNotificationOfDevices(); // log("List: $list"); Set thingIdsInList = list.map((device) => device.thingId!).toSet(); for (var device in devices) { if (!thingIdsInList.contains(device.thingId)) { log("Device with Thing ID ${device.thingId} is not in the notification settings list."); await apiServices.execute(context, () async { await apiServices.setupDeviceNotification( device.thingId!, device.name!); }); } else { log("All devices are in the notification settings list."); } } }); } isFunctionCall = true; } }