From 01ae020374664710bb9719b8316709697bb24927 Mon Sep 17 00:00:00 2001 From: anhtunz Date: Mon, 26 May 2025 11:58:19 +0700 Subject: [PATCH] Fix(bugs): Can't logout ui display when user doesn't has device --- lib/bloc/home_bloc.dart | 4 + lib/bloc/inter_family_bloc.dart | 51 ++- .../device_log/device_logs_screen.dart | 2 +- .../devices/add_new_device_widget.dart | 10 +- .../devices/devices_manager_screen.dart | 168 +++++---- lib/feature/home/home_screen.dart | 341 +++++++++++------- .../inter_family/groups/groups_screen.dart | 113 +++--- lib/feature/main/main_screen.dart | 2 +- lib/main.dart | 2 +- lib/product/services/api_services.dart | 2 +- 10 files changed, 417 insertions(+), 278 deletions(-) diff --git a/lib/bloc/home_bloc.dart b/lib/bloc/home_bloc.dart index 06a0a28..670958c 100644 --- a/lib/bloc/home_bloc.dart +++ b/lib/bloc/home_bloc.dart @@ -22,6 +22,10 @@ class HomeBloc extends BlocBase { StreamSink get sinkCountNotification => countNotification.sink; Stream get streamCountNotification => countNotification.stream; + final hasJoinedDevice = StreamController.broadcast(); + StreamSink get sinkHasJoinedDevice => hasJoinedDevice.sink; + Stream get streamHasJoinedDevice => hasJoinedDevice.stream; + final ownerDevicesStatus = StreamController>>.broadcast(); StreamSink>> diff --git a/lib/bloc/inter_family_bloc.dart b/lib/bloc/inter_family_bloc.dart index 1387676..2d7731d 100644 --- a/lib/bloc/inter_family_bloc.dart +++ b/lib/bloc/inter_family_bloc.dart @@ -38,33 +38,48 @@ class InterFamilyBloc extends BlocBase { void getAllGroup(String role) async { List groups = []; sinkCurrentGroups.add(groups); + final body = await apiServices.getAllGroups(); if (body.isNotEmpty) { - final data = jsonDecode(body); - List items = data["items"]; - groups = Group.fromJsonDynamicList(items); - groups = sortGroupByName(groups); + try { + final data = jsonDecode(body); - List currentGroups = groups.where( - (group) { - bool isPublic = group.visibility == "PUBLIC"; + // Kiểm tra nếu data là một Map và có chứa key "items" + if (data is Map && data.containsKey("items") && data["items"] is List) { + List items = data["items"]; + groups = Group.fromJsonDynamicList(items); + groups = sortGroupByName(groups); - if (role == ApplicationConstants.OWNER_GROUP) { - return group.isOwner == true && isPublic; - } + List currentGroups = groups.where( + (group) { + bool isPublic = group.visibility == "PUBLIC"; - if (role == ApplicationConstants.PARTICIPANT_GROUP) { - return group.isOwner == null && isPublic; - } + if (role == ApplicationConstants.OWNER_GROUP) { + return group.isOwner == true && isPublic; + } - return false; - }, - ).toList(); + if (role == ApplicationConstants.PARTICIPANT_GROUP) { + return group.isOwner == null && isPublic; + } - sinkCurrentGroups.add(currentGroups); + return false; + }, + ).toList(); + + sinkCurrentGroups.add(currentGroups); + } else { + log("No items found in API response or empty JSON object"); + sinkCurrentGroups.add([]); + } + } catch (e) { + // Xử lý lỗi khi jsonDecode thất bại + log("Error decoding JSON: $e"); + sinkCurrentGroups.add([]); + } } else { - log("Get groups from API failed"); + log("Get groups from API failed: Empty response"); + sinkCurrentGroups.add([]); } log("Inter Family Role: $role"); } diff --git a/lib/feature/device_log/device_logs_screen.dart b/lib/feature/device_log/device_logs_screen.dart index 775af68..f496817 100644 --- a/lib/feature/device_log/device_logs_screen.dart +++ b/lib/feature/device_log/device_logs_screen.dart @@ -63,7 +63,7 @@ class _DeviceLogsScreenState extends State { body: StreamBuilder>( stream: deviceLogsBloc.streamAllDevices, builder: (context, allDevicesSnapshot) { - if (allDevicesSnapshot.data?[0].thingId == null) { + if (allDevicesSnapshot.data == null) { deviceLogsBloc.getAllDevices(); return const Center( child: CircularProgressIndicator(), diff --git a/lib/feature/devices/add_new_device_widget.dart b/lib/feature/devices/add_new_device_widget.dart index ea31512..f1cdc59 100644 --- a/lib/feature/devices/add_new_device_widget.dart +++ b/lib/feature/devices/add_new_device_widget.dart @@ -1,6 +1,7 @@ // ignore_for_file: use_build_context_synchronously import 'package:flutter/material.dart'; +import 'package:sfm_app/bloc/devices_manager_bloc.dart'; import 'package:sfm_app/product/shared/shared_snack_bar.dart'; import '../../product/utils/response_status_utils.dart'; import '../../product/constant/enums/role_enums.dart'; @@ -10,7 +11,7 @@ import '../../product/constant/icon/icon_constants.dart'; import '../../product/extension/context_extension.dart'; import '../../product/services/language_services.dart'; -addNewDevice(BuildContext context, String role) async { +addNewDevice(BuildContext context, String role, DevicesManagerBloc deviceManagerBloc) async { TextEditingController extIDController = TextEditingController(text: ""); TextEditingController deviceNameController = TextEditingController(text: ""); ScaffoldMessenger.of(context).showSnackBar( @@ -76,7 +77,7 @@ addNewDevice(BuildContext context, String role) async { Colors.white); ScaffoldMessenger.of(context).hideCurrentSnackBar(); } else { - addDevices(context, role, extID, deviceName); + addDevices(context, role, extID, deviceName, deviceManagerBloc); ScaffoldMessenger.of(context).hideCurrentSnackBar(); } }, @@ -90,7 +91,7 @@ addNewDevice(BuildContext context, String role) async { } void addDevices( - BuildContext context, String role, String extID, String deviceName) async { + BuildContext context, String role, String extID, String deviceName, DevicesManagerBloc deviceManagerBloc) async { APIServices apiServices = APIServices(); Map body = {}; if (role == RoleEnums.ADMIN.name) { @@ -101,6 +102,7 @@ void addDevices( statusCode, appLocalization(context).notification_create_device_success, appLocalization(context).notification_create_device_failed); + deviceManagerBloc.getDeviceByState(-2); } else { body = {"ext_id": extID}; int statusCode = await apiServices.registerDevice(body); @@ -109,5 +111,7 @@ void addDevices( statusCode, appLocalization(context).notification_add_device_success, appLocalization(context).notification_device_not_exist); + deviceManagerBloc.getDeviceByState(-2); } + } diff --git a/lib/feature/devices/devices_manager_screen.dart b/lib/feature/devices/devices_manager_screen.dart index 7b88736..6af1bc5 100644 --- a/lib/feature/devices/devices_manager_screen.dart +++ b/lib/feature/devices/devices_manager_screen.dart @@ -29,7 +29,7 @@ class _DevicesManagerScreenState extends State { late DevicesManagerBloc devicesManagerBloc; String role = "Undefine"; APIServices apiServices = APIServices(); - List devices = []; + // List devices = []; Timer? getAllDevicesTimer; List tags = []; int tagIndex = -2; @@ -58,36 +58,60 @@ class _DevicesManagerScreenState extends State { body: StreamBuilder>( stream: devicesManagerBloc.streamTagStates, builder: (context, tagSnapshot) { - return SafeArea( - child: StreamBuilder>( - stream: devicesManagerBloc.streamAllDevices, - initialData: devices, - builder: (context, allDeviceSnapshot) { - if (allDeviceSnapshot.data?.isEmpty ?? devices.isEmpty) { - devicesManagerBloc - .getDeviceByState(tagSnapshot.data?[0] ?? -2); - return const Center(child: CircularProgressIndicator()); - } else { - if (tagSnapshot.data!.isNotEmpty) { - tagIndex = tagSnapshot.data![0]; - devicesManagerBloc.sinkTagStates.add([tagIndex]); - } - return SingleChildScrollView( - child: Column( - children: [ - if (tagSnapshot.hasData && - tagSnapshot.data!.isNotEmpty && - tagSnapshot.data![0] != -2) - TagState( - state: tagSnapshot.data![0], - devicesManagerBloc: devicesManagerBloc, - ), - SizedBox(height: context.lowValue), - StreamBuilder( - stream: devicesManagerBloc.streamUserRole, - initialData: role, - builder: (context, roleSnapshot) { - return SizedBox( + return StreamBuilder( + stream: devicesManagerBloc.streamUserRole, + initialData: role, + builder: (context, roleSnapshot) { + return SafeArea( + child: StreamBuilder>( + stream: devicesManagerBloc.streamAllDevices, + builder: (context, allDeviceSnapshot) { + if(allDeviceSnapshot.data == null){ + devicesManagerBloc + .getDeviceByState(tagSnapshot.data?[0] ?? -2); + return const Center(child: CircularProgressIndicator()); + } + if (allDeviceSnapshot.data!.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + border: Border.all(color: Theme.of(context).colorScheme.primary), + borderRadius: BorderRadius.circular(50) + ), + child: IconButton(onPressed: (){ + ScaffoldMessenger.of(context) + .clearSnackBars(); + addNewDevice(context, + roleSnapshot.data ?? role, devicesManagerBloc); + }, iconSize: 50, icon: const Icon(Icons.add),),), + SizedBox(height: context.mediumValue,), + Text(appLocalization(context).dont_have_device, style: context.responsiveBodyMediumWithBold,) + ], + ), + ); + } else { + if (tagSnapshot.data!.isNotEmpty) { + tagIndex = tagSnapshot.data![0]; + devicesManagerBloc.sinkTagStates.add([tagIndex]); + } + return SingleChildScrollView( + child: Column( + children: [ + if (tagSnapshot.hasData && + tagSnapshot.data!.isNotEmpty && + tagSnapshot.data![0] != -2) + TagState( + state: tagSnapshot.data![0], + devicesManagerBloc: devicesManagerBloc, + ), + SizedBox(height: context.lowValue), + SizedBox( height: getTableHeight(allDeviceSnapshot.data?.length ?? 1), child: PaginatedDataTable2( wrapInCard: false, @@ -108,7 +132,7 @@ class _DevicesManagerScreenState extends State { ), columns: [ if (roleSnapshot.data == - RoleEnums.ADMIN.name || + RoleEnums.ADMIN.name || roleSnapshot.data == RoleEnums.USER.name) DataColumn2( @@ -149,23 +173,23 @@ class _DevicesManagerScreenState extends State { // log('Chuyen page: $pageIndex'); }, rowsPerPage: - (allDeviceSnapshot.data?.length ?? 1) < 6 - ? (allDeviceSnapshot.data?.length ?? - 0) - : 5, + (allDeviceSnapshot.data?.length ?? 1) < 6 + ? (allDeviceSnapshot.data?.length ?? + 0) + : 5, actions: [ if (roleSnapshot.data == - RoleEnums.USER.name || + RoleEnums.USER.name || roleSnapshot.data == RoleEnums.ADMIN.name) IconButton( style: ButtonStyle( backgroundColor: - WidgetStateProperty.all( - Colors.green), + WidgetStateProperty.all( + Colors.green), iconColor: - WidgetStateProperty.all( + WidgetStateProperty.all( Colors.white, ), ), @@ -173,49 +197,49 @@ class _DevicesManagerScreenState extends State { ScaffoldMessenger.of(context) .clearSnackBars(); addNewDevice(context, - roleSnapshot.data ?? role); + roleSnapshot.data ?? role, devicesManagerBloc); }, icon: IconConstants.instance .getMaterialIcon(Icons.add)) ], source: DeviceSource( - devices: allDeviceSnapshot.data ?? devices, + devices: allDeviceSnapshot.data ?? [], context: context, devicesBloc: devicesManagerBloc, role: role, ), ), - ); - }, + ), + SizedBox(height: context.lowValue), + Text( + appLocalization(context).overview_message, + style: context.responsiveBodyLargeWithBold + ), + StreamBuilder>>( + stream: devicesManagerBloc.streamDeviceByState, + builder: (context, devicesByStateSnapshot) { + if (devicesByStateSnapshot.data == null) { + devicesManagerBloc.getDeviceByState( + tagSnapshot.data?[0] ?? -2); + return const Center( + child: CircularProgressIndicator()); + } else { + return SharedPieChart( + deviceByState: + devicesByStateSnapshot.data ?? {}, + devicesManagerBloc: devicesManagerBloc, + ); + } + }, + ), + ], ), - SizedBox(height: context.lowValue), - Text( - appLocalization(context).overview_message, - style: context.responsiveBodyLargeWithBold - ), - StreamBuilder>>( - stream: devicesManagerBloc.streamDeviceByState, - builder: (context, devicesByStateSnapshot) { - if (devicesByStateSnapshot.data == null) { - devicesManagerBloc.getDeviceByState( - tagSnapshot.data?[0] ?? -2); - return const Center( - child: CircularProgressIndicator()); - } else { - return SharedPieChart( - deviceByState: - devicesByStateSnapshot.data ?? {}, - devicesManagerBloc: devicesManagerBloc, - ); - } - }, - ), - ], - ), - ); - } - }, - ), + ); + } + }, + ), + ); + } ); }), ); diff --git a/lib/feature/home/home_screen.dart b/lib/feature/home/home_screen.dart index 5d268bf..f0a66a1 100644 --- a/lib/feature/home/home_screen.dart +++ b/lib/feature/home/home_screen.dart @@ -40,7 +40,8 @@ class _HomeScreenState extends State { homeBloc = BlocProvider.of(context); getOwnerAndJoinedDevices(); const duration = Duration(seconds: 10); - getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices()); + getAllDevicesTimer = + Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices()); } @override @@ -81,127 +82,199 @@ class _HomeScreenState extends State { child: StreamBuilder>>( stream: homeBloc.streamOwnerDevicesStatus, builder: (context, snapshot) { - if (snapshot.data?['state'] != null || snapshot.data?['battery'] != null) { - return ConstrainedBox( - 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(), - ], - ), - ); - } else { - return Padding( - 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, - ), - ], + 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()); + } - - - - - StreamBuilder>>( - stream: homeBloc.streamAllDevicesAliasMap, - builder: (context, allDevicesAliasMapSnapshot) { - if (!allDevicesAliasMapSnapshot.hasData || - allDevicesAliasMapSnapshot.data == null) { - return const Center(child: CircularProgressIndicator()); - } - 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); - }), - SizedBox(height: context.lowValue), - StreamBuilder>>( - stream: homeBloc.streamAllDevicesAliasJoinedMap, - builder: (context, allDevicesAliasJoinedMapSnapshot) { - if (!allDevicesAliasJoinedMapSnapshot.hasData || - allDevicesAliasJoinedMapSnapshot.data == null) { - return const Center(child: CircularProgressIndicator()); - } - final data = allDevicesAliasJoinedMapSnapshot.data!; - final total = data['all']?.length ?? 0; - final active = data['online']?.length ?? 0; - final inactive = data['offline']?.length ?? 0; - final warning = data['warn']?.length ?? 0; - final unused = data['not-use']?.length ?? 0; - - if (total == 0 && active == 0 && inactive == 0 && warning == 0 && unused == 0) { - return const SizedBox.shrink(); - } - return OverviewCard( - isOwner: false, - total: total, - active: active, - inactive: inactive, - warning: warning, - unused: unused, + 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), + ], + ), + ], + ), + ); + } + } + }, + ); + }, ); }, ), @@ -217,9 +290,15 @@ class _HomeScreenState extends State { final data = jsonDecode(response); List result = data["items"]; devices = DeviceWithAlias.fromJsonDynamicList(result); - getOwnerDeviceState(devices); - checkSettingDevice(devices); - getDeviceStatusAliasMap(devices); + 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 { @@ -229,21 +308,23 @@ class _HomeScreenState extends State { ownerDevices.add(device); } } - if (ownerDevicesState.isEmpty || ownerDevicesState.length < devices.length) { + 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 ?? []); + 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 (sensorMap['sensorBattery'] != + appLocalization(context).no_data_message) { if (double.parse(sensorMap['sensorBattery']) <= 20) { ownerDevicesStatus['battery'] ??= []; ownerDevicesStatus['battery']!.add(device); @@ -260,7 +341,7 @@ class _HomeScreenState extends State { 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] = []; @@ -282,6 +363,7 @@ class _HomeScreenState extends State { allDevicesAliasMap['not-use']!.add(device); } } else { + check = true; allDevicesAliasJoinedMap['all']!.add(device); if (device.state == 0 || device.state == 1) { allDevicesAliasJoinedMap['online']!.add(device); @@ -297,7 +379,7 @@ class _HomeScreenState extends State { } } } - + homeBloc.sinkHasJoinedDevice.add(check); homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap); homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap); } @@ -306,7 +388,8 @@ class _HomeScreenState extends State { if (isFunctionCall) { log("Ham check setting da duoc goi"); } else { - String? response = await apiServices.getAllSettingsNotificationOfDevices(); + String? response = + await apiServices.getAllSettingsNotificationOfDevices(); if (response != "") { final data = jsonDecode(response); final result = data['data']; @@ -314,11 +397,13 @@ class _HomeScreenState extends State { List list = DeviceNotificationSettings.mapFromJson(result).values.toList(); // log("List: $list"); - Set thingIdsInList = list.map((device) => device.thingId!).toSet(); + 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!); + await apiServices.setupDeviceNotification( + device.thingId!, device.name!); } else { log("All devices are in the notification settings list."); } diff --git a/lib/feature/inter_family/groups/groups_screen.dart b/lib/feature/inter_family/groups/groups_screen.dart index 008d2e5..755db00 100644 --- a/lib/feature/inter_family/groups/groups_screen.dart +++ b/lib/feature/inter_family/groups/groups_screen.dart @@ -44,69 +44,76 @@ class _GroupsScreenState extends State { @override void dispose() { getAllGroupsTimer?.cancel(); + super.dispose(); } @override Widget build(BuildContext context) { if (widget.role == ApplicationConstants.OWNER_GROUP || widget.role == ApplicationConstants.PARTICIPANT_GROUP) { - interFamilyBloc.getAllGroup(widget.role); return StreamBuilder>( stream: interFamilyBloc.streamCurrentGroups, builder: (context, groupsSnapshot) { - return Scaffold( - body: groupsSnapshot.data?.isEmpty ?? true - ? const Center( - child: CircularProgressIndicator(), - ) - : ListView.builder( - itemCount: groupsSnapshot.data!.length, - itemBuilder: (context, index) { - return ListTile( - onTap: () { - context.pushNamed(AppRoutes.GROUP_DETAIL.name, - pathParameters: {"groupId": groupsSnapshot.data![index].id!}, - extra: widget.role); - }, - leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2), - title: Text( - groupsSnapshot.data![index].name ?? '', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: Text(groupsSnapshot.data![index].description ?? ""), - trailing: widget.role == ApplicationConstants.OWNER_GROUP - ? PopupMenuButton( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(8.0), - bottomRight: Radius.circular(8.0), - topLeft: Radius.circular(8.0), - topRight: Radius.circular(8.0), - ), - ), - itemBuilder: (ctx) => [ - _buildPopupMenuItem(groupsSnapshot.data![index], context, - appLocalization(context).share_group_title, Icons.share, 4), - _buildPopupMenuItem( - groupsSnapshot.data![index], - context, - appLocalization(context).change_group_infomation_title, - Icons.settings_backup_restore, - 2), - _buildPopupMenuItem( - groupsSnapshot.data![index], - context, - appLocalization(context).delete_group_title, - Icons.delete_forever_rounded, - 3), - ], - icon: const Icon(Icons.more_horiz), - ) - : const SizedBox.shrink(), - ); + if(groupsSnapshot.data == null){ + interFamilyBloc.getAllGroup(widget.role); + return const Center(child: CircularProgressIndicator(),); + }else if(groupsSnapshot.data!.isEmpty){ + return Center(child: Text(appLocalization(context).dont_have_group),); + }else { + return Scaffold( + body: groupsSnapshot.data?.isEmpty ?? true + ? const Center( + child: CircularProgressIndicator(), + ) + : ListView.builder( + itemCount: groupsSnapshot.data!.length, + itemBuilder: (context, index) { + return ListTile( + onTap: () { + context.pushNamed(AppRoutes.GROUP_DETAIL.name, + pathParameters: {"groupId": groupsSnapshot.data![index].id!}, + extra: widget.role); }, - ), - ); + leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2), + title: Text( + groupsSnapshot.data![index].name ?? '', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + subtitle: Text(groupsSnapshot.data![index].description ?? ""), + trailing: widget.role == ApplicationConstants.OWNER_GROUP + ? PopupMenuButton( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(8.0), + bottomRight: Radius.circular(8.0), + topLeft: Radius.circular(8.0), + topRight: Radius.circular(8.0), + ), + ), + itemBuilder: (ctx) => [ + _buildPopupMenuItem(groupsSnapshot.data![index], context, + appLocalization(context).share_group_title, Icons.share, 4), + _buildPopupMenuItem( + groupsSnapshot.data![index], + context, + appLocalization(context).change_group_infomation_title, + Icons.settings_backup_restore, + 2), + _buildPopupMenuItem( + groupsSnapshot.data![index], + context, + appLocalization(context).delete_group_title, + Icons.delete_forever_rounded, + 3), + ], + icon: const Icon(Icons.more_horiz), + ) + : const SizedBox.shrink(), + ); + }, + ), + ); + } }, ); } else { diff --git a/lib/feature/main/main_screen.dart b/lib/feature/main/main_screen.dart index f9bc143..665d153 100644 --- a/lib/feature/main/main_screen.dart +++ b/lib/feature/main/main_screen.dart @@ -385,7 +385,7 @@ class _MainScreenState extends State with WidgetsBindingObserver { items: _navBarsItems(), handleAndroidBackButtonPress: true, resizeToAvoidBottomInset: true, - stateManagement: true, + stateManagement: false, backgroundColor: themeModeSnapshot.data! ? Colors.white : Colors.black, decoration: NavBarDecoration( diff --git a/lib/main.dart b/lib/main.dart index 7bf9b6a..e356485 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -import 'dart:developer'; + import 'dart:developer'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; diff --git a/lib/product/services/api_services.dart b/lib/product/services/api_services.dart index ac89462..2152f49 100644 --- a/lib/product/services/api_services.dart +++ b/lib/product/services/api_services.dart @@ -69,7 +69,7 @@ class APIServices { actions: [ TextButton( onPressed: () async { - var url = Uri.http(ApplicationConstants.DOMAIN, + var url = Uri.https(ApplicationConstants.DOMAIN, APIPathConstants.LOGOUT_PATH); final headers = await NetworkManager.instance!.getHeaders(); final response = await http.post(url, headers: headers);