diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart index 5c99d85c..6eb03160 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart @@ -38,8 +38,8 @@ class RoutineBloc extends Bloc { final updatedIfItems = List>.from(state.ifItems); // Find the index of the item in teh current itemsList - int index = updatedIfItems.indexWhere( - (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); + int index = + updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { updatedIfItems[index] = event.item; @@ -48,21 +48,18 @@ class RoutineBloc extends Bloc { } if (event.isTabToRun) { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); + emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); } else { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); + emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); } } - void _onAddToThenContainer( - AddToThenContainer event, Emitter emit) { + void _onAddToThenContainer(AddToThenContainer event, Emitter emit) { final currentItems = List>.from(state.thenItems); // Find the index of the item in teh current itemsList - int index = currentItems.indexWhere( - (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); + int index = + currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { currentItems[index] = event.item; @@ -73,26 +70,22 @@ class RoutineBloc extends Bloc { emit(state.copyWith(thenItems: currentItems)); } - void _onAddFunctionsToRoutine( - AddFunctionToRoutine event, Emitter emit) { + void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter emit) { try { if (event.functions.isEmpty) return; - List selectedFunction = - List.from(event.functions); + List selectedFunction = List.from(event.functions); Map> currentSelectedFunctions = Map>.from(state.selectedFunctions); if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { List currentFunctions = - List.from( - currentSelectedFunctions[event.uniqueCustomId] ?? []); + List.from(currentSelectedFunctions[event.uniqueCustomId] ?? []); List functionCode = []; for (int i = 0; i < selectedFunction.length; i++) { for (int j = 0; j < currentFunctions.length; j++) { - if (selectedFunction[i].functionCode == - currentFunctions[j].functionCode) { + if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) { currentFunctions[j] = selectedFunction[i]; if (!functionCode.contains(currentFunctions[j].functionCode)) { functionCode.add(currentFunctions[j].functionCode); @@ -102,15 +95,13 @@ class RoutineBloc extends Bloc { } for (int i = 0; i < functionCode.length; i++) { - selectedFunction - .removeWhere((code) => code.functionCode == functionCode[i]); + selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]); } - currentSelectedFunctions[event.uniqueCustomId] = - List.from(currentFunctions)..addAll(selectedFunction); + currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions) + ..addAll(selectedFunction); } else { - currentSelectedFunctions[event.uniqueCustomId] = - List.from(event.functions); + currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); } emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); @@ -119,8 +110,7 @@ class RoutineBloc extends Bloc { } } - Future _onLoadScenes( - LoadScenes event, Emitter emit) async { + Future _onLoadScenes(LoadScenes event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { @@ -139,16 +129,24 @@ class RoutineBloc extends Bloc { } } - Future _onLoadAutomation( - LoadAutomation event, Emitter emit) async { + Future _onLoadAutomation(LoadAutomation event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { final automations = await SceneApi.getAutomationByUnitId(event.unitId); - emit(state.copyWith( - automations: automations, - isLoading: false, - )); + if (automations.isNotEmpty) { + emit(state.copyWith( + automations: automations, + isLoading: false, + )); + } else { + emit(state.copyWith( + isLoading: false, + loadAutomationErrorMessage: 'Failed to load automations', + errorMessage: '', + loadScenesErrorMessage: '', + )); + } } catch (e) { emit(state.copyWith( isLoading: false, @@ -159,15 +157,14 @@ class RoutineBloc extends Bloc { } } - FutureOr _onSearchRoutines( - SearchRoutines event, Emitter emit) async { + FutureOr _onSearchRoutines(SearchRoutines event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); await Future.delayed(const Duration(seconds: 1)); + emit(state.copyWith(isLoading: false, errorMessage: null)); emit(state.copyWith(searchText: event.query)); } - FutureOr _onAddSelectedIcon( - AddSelectedIcon event, Emitter emit) { + FutureOr _onAddSelectedIcon(AddSelectedIcon event, Emitter emit) { emit(state.copyWith(selectedIcon: event.icon)); } @@ -176,8 +173,7 @@ class RoutineBloc extends Bloc { return actions.first['deviceId'] == 'delay'; } - Future _onCreateScene( - CreateSceneEvent event, Emitter emit) async { + Future _onCreateScene(CreateSceneEvent event, Emitter emit) async { try { // Check if first action is delay if (_isFirstActionDelay(state.thenItems)) { @@ -252,8 +248,7 @@ class RoutineBloc extends Bloc { } } - Future _onCreateAutomation( - CreateAutomationEvent event, Emitter emit) async { + Future _onCreateAutomation(CreateAutomationEvent event, Emitter emit) async { try { if (state.routineName == null || state.routineName!.isEmpty) { emit(state.copyWith( @@ -353,26 +348,21 @@ class RoutineBloc extends Bloc { } } - FutureOr _onRemoveDragCard( - RemoveDragCard event, Emitter emit) { + FutureOr _onRemoveDragCard(RemoveDragCard event, Emitter emit) { if (event.isFromThen) { final thenItems = List>.from(state.thenItems); - final selectedFunctions = - Map>.from(state.selectedFunctions); + final selectedFunctions = Map>.from(state.selectedFunctions); thenItems.removeAt(event.index); selectedFunctions.remove(event.key); - emit(state.copyWith( - thenItems: thenItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions)); } else { final ifItems = List>.from(state.ifItems); - final selectedFunctions = - Map>.from(state.selectedFunctions); + final selectedFunctions = Map>.from(state.selectedFunctions); ifItems.removeAt(event.index); selectedFunctions.remove(event.key); - emit(state.copyWith( - ifItems: ifItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions)); } } @@ -383,13 +373,11 @@ class RoutineBloc extends Bloc { )); } - FutureOr _onEffectiveTimeEvent( - EffectiveTimePeriodEvent event, Emitter emit) { + FutureOr _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter emit) { emit(state.copyWith(effectiveTime: event.effectiveTime)); } - FutureOr _onSetRoutineName( - SetRoutineName event, Emitter emit) { + FutureOr _onSetRoutineName(SetRoutineName event, Emitter emit) { emit(state.copyWith(routineName: event.name)); } @@ -414,8 +402,7 @@ class RoutineBloc extends Bloc { ); } - FutureOr _onResetRoutineState( - ResetRoutineState event, Emitter emit) { + FutureOr _onResetRoutineState(ResetRoutineState event, Emitter emit) { emit(_resetState()); } } diff --git a/lib/pages/routiens/widgets/routine_search_and_buttons.dart b/lib/pages/routiens/widgets/routine_search_and_buttons.dart index 73bc403d..6696225f 100644 --- a/lib/pages/routiens/widgets/routine_search_and_buttons.dart +++ b/lib/pages/routiens/widgets/routine_search_and_buttons.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; -import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/helper/save_routine_helper.dart'; import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/discard_dialog.dart'; import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/setting_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class RoutineSearchAndButtons extends StatelessWidget { @@ -34,24 +34,73 @@ class RoutineSearchAndButtons extends StatelessWidget { children: [ ConstrainedBox( constraints: BoxConstraints( - maxWidth: constraints.maxWidth > 700 - ? 450 - : constraints.maxWidth - 32), - child: StatefulTextField( - title: 'Routine Name', - height: 40, - controller: TextEditingController(), - hintText: 'Please enter the name', - boxDecoration: containerWhiteDecoration, - elevation: 0, - borderRadius: 15, - isRequired: true, - width: 450, - onChanged: (value) { - context - .read() - .add(SetRoutineName(value)); - }, + maxWidth: + constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32), + // child: StatefulTextField( + // title: 'Routine Name', + // initialValue: state.routineName ?? '', + // height: 40, + // // controller: TextEditingController(), + // hintText: 'Please enter the name', + // boxDecoration: containerWhiteDecoration, + // elevation: 0, + // borderRadius: 15, + // isRequired: true, + // width: 450, + // onSubmitted: (value) { + // // context.read().add(SetRoutineName(value)); + // }, + // onChanged: (value) { + // context.read().add(SetRoutineName(value)); + // }, + // ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text('* ', + style: context.textTheme.bodyMedium! + .copyWith(color: ColorsManager.red, fontSize: 13)), + Text( + 'Routine Name', + style: context.textTheme.bodyMedium!.copyWith( + fontSize: 13, + fontWeight: FontWeight.w600, + color: ColorsManager.blackColor, + ), + ), + ], + ), + Container( + width: 450, + height: 40, + decoration: containerWhiteDecoration, + child: TextFormField( + style: context.textTheme.bodyMedium! + .copyWith(color: ColorsManager.blackColor), + initialValue: state.routineName, + decoration: InputDecoration( + hintText: 'Please enter the name', + hintStyle: context.textTheme.bodyMedium! + .copyWith(fontSize: 12, color: ColorsManager.grayColor), + contentPadding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + border: InputBorder.none, + ), + onChanged: (value) { + context.read().add(SetRoutineName(value)); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'This field is required'; + } + return null; + }, + ), + ), + ], ), ), (constraints.maxWidth <= 1000) @@ -61,16 +110,15 @@ class RoutineSearchAndButtons extends StatelessWidget { width: 200, child: Center( child: DefaultButton( - onPressed: state.isAutomation || - state.isTabToRun + onPressed: state.isAutomation || state.isTabToRun ? () async { - final result = await SettingHelper - .showSettingDialog( + final result = await SettingHelper.showSettingDialog( context: context, ); if (result != null) { - context.read().add( - AddSelectedIcon(result)); + context + .read() + .add(AddSelectedIcon(result)); } } : null, @@ -126,8 +174,40 @@ class RoutineSearchAndButtons extends StatelessWidget { child: Center( child: DefaultButton( onPressed: () { - SaveRoutineHelper.showSaveRoutineDialog( - context); + if (state.routineName == null || state.routineName!.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Please enter the routine name'), + duration: const Duration(seconds: 2), + backgroundColor: ColorsManager.red, + action: SnackBarAction( + label: 'Dismiss', + onPressed: () { + // Optional action on Snackbar + }, + ), + ), + ); + return; + } + + if (state.ifItems.isEmpty || state.thenItems.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Please add if and then condition'), + duration: const Duration(seconds: 2), + backgroundColor: ColorsManager.red, + action: SnackBarAction( + label: 'Dismiss', + onPressed: () { + // Optional action on Snackbar + }, + ), + ), + ); + return; + } + SaveRoutineHelper.showSaveRoutineDialog(context); }, borderRadius: 15, elevation: 0, @@ -158,14 +238,11 @@ class RoutineSearchAndButtons extends StatelessWidget { child: DefaultButton( onPressed: state.isAutomation || state.isTabToRun ? () async { - final result = - await SettingHelper.showSettingDialog( + final result = await SettingHelper.showSettingDialog( context: context, ); if (result != null) { - context - .read() - .add(AddSelectedIcon(result)); + context.read().add(AddSelectedIcon(result)); } } : null, @@ -215,6 +292,39 @@ class RoutineSearchAndButtons extends StatelessWidget { child: Center( child: DefaultButton( onPressed: () { + if (state.routineName == null || state.routineName!.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Please enter the routine name'), + duration: const Duration(seconds: 2), + backgroundColor: ColorsManager.red, + action: SnackBarAction( + label: 'Dismiss', + onPressed: () { + // Optional action on Snackbar + }, + ), + ), + ); + return; + } + + if (state.ifItems.isEmpty || state.thenItems.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Please add if and then condition'), + duration: const Duration(seconds: 2), + backgroundColor: ColorsManager.red, + action: SnackBarAction( + label: 'Dismiss', + onPressed: () { + // Optional action on Snackbar + }, + ), + ), + ); + return; + } SaveRoutineHelper.showSaveRoutineDialog(context); }, borderRadius: 15, diff --git a/lib/pages/routiens/widgets/scenes_and_automations.dart b/lib/pages/routiens/widgets/scenes_and_automations.dart index 746795af..36ee7db2 100644 --- a/lib/pages/routiens/widgets/scenes_and_automations.dart +++ b/lib/pages/routiens/widgets/scenes_and_automations.dart @@ -26,7 +26,7 @@ class _ScenesAndAutomationsState extends State { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - if (state.scenes.isNotEmpty || state.automations.isNotEmpty) { + if (!state.isLoading) { var scenes = [...state.scenes, ...state.automations]; return Wrap( spacing: 10,