import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.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}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { late HomeBloc homeBloc; APIServices apiServices = APIServices(); Map> allDevicesAliasMap = {}; Map> allDevicesAliasJoinedMap = {}; List devices = []; bool isFunctionCall = false; Timer? getAllDevicesTimer; int notificationCount = 0; Map> ownerDevicesStatus = {}; List ownerDevicesState = []; @override void initState() { super.initState(); homeBloc = BlocProvider.of(context); getOwnerAndJoinedDevices(); const duration = Duration(seconds: 10); getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices()); } @override void dispose() { getAllDevicesTimer?.cancel(); 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.streamHasJoinedDevice, initialData: null, builder: (context, hasJoinedDeviceSnapshot) { return StreamBuilder>>( stream: homeBloc.streamAllDevicesAliasMap, builder: (context, allDevicesAliasMapSnapshot) { return StreamBuilder>>( stream: homeBloc.streamAllDevicesAliasJoinedMap, builder: (context, allDevicesAliasJoinedMapSnapshot) { if (hasJoinedDeviceSnapshot.data == null) { return const CircularProgressIndicator(); } else { final data = allDevicesAliasMapSnapshot.data!; final dataJoined = allDevicesAliasJoinedMapSnapshot.data!; if (hasJoinedDeviceSnapshot.data == false) { if (!allDevicesAliasMapSnapshot.hasData || allDevicesAliasMapSnapshot.data == null) { return const Center( child: CircularProgressIndicator()); } 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); } else { return DefaultTabController( length: 2, child: Column( children: [ const TabBar( tabs: [ Tab(text: 'Owner Devices'), Tab(text: 'Joined Devices'), ], labelColor: Colors.blue, unselectedLabelColor: Colors.grey, indicatorColor: Colors.blue, ), TabBarView( children: [ 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), OverviewCard( isOwner: false, total: dataJoined['all']?.length ?? 0, active: dataJoined['online']?.length ?? 0, inactive: dataJoined['offline']?.length ?? 0, warning: dataJoined['warn']?.length ?? 0, unused: dataJoined['not-use']?.length ?? 0), ], ), ], ), ); } } }, ); }, ); }, ), ], ), ), ), ); } void getOwnerAndJoinedDevices() async { String response = await apiServices.getDashBoardDevices(); final data = jsonDecode(response); List result = data["items"]; devices = DeviceWithAlias.fromJsonDynamicList(result); 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 { List ownerDevices = []; for (var device in allDevices) { if (device.isOwner!) { ownerDevices.add(device); } } if (ownerDevicesState.isEmpty || ownerDevicesState.length < devices.length) { ownerDevicesState.clear(); ownerDevicesStatus.clear(); homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); int count = 0; for (var device in ownerDevices) { Map sensorMap = DeviceUtils.instance .getDeviceSensors(context, device.status?.sensors ?? []); if (device.state == 1 || device.state == 3) { ownerDevicesStatus["state"] ??= []; ownerDevicesStatus["state"]!.add(device); homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); count++; } if (sensorMap['sensorBattery'] != appLocalization(context).no_data_message) { if (double.parse(sensorMap['sensorBattery']) <= 20) { ownerDevicesStatus['battery'] ??= []; ownerDevicesStatus['battery']!.add(device); homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); count++; } } notificationCount = count; homeBloc.sinkCountNotification.add(notificationCount); } } } void getDeviceStatusAliasMap(List devices) { allDevicesAliasMap.clear(); allDevicesAliasJoinedMap.clear(); bool check = false; for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) { allDevicesAliasMap[key] = []; allDevicesAliasJoinedMap[key] = []; } for (DeviceWithAlias device in devices) { if (device.isOwner == true) { 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); } } else { check = true; allDevicesAliasJoinedMap['all']!.add(device); if (device.state == 0 || device.state == 1) { allDevicesAliasJoinedMap['online']!.add(device); } if (device.state == -1) { allDevicesAliasJoinedMap['offline']!.add(device); } if (device.state == 1) { allDevicesAliasJoinedMap['warning']!.add(device); } if (device.state == -2) { allDevicesAliasJoinedMap['not-use']!.add(device); } } } homeBloc.sinkHasJoinedDevice.add(check); homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap); homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap); } void checkSettingDevice(List devices) async { if (isFunctionCall) { log("Ham check setting da duoc goi"); } else { String? response = await apiServices.getAllSettingsNotificationOfDevices(); if (response != "") { final data = jsonDecode(response); final result = data['data']; // log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}"); List list = DeviceNotificationSettings.mapFromJson(result).values.toList(); // 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.setupDeviceNotification( device.thingId!, device.name!); } else { log("All devices are in the notification settings list."); } } } else { log("apiServices: getAllSettingsNotificationofDevices error!"); } } isFunctionCall = true; } }