From 8136804694616a84d9065f14d96cebe158f5d715 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Thu, 17 Apr 2025 12:18:09 +0300 Subject: [PATCH 1/5] bugfix. --- lib/pages/space_tree/view/custom_expansion.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index e4e7f423..dab0a49f 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -31,7 +31,7 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { children: [ Checkbox( value: isSoldCheck ? null : isSelected, - onChanged: (value) => onItemSelected ?? () {}, + onChanged: (value) => onItemSelected?.call(), tristate: true, side: WidgetStateBorderSide.resolveWith( (states) => const BorderSide(color: ColorsManager.grayBorder), From 977875f1f2e82b1ba44365fc37d08150cf79f802 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Thu, 17 Apr 2025 13:08:16 +0300 Subject: [PATCH 2/5] SP-1435 --- lib/pages/routines/view/routines_view.dart | 78 ++++---- .../fetch_routine_scenes_automation.dart | 168 ++++++++---------- .../main_routine_view/routine_view_card.dart | 104 ++++++----- 3 files changed, 170 insertions(+), 180 deletions(-) diff --git a/lib/pages/routines/view/routines_view.dart b/lib/pages/routines/view/routines_view.dart index 2d6ee648..9d4639ed 100644 --- a/lib/pages/routines/view/routines_view.dart +++ b/lib/pages/routines/view/routines_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart'; import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart'; +import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart'; import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routines/create_new_routines/create_new_routines.dart'; import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart'; @@ -9,6 +9,7 @@ import 'package:syncrow_web/pages/routines/widgets/main_routine_view/fetch_routi import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class RoutinesView extends StatefulWidget { const RoutinesView({super.key}); @@ -27,9 +28,10 @@ class _RoutinesViewState extends State { if (result == null) return; final communityId = result['community']; final spaceId = result['space']; - final _bloc = BlocProvider.of(context); + final bloc = BlocProvider.of(context); final routineBloc = context.read(); - _bloc.add(SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId)); + bloc.add( + SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId)); await Future.delayed(const Duration(seconds: 1)); routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true)); } @@ -54,43 +56,41 @@ class _RoutinesViewState extends State { ), Expanded( flex: 4, - child: ListView( - children: [ - Container( - padding: const EdgeInsets.all(16), - height: MediaQuery.sizeOf(context).height, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Create New Routines", - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - RoutineViewCard( - isLoading: false, - onChanged: (v) {}, - status: '', - spaceId: '', - automationId: '', - communityId: '', - sceneId: '', - cardType: '', - spaceName: '', - onTap: () => _handleRoutineCreation(context), - icon: Icons.add, - textString: '', - ), - const SizedBox(height: 15), - const Expanded(child: FetchRoutineScenesAutomation()), - ], - ), + child: SizedBox( + height: context.screenHeight, + width: context.screenWidth, + child: SingleChildScrollView( + padding: const EdgeInsetsDirectional.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + spacing: 16, + children: [ + Text( + "Create New Routines", + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, + ), + ), + RoutineViewCard( + isLoading: false, + onChanged: (v) {}, + status: '', + spaceId: '', + automationId: '', + communityId: '', + sceneId: '', + cardType: '', + spaceName: '', + onTap: () => _handleRoutineCreation(context), + icon: Icons.add, + textString: '', + ), + const FetchRoutineScenesAutomation(), + ], ), - const SizedBox(height: 50), - ], + ), ), ) ], diff --git a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart index 92a837b6..0e25dcea 100644 --- a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart +++ b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart @@ -12,8 +12,7 @@ class FetchRoutineScenesAutomation extends StatefulWidget { const FetchRoutineScenesAutomation({super.key}); @override - State createState() => - _FetchRoutineScenesState(); + State createState() => _FetchRoutineScenesState(); } class _FetchRoutineScenesState extends State @@ -55,20 +54,17 @@ class _FetchRoutineScenesState extends State ), if (state.scenes.isNotEmpty) SizedBox( - height: 200, + height: 200, child: ListView.builder( - shrinkWrap: true, scrollDirection: Axis.horizontal, itemCount: state.scenes.length, itemBuilder: (context, index) { final scene = state.scenes[index]; - final isLoading = - state.loadingSceneId == scene.id; + final isLoading = state.loadingSceneId == scene.id; return Padding( padding: EdgeInsets.only( - right: - isSmallScreenSize(context) ? 4.0 : 8.0, + right: isSmallScreenSize(context) ? 4.0 : 8.0, ), child: Column( children: [ @@ -76,31 +72,28 @@ class _FetchRoutineScenesState extends State isLoading: isLoading, sceneOnTap: () { context.read().add( - SceneTrigger( + SceneTrigger( sceneId: scene.id, - name: scene.name)); + name: scene.name, + ), + ); }, status: state.scenes[index].status, - communityId: - state.scenes[index].communityId ?? - '', + communityId: state.scenes[index].communityId, spaceId: state.scenes[index].spaceId, - sceneId: - state.scenes[index].sceneTuyaId!, + sceneId: state.scenes[index].sceneTuyaId!, automationId: state.scenes[index].id, cardType: 'scenes', - spaceName: - state.scenes[index].spaceName, + spaceName: state.scenes[index].spaceName, onTap: () { - BlocProvider.of(context) - .add( + BlocProvider.of(context).add( const CreateNewRoutineViewEvent( - createRoutineView: true), + createRoutineView: true, + ), ); context.read().add( GetSceneDetails( - sceneId: - state.scenes[index].id, + sceneId: state.scenes[index].id, isTabToRun: true, isUpdate: true, ), @@ -110,8 +103,7 @@ class _FetchRoutineScenesState extends State icon: state.scenes[index].icon ?? Assets.logoHorizontal, isFromScenes: true, - iconInBytes: - state.scenes[index].iconInBytes, + iconInBytes: state.scenes[index].iconInBytes, ), ], ), @@ -136,77 +128,69 @@ class _FetchRoutineScenesState extends State ), if (state.automations.isNotEmpty) SizedBox( - height: 200, - + height: 200, child: ListView.builder( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - itemCount: state.automations.length, - itemBuilder: (context, index) { - final isLoading = state.automations! - .contains(state.automations[index].id); + scrollDirection: Axis.horizontal, + itemCount: state.automations.length, + itemBuilder: (context, index) { + final isLoading = state.automations + .contains(state.automations[index].id); - return Column( - children: [ - Padding( - padding: EdgeInsets.only( - right: isSmallScreenSize(context) - ? 4.0 - : 8.0, - ), - child: RoutineViewCard( - isLoading: isLoading, - onChanged: (v) { - context.read().add( - UpdateAutomationStatus( - automationId: state - .automations[index].id, - automationStatusUpdate: - AutomationStatusUpdate( - spaceUuid: state - .automations[ - index] - .spaceId, - isEnable: v), - communityId: state - .automations[index] - .communityId, - ), - ); - }, - status: state.automations[index].status, - communityId: '', - spaceId: - state.automations[index].spaceId, - sceneId: '', - automationId: - state.automations[index].id, - cardType: 'automations', - spaceName: - state.automations[index].spaceName, - onTap: () { - BlocProvider.of(context) - .add( - const CreateNewRoutineViewEvent( - createRoutineView: true), - ); - context.read().add( - GetAutomationDetails( - automationId: state - .automations[index].id, - isAutomation: true, - isUpdate: true), - ); - }, - textString: - state.automations[index].name, - icon: state.automations[index].icon ?? - Assets.automation, - ), + return Column( + children: [ + Padding( + padding: EdgeInsets.only( + right: isSmallScreenSize(context) ? 4.0 : 8.0, ), - ], - ); - }), + child: RoutineViewCard( + isLoading: isLoading, + onChanged: (v) { + context.read().add( + UpdateAutomationStatus( + automationId: + state.automations[index].id, + automationStatusUpdate: + AutomationStatusUpdate( + spaceUuid: state + .automations[index].spaceId, + isEnable: v, + ), + communityId: state + .automations[index].communityId, + ), + ); + }, + status: state.automations[index].status, + communityId: '', + spaceId: state.automations[index].spaceId, + sceneId: '', + automationId: state.automations[index].id, + cardType: 'automations', + spaceName: state.automations[index].spaceName, + onTap: () { + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent( + createRoutineView: true, + ), + ); + context.read().add( + GetAutomationDetails( + automationId: + state.automations[index].id, + isAutomation: true, + isUpdate: true, + ), + ); + }, + textString: state.automations[index].name, + icon: state.automations[index].icon ?? + Assets.automation, + ), + ), + ], + ); + }, + ), ), ], ), diff --git a/lib/pages/routines/widgets/main_routine_view/routine_view_card.dart b/lib/pages/routines/widgets/main_routine_view/routine_view_card.dart index 7be5a959..4fc4bd0f 100644 --- a/lib/pages/routines/widgets/main_routine_view/routine_view_card.dart +++ b/lib/pages/routines/widgets/main_routine_view/routine_view_card.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -66,7 +67,6 @@ class _RoutineViewCardState extends State { @override Widget build(BuildContext context) { - // Use widget. instead of just final double cardWidth = widget.isSmallScreenSize(context) ? 120 : widget.isMediumScreenSize(context) @@ -127,22 +127,23 @@ class _RoutineViewCardState extends State { ) else CupertinoSwitch( - activeColor: ColorsManager.primaryColor, + activeTrackColor: ColorsManager.primaryColor, value: widget.status == 'enable', onChanged: widget.onChanged, ) ], ) : const SizedBox(), - InkWell( - onTap: widget.onTap, - child: Column( - children: [ - Center( + Column( + children: [ + Center( + child: InkWell( + customBorder: const CircleBorder(), + onTap: widget.onTap, child: Container( decoration: BoxDecoration( color: ColorsManager.graysColor, - borderRadius: BorderRadius.circular(120), + shape: BoxShape.circle, border: Border.all( color: ColorsManager.greyColor, width: 2.0, @@ -158,7 +159,8 @@ class _RoutineViewCardState extends State { height: iconSize, width: iconSize, fit: BoxFit.contain, - errorBuilder: (context, error, stackTrace) => Image.asset( + errorBuilder: (context, error, stackTrace) => + Image.asset( Assets.logo, height: iconSize, width: iconSize, @@ -171,7 +173,8 @@ class _RoutineViewCardState extends State { width: iconSize, fit: BoxFit.contain, ) - : (widget.icon is String && widget.icon.endsWith('.svg')) + : (widget.icon is String && + widget.icon.endsWith('.svg')) ? SvgPicture.asset( height: iconSize, width: iconSize, @@ -181,51 +184,54 @@ class _RoutineViewCardState extends State { : Icon( widget.icon, color: ColorsManager.dialogBlueTitle, - size: widget.isSmallScreenSize(context) ? 30 : 40, + size: widget.isSmallScreenSize(context) + ? 30 + : 40, ), ), ), - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 3), - child: Column( - children: [ - Text( - widget.textString, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.blackColor, - fontSize: widget.isSmallScreenSize(context) ? 10 : 12, - ), + ), + const SizedBox(height: 8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: Column( + children: [ + Text( + widget.textString, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.blackColor, + fontSize: widget.isSmallScreenSize(context) ? 10 : 12, ), - if (widget.spaceName != '') - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - Assets.spaceLocationIcon, - fit: BoxFit.contain, + ), + if (widget.spaceName != '') + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + Assets.spaceLocationIcon, + fit: BoxFit.contain, + ), + Text( + widget.spaceName, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.blackColor, + fontSize: + widget.isSmallScreenSize(context) ? 10 : 12, ), - Text( - widget.spaceName, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.blackColor, - fontSize: widget.isSmallScreenSize(context) ? 10 : 12, - ), - ), - ], - ), - ], - ), + ), + ], + ), + ], ), - ], - ), + ), + ], ), ], ), From f912b41fd8c93e8c072fe444b9f702adcf3e7bc1 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Thu, 17 Apr 2025 13:12:09 +0300 Subject: [PATCH 3/5] Refactor visibility handling for scenes and automations in FetchRoutineScenesAutomation --- .../fetch_routine_scenes_automation.dart | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart index 0e25dcea..c46ba377 100644 --- a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart +++ b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart @@ -17,10 +17,6 @@ class FetchRoutineScenesAutomation extends StatefulWidget { class _FetchRoutineScenesState extends State with HelperResponsiveLayout { - @override - void initState() { - super.initState(); - } @override Widget build(BuildContext context) { @@ -45,15 +41,15 @@ class _FetchRoutineScenesState extends State ), ), const SizedBox(height: 10), - if (state.scenes.isEmpty) - Text( + Visibility( + visible: state.scenes.isNotEmpty, + replacement: Text( "No scenes found", style: context.textTheme.bodyMedium?.copyWith( color: ColorsManager.grayColor, ), ), - if (state.scenes.isNotEmpty) - SizedBox( + child: SizedBox( height: 200, child: ListView.builder( scrollDirection: Axis.horizontal, @@ -110,6 +106,7 @@ class _FetchRoutineScenesState extends State ); }), ), + ), const SizedBox(height: 10), Text( "Automations", @@ -119,15 +116,15 @@ class _FetchRoutineScenesState extends State ), ), const SizedBox(height: 3), - if (state.automations.isEmpty) - Text( + Visibility( + visible: state.automations.isNotEmpty, + replacement: Text( "No automations found", style: context.textTheme.bodyMedium?.copyWith( color: ColorsManager.grayColor, ), ), - if (state.automations.isNotEmpty) - SizedBox( + child: SizedBox( height: 200, child: ListView.builder( scrollDirection: Axis.horizontal, @@ -192,6 +189,7 @@ class _FetchRoutineScenesState extends State }, ), ), + ) ], ), ), From 70f1f39fce8f84428e2fb60753fd4de90f47a6b1 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Thu, 17 Apr 2025 13:13:48 +0300 Subject: [PATCH 4/5] Improve loading state handling and in `FetchRoutineScenesAutomation`. --- .../fetch_routine_scenes_automation.dart | 336 +++++++++--------- 1 file changed, 163 insertions(+), 173 deletions(-) diff --git a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart index c46ba377..3e5d4e7f 100644 --- a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart +++ b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart @@ -8,192 +8,182 @@ import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class FetchRoutineScenesAutomation extends StatefulWidget { - const FetchRoutineScenesAutomation({super.key}); - - @override - State createState() => _FetchRoutineScenesState(); -} - -class _FetchRoutineScenesState extends State +class FetchRoutineScenesAutomation extends StatelessWidget with HelperResponsiveLayout { + const FetchRoutineScenesAutomation({super.key}); @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - return state.isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Scenes (Tab to Run)", - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - Visibility( - visible: state.scenes.isNotEmpty, - replacement: Text( - "No scenes found", - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.grayColor, - ), - ), - child: SizedBox( - height: 200, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: state.scenes.length, - itemBuilder: (context, index) { - final scene = state.scenes[index]; - final isLoading = state.loadingSceneId == scene.id; + if (state.isLoading) const Center(child: CircularProgressIndicator()); - return Padding( - padding: EdgeInsets.only( - right: isSmallScreenSize(context) ? 4.0 : 8.0, - ), - child: Column( - children: [ - RoutineViewCard( - isLoading: isLoading, - sceneOnTap: () { - context.read().add( - SceneTrigger( - sceneId: scene.id, - name: scene.name, - ), - ); - }, - status: state.scenes[index].status, - communityId: state.scenes[index].communityId, - spaceId: state.scenes[index].spaceId, - sceneId: state.scenes[index].sceneTuyaId!, - automationId: state.scenes[index].id, - cardType: 'scenes', - spaceName: state.scenes[index].spaceName, - onTap: () { - BlocProvider.of(context).add( - const CreateNewRoutineViewEvent( - createRoutineView: true, - ), - ); - context.read().add( - GetSceneDetails( - sceneId: state.scenes[index].id, - isTabToRun: true, - isUpdate: true, - ), - ); - }, - textString: state.scenes[index].name, - icon: state.scenes[index].icon ?? - Assets.logoHorizontal, - isFromScenes: true, - iconInBytes: state.scenes[index].iconInBytes, - ), - ], - ), - ); - }), - ), + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Scenes (Tab to Run)", + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, ), - const SizedBox(height: 10), - Text( - "Automations", - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 3), - Visibility( - visible: state.automations.isNotEmpty, - replacement: Text( - "No automations found", - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.grayColor, - ), - ), - child: SizedBox( - height: 200, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: state.automations.length, - itemBuilder: (context, index) { - final isLoading = state.automations - .contains(state.automations[index].id); + ), + const SizedBox(height: 10), + Visibility( + visible: state.scenes.isNotEmpty, + replacement: Text( + "No scenes found", + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.grayColor, + ), + ), + child: SizedBox( + height: 200, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: state.scenes.length, + itemBuilder: (context, index) { + final scene = state.scenes[index]; + final isLoading = state.loadingSceneId == scene.id; - return Column( - children: [ - Padding( - padding: EdgeInsets.only( - right: isSmallScreenSize(context) ? 4.0 : 8.0, - ), - child: RoutineViewCard( - isLoading: isLoading, - onChanged: (v) { - context.read().add( - UpdateAutomationStatus( - automationId: - state.automations[index].id, - automationStatusUpdate: - AutomationStatusUpdate( - spaceUuid: state - .automations[index].spaceId, - isEnable: v, - ), - communityId: state - .automations[index].communityId, - ), - ); - }, - status: state.automations[index].status, - communityId: '', - spaceId: state.automations[index].spaceId, - sceneId: '', - automationId: state.automations[index].id, - cardType: 'automations', - spaceName: state.automations[index].spaceName, - onTap: () { - BlocProvider.of(context).add( - const CreateNewRoutineViewEvent( - createRoutineView: true, + return Padding( + padding: EdgeInsets.only( + right: isSmallScreenSize(context) ? 4.0 : 8.0, + ), + child: Column( + children: [ + RoutineViewCard( + isLoading: isLoading, + sceneOnTap: () { + context.read().add( + SceneTrigger( + sceneId: scene.id, + name: scene.name, ), ); - context.read().add( - GetAutomationDetails( - automationId: - state.automations[index].id, - isAutomation: true, - isUpdate: true, - ), - ); - }, - textString: state.automations[index].name, - icon: state.automations[index].icon ?? - Assets.automation, - ), - ), - ], - ); - }, - ), - ), - ) - ], + }, + status: state.scenes[index].status, + communityId: state.scenes[index].communityId, + spaceId: state.scenes[index].spaceId, + sceneId: state.scenes[index].sceneTuyaId!, + automationId: state.scenes[index].id, + cardType: 'scenes', + spaceName: state.scenes[index].spaceName, + onTap: () { + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent( + createRoutineView: true, + ), + ); + context.read().add( + GetSceneDetails( + sceneId: state.scenes[index].id, + isTabToRun: true, + isUpdate: true, + ), + ); + }, + textString: state.scenes[index].name, + icon: state.scenes[index].icon ?? + Assets.logoHorizontal, + isFromScenes: true, + iconInBytes: state.scenes[index].iconInBytes, + ), + ], + ), + ); + }), ), ), - ); + const SizedBox(height: 10), + Text( + "Automations", + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 3), + Visibility( + visible: state.automations.isNotEmpty, + replacement: Text( + "No automations found", + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.grayColor, + ), + ), + child: SizedBox( + height: 200, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: state.automations.length, + itemBuilder: (context, index) { + final isLoading = + state.automations.contains(state.automations[index].id); + + return Column( + children: [ + Padding( + padding: EdgeInsets.only( + right: isSmallScreenSize(context) ? 4.0 : 8.0, + ), + child: RoutineViewCard( + isLoading: isLoading, + onChanged: (v) { + context.read().add( + UpdateAutomationStatus( + automationId: state.automations[index].id, + automationStatusUpdate: + AutomationStatusUpdate( + spaceUuid: + state.automations[index].spaceId, + isEnable: v, + ), + communityId: + state.automations[index].communityId, + ), + ); + }, + status: state.automations[index].status, + communityId: '', + spaceId: state.automations[index].spaceId, + sceneId: '', + automationId: state.automations[index].id, + cardType: 'automations', + spaceName: state.automations[index].spaceName, + onTap: () { + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent( + createRoutineView: true, + ), + ); + context.read().add( + GetAutomationDetails( + automationId: state.automations[index].id, + isAutomation: true, + isUpdate: true, + ), + ); + }, + textString: state.automations[index].name, + icon: state.automations[index].icon ?? + Assets.automation, + ), + ), + ], + ); + }, + ), + ), + ) + ], + ), + ), + ); }, ); } From 9431eb79c1ab7b7f062d58921b431a0738310386 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Thu, 17 Apr 2025 13:18:44 +0300 Subject: [PATCH 5/5] Fix loading state handling and refactor scene/automation rendering in `FetchRoutineScenesAutomation` --- .../fetch_routine_scenes_automation.dart | 281 +++++++++--------- 1 file changed, 140 insertions(+), 141 deletions(-) diff --git a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart index 3e5d4e7f..f935fef8 100644 --- a/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart +++ b/lib/pages/routines/widgets/main_routine_view/fetch_routine_scenes_automation.dart @@ -16,7 +16,7 @@ class FetchRoutineScenesAutomation extends StatelessWidget Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - if (state.isLoading) const Center(child: CircularProgressIndicator()); + if (state.isLoading) return const Center(child: CircularProgressIndicator()); return SingleChildScrollView( child: Padding( @@ -25,159 +25,25 @@ class FetchRoutineScenesAutomation extends StatelessWidget crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Text( - "Scenes (Tab to Run)", - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.bold, - ), - ), + _buildListTitle(context, "Scenes (Tab to Run)"), const SizedBox(height: 10), Visibility( visible: state.scenes.isNotEmpty, - replacement: Text( - "No scenes found", - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.grayColor, - ), - ), + replacement: _buildEmptyState(context, "No scenes found"), child: SizedBox( height: 200, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: state.scenes.length, - itemBuilder: (context, index) { - final scene = state.scenes[index]; - final isLoading = state.loadingSceneId == scene.id; - - return Padding( - padding: EdgeInsets.only( - right: isSmallScreenSize(context) ? 4.0 : 8.0, - ), - child: Column( - children: [ - RoutineViewCard( - isLoading: isLoading, - sceneOnTap: () { - context.read().add( - SceneTrigger( - sceneId: scene.id, - name: scene.name, - ), - ); - }, - status: state.scenes[index].status, - communityId: state.scenes[index].communityId, - spaceId: state.scenes[index].spaceId, - sceneId: state.scenes[index].sceneTuyaId!, - automationId: state.scenes[index].id, - cardType: 'scenes', - spaceName: state.scenes[index].spaceName, - onTap: () { - BlocProvider.of(context).add( - const CreateNewRoutineViewEvent( - createRoutineView: true, - ), - ); - context.read().add( - GetSceneDetails( - sceneId: state.scenes[index].id, - isTabToRun: true, - isUpdate: true, - ), - ); - }, - textString: state.scenes[index].name, - icon: state.scenes[index].icon ?? - Assets.logoHorizontal, - isFromScenes: true, - iconInBytes: state.scenes[index].iconInBytes, - ), - ], - ), - ); - }), + child: _buildScenes(state), ), ), const SizedBox(height: 10), - Text( - "Automations", - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.bold, - ), - ), + _buildListTitle(context, "Automations"), const SizedBox(height: 3), Visibility( visible: state.automations.isNotEmpty, - replacement: Text( - "No automations found", - style: context.textTheme.bodyMedium?.copyWith( - color: ColorsManager.grayColor, - ), - ), + replacement: _buildEmptyState(context, "No automations found"), child: SizedBox( height: 200, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: state.automations.length, - itemBuilder: (context, index) { - final isLoading = - state.automations.contains(state.automations[index].id); - - return Column( - children: [ - Padding( - padding: EdgeInsets.only( - right: isSmallScreenSize(context) ? 4.0 : 8.0, - ), - child: RoutineViewCard( - isLoading: isLoading, - onChanged: (v) { - context.read().add( - UpdateAutomationStatus( - automationId: state.automations[index].id, - automationStatusUpdate: - AutomationStatusUpdate( - spaceUuid: - state.automations[index].spaceId, - isEnable: v, - ), - communityId: - state.automations[index].communityId, - ), - ); - }, - status: state.automations[index].status, - communityId: '', - spaceId: state.automations[index].spaceId, - sceneId: '', - automationId: state.automations[index].id, - cardType: 'automations', - spaceName: state.automations[index].spaceName, - onTap: () { - BlocProvider.of(context).add( - const CreateNewRoutineViewEvent( - createRoutineView: true, - ), - ); - context.read().add( - GetAutomationDetails( - automationId: state.automations[index].id, - isAutomation: true, - isUpdate: true, - ), - ); - }, - textString: state.automations[index].name, - icon: state.automations[index].icon ?? - Assets.automation, - ), - ), - ], - ); - }, - ), + child: _buildAutomations(state), ), ) ], @@ -187,4 +53,137 @@ class FetchRoutineScenesAutomation extends StatelessWidget }, ); } + + Widget _buildAutomations(RoutineState state) { + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: state.automations.length, + itemBuilder: (context, index) { + final isLoading = state.automations.contains(state.automations[index].id); + + return Column( + children: [ + Padding( + padding: EdgeInsets.only( + right: isSmallScreenSize(context) ? 4.0 : 8.0, + ), + child: RoutineViewCard( + isLoading: isLoading, + onChanged: (v) { + context.read().add( + UpdateAutomationStatus( + automationId: state.automations[index].id, + automationStatusUpdate: AutomationStatusUpdate( + spaceUuid: state.automations[index].spaceId, + isEnable: v, + ), + communityId: state.automations[index].communityId, + ), + ); + }, + status: state.automations[index].status, + communityId: '', + spaceId: state.automations[index].spaceId, + sceneId: '', + automationId: state.automations[index].id, + cardType: 'automations', + spaceName: state.automations[index].spaceName, + onTap: () { + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent( + createRoutineView: true, + ), + ); + context.read().add( + GetAutomationDetails( + automationId: state.automations[index].id, + isAutomation: true, + isUpdate: true, + ), + ); + }, + textString: state.automations[index].name, + icon: state.automations[index].icon ?? Assets.automation, + ), + ), + ], + ); + }, + ); + } + + Widget _buildScenes(RoutineState state) { + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: state.scenes.length, + itemBuilder: (context, index) { + final scene = state.scenes[index]; + final isLoading = state.loadingSceneId == scene.id; + + return Padding( + padding: EdgeInsets.only( + right: isSmallScreenSize(context) ? 4.0 : 8.0, + ), + child: Column( + children: [ + RoutineViewCard( + isLoading: isLoading, + sceneOnTap: () { + context.read().add( + SceneTrigger( + sceneId: scene.id, + name: scene.name, + ), + ); + }, + status: state.scenes[index].status, + communityId: state.scenes[index].communityId, + spaceId: state.scenes[index].spaceId, + sceneId: state.scenes[index].sceneTuyaId!, + automationId: state.scenes[index].id, + cardType: 'scenes', + spaceName: state.scenes[index].spaceName, + onTap: () { + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent( + createRoutineView: true, + ), + ); + context.read().add( + GetSceneDetails( + sceneId: state.scenes[index].id, + isTabToRun: true, + isUpdate: true, + ), + ); + }, + textString: state.scenes[index].name, + icon: state.scenes[index].icon ?? Assets.logoHorizontal, + isFromScenes: true, + iconInBytes: state.scenes[index].iconInBytes, + ), + ], + ), + ); + }); + } + + Widget _buildListTitle(BuildContext context, String title) { + return Text( + title, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, + ), + ); + } + + Widget _buildEmptyState(BuildContext context, String title) { + return Text( + title, + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.grayColor, + ), + ); + } }