From 2f6d0739554ebf551080a757a8bc629bf1963ad1 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 29 Jul 2024 22:36:05 +0300 Subject: [PATCH 1/3] fix bugs --- .../smart_scene_select_dart_bloc.dart | 32 +- .../scene/enum/create_scene_enum.dart | 1 + .../scene/helper/scene_logic_helper.dart | 236 +++++++------ .../scene/model/create_scene_model.dart | 16 +- .../scene/model/smart_scene_enable.dart | 8 + lib/features/scene/view/scene_tasks_view.dart | 7 + .../view/smart_automation_select_route.dart | 44 ++- .../widgets/create_scene_save_button.dart | 10 +- .../if_then_containers/if_container.dart | 316 +++++++++--------- .../if_then_containers/then_added_tasks.dart | 112 ++++--- .../smart_automation_list.dart | 14 +- .../smart_tab_run_list.dart | 4 + 12 files changed, 441 insertions(+), 359 deletions(-) diff --git a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart index daf9e75..9ef5b8b 100644 --- a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart +++ b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart @@ -2,8 +2,14 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; +import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; +import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/model/smart_scene_enable.dart'; - +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/navigation/navigation_service.dart'; part 'smart_scene_select_dart_event.dart'; part 'smart_scene_select_dart_state.dart'; @@ -19,7 +25,29 @@ class SmartSceneSelectBloc FutureOr _onSmartSceneEnable( SmartSceneEnableEvent event, Emitter emit) { smartSceneEnable = event.smartSceneEnable; + NavigationService.navigatorKey.currentState!.context + .read() + .add(TempHoldSceneTasksEvent( + deviceControlModel: DeviceControlModel( + deviceId: smartSceneEnable?.entityId ?? '', + code: CreateSceneEnum.smartSceneSelect.name, + value: '', + ), + deviceId: smartSceneEnable?.sceneORAutomationName ?? '', + operation: smartSceneEnable?.actionExecutor ?? '', + icon: smartSceneEnable?.isAutomation == true + ? Assets.player + : Assets.handClickIcon, + deviceName: smartSceneEnable?.sceneORAutomationName ?? '', + uniqueId: '', + operationType: OperationDialogType.none, + isAutomation: false, + )); + emit(SmartSceneSelected(smartSceneEnable: smartSceneEnable!)); + NavigationService.navigatorKey.currentState!.context + .read() + .add(const AddTaskEvent(isAutomation: false)); } FutureOr _smartSceneClear( @@ -27,4 +55,4 @@ class SmartSceneSelectBloc smartSceneEnable = null; emit(SmartSceneSelectInitial()); } -} \ No newline at end of file +} diff --git a/lib/features/scene/enum/create_scene_enum.dart b/lib/features/scene/enum/create_scene_enum.dart index 5eaf0fb..9a88069 100644 --- a/lib/features/scene/enum/create_scene_enum.dart +++ b/lib/features/scene/enum/create_scene_enum.dart @@ -1,5 +1,6 @@ enum CreateSceneEnum { tabToRun, deviceStatusChanges, + smartSceneSelect, none, } diff --git a/lib/features/scene/helper/scene_logic_helper.dart b/lib/features/scene/helper/scene_logic_helper.dart index b1d3086..887370f 100644 --- a/lib/features/scene/helper/scene_logic_helper.dart +++ b/lib/features/scene/helper/scene_logic_helper.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/model/create_automation_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; @@ -32,142 +33,129 @@ mixin SceneLogicHelper { final sceneBloc = context.read(); final smartSceneBloc = context.read(); + if (isOnlyDelayOrDelayLast(actions)) { + context.showCustomSnackbar( + message: 'A single delay or delay-last operations are NOT allowed.', + icon: const Icon( + Icons.error, + color: Colors.red, + ), + ); + return; + } + if (isAutomation) { - // Handle Automation Creation - if (isOnlyDelayOrDelayLast(actions)) { - Navigator.pop(context); - context.showCustomSnackbar( - message: 'A single delay or delay-last operations are NOT allowed.', - icon: const Icon( - Icons.error, - color: Colors.red, - ), - ); - } else { - final createAutomationModel = CreateAutomationModel( - unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '', - automationName: sceneName.text, - decisionExpr: sceneBloc.conditionRule, - effectiveTime: sceneBloc.effectiveTime ?? - EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'), - conditions: List.generate( - conditions.length, + final createAutomationModel = CreateAutomationModel( + unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '', + automationName: sceneName.text, + decisionExpr: sceneBloc.conditionRule, + effectiveTime: sceneBloc.effectiveTime ?? + EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'), + conditions: List.generate( + conditions.length, + (index) { + final task = conditions[index]; + return CreateCondition( + code: index + 1, + entityId: task.deviceId, + entityType: 'device_report', + expr: ConditionExpr( + statusCode: task.code, + comparator: task.comparator ?? '==', + statusValue: task.functionValue, + ), + ); + }, + ), + actions: [ + ...List.generate( + actions.length, (index) { - final task = conditions[index]; - return CreateCondition( - code: index + 1, + final task = actions[index]; + if (task.deviceId == 'delay') { + return CreateSceneAction( + entityId: actions[index].deviceId, + actionExecutor: 'delay', + executorProperty: CreateSceneExecutorProperty( + functionCode: '', + functionValue: '', + delaySeconds: task.functionValue, + ), + ); + } + if (task.code == CreateSceneEnum.smartSceneSelect.name) { + return CreateSceneAction( + entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', + actionExecutor: + smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', + executorProperty: null); + } + return CreateSceneAction( entityId: task.deviceId, - entityType: 'device_report', - expr: ConditionExpr( - statusCode: task.code, - comparator: task.comparator ?? '==', - statusValue: task.functionValue, + actionExecutor: 'device_issue', + executorProperty: CreateSceneExecutorProperty( + functionCode: task.code, + functionValue: task.functionValue, + delaySeconds: 0, ), ); }, ), - actions: [ - ...List.generate( - actions.length, - (index) { - final task = actions[index]; - if (task.deviceId == 'delay') { - return CreateSceneAction( - entityId: actions[index].deviceId, - actionExecutor: 'delay', - executorProperty: CreateSceneExecutorProperty( - functionCode: '', - functionValue: '', - delaySeconds: task.functionValue, - ), - ); - } - return CreateSceneAction( - entityId: task.deviceId, - actionExecutor: 'device_issue', - executorProperty: CreateSceneExecutorProperty( - functionCode: task.code, - functionValue: task.functionValue, - delaySeconds: 0, - ), - ); - }, - ), - if (smartSceneBloc.smartSceneEnable != null) - CreateSceneAction( - entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', - actionExecutor: - smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', - executorProperty: null) - ], - ); - sceneBloc.add(CreateSceneWithTasksEvent( - createSceneModel: null, - updateScene: updateScene, - sceneId: sceneId, - createAutomationModel: createAutomationModel, - )); - Navigator.pop(context); - } + ], + ); + sceneBloc.add(CreateSceneWithTasksEvent( + createSceneModel: null, + updateScene: updateScene, + sceneId: sceneId, + createAutomationModel: createAutomationModel, + )); } else { - if (isOnlyDelayOrDelayLast(actions)) { - Navigator.pop(context); - context.showCustomSnackbar( - message: 'A single delay or delay-last operations are NOT allowed.', - icon: const Icon( - Icons.error, - color: Colors.red, - ), - ); - } else { - // Handle Scene Creation - final createSceneModel = CreateSceneModel( - unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '', - sceneName: sceneName.text, - decisionExpr: 'and', - actions: [ - ...List.generate( - actions.length, - (index) { - final task = actions[index]; - if (task.deviceId == 'delay') { - return CreateSceneAction( - entityId: actions[index].deviceId, - actionExecutor: 'delay', - executorProperty: CreateSceneExecutorProperty( - functionCode: '', - functionValue: '', - delaySeconds: task.functionValue, - ), - ); - } + final createSceneModel = CreateSceneModel( + unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '', + sceneName: sceneName.text, + decisionExpr: 'and', + actions: [ + ...List.generate( + actions.length, + (index) { + final task = actions[index]; + if (task.deviceId == 'delay') { return CreateSceneAction( - entityId: task.deviceId, - actionExecutor: 'device_issue', + entityId: actions[index].deviceId, + actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( - functionCode: task.code, - functionValue: task.functionValue, - delaySeconds: 0, + functionCode: '', + functionValue: '', + delaySeconds: task.functionValue, ), ); - }, - ), - if (smartSceneBloc.smartSceneEnable != null) - CreateSceneAction( - entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', - actionExecutor: - smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', - executorProperty: null) - ], - ); - sceneBloc.add(CreateSceneWithTasksEvent( - createSceneModel: createSceneModel, - createAutomationModel: null, - updateScene: updateScene, - sceneId: sceneId, - )); - Navigator.pop(context); - } + } + if (task.code == CreateSceneEnum.smartSceneSelect.name) { + return CreateSceneAction( + entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', + actionExecutor: + smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', + executorProperty: null); + } + return CreateSceneAction( + entityId: task.deviceId, + actionExecutor: 'device_issue', + executorProperty: CreateSceneExecutorProperty( + functionCode: task.code, + functionValue: task.functionValue, + delaySeconds: 0, + ), + ); + }, + ), + ], + ); + sceneBloc.add(CreateSceneWithTasksEvent( + createSceneModel: createSceneModel, + createAutomationModel: null, + updateScene: updateScene, + sceneId: sceneId, + )); } } diff --git a/lib/features/scene/model/create_scene_model.dart b/lib/features/scene/model/create_scene_model.dart index 0d19345..5475b93 100644 --- a/lib/features/scene/model/create_scene_model.dart +++ b/lib/features/scene/model/create_scene_model.dart @@ -102,12 +102,18 @@ class CreateSceneAction { } Map toMap() { - return { - 'entityId': entityId, - 'actionExecutor': actionExecutor, - if (executorProperty != null) + if (executorProperty != null) { + return { + 'entityId': entityId, + 'actionExecutor': actionExecutor, 'executorProperty': executorProperty?.toMap(actionExecutor), - }; + }; + } else { + return { + 'entityId': entityId, + 'actionExecutor': actionExecutor, + }; + } } factory CreateSceneAction.fromMap(Map map) { diff --git a/lib/features/scene/model/smart_scene_enable.dart b/lib/features/scene/model/smart_scene_enable.dart index c855925..40a2d8c 100644 --- a/lib/features/scene/model/smart_scene_enable.dart +++ b/lib/features/scene/model/smart_scene_enable.dart @@ -1,16 +1,22 @@ class SmartSceneEnable { final String entityId; final String actionExecutor; + final String sceneORAutomationName; + final bool isAutomation; SmartSceneEnable({ required this.entityId, required this.actionExecutor, + required this.sceneORAutomationName, + required this.isAutomation, }); factory SmartSceneEnable.fromJson(Map json) { return SmartSceneEnable( entityId: json['entityId'], actionExecutor: json['actionExecutor'], + sceneORAutomationName: json['sceneORAutomationName'], + isAutomation: json['isAutomation'], ); } @@ -18,6 +24,8 @@ class SmartSceneEnable { return { 'entityId': entityId, 'actionExecutor': actionExecutor, + 'sceneORAutomationName': sceneORAutomationName, + 'isAutomation': isAutomation, }; } } diff --git a/lib/features/scene/view/scene_tasks_view.dart b/lib/features/scene/view/scene_tasks_view.dart index 4ac5b4f..ccd275b 100644 --- a/lib/features/scene/view/scene_tasks_view.dart +++ b/lib/features/scene/view/scene_tasks_view.dart @@ -36,6 +36,13 @@ class SceneTasksView extends StatelessWidget { ? sceneSettings.sceneName : StringsManager.createScene, padding: EdgeInsets.zero, + leading: IconButton( + onPressed: () { + navigateToRoute(context, Routes.homeRoute); + }, + icon: const Icon( + Icons.arrow_back_ios, + )), actions: [ Visibility( visible: sceneSettings.sceneType.isNotEmpty, diff --git a/lib/features/scene/view/smart_automation_select_route.dart b/lib/features/scene/view/smart_automation_select_route.dart index 6b059ef..76efd84 100644 --- a/lib/features/scene/view/smart_automation_select_route.dart +++ b/lib/features/scene/view/smart_automation_select_route.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_enable_autoamtion.dart'; import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_enable_tab_run.dart'; @@ -15,6 +18,7 @@ class SmartAutomationSelectView extends StatelessWidget { @override Widget build(BuildContext context) { + final sceneType = context.read().sceneType; return DefaultScaffold( title: "Select Smart Scene", padding: const EdgeInsets.only(top: 24), @@ -25,28 +29,38 @@ class SmartAutomationSelectView extends StatelessWidget { icon: const Icon( Icons.arrow_back_ios, )), - height: 260, + height: sceneType.name == CreateSceneEnum.deviceStatusChanges.name + ? 260 + : 200, child: DefaultContainer( width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SceneListTile( - assetPath: Assets.handClickIcon, - titleString: "Tap To Run", - subtitleString: '', - trailingWidget: const Icon( - Icons.arrow_forward_ios_rounded, - color: ColorsManager.greyColor, + Visibility( + visible: + sceneType.name == CreateSceneEnum.deviceStatusChanges.name, + child: SceneListTile( + assetPath: Assets.handClickIcon, + titleString: "Tap To Run", + subtitleString: '', + trailingWidget: const Icon( + Icons.arrow_forward_ios_rounded, + color: ColorsManager.greyColor, + ), + onPressed: () { + context.customBottomSheet( + child: const SmartEnableTabRun(), + ); + }, ), - onPressed: () { - context.customBottomSheet( - child: const SmartEnableTabRun(), - ); - }, ), - const Divider( - color: ColorsManager.dividerColor, + Visibility( + visible: + sceneType.name == CreateSceneEnum.deviceStatusChanges.name, + child: const Divider( + color: ColorsManager.dividerColor, + ), ), SceneListTile( assetPath: Assets.refreshIcon, diff --git a/lib/features/scene/widgets/create_scene_save_button.dart b/lib/features/scene/widgets/create_scene_save_button.dart index 59e375b..1bb7f8c 100644 --- a/lib/features/scene/widgets/create_scene_save_button.dart +++ b/lib/features/scene/widgets/create_scene_save_button.dart @@ -8,6 +8,7 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart import 'package:syncrow_app/navigation/navigate_to_route.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/utils/context_extension.dart'; +import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class CreateSceneSaveButton extends StatefulWidget { @@ -57,13 +58,7 @@ class _CreateSceneSaveButtonState extends State sceneNameController.text = ''; } } else if (state is CreateSceneError) { - context.showCustomSnackbar( - message: state.message, - icon: const Icon( - Icons.error, - color: Colors.red, - ), - ); + CustomSnackBar.displaySnackBar(state.message); } }, builder: (context, state) { @@ -106,6 +101,7 @@ class _CreateSceneSaveButtonState extends State ), title: 'Scene Name', onConfirm: () { + Navigator.pop(context); if (sceneNameController.text.isNotEmpty) { handleSaveButtonPress( context, diff --git a/lib/features/scene/widgets/if_then_containers/if_container.dart b/lib/features/scene/widgets/if_then_containers/if_container.dart index c7fe028..32b832b 100644 --- a/lib/features/scene/widgets/if_then_containers/if_container.dart +++ b/lib/features/scene/widgets/if_then_containers/if_container.dart @@ -27,94 +27,164 @@ class IFDefaultContainer extends StatelessWidget { @override Widget build(BuildContext context) { - final sceneType = context.read().sceneType; - return DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SceneListTile( - leadingWidget: InkWell( - onTap: () { - if (sceneType.name == - CreateSceneEnum.deviceStatusChanges.name) { - context.customAlertDialog( - hideConfirmButton: true, - alertBody: Column( - children: [ - ListTile( - title: const BodyMedium( - text: "When all conditions are met"), - onTap: () { - context.read().add( - const SelectConditionEvent( - "When all conditions are met")); - Navigator.pop(context); + return BlocBuilder( + builder: (context, state) { + final sceneType = context.read().sceneType; + return DefaultContainer( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SceneListTile( + leadingWidget: InkWell( + onTap: () { + if (sceneType.name == + CreateSceneEnum.deviceStatusChanges.name) { + context.customAlertDialog( + hideConfirmButton: true, + alertBody: Column( + children: [ + ListTile( + title: const BodyMedium( + text: "When all conditions are met"), + onTap: () { + context.read().add( + const SelectConditionEvent( + "When all conditions are met")); + Navigator.pop(context); + }, + ), + ListTile( + title: const BodyMedium( + text: "When any condition is met"), + onTap: () { + context.read().add( + const SelectConditionEvent( + "When any condition is met")); + Navigator.pop(context); + }, + ), + ], + ), + title: 'Conditions Rule', + onConfirm: () {}, + ); + } + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + BodyLarge( + text: 'IF', + style: context.bodyLarge.copyWith( + fontWeight: FontWeight.bold, + color: ColorsManager.primaryTextColor, + ), + ), + Visibility( + visible: sceneType.name == + CreateSceneEnum.deviceStatusChanges.name, + child: BlocBuilder( + builder: (context, state) { + String conditionText = "When any condition is met"; + if (state is AddSceneTask) { + if (state.condition == 'or') { + conditionText = "When any condition is met"; + } else { + conditionText = "When all conditions are met"; + } + } + return SizedBox( + width: context.width * 0.6, + child: Row(children: [ + BodySmall(text: conditionText), + const Icon(Icons.keyboard_arrow_down) + ]), + ); }, ), - ListTile( - title: const BodyMedium( - text: "When any condition is met"), - onTap: () { - context.read().add( - const SelectConditionEvent( - "When any condition is met")); - Navigator.pop(context); - }, + ), + ], + ), + ), + trailingWidget: BlocBuilder( + builder: (context, state) { + bool isClickable = false; + if (state is AddSceneTask) { + isClickable = + state.automationTasksList?.isNotEmpty ?? false; + } + return GestureDetector( + onTap: isClickable + ? () => Navigator.pushNamed( + context, + Routes.sceneControlDevicesRoute, + arguments: SceneSettingsRouteArguments( + sceneType: + CreateSceneEnum.deviceStatusChanges.name, + sceneId: '', + sceneName: '', + ), + ) + : null, + child: SvgPicture.asset( + Assets.addIcon, + colorFilter: ColorFilter.mode( + isClickable + ? ColorsManager.primaryColor + : ColorsManager.greyColor, + BlendMode.srcIn, ), - ], - ), - title: 'Conditions Rule', - onConfirm: () {}, - ); - } - }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - BodyLarge( - text: 'IF', - style: context.bodyLarge.copyWith( - fontWeight: FontWeight.bold, - color: ColorsManager.primaryTextColor, - ), - ), - Visibility( - visible: sceneType.name == - CreateSceneEnum.deviceStatusChanges.name, - child: BlocBuilder( - builder: (context, state) { - String conditionText = "When any condition is met"; - if (state is AddSceneTask) { - if (state.condition == 'or') { - conditionText = "When any condition is met"; - } else { - conditionText = "When all conditions are met"; - } - } - return SizedBox( - width: context.width * 0.6, - child: Row(children: [ - BodySmall(text: conditionText), - const Icon(Icons.keyboard_arrow_down) - ]), - ); - }, - ), - ), - ], + ), + ); + }, + ), + padding: EdgeInsets.zero, ), - ), - trailingWidget: BlocBuilder( - builder: (context, state) { - bool isClickable = false; - if (state is AddSceneTask) { - isClickable = state.automationTasksList?.isNotEmpty ?? false; - } - return GestureDetector( - onTap: isClickable - ? () => Navigator.pushNamed( + const LightDivider(), + BlocBuilder( + builder: (context, state) { + if (state is AddSceneTask) { + final automationTasksList = state.automationTasksList; + if (automationTasksList?.isNotEmpty == true) { + return ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: automationTasksList?.length, + reverse: true, + itemBuilder: (context, index) { + return ThenAddedTasksContainer( + taskItem: automationTasksList![index], + isAutomation: true, + ); + }, + ); + } + } + final sceneType = context.read().sceneType; + if (sceneType.name == CreateSceneEnum.tabToRun.name) { + return const SceneListTile( + padding: EdgeInsets.symmetric(horizontal: 2), + assetPath: Assets.handClickIcon, + titleString: StringsManager.tapToRun, + subtitleString: '', + ); + } + return SceneListTile( + titleString: '+ Add Condition', + textAlign: TextAlign.center, + onPressed: () { + final sceneType = + context.read().sceneType; + if (sceneType.name == CreateSceneEnum.none.name) { + Navigator.push( + context, + CustomPageRoute( + builder: (context) => + const CreateSceneView())); + } else { + Navigator.pushNamed( context, Routes.sceneControlDevicesRoute, arguments: SceneSettingsRouteArguments( @@ -123,77 +193,15 @@ class IFDefaultContainer extends StatelessWidget { sceneId: '', sceneName: '', ), - ) - : null, - child: SvgPicture.asset( - Assets.addIcon, - colorFilter: ColorFilter.mode( - isClickable - ? ColorsManager.primaryColor - : ColorsManager.greyColor, - BlendMode.srcIn, - ), - ), - ); - }, - ), - padding: EdgeInsets.zero, + ); + } + }); + }, + ) + ], ), - const LightDivider(), - BlocBuilder( - builder: (context, state) { - if (state is AddSceneTask) { - final automationTasksList = state.automationTasksList; - if (automationTasksList?.isNotEmpty == true) { - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: automationTasksList?.length, - reverse: true, - itemBuilder: (context, index) { - return ThenAddedTasksContainer( - taskItem: automationTasksList![index], - isAutomation: true, - ); - }, - ); - } - } - final sceneType = context.read().sceneType; - if (sceneType.name == CreateSceneEnum.tabToRun.name) { - return const SceneListTile( - padding: EdgeInsets.symmetric(horizontal: 2), - assetPath: Assets.handClickIcon, - titleString: StringsManager.tapToRun, - subtitleString: '', - ); - } - return SceneListTile( - titleString: '+ Add Condition', - textAlign: TextAlign.center, - onPressed: () { - final sceneType = context.read().sceneType; - if (sceneType.name == CreateSceneEnum.none.name) { - Navigator.push( - context, - CustomPageRoute( - builder: (context) => const CreateSceneView())); - } else { - Navigator.pushNamed( - context, - Routes.sceneControlDevicesRoute, - arguments: SceneSettingsRouteArguments( - sceneType: CreateSceneEnum.deviceStatusChanges.name, - sceneId: '', - sceneName: '', - ), - ); - } - }); - }, - ) - ], - ), + ); + }, ); } } diff --git a/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart b/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart index 8cbb450..8f7f4ee 100644 --- a/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart +++ b/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart'; import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart'; import 'package:syncrow_app/features/scene/model/scene_static_function.dart'; @@ -62,58 +63,63 @@ class ThenAddedTasksContainer extends StatelessWidget operationValue = functionValue.toString(); } return DefaultContainer( - onTap: () { - List functionOperation = []; + onTap: taskItem.code == CreateSceneEnum.smartSceneSelect.name + ? null + : () { + List functionOperation = []; - /// get the task functions - functionOperation = List.from(getOperationsForOneFunction( - taskItem: taskItem, - deviceId: taskItem.deviceId, - isAutomation: isAutomation ?? false)); + /// get the task functions + functionOperation = List.from(getOperationsForOneFunction( + taskItem: taskItem, + deviceId: taskItem.deviceId, + isAutomation: isAutomation ?? false)); - /// show alert dialog based on type - context.customAlertDialog( - alertBody: getTheCorrectDialogBody(functionOperation.first, null, - isAutomation: isAutomation ?? false), - title: functionOperation.first.operationName, - onConfirm: () { - final savedCode = functionOperation.first.deviceId.contains('delay') - ? 'delay' - : functionOperation.first.code; - if (isAutomation == true) { - final automationSelectedValue = - createSceneBloc.automationSelectedValues[savedCode]; + /// show alert dialog based on type + context.customAlertDialog( + alertBody: getTheCorrectDialogBody( + functionOperation.first, null, + isAutomation: isAutomation ?? false), + title: functionOperation.first.operationName, + onConfirm: () { + final savedCode = + functionOperation.first.deviceId.contains('delay') + ? 'delay' + : functionOperation.first.code; + if (isAutomation == true) { + final automationSelectedValue = + createSceneBloc.automationSelectedValues[savedCode]; - try { - createSceneBloc.add( - UpdateTaskEvent( - newValue: automationSelectedValue, - taskId: taskItem.uniqueCustomId, - isAutomation: true, - ), - ); - } catch (e) { - debugPrint('Error adding UpdateTaskEvent: $e'); - } - } else { - final selectedValue = createSceneBloc.selectedValues[savedCode]; + try { + createSceneBloc.add( + UpdateTaskEvent( + newValue: automationSelectedValue, + taskId: taskItem.uniqueCustomId, + isAutomation: true, + ), + ); + } catch (e) { + debugPrint('Error adding UpdateTaskEvent: $e'); + } + } else { + final selectedValue = + createSceneBloc.selectedValues[savedCode]; - try { - createSceneBloc.add( - UpdateTaskEvent( - newValue: selectedValue, - taskId: taskItem.uniqueCustomId, - ), - ); - } catch (e) { - debugPrint('Error adding UpdateTaskEvent: $e'); - } - } + try { + createSceneBloc.add( + UpdateTaskEvent( + newValue: selectedValue, + taskId: taskItem.uniqueCustomId, + ), + ); + } catch (e) { + debugPrint('Error adding UpdateTaskEvent: $e'); + } + } - Navigator.pop(context); - }, - ); - }, + Navigator.pop(context); + }, + ); + }, padding: EdgeInsets.zero, child: Dismissible( key: Key(taskItem.uniqueCustomId.toString()), @@ -171,12 +177,20 @@ class ThenAddedTasksContainer extends StatelessWidget subtitleWidget: Row( children: [ BodyMedium( - text: "${taskItem.operationName}: ", + text: taskItem.code == CreateSceneEnum.smartSceneSelect.name + ? taskItem.icon.contains('player') + ? 'Automation: ' + : "Tab-To-Run: " + : "${taskItem.operationName}: ", fontColor: ColorsManager.secondaryTextColor, fontWeight: FontWeight.normal, ), BodyMedium( - text: operationValue, + text: taskItem.code == CreateSceneEnum.smartSceneSelect.name + ? taskItem.operationName == 'rule_enable' + ? 'Enable' + : "Disable" + : operationValue, fontColor: ColorsManager.secondaryTextColor, fontWeight: FontWeight.normal, ), diff --git a/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart b/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart index e987f4a..afdef0f 100644 --- a/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart +++ b/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart @@ -125,6 +125,7 @@ class _SmartSceneSelectAutomationListState alertBody: EnableDisableAutomationDialog( automationId: automation.id, descriptionSelected: descriptionSelected, + sceneORAutomationName: automation.name, ), title: automation.name, onConfirm: () { @@ -157,6 +158,7 @@ class _SmartSceneSelectAutomationListState alertBody: EnableDisableAutomationDialog( automationId: automation.id, descriptionSelected: descriptionSelected, + sceneORAutomationName: automation.name, ), title: automation.name, onConfirm: () { @@ -191,10 +193,12 @@ class EnableDisableAutomationDialog extends StatefulWidget { super.key, required this.automationId, required this.descriptionSelected, + required this.sceneORAutomationName, }); final String automationId; final String descriptionSelected; + final String sceneORAutomationName; @override State createState() => @@ -251,9 +255,11 @@ class _EnableDisableAutomationDialogState .read() .add(SmartSceneEnableEvent( SmartSceneEnable( - entityId: widget.automationId, - actionExecutor: value!, - ), + entityId: widget.automationId, + actionExecutor: value!, + sceneORAutomationName: + widget.sceneORAutomationName, + isAutomation: true), )); }, ), @@ -267,6 +273,8 @@ class _EnableDisableAutomationDialogState SmartSceneEnable( entityId: widget.automationId, actionExecutor: operation.value, + sceneORAutomationName: widget.sceneORAutomationName, + isAutomation: true, ), )); }, diff --git a/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart b/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart index 15fc2b6..384b52a 100644 --- a/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart +++ b/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart @@ -89,6 +89,8 @@ class _SmartSceneSelectTabToRunListState .add(SmartSceneEnableEvent(SmartSceneEnable( entityId: scene.id, actionExecutor: 'rule_enable', + sceneORAutomationName: scene.name, + isAutomation: false, ))); } }), @@ -101,6 +103,8 @@ class _SmartSceneSelectTabToRunListState .add(SmartSceneEnableEvent(SmartSceneEnable( entityId: scene.id, actionExecutor: 'rule_enable', + sceneORAutomationName: scene.name, + isAutomation: false, ))); }, ); From a242876e16fba7bdec348233b888e1c8fa5049c1 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Tue, 30 Jul 2024 12:34:26 +0300 Subject: [PATCH 2/3] fix setting icon appearance --- lib/features/scene/view/scene_tasks_view.dart | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/lib/features/scene/view/scene_tasks_view.dart b/lib/features/scene/view/scene_tasks_view.dart index ccd275b..9cfea64 100644 --- a/lib/features/scene/view/scene_tasks_view.dart +++ b/lib/features/scene/view/scene_tasks_view.dart @@ -44,31 +44,36 @@ class SceneTasksView extends StatelessWidget { Icons.arrow_back_ios, )), actions: [ - Visibility( - visible: sceneSettings.sceneType.isNotEmpty, - child: SizedBox( - width: 40, - child: GestureDetector( - onTap: () { - Navigator.pushNamed( - context, - Routes.sceneAutoSettingsRoute, - arguments: { - "sceneId": sceneSettings.sceneId, - "isAutomation": isAutomation, - "sceneName": sceneSettings.sceneName, + BlocBuilder( + builder: (context, state) { + final sceneType = context.read().sceneType; + return Visibility( + visible: sceneType != CreateSceneEnum.none, + child: SizedBox( + width: 40, + child: GestureDetector( + onTap: () { + Navigator.pushNamed( + context, + Routes.sceneAutoSettingsRoute, + arguments: { + "sceneId": sceneSettings.sceneId, + "isAutomation": isAutomation, + "sceneName": sceneSettings.sceneName, + }, + ); }, - ); - }, - child: SvgPicture.asset( - Assets.assetsIconsSettings, - colorFilter: const ColorFilter.mode( - ColorsManager.textPrimaryColor, - BlendMode.srcIn, + child: SvgPicture.asset( + Assets.assetsIconsSettings, + colorFilter: const ColorFilter.mode( + ColorsManager.textPrimaryColor, + BlendMode.srcIn, + ), + ), ), ), - ), - ), + ); + }, ), ], child: Stack( From b66fbc32e765459bec5bb81b6fa4976c5da67975 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Thu, 1 Aug 2024 03:11:03 +0300 Subject: [PATCH 3/3] push fixes --- lib/features/app_layout/bloc/home_cubit.dart | 6 + .../devices/view/widgets/scene_listview.dart | 3 + .../bloc/create_scene/create_scene_bloc.dart | 127 ++++++--- .../effective_period/effect_period_bloc.dart | 55 +++- .../effective_period/effect_period_event.dart | 7 + .../effective_period/effect_period_state.dart | 12 + .../smart_scene_select_dart_bloc.dart | 53 ++-- .../smart_scene_select_dart_event.dart | 4 + .../scene/helper/scene_logic_helper.dart | 24 +- .../helper/scene_operations_data_helper.dart | 72 +++++- .../scene/model/scene_details_model.dart | 20 +- .../scene/model/smart_scene_enable.dart | 4 + .../scene/view/device_functions_view.dart | 242 +++++++++--------- .../scene/view/scene_auto_settings.dart | 102 ++++++-- lib/features/scene/view/scene_tasks_view.dart | 70 +++-- .../period_options.dart | 4 +- .../if_then_containers/then_added_tasks.dart | 126 +++++---- .../widgets/scene_view_widget/scene_item.dart | 2 + .../smart_automation_list.dart | 20 ++ .../smart_tab_run_list.dart | 17 ++ lib/my_app.dart | 8 +- 21 files changed, 647 insertions(+), 331 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 9168283..bb1863c 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -18,8 +18,11 @@ import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view. import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart'; import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; +import 'package:syncrow_app/features/scene/model/create_automation_model.dart'; import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart'; import 'package:syncrow_app/features/scene/view/create_scene_view.dart'; import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart'; @@ -385,6 +388,9 @@ class HomeCubit extends Cubit { NavigationService.navigatorKey.currentContext! .read() .add(const SmartSceneClearEvent()); + BlocProvider.of( + NavigationService.navigatorKey.currentState!.context) + .add(ResetEffectivePeriod()); }, ), IconButton( diff --git a/lib/features/devices/view/widgets/scene_listview.dart b/lib/features/devices/view/widgets/scene_listview.dart index cbea49d..d825c6b 100644 --- a/lib/features/devices/view/widgets/scene_listview.dart +++ b/lib/features/devices/view/widgets/scene_listview.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart'; +import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart'; import 'package:syncrow_app/features/scene/model/scenes_model.dart'; diff --git a/lib/features/scene/bloc/create_scene/create_scene_bloc.dart b/lib/features/scene/bloc/create_scene/create_scene_bloc.dart index 6ebfcae..915d8af 100644 --- a/lib/features/scene/bloc/create_scene/create_scene_bloc.dart +++ b/lib/features/scene/bloc/create_scene/create_scene_bloc.dart @@ -92,30 +92,59 @@ class CreateSceneBloc extends Bloc TempHoldSceneTasksEvent event, Emitter emit) { emit(CreateSceneLoading()); bool updated = false; + + // Check and update if the task exists in tempTasksList for (var element in tempTasksList) { - if (element.code == event.deviceControlModel.code) { - // Update the existing function with new values - var updatedElement = element.copyWith( - operationName: event.operation, - deviceName: event.deviceName, - icon: event.icon, - code: event.deviceControlModel.code ?? '', - deviceId: event.deviceId, - functionValue: event.deviceControlModel.value, - operationDialogType: event.operationType, - operationalValues: [ - SceneOperationalValue( - value: event.deviceControlModel.value, - icon: '', - ), - ], - ); - tempTasksList[tempTasksList.indexOf(element)] = updatedElement; - selectedValues[updatedElement.code] = event.deviceControlModel.value; - updated = true; - break; + var updatedElement = element.copyWith( + operationName: event.operation, + deviceName: event.deviceName, + icon: event.icon, + code: event.deviceControlModel.code ?? '', + deviceId: event.deviceId, + functionValue: event.deviceControlModel.value, + operationDialogType: event.operationType, + operationalValues: [ + SceneOperationalValue( + value: event.deviceControlModel.value, + icon: '', + ), + ], + ); + tempTasksList[tempTasksList.indexOf(element)] = updatedElement; + selectedValues[updatedElement.code] = event.deviceControlModel.value; + updated = true; + break; + } + + if (!updated) { + /// for smart scene add to view + for (var element in tasksList) { + if (element.deviceId == event.deviceControlModel.deviceId && + element.code == event.deviceControlModel.code) { + var updatedElement = element.copyWith( + operationName: event.operation, + deviceName: event.deviceName, + icon: event.icon, + code: event.deviceControlModel.code ?? '', + deviceId: event.deviceId, + functionValue: event.deviceControlModel.value, + operationDialogType: event.operationType, + operationalValues: [ + SceneOperationalValue( + value: event.deviceControlModel.value, + icon: '', + ), + ], + ); + tasksList[tasksList.indexOf(element)] = updatedElement; + selectedValues[updatedElement.code] = event.deviceControlModel.value; + updated = true; + break; + } } } + + // Add new element if it doesn't exist in either list if (!updated) { var newElement = SceneStaticFunction( operationName: event.operation, @@ -319,7 +348,8 @@ class CreateSceneBloc extends Bloc automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); - effectiveTime = null; + effectiveTime = + EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); sceneType = CreateSceneEnum.none; conditionRule = 'or'; emit(const CreateSceneWithTasks(success: true)); @@ -369,14 +399,31 @@ class CreateSceneBloc extends Bloc conditionRule = response.decisionExpr ?? conditionRule; - if (response.effectiveTime != null) { - BlocProvider.of( - NavigationService.navigatorKey.currentState!.context) - .add(SetCustomTime(response.effectiveTime!.start, - response.effectiveTime!.end)); - BlocProvider.of( - NavigationService.navigatorKey.currentState!.context) - .add(ToggleDay(response.effectiveTime!.loops)); + effectiveTime = response.effectiveTime != null + ? EffectiveTime( + start: response.effectiveTime!.start, + end: response.effectiveTime!.end, + loops: response.effectiveTime!.loops, + ) + : EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); + + // Set Custom Time and reset days first + BlocProvider.of( + NavigationService.navigatorKey.currentContext!) + .add(SetCustomTime(effectiveTime!.start, effectiveTime!.end)); + + // Reset all days to not selected before toggling + BlocProvider.of( + NavigationService.navigatorKey.currentContext!) + .add(ResetDays()); + + // Iterate over the loops and toggle each day + for (int i = 0; i < effectiveTime!.loops.length; i++) { + if (effectiveTime!.loops[i] == '1') { + BlocProvider.of( + NavigationService.navigatorKey.currentContext!) + .add(ToggleDay(_getDayFromIndex(i))); + } } emit(AddSceneTask( @@ -401,6 +448,11 @@ class CreateSceneBloc extends Bloc } } + String _getDayFromIndex(int index) { + const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + return days[index]; + } + FutureOr _clearTempTaskList( ClearTempTaskListEvent event, Emitter emit) { emit(CreateSceneLoading()); @@ -408,20 +460,15 @@ class CreateSceneBloc extends Bloc automationTempTasksList.clear(); automationSelectedValues.clear(); automationComparatorValues.clear(); - emit(AddSceneTask( - tasksList: tasksList, - automationTasksList: automationTasksList, - condition: conditionRule, - )); } else { tempTasksList.clear(); selectedValues.clear(); - emit(AddSceneTask( - tasksList: tasksList, - automationTasksList: automationTasksList, - condition: conditionRule, - )); } + emit(AddSceneTask( + tasksList: tasksList, + automationTasksList: automationTasksList, + condition: conditionRule, + )); } FutureOr _removeFromSelectedValueById( diff --git a/lib/features/scene/bloc/effective_period/effect_period_bloc.dart b/lib/features/scene/bloc/effective_period/effect_period_bloc.dart index 7fa071c..ea2c501 100644 --- a/lib/features/scene/bloc/effective_period/effect_period_bloc.dart +++ b/lib/features/scene/bloc/effective_period/effect_period_bloc.dart @@ -12,6 +12,8 @@ class EffectPeriodBloc extends Bloc { on(_onSetPeriod); on(_onToggleDay); on(_onSetCustomTime); + on(_onResetEffectivePeriod); + on(_onResetDays); } void _onSetPeriod(SetPeriod event, Emitter emit) { @@ -39,13 +41,15 @@ class EffectPeriodBloc extends Bloc { break; } - // Update CreateSceneBloc BlocProvider.of( - NavigationService.navigatorKey.currentState!.context) + NavigationService.navigatorKey.currentContext!) .add(EffectiveTimePeriodEvent(EffectiveTime( start: startTime, end: endTime, loops: state.selectedDaysBinary))); - emit(state.copyWith(selectedPeriod: event.period)); + emit(state.copyWith( + selectedPeriod: event.period, + customStartTime: startTime, + customEndTime: endTime)); } void _onToggleDay(ToggleDay event, Emitter emit) { @@ -60,7 +64,7 @@ class EffectPeriodBloc extends Bloc { emit(state.copyWith(selectedDaysBinary: newDaysBinary)); BlocProvider.of( - NavigationService.navigatorKey.currentState!.context) + NavigationService.navigatorKey.currentContext!) .add(EffectiveTimePeriodEvent(EffectiveTime( start: state.customStartTime ?? '00:00', end: state.customEndTime ?? '23:59', @@ -68,15 +72,48 @@ class EffectPeriodBloc extends Bloc { } void _onSetCustomTime(SetCustomTime event, Emitter emit) { + String startTime = event.startTime; + String endTime = event.endTime; + EnumEffectivePeriodOptions period; + + // Determine the period based on start and end times + if (startTime == '00:00' && endTime == '23:59') { + period = EnumEffectivePeriodOptions.allDay; + } else if (startTime == '06:00' && endTime == '18:00') { + period = EnumEffectivePeriodOptions.daytime; + } else if (startTime == '18:00' && endTime == '06:00') { + period = EnumEffectivePeriodOptions.night; + } else { + period = EnumEffectivePeriodOptions.custom; + } + emit(state.copyWith( - customStartTime: event.startTime, customEndTime: event.endTime)); + customStartTime: startTime, + customEndTime: endTime, + selectedPeriod: period)); BlocProvider.of( - NavigationService.navigatorKey.currentState!.context) + NavigationService.navigatorKey.currentContext!) .add(EffectiveTimePeriodEvent(EffectiveTime( - start: event.startTime, - end: event.endTime, - loops: state.selectedDaysBinary))); + start: startTime, end: endTime, loops: state.selectedDaysBinary))); + } + + void _onResetEffectivePeriod( + ResetEffectivePeriod event, Emitter emit) { + emit(state.copyWith( + selectedPeriod: EnumEffectivePeriodOptions.allDay, + customStartTime: '00:00', + customEndTime: '23:59', + selectedDaysBinary: '1111111')); + + BlocProvider.of( + NavigationService.navigatorKey.currentContext!) + .add(EffectiveTimePeriodEvent( + EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'))); + } + + void _onResetDays(ResetDays event, Emitter emit) { + emit(state.copyWith(selectedDaysBinary: '1111111')); } int _getDayIndex(String day) { diff --git a/lib/features/scene/bloc/effective_period/effect_period_event.dart b/lib/features/scene/bloc/effective_period/effect_period_event.dart index 809bf82..c628983 100644 --- a/lib/features/scene/bloc/effective_period/effect_period_event.dart +++ b/lib/features/scene/bloc/effective_period/effect_period_event.dart @@ -35,3 +35,10 @@ class SetCustomTime extends EffectPeriodEvent { @override List get props => [startTime, endTime]; } + +class ResetEffectivePeriod extends EffectPeriodEvent {} + +class ResetDays extends EffectPeriodEvent { + @override + List get props => []; +} diff --git a/lib/features/scene/bloc/effective_period/effect_period_state.dart b/lib/features/scene/bloc/effective_period/effect_period_state.dart index 029652b..2b00a45 100644 --- a/lib/features/scene/bloc/effective_period/effect_period_state.dart +++ b/lib/features/scene/bloc/effective_period/effect_period_state.dart @@ -37,6 +37,18 @@ class EffectPeriodState extends Equatable { ); } + EnumEffectivePeriodOptions getEffectivePeriod() { + if (customStartTime == '00:00' && customEndTime == '23:59') { + return EnumEffectivePeriodOptions.allDay; + } else if (customStartTime == '06:00' && customEndTime == '18:00') { + return EnumEffectivePeriodOptions.daytime; + } else if (customStartTime == '18:00' && customEndTime == '06:00') { + return EnumEffectivePeriodOptions.night; + } else { + return EnumEffectivePeriodOptions.custom; + } + } + @override List get props => [selectedPeriod, selectedDaysBinary, customStartTime, customEndTime]; diff --git a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart index 9ef5b8b..a6370d8 100644 --- a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart +++ b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart @@ -18,6 +18,7 @@ class SmartSceneSelectBloc SmartSceneSelectBloc() : super(SmartSceneSelectInitial()) { on(_onSmartSceneEnable); on(_smartSceneClear); + on(_smartSceneConfirmSelection); } SmartSceneEnable? smartSceneEnable; @@ -25,29 +26,6 @@ class SmartSceneSelectBloc FutureOr _onSmartSceneEnable( SmartSceneEnableEvent event, Emitter emit) { smartSceneEnable = event.smartSceneEnable; - NavigationService.navigatorKey.currentState!.context - .read() - .add(TempHoldSceneTasksEvent( - deviceControlModel: DeviceControlModel( - deviceId: smartSceneEnable?.entityId ?? '', - code: CreateSceneEnum.smartSceneSelect.name, - value: '', - ), - deviceId: smartSceneEnable?.sceneORAutomationName ?? '', - operation: smartSceneEnable?.actionExecutor ?? '', - icon: smartSceneEnable?.isAutomation == true - ? Assets.player - : Assets.handClickIcon, - deviceName: smartSceneEnable?.sceneORAutomationName ?? '', - uniqueId: '', - operationType: OperationDialogType.none, - isAutomation: false, - )); - - emit(SmartSceneSelected(smartSceneEnable: smartSceneEnable!)); - NavigationService.navigatorKey.currentState!.context - .read() - .add(const AddTaskEvent(isAutomation: false)); } FutureOr _smartSceneClear( @@ -55,4 +33,33 @@ class SmartSceneSelectBloc smartSceneEnable = null; emit(SmartSceneSelectInitial()); } + + FutureOr _smartSceneConfirmSelection( + SmartSceneConfirmSelectionEvent event, + Emitter emit) { + final createSceneBloc = NavigationService.navigatorKey.currentState!.context + .read(); + + createSceneBloc.add(TempHoldSceneTasksEvent( + deviceControlModel: DeviceControlModel( + deviceId: smartSceneEnable?.entityId ?? '', + code: CreateSceneEnum.smartSceneSelect.name, + value: smartSceneEnable?.actionExecutor ?? '', + ), + deviceId: smartSceneEnable?.entityId ?? '', + operation: smartSceneEnable?.type ?? '', + icon: smartSceneEnable?.isAutomation == true + ? Assets.player + : Assets.handClickIcon, + deviceName: smartSceneEnable?.sceneORAutomationName ?? '', + uniqueId: smartSceneEnable?.entityId ?? '', + operationType: OperationDialogType.none, + isAutomation: false, + )); + + emit(SmartSceneSelected(smartSceneEnable: smartSceneEnable!)); + NavigationService.navigatorKey.currentState!.context + .read() + .add(const AddTaskEvent(isAutomation: false)); + } } diff --git a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_event.dart b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_event.dart index ecdf30a..ce70e65 100644 --- a/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_event.dart +++ b/lib/features/scene/bloc/smart_scene/smart_scene_select_dart_event.dart @@ -19,3 +19,7 @@ class SmartSceneEnableEvent extends SmartSceneSelectEvent { class SmartSceneClearEvent extends SmartSceneSelectEvent { const SmartSceneClearEvent(); } + +class SmartSceneConfirmSelectionEvent extends SmartSceneSelectEvent { + const SmartSceneConfirmSelectionEvent(); +} diff --git a/lib/features/scene/helper/scene_logic_helper.dart b/lib/features/scene/helper/scene_logic_helper.dart index 887370f..35dea80 100644 --- a/lib/features/scene/helper/scene_logic_helper.dart +++ b/lib/features/scene/helper/scene_logic_helper.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; -import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/model/create_automation_model.dart'; @@ -31,7 +30,6 @@ mixin SceneLogicHelper { required List conditions, }) { final sceneBloc = context.read(); - final smartSceneBloc = context.read(); if (isOnlyDelayOrDelayLast(actions)) { context.showCustomSnackbar( @@ -85,9 +83,8 @@ mixin SceneLogicHelper { } if (task.code == CreateSceneEnum.smartSceneSelect.name) { return CreateSceneAction( - entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', - actionExecutor: - smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', + entityId: actions[index].deviceId, + actionExecutor: actions[index].functionValue, executorProperty: null); } return CreateSceneAction( @@ -132,9 +129,8 @@ mixin SceneLogicHelper { } if (task.code == CreateSceneEnum.smartSceneSelect.name) { return CreateSceneAction( - entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '', - actionExecutor: - smartSceneBloc.smartSceneEnable?.actionExecutor ?? '', + entityId: actions[index].deviceId, + actionExecutor: actions[index].functionValue, executorProperty: null); } return CreateSceneAction( @@ -190,4 +186,16 @@ mixin SceneLogicHelper { isAutomation: isAutomation, ); } + + String getTaskDescription(SceneStaticFunction taskItem) { + if (taskItem.code == CreateSceneEnum.smartSceneSelect.name) { + if (taskItem.operationName == 'automation') { + return 'Automation: '; + } else { + return 'Tab-To-Run: '; + } + } else { + return "${taskItem.operationName}: "; + } + } } diff --git a/lib/features/scene/helper/scene_operations_data_helper.dart b/lib/features/scene/helper/scene_operations_data_helper.dart index 4b75b78..e2bb943 100644 --- a/lib/features/scene/helper/scene_operations_data_helper.dart +++ b/lib/features/scene/helper/scene_operations_data_helper.dart @@ -1,5 +1,6 @@ import 'package:syncrow_app/features/devices/model/function_model.dart'; import 'package:syncrow_app/features/scene/enum/ac_values.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/helper/functions_per_device/ac_functions.dart'; import 'package:syncrow_app/features/scene/helper/functions_per_device/door_lock_functions.dart'; @@ -171,13 +172,43 @@ mixin SceneOperationsDataHelper { icon: Assets.delay, operationName: 'delay', operationDialogType: OperationDialogType.delay, - functionValue: action.executorProperty.delaySeconds, + functionValue: action.executorProperty?.delaySeconds, code: '', operationalValues: [ SceneOperationalValue( icon: '', description: "", - value: action.executorProperty.delaySeconds, + value: action.executorProperty?.delaySeconds, + ), + ], + ), + ); + } else if (action.name != null && action.type != null) { + // Handle smart scenes + functions.add( + SceneStaticFunction( + deviceId: action.entityId, + deviceName: action.name.toString(), + deviceIcon: action.type == 'automation' + ? Assets.player + : Assets.handClickIcon, + icon: action.type == 'automation' + ? Assets.player + : Assets.handClickIcon, + operationName: action.type.toString(), + operationDialogType: OperationDialogType.onOff, + functionValue: action.actionExecutor, + code: CreateSceneEnum.smartSceneSelect.name, + operationalValues: [ + SceneOperationalValue( + icon: Assets.assetsAcPower, + description: "Enable", + value: 'rule_enable', + ), + SceneOperationalValue( + icon: Assets.assetsAcPowerOFF, + description: "Disable", + value: 'rule_disable', ), ], ), @@ -260,7 +291,7 @@ mixin SceneOperationsDataHelper { 'factory_reset': _createFactoryResetFunction, }; - final functionCode = executorProperty.functionCode ?? ''; + final functionCode = executorProperty?.functionCode ?? ''; final createFunction = functionMap[functionCode]; if (createFunction != null) { return createFunction(action, isAutomation, comparator); @@ -279,7 +310,7 @@ mixin SceneOperationsDataHelper { bool isAutomation, [ String? comparator, ]) { - final functionValue = action.executorProperty.functionValue; + final functionValue = action.executorProperty?.functionValue; return SceneStaticFunction( deviceId: action.entityId, deviceName: deviceName, @@ -287,7 +318,7 @@ mixin SceneOperationsDataHelper { icon: icon, operationName: operationName, functionValue: functionValue, - code: action.executorProperty.functionCode ?? '', + code: action.executorProperty?.functionCode ?? '', operationDialogType: operationDialogType, operationalValues: operationalValues, comparator: comparator ?? '==', @@ -1168,7 +1199,36 @@ mixin SceneOperationsDataHelper { ), ]; } - + if (taskItem.code == CreateSceneEnum.smartSceneSelect.name) { + return [ + SceneStaticFunction( + deviceId: taskItem.deviceId, + deviceName: taskItem.deviceName.toString(), + deviceIcon: taskItem.operationName == 'automation' + ? Assets.player + : Assets.handClickIcon, + icon: taskItem.operationName == 'automation' + ? Assets.player + : Assets.handClickIcon, + operationName: taskItem.operationName, + operationDialogType: OperationDialogType.onOff, + functionValue: taskItem.functionValue == 'rule_enable' ? true : false, + code: CreateSceneEnum.smartSceneSelect.name, + operationalValues: [ + SceneOperationalValue( + icon: Assets.assetsAcPower, + description: "Enable", + value: 'rule_enable', + ), + SceneOperationalValue( + icon: Assets.assetsAcPowerOFF, + description: "Disable", + value: 'rule_disable', + ), + ], + ), + ]; + } return [ _mapExecutorPropertyToSceneFunction( Action( diff --git a/lib/features/scene/model/scene_details_model.dart b/lib/features/scene/model/scene_details_model.dart index 3c40476..646b3b1 100644 --- a/lib/features/scene/model/scene_details_model.dart +++ b/lib/features/scene/model/scene_details_model.dart @@ -65,19 +65,31 @@ class SceneDetailsModel { class Action { final String actionExecutor; final String entityId; - final ExecutorProperty executorProperty; + ExecutorProperty? executorProperty; + String? name; + String? type; Action({ required this.actionExecutor, required this.entityId, - required this.executorProperty, + this.executorProperty, + this.name, + this.type, }); String toRawJson() => json.encode(toJson()); static Action? fromJson(Map json) { + if (json['name'] != null && json['type'] != null) { + return Action( + actionExecutor: json["actionExecutor"], + entityId: json["entityId"], + name: json['name'], + type: json['type'], + ); + } if (json["executorProperty"] == null) { - return null; // Return null if executorProperty is not present + return null; } return Action( @@ -90,7 +102,7 @@ class Action { Map toJson() => { "actionExecutor": actionExecutor, "entityId": entityId, - "executorProperty": executorProperty.toJson(), + "executorProperty": executorProperty?.toJson(), }; } diff --git a/lib/features/scene/model/smart_scene_enable.dart b/lib/features/scene/model/smart_scene_enable.dart index 40a2d8c..0195b7f 100644 --- a/lib/features/scene/model/smart_scene_enable.dart +++ b/lib/features/scene/model/smart_scene_enable.dart @@ -3,12 +3,14 @@ class SmartSceneEnable { final String actionExecutor; final String sceneORAutomationName; final bool isAutomation; + final String type; SmartSceneEnable({ required this.entityId, required this.actionExecutor, required this.sceneORAutomationName, required this.isAutomation, + required this.type, }); factory SmartSceneEnable.fromJson(Map json) { @@ -17,6 +19,7 @@ class SmartSceneEnable { actionExecutor: json['actionExecutor'], sceneORAutomationName: json['sceneORAutomationName'], isAutomation: json['isAutomation'], + type: json['type'], ); } @@ -26,6 +29,7 @@ class SmartSceneEnable { 'actionExecutor': actionExecutor, 'sceneORAutomationName': sceneORAutomationName, 'isAutomation': isAutomation, + 'type': type, }; } } diff --git a/lib/features/scene/view/device_functions_view.dart b/lib/features/scene/view/device_functions_view.dart index bb9c48f..23a874b 100644 --- a/lib/features/scene/view/device_functions_view.dart +++ b/lib/features/scene/view/device_functions_view.dart @@ -24,17 +24,12 @@ class DeviceFunctionsView extends StatelessWidget @override Widget build(BuildContext context) { - /// this whole widget needs a refactor later - /// - /// static functions based on type final device = (ModalRoute.of(context)?.settings.arguments as Map)['device'] as DeviceModel; final isAutomation = (ModalRoute.of(context)?.settings.arguments as Map)['isAutomationDeviceStatus'] as bool; - /// static custom functions based on type - /// used for now until later backend fixes List functions = []; if (device.functions.isNotEmpty) { functions = getFunctionsWithIcons( @@ -47,128 +42,133 @@ class DeviceFunctionsView extends StatelessWidget } return DefaultScaffold( - title: getTitle(type: device.productType), - actions: [ - TextButton( - onPressed: () { - context - .read() - .add(AddTaskEvent(isAutomation: isAutomation)); - navigateToRoute(context, Routes.sceneTasksRoute); - }, - child: BodyMedium( - text: 'Save', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.secondaryColor.withOpacity(0.6), - ), - ), - ], - leading: TextButton( + title: getTitle(type: device.productType), + actions: [ + TextButton( onPressed: () { - final automationSelectedValue = - context.read().automationSelectedValues; - for (var element in device.functions) { - if (automationSelectedValue.containsKey(element.code)) { - context.read().add(RemoveTempTaskByIdEvent( - code: element.code!, isAutomation: true)); - context.read().add(RemoveFromSelectedValueById( - code: element.code!, isAutomation: true)); - } - } - final selectedValue = - context.read().selectedValues; - for (var element in device.functions) { - if (selectedValue.containsKey(element.code)) { - context - .read() - .add(RemoveTempTaskByIdEvent(code: element.code!)); - context - .read() - .add(RemoveFromSelectedValueById(code: element.code!)); - } - } - - Navigator.pop(context); + context + .read() + .add(AddTaskEvent(isAutomation: isAutomation)); + navigateToRoute(context, Routes.sceneTasksRoute); }, child: BodyMedium( - text: 'Cancel', + text: 'Save', fontWeight: FontWeight.normal, - fontColor: ColorsManager.textPrimaryColor.withOpacity(0.6), + fontColor: ColorsManager.secondaryColor.withOpacity(0.6), ), ), - leadingWidth: 80, - padding: EdgeInsets.zero, - child: ListView.builder( - shrinkWrap: true, - itemCount: functions.length, - padding: const EdgeInsets.only(top: 24.0), - itemBuilder: (context, index) { - return DefaultContainer( - padding: index == 0 - ? const EdgeInsets.only(top: 8) - : index == functions.length - 1 - ? const EdgeInsets.only(bottom: 8) - : EdgeInsets.zero, - margin: EdgeInsets.zero, - borderRadius: index == 0 - ? const BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20)) - : index == functions.length - 1 - ? const BorderRadius.only( - bottomLeft: Radius.circular(20), - bottomRight: Radius.circular(20)) - : BorderRadius.zero, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - BlocBuilder( - builder: (context, state) { - return SceneListTile( - iconsSize: 22, - minLeadingWidth: 20, - assetPath: functions[index].icon, - titleString: functions[index].operationName, - trailingWidget: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - /// selected value or the default value - // BodyMedium(text: ), - Icon( - Icons.arrow_forward_ios_rounded, - color: ColorsManager.greyColor, - size: 16, - ), - ], - ), - onPressed: () { - if (isAutomation) { - _showAutomationDialog( - context, - functions[index], - device, - ); - } else { - _showTabToRunDialog( - context, - functions[index], - device, - ); - } - }, - ); - }, - ), - index != functions.length - 1 - ? SizedBox( - width: context.width * 0.8, - child: const LightDivider()) - : const SizedBox(), - ], - ), - ); - }, - )); + ], + leading: TextButton( + onPressed: () { + _cancelOperation(context, device, isAutomation); + }, + child: BodyMedium( + text: 'Cancel', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.textPrimaryColor.withOpacity(0.6), + ), + ), + leadingWidth: 80, + padding: EdgeInsets.zero, + child: ListView.builder( + shrinkWrap: true, + itemCount: functions.length, + padding: const EdgeInsets.only(top: 24.0), + itemBuilder: (context, index) { + return DefaultContainer( + padding: index == 0 + ? const EdgeInsets.only(top: 8) + : index == functions.length - 1 + ? const EdgeInsets.only(bottom: 8) + : EdgeInsets.zero, + margin: EdgeInsets.zero, + borderRadius: index == 0 + ? const BorderRadius.only( + topLeft: Radius.circular(20), topRight: Radius.circular(20)) + : index == functions.length - 1 + ? const BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20)) + : BorderRadius.zero, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BlocBuilder( + builder: (context, state) { + return SceneListTile( + iconsSize: 22, + minLeadingWidth: 20, + assetPath: functions[index].icon, + titleString: functions[index].operationName, + trailingWidget: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.arrow_forward_ios_rounded, + color: ColorsManager.greyColor, + size: 16, + ), + ], + ), + onPressed: () { + if (isAutomation) { + _showAutomationDialog( + context, + functions[index], + device, + ); + } else { + _showTabToRunDialog( + context, + functions[index], + device, + ); + } + }, + ); + }, + ), + index != functions.length - 1 + ? SizedBox( + width: context.width * 0.8, child: const LightDivider()) + : const SizedBox(), + ], + ), + ); + }, + ), + ); + } + + void _cancelOperation( + BuildContext context, DeviceModel device, bool isAutomation) { + final createSceneBloc = context.read(); + final automationSelectedValue = createSceneBloc.automationSelectedValues; + if (automationSelectedValue.isNotEmpty) { + for (var element in device.functions) { + if (automationSelectedValue.containsKey(element.code)) { + createSceneBloc.add( + RemoveTempTaskByIdEvent(code: element.code!, isAutomation: true)); + createSceneBloc.add(RemoveFromSelectedValueById( + code: element.code!, isAutomation: true)); + } + } + } + + final selectedValue = createSceneBloc.selectedValues; + if (selectedValue.isNotEmpty) { + for (var element in device.functions) { + if (selectedValue.containsKey(element.code)) { + createSceneBloc.add(RemoveTempTaskByIdEvent(code: element.code!)); + createSceneBloc.add(RemoveFromSelectedValueById(code: element.code!)); + } + } + } + + Navigator.pop(context); + + createSceneBloc.add(const ClearTempTaskListEvent(isAutomation: false)); + createSceneBloc.add(const ClearTempTaskListEvent(isAutomation: true)); } void _showTabToRunDialog( diff --git a/lib/features/scene/view/scene_auto_settings.dart b/lib/features/scene/view/scene_auto_settings.dart index 5bc8d44..fe39b09 100644 --- a/lib/features/scene/view/scene_auto_settings.dart +++ b/lib/features/scene/view/scene_auto_settings.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart'; import 'package:syncrow_app/features/scene/widgets/effective_period_setting/effective_period_bottom_sheet.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; -import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; @@ -17,7 +20,8 @@ class SceneAutoSettings extends StatelessWidget { ModalRoute.of(context)!.settings.arguments as Map? ?? {}; final sceneId = sceneSettings['sceneId'] as String? ?? ''; - final isAutomation = sceneSettings['isAutomation'] as bool? ?? false; + final isAutomation = context.read().sceneType == + CreateSceneEnum.deviceStatusChanges; final sceneName = sceneSettings['sceneName'] as String? ?? ''; return Scaffold( @@ -31,35 +35,79 @@ class SceneAutoSettings extends StatelessWidget { fontWeight: FontsManager.bold, ), ), - body: DefaultContainer( - padding: EdgeInsets.zero, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Visibility( - visible: isAutomation == true, - child: SceneListTile( - padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - titleString: "Effective Period", - trailingWidget: const Icon(Icons.arrow_forward_ios_rounded), - onPressed: () { - context.customBottomSheet( - child: const EffectPeriodBottomSheetContent(), - ); - }, + body: Stack( + children: [ + Container( + width: double.infinity, + height: context.height, + decoration: const BoxDecoration( + color: ColorsManager.backgroundColor, + image: DecorationImage( + image: AssetImage( + Assets.assetsImagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, ), ), - Visibility( - visible: sceneName.isNotEmpty, - child: DeleteBottomSheetContent( - isAutomation: isAutomation, - sceneId: sceneId, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + constraints: const BoxConstraints( + maxWidth: 600, + maxHeight: 300, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox( + height: 8, + ), + Visibility( + visible: isAutomation == true, + child: SceneListTile( + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 8), + titleString: "Effective Period", + trailingWidget: + const Icon(Icons.arrow_forward_ios_rounded), + onPressed: () { + context.customBottomSheet( + child: const EffectPeriodBottomSheetContent(), + ); + }, + ), + ), + Visibility( + visible: sceneName.isNotEmpty, + child: SizedBox( + width: context.width * 0.9, + child: const Divider( + color: ColorsManager.greyColor, + ), + ), + ), + Visibility( + visible: sceneName.isNotEmpty, + child: DeleteBottomSheetContent( + isAutomation: isAutomation, + sceneId: sceneId, + ), + ), + const SizedBox( + height: 16, + ), + ], ), ), - ], - ), + ), + ], ), ); } diff --git a/lib/features/scene/view/scene_tasks_view.dart b/lib/features/scene/view/scene_tasks_view.dart index 9cfea64..619353f 100644 --- a/lib/features/scene/view/scene_tasks_view.dart +++ b/lib/features/scene/view/scene_tasks_view.dart @@ -11,7 +11,6 @@ import 'package:syncrow_app/features/scene/widgets/create_scene_save_button.dart import 'package:syncrow_app/features/scene/widgets/if_then_containers/if_container.dart'; import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_container.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.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/generated/assets.dart'; import 'package:syncrow_app/navigation/navigate_to_route.dart'; @@ -125,44 +124,39 @@ class DeleteBottomSheetContent extends StatelessWidget { @override Widget build(BuildContext context) { - return DefaultContainer( - padding: EdgeInsets.zero, - child: BlocConsumer( - listener: (context, state) { - if (state is DeleteSceneSuccess) { - if (state.success) { - navigateToRoute(context, Routes.homeRoute); - BlocProvider.of(context).add( - LoadScenes(HomeCubit.getInstance().selectedSpace!.id!)); - BlocProvider.of(context).add( - LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!)); - } - } - }, - builder: (context, state) { - return DefaultContainer( - onTap: () { - context.read().add(DeleteSceneEvent( - sceneId: sceneId, - unitUuid: HomeCubit.getInstance().selectedSpace!.id!, - )); - }, - child: SceneListTile( - padding: const EdgeInsets.symmetric(horizontal: 8), - titleString: isAutomation - ? StringsManager.deleteAutomation - : StringsManager.deleteScene, - leadingWidget: (state is DeleteSceneLoading) - ? const SizedBox( - height: 24, - width: 24, - child: CircularProgressIndicator()) - : SvgPicture.asset( - Assets.assetsDeleteIcon, - color: ColorsManager.red, - ), + return BlocConsumer( + listener: (context, state) { + if (state is DeleteSceneSuccess) { + if (state.success) { + navigateToRoute(context, Routes.homeRoute); + BlocProvider.of(context) + .add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!)); + BlocProvider.of(context).add( + LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!)); + } + } + }, + builder: (context, state) { + return SceneListTile( + onPressed: () { + context.read().add(DeleteSceneEvent( + sceneId: sceneId, + unitUuid: HomeCubit.getInstance().selectedSpace!.id!, )); }, - )); + padding: const EdgeInsets.symmetric(horizontal: 8), + titleString: isAutomation + ? StringsManager.deleteAutomation + : StringsManager.deleteScene, + leadingWidget: (state is DeleteSceneLoading) + ? const SizedBox( + height: 24, width: 24, child: CircularProgressIndicator()) + : SvgPicture.asset( + Assets.assetsDeleteIcon, + color: ColorsManager.red, + ), + ); + }, + ); } } diff --git a/lib/features/scene/widgets/effective_period_setting/period_options.dart b/lib/features/scene/widgets/effective_period_setting/period_options.dart index cdc4088..4fed34c 100644 --- a/lib/features/scene/widgets/effective_period_setting/period_options.dart +++ b/lib/features/scene/widgets/effective_period_setting/period_options.dart @@ -39,11 +39,11 @@ class PeriodOptions extends StatelessWidget { state.customStartTime != null && state.customEndTime != null ? BodySmall( text: - '${"${state.customStartTime} AM"} - ${"${state.customEndTime} PM"}', + '${"${state.customStartTime}"} - ${"${state.customEndTime}"}', style: context.bodySmall.copyWith(fontSize: 10), ) : BodySmall( - text: '00:00 AM - 11:59 PM', + text: '00:00 - 23:59', style: context.bodySmall.copyWith(fontSize: 10), ), trailing: Radio( diff --git a/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart b/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart index 8f7f4ee..1af98c4 100644 --- a/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart +++ b/lib/features/scene/widgets/if_then_containers/then_added_tasks.dart @@ -4,12 +4,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; +import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart'; import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart'; import 'package:syncrow_app/features/scene/model/scene_static_function.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; +import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_automation_list.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/generated/assets.dart'; @@ -63,7 +65,8 @@ class ThenAddedTasksContainer extends StatelessWidget operationValue = functionValue.toString(); } return DefaultContainer( - onTap: taskItem.code == CreateSceneEnum.smartSceneSelect.name + onTap: taskItem.operationName == 'tap_to_run' || + taskItem.operationName == 'scene' ? null : () { List functionOperation = []; @@ -74,51 +77,77 @@ class ThenAddedTasksContainer extends StatelessWidget deviceId: taskItem.deviceId, isAutomation: isAutomation ?? false)); - /// show alert dialog based on type - context.customAlertDialog( - alertBody: getTheCorrectDialogBody( - functionOperation.first, null, - isAutomation: isAutomation ?? false), - title: functionOperation.first.operationName, - onConfirm: () { - final savedCode = - functionOperation.first.deviceId.contains('delay') - ? 'delay' - : functionOperation.first.code; - if (isAutomation == true) { - final automationSelectedValue = - createSceneBloc.automationSelectedValues[savedCode]; + if (taskItem.code == CreateSceneEnum.smartSceneSelect.name) { + context.customAlertDialog( + alertBody: EnableDisableAutomationDialog( + automationId: taskItem.deviceId, + descriptionSelected: taskItem.functionValue == 'rule_enable' + ? 'Enable' + : "Disable", + sceneORAutomationName: taskItem.deviceName, + type: taskItem.operationName, + ), + title: taskItem.deviceName, + onConfirm: () { + context + .read() + .add(const SmartSceneConfirmSelectionEvent()); + Navigator.pop(context); + }, + onDismiss: () { + context + .read() + .add(const SmartSceneClearEvent()); + Navigator.pop(context); + }, + ); + } else { + /// show alert dialog based on type + context.customAlertDialog( + alertBody: getTheCorrectDialogBody( + functionOperation.first, null, + isAutomation: isAutomation ?? false), + title: functionOperation.first.operationName, + onConfirm: () { + final savedCode = + functionOperation.first.deviceId.contains('delay') + ? 'delay' + : functionOperation.first.code; + if (isAutomation == true) { + final automationSelectedValue = + createSceneBloc.automationSelectedValues[savedCode]; - try { - createSceneBloc.add( - UpdateTaskEvent( - newValue: automationSelectedValue, - taskId: taskItem.uniqueCustomId, - isAutomation: true, - ), - ); - } catch (e) { - debugPrint('Error adding UpdateTaskEvent: $e'); + try { + createSceneBloc.add( + UpdateTaskEvent( + newValue: automationSelectedValue, + taskId: taskItem.uniqueCustomId, + isAutomation: true, + ), + ); + } catch (e) { + debugPrint('Error adding UpdateTaskEvent: $e'); + } + } else { + final selectedValue = + createSceneBloc.selectedValues[savedCode]; + + try { + createSceneBloc.add( + UpdateTaskEvent( + newValue: selectedValue, + taskId: taskItem.uniqueCustomId, + ), + ); + } catch (e) { + debugPrint('Error adding UpdateTaskEvent: $e'); + } } - } else { - final selectedValue = - createSceneBloc.selectedValues[savedCode]; - try { - createSceneBloc.add( - UpdateTaskEvent( - newValue: selectedValue, - taskId: taskItem.uniqueCustomId, - ), - ); - } catch (e) { - debugPrint('Error adding UpdateTaskEvent: $e'); - } - } - - Navigator.pop(context); - }, - ); + Navigator.pop(context); + }, + ); + } }, padding: EdgeInsets.zero, child: Dismissible( @@ -155,6 +184,9 @@ class ThenAddedTasksContainer extends StatelessWidget taskId: removeFunctionById, )); } + context + .read() + .add(const SmartSceneClearEvent()); String removeFunction = "${taskItem.operationName} with value ${taskItem.operationalValues.first.value}"; @@ -177,17 +209,13 @@ class ThenAddedTasksContainer extends StatelessWidget subtitleWidget: Row( children: [ BodyMedium( - text: taskItem.code == CreateSceneEnum.smartSceneSelect.name - ? taskItem.icon.contains('player') - ? 'Automation: ' - : "Tab-To-Run: " - : "${taskItem.operationName}: ", + text: getTaskDescription(taskItem), fontColor: ColorsManager.secondaryTextColor, fontWeight: FontWeight.normal, ), BodyMedium( text: taskItem.code == CreateSceneEnum.smartSceneSelect.name - ? taskItem.operationName == 'rule_enable' + ? taskItem.functionValue == 'rule_enable' ? 'Enable' : "Disable" : operationValue, diff --git a/lib/features/scene/widgets/scene_view_widget/scene_item.dart b/lib/features/scene/widgets/scene_view_widget/scene_item.dart index 0dc4fff..b82d637 100644 --- a/lib/features/scene/widgets/scene_view_widget/scene_item.dart +++ b/lib/features/scene/widgets/scene_view_widget/scene_item.dart @@ -5,6 +5,7 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart'; +import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/model/scenes_model.dart'; import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart'; @@ -45,6 +46,7 @@ class SceneItem extends StatelessWidget { sceneName: scene.name, ), ); + context.read().add(const SmartSceneClearEvent()); if (disablePlayButton == false) { BlocProvider.of(context) .add(const SceneTypeEvent(CreateSceneEnum.tabToRun)); diff --git a/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart b/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart index afdef0f..8ea2aaa 100644 --- a/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart +++ b/lib/features/scene/widgets/select_smart_scene/smart_automation_list.dart @@ -126,9 +126,13 @@ class _SmartSceneSelectAutomationListState automationId: automation.id, descriptionSelected: descriptionSelected, sceneORAutomationName: automation.name, + type: automation.type, ), title: automation.name, onConfirm: () { + context + .read() + .add(const SmartSceneConfirmSelectionEvent()); Navigator.pop(context); }, onDismiss: () { @@ -159,9 +163,13 @@ class _SmartSceneSelectAutomationListState automationId: automation.id, descriptionSelected: descriptionSelected, sceneORAutomationName: automation.name, + type: automation.type, ), title: automation.name, onConfirm: () { + context + .read() + .add(const SmartSceneConfirmSelectionEvent()); Navigator.pop(context); }, onDismiss: () { @@ -194,11 +202,13 @@ class EnableDisableAutomationDialog extends StatefulWidget { required this.automationId, required this.descriptionSelected, required this.sceneORAutomationName, + required this.type, }); final String automationId; final String descriptionSelected; final String sceneORAutomationName; + final String type; @override State createState() => @@ -226,6 +236,14 @@ class _EnableDisableAutomationDialogState super.initState(); groupValue = widget.descriptionSelected == 'Enable' ? 'rule_enable' : 'rule_disable'; + + context.read().add(SmartSceneEnableEvent( + SmartSceneEnable( + entityId: widget.automationId, + actionExecutor: groupValue!, + sceneORAutomationName: widget.sceneORAutomationName, + type: widget.type, + isAutomation: true))); } @override @@ -259,6 +277,7 @@ class _EnableDisableAutomationDialogState actionExecutor: value!, sceneORAutomationName: widget.sceneORAutomationName, + type: widget.type, isAutomation: true), )); }, @@ -274,6 +293,7 @@ class _EnableDisableAutomationDialogState entityId: widget.automationId, actionExecutor: operation.value, sceneORAutomationName: widget.sceneORAutomationName, + type: widget.type, isAutomation: true, ), )); diff --git a/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart b/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart index 384b52a..6d6b65d 100644 --- a/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart +++ b/lib/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart @@ -25,6 +25,7 @@ class SmartSceneSelectTabToRunList extends StatefulWidget { class _SmartSceneSelectTabToRunListState extends State { String groupValue = ''; + @override Widget build(BuildContext context) { return Column( @@ -67,6 +68,13 @@ class _SmartSceneSelectTabToRunListState itemCount: widget.scenes.length, itemBuilder: (context, index) { final scene = widget.scenes[index]; + final selectedScene = + context.read().smartSceneEnable; + if (selectedScene != null) { + if (scene.id == selectedScene.entityId) { + groupValue = scene.id; + } + } return SceneListTile( padding: const EdgeInsets.symmetric(horizontal: 10), leadingWidget: Image.asset( @@ -84,14 +92,19 @@ class _SmartSceneSelectTabToRunListState setState(() { groupValue = value; }); + context .read() .add(SmartSceneEnableEvent(SmartSceneEnable( entityId: scene.id, actionExecutor: 'rule_enable', sceneORAutomationName: scene.name, + type: scene.type, isAutomation: false, ))); + context + .read() + .add(const SmartSceneConfirmSelectionEvent()); } }), onPressed: () { @@ -104,8 +117,12 @@ class _SmartSceneSelectTabToRunListState entityId: scene.id, actionExecutor: 'rule_enable', sceneORAutomationName: scene.name, + type: scene.type, isAutomation: false, ))); + context + .read() + .add(const SmartSceneConfirmSelectionEvent()); }, ); }), diff --git a/lib/my_app.dart b/lib/my_app.dart index f6d7a5b..e3317d9 100644 --- a/lib/my_app.dart +++ b/lib/my_app.dart @@ -27,13 +27,13 @@ class MyApp extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider(create: (context) => AuthCubit()), - BlocProvider(create: (context) => CreateSceneBloc()), - BlocProvider(create: (context) => SceneBloc()), - BlocProvider(create: (context) => ProfileBloc()), - BlocProvider(create: (context) => SmartSceneSelectBloc()), BlocProvider( create: (context) => EffectPeriodBloc(), ), + BlocProvider(create: (context) => SmartSceneSelectBloc()), + BlocProvider(create: (context) => CreateSceneBloc()), + BlocProvider(create: (context) => SceneBloc()), + BlocProvider(create: (context) => ProfileBloc()), ], child: MaterialApp( navigatorKey: NavigationService.navigatorKey,