diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart index 9cb3adb5..ace64856 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart @@ -13,6 +13,7 @@ import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/routines_api.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/snack_bar.dart'; import 'package:uuid/uuid.dart'; part 'routine_event.dart'; @@ -47,14 +48,14 @@ class RoutineBloc extends Bloc { on(_onSetAutomationActionExecutor); on(_triggerSwitchTabsEvent); on(_createNewRoutineViewEvent); + on(_resetErrorMessage); } FutureOr _triggerSwitchTabsEvent( TriggerSwitchTabsEvent event, Emitter emit, ) { - emit(state.copyWith( - routineTab: event.isRoutineTab, createRoutineView: false)); + emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false)); add(ResetRoutineState()); if (event.isRoutineTab) { add(const LoadScenes(spaceId, communityId)); @@ -62,6 +63,13 @@ class RoutineBloc extends Bloc { } } + _resetErrorMessage( + ResetErrorMessage event, + Emitter emit, + ) { + emit(state.copyWith(errorMessage: '')); + } + FutureOr _createNewRoutineViewEvent( CreateNewRoutineViewEvent event, Emitter emit, @@ -73,8 +81,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; @@ -83,21 +91,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; @@ -108,26 +113,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); @@ -137,15 +138,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)); @@ -154,13 +153,11 @@ 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 { - final scenes = - await SceneApi.getScenesByUnitId(event.unitId, event.communityId); + final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId); emit(state.copyWith( scenes: scenes, isLoading: false, @@ -175,8 +172,7 @@ 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 { @@ -204,44 +200,41 @@ 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)); } - bool _isFirstActionDelay(List> actions) { - if (actions.isEmpty) return false; - return actions.first['deviceId'] == 'delay'; - } + // bool _isFirstActionDelay(List> actions) { + // if (actions.isEmpty) return false; + // return actions.first['deviceId'] == 'delay'; + // } bool _isLastActionDelay(List> actions) { if (actions.isEmpty) return false; return actions.last['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)) { - emit(state.copyWith( - errorMessage: 'Cannot have delay as the first action', - isLoading: false, - )); - return; - } + // if (_isFirstActionDelay(state.thenItems)) { + // emit(state.copyWith( + // errorMessage: 'Cannot have delay as the first action', + // isLoading: false, + // )); + // return; + // } if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: 'Cannot have delay as the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); return; @@ -314,28 +307,31 @@ 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( errorMessage: 'Automation name is required', )); + CustomSnackBar.redSnackBar('Automation name is required'); return; } - if (_isFirstActionDelay(state.thenItems)) { - emit(state.copyWith( - errorMessage: 'Cannot have delay as the first action', - isLoading: false, - )); - return; - } + // if (_isFirstActionDelay(state.thenItems)) { + // emit(state.copyWith( + // errorMessage: 'Cannot have delay as the first action', + // isLoading: false, + // )); + // CustomSnackBar.redSnackBar('Cannot have delay as the first action'); + + // return; + // } if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: 'Cannot have delay as the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); + CustomSnackBar.redSnackBar('Cannot have delay as the last action'); return; } emit(state.copyWith(isLoading: true, errorMessage: null)); @@ -430,30 +426,28 @@ class RoutineBloc extends Bloc { isLoading: false, errorMessage: result['message'], )); + CustomSnackBar.redSnackBar('Something went wrong'); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: 'Something went wrong', )); + CustomSnackBar.redSnackBar('Something went wrong'); } } - 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); @@ -464,8 +458,7 @@ class RoutineBloc extends Bloc { isAutomation: false, isTabToRun: false)); } else { - emit(state.copyWith( - ifItems: ifItems, selectedFunctions: selectedFunctions)); + emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions)); } } } @@ -477,23 +470,18 @@ 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, )); } - ( - List>, - List>, - Map> - ) _createCardData( + (List>, List>, Map>) + _createCardData( List actions, List? conditions, Map> currentFunctions, @@ -526,8 +514,7 @@ class RoutineBloc extends Bloc { 'deviceId': condition.entityId, 'title': matchingDevice.name ?? condition.entityId, 'productType': condition.entityType, - 'imagePath': - matchingDevice.getDefaultIcon(condition.entityType), + 'imagePath': matchingDevice.getDefaultIcon(condition.entityType), }; final functions = matchingDevice.functions; @@ -563,11 +550,8 @@ class RoutineBloc extends Bloc { final cardData = { 'entityId': action.entityId, 'uniqueCustomId': const Uuid().v4(), - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, - 'title': action.actionExecutor == 'delay' - ? 'Delay' - : (matchingDevice.name ?? 'Device'), + 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'), 'productType': action.productType, 'imagePath': matchingDevice.getDefaultIcon(action.productType), }; @@ -610,8 +594,7 @@ class RoutineBloc extends Bloc { return (thenItems, ifItems, currentFunctions); } - Future _onGetSceneDetails( - GetSceneDetails event, Emitter emit) async { + Future _onGetSceneDetails(GetSceneDetails event, Emitter emit) async { try { emit(state.copyWith( isLoading: true, @@ -659,12 +642,10 @@ class RoutineBloc extends Bloc { if (!deviceCards.containsKey(deviceId)) { deviceCards[deviceId] = { 'entityId': action.entityId, - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, - 'uniqueCustomId': - action.type == 'automation' || action.actionExecutor == 'delay' - ? const Uuid().v4() - : action.entityId, + 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay' + ? const Uuid().v4() + : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : action.type == 'automation' @@ -699,8 +680,7 @@ class RoutineBloc extends Bloc { ), ); emit(state.copyWith(automationActionExecutor: action.actionExecutor)); - } else if (action.executorProperty != null && - action.actionExecutor != 'delay') { + } else if (action.executorProperty != null && action.actionExecutor != 'delay') { if (!updatedFunctions.containsKey(uniqueCustomId)) { updatedFunctions[uniqueCustomId] = []; } @@ -785,8 +765,7 @@ class RoutineBloc extends Bloc { thenItems: [], )); - final automationDetails = - await SceneApi.getAutomationDetails(event.automationId); + final automationDetails = await SceneApi.getAutomationDetails(event.automationId); final List> thenItems; final List> ifItems; @@ -805,16 +784,13 @@ class RoutineBloc extends Bloc { final cardData = { 'entityId': condition.entityId, 'uniqueCustomId': const Uuid().v4(), - 'deviceId': condition.expr.statusCode == 'delay' - ? 'delay' - : condition.entityId, + 'deviceId': condition.expr.statusCode == 'delay' ? 'delay' : condition.entityId, 'title': condition.expr.statusCode == 'delay' ? 'Delay' : (matchingDevice?.name ?? 'Device'), 'productType': condition.productType, 'functions': matchingDevice?.functions ?? [], - 'imagePath': - matchingDevice?.getDefaultIcon(condition.productType) ?? '', + 'imagePath': matchingDevice?.getDefaultIcon(condition.productType) ?? '', 'device': matchingDevice, }; @@ -851,19 +827,15 @@ class RoutineBloc extends Bloc { final cardData = { 'entityId': action.entityId, 'uniqueCustomId': const Uuid().v4(), - 'deviceId': - action.actionExecutor == 'delay' ? 'delay' : action.entityId, - 'title': action.actionExecutor == 'delay' - ? 'Delay' - : (matchingDevice.name ?? 'Device'), + 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId, + 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'), 'productType': action.productType, 'functions': matchingDevice.functions, 'imagePath': matchingDevice.getDefaultIcon(action.productType), 'device': matchingDevice, }; - if (action.executorProperty != null && - action.actionExecutor != 'delay') { + if (action.executorProperty != null && action.actionExecutor != 'delay') { final functions = matchingDevice.functions; final functionCode = action.executorProperty!.functionCode; for (var function in functions) { @@ -926,8 +898,7 @@ class RoutineBloc extends Bloc { } } - FutureOr _onResetRoutineState( - ResetRoutineState event, Emitter emit) { + FutureOr _onResetRoutineState(ResetRoutineState event, Emitter emit) { emit(state.copyWith( ifItems: [], thenItems: [], @@ -955,8 +926,7 @@ class RoutineBloc extends Bloc { if (state.isTabToRun) { SceneApi.deleteScene(unitUuid: spaceId, sceneId: state.sceneId ?? ''); } else { - SceneApi.deleteAutomation( - unitUuid: spaceId, automationId: state.automationId ?? ''); + SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? ''); } add(const LoadScenes(spaceId, communityId)); @@ -985,8 +955,7 @@ class RoutineBloc extends Bloc { // } // } - FutureOr _fetchDevices( - FetchDevicesInRoutine event, Emitter emit) async { + FutureOr _fetchDevices(FetchDevicesInRoutine event, Emitter emit) async { emit(state.copyWith(isLoading: true)); try { final devices = await DevicesManagementApi().fetchDevices(); @@ -997,22 +966,21 @@ class RoutineBloc extends Bloc { } } - FutureOr _onUpdateScene( - UpdateScene event, Emitter emit) async { + FutureOr _onUpdateScene(UpdateScene event, Emitter emit) async { try { // Check if first action is delay - if (_isFirstActionDelay(state.thenItems)) { - emit(state.copyWith( - errorMessage: 'Cannot have delay as the first action', - isLoading: false, - )); + // if (_isFirstActionDelay(state.thenItems)) { + // emit(state.copyWith( + // errorMessage: 'Cannot have delay as the first action', + // isLoading: false, + // )); - return; - } + // return; + // } if (_isLastActionDelay(state.thenItems)) { emit(state.copyWith( - errorMessage: 'Cannot have delay as the last action', + errorMessage: 'A delay condition cannot be the only or the last action', isLoading: false, )); return; @@ -1065,8 +1033,7 @@ class RoutineBloc extends Bloc { actions: actions, ); - final result = - await SceneApi.updateScene(createSceneModel, state.sceneId ?? ''); + final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? ''); if (result['success']) { add(ResetRoutineState()); add(const LoadScenes(spaceId, communityId)); @@ -1085,21 +1052,19 @@ class RoutineBloc extends Bloc { } } - FutureOr _onUpdateAutomation( - UpdateAutomation event, Emitter emit) async { - if (_isFirstActionDelay(state.thenItems)) { - emit(state.copyWith( - errorMessage: 'Cannot have delay as the first action', - isLoading: false, - )); - return; - } + FutureOr _onUpdateAutomation(UpdateAutomation event, Emitter emit) async { + // if (_isFirstActionDelay(state.thenItems)) { + // emit(state.copyWith( + // errorMessage: 'Cannot have delay as the first action', + // isLoading: false, + // )); + // return; + // } emit(state.copyWith(isLoading: true)); try { final conditions = state.ifItems .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; + final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; @@ -1119,8 +1084,7 @@ class RoutineBloc extends Bloc { final actions = state.thenItems .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; + final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; @@ -1131,9 +1095,8 @@ class RoutineBloc extends Bloc { executorProperty: ExecutorProperty( functionCode: function.functionCode, functionValue: function.value, - delaySeconds: function.functionCode == 'delay' - ? (function.value as num).toInt() - : null, + delaySeconds: + function.functionCode == 'delay' ? (function.value as num).toInt() : null, ), ); }) @@ -1144,14 +1107,13 @@ class RoutineBloc extends Bloc { spaceUuid: spaceId, automationName: state.routineName ?? '', decisionExpr: state.selectedAutomationOperator, - effectiveTime: - state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''), + effectiveTime: state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''), conditions: conditions, actions: actions, ); - final result = await SceneApi.updateAutomation( - createAutomationModel, state.automationId ?? ''); + final result = + await SceneApi.updateAutomation(createAutomationModel, state.automationId ?? ''); if (result['success']) { add(ResetRoutineState()); @@ -1173,7 +1135,6 @@ class RoutineBloc extends Bloc { FutureOr _onSetAutomationActionExecutor( SetAutomationActionExecutor event, Emitter emit) { - emit(state.copyWith( - automationActionExecutor: event.automationActionExecutor)); + emit(state.copyWith(automationActionExecutor: event.automationActionExecutor)); } } diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart index 1f703c92..f3d35eb8 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart @@ -206,3 +206,5 @@ class FetchDevicesInRoutine extends RoutineEvent {} class ResetRoutineState extends RoutineEvent {} class ClearFunctions extends RoutineEvent {} + +class ResetErrorMessage extends RoutineEvent {} diff --git a/lib/pages/routiens/helper/save_routine_helper.dart b/lib/pages/routiens/helper/save_routine_helper.dart index 3bd5a5d2..6a725145 100644 --- a/lib/pages/routiens/helper/save_routine_helper.dart +++ b/lib/pages/routiens/helper/save_routine_helper.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -6,6 +8,7 @@ import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart'; import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class SaveRoutineHelper { static Future showSaveRoutineDialog(BuildContext context) async { @@ -98,18 +101,29 @@ class SaveRoutineHelper { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; return ListTile( - leading: SvgPicture.asset( - item['imagePath'], - width: 22, - height: 22, + leading: item['type'] == 'tap_to_run' + ? Image.memory( + base64Decode(item['icon']), + width: 22, + height: 22, + ) + : SvgPicture.asset( + item['imagePath'], + width: 22, + height: 22, + ), + title: Text( + item['title'], + style: context.textTheme.bodySmall?.copyWith( + fontSize: 14, + color: ColorsManager.grayColor, + ), ), - title: - Text(item['title'], style: const TextStyle(fontSize: 14)), subtitle: Wrap( children: functions .map((f) => Text( '${f.operationName}: ${f.value}, ', - style: const TextStyle( + style: context.textTheme.bodySmall?.copyWith( color: ColorsManager.grayColor, fontSize: 8), overflow: TextOverflow.ellipsis, maxLines: 3, @@ -124,17 +138,17 @@ class SaveRoutineHelper { ], ), ), - if (state.errorMessage != null || state.errorMessage!.isNotEmpty) - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - state.errorMessage!, - style: const TextStyle(color: Colors.red), - ), - ), + // if (state.errorMessage != null || state.errorMessage!.isNotEmpty) + // Padding( + // padding: const EdgeInsets.all(8.0), + // child: Text( + // state.errorMessage!, + // style: const TextStyle(color: Colors.red), + // ), + // ), DialogFooter( onCancel: () => Navigator.pop(context), - onConfirm: () { + onConfirm: () async { if (state.isAutomation) { if (state.automationId != null) { context.read().add(const UpdateAutomation()); @@ -148,10 +162,9 @@ class SaveRoutineHelper { context.read().add(const CreateSceneEvent()); } } - if (context.read().state.errorMessage == null || - context.read().state.errorMessage!.isEmpty) { - Navigator.pop(context); - } + // if (state.errorMessage == null || state.errorMessage!.isEmpty) { + Navigator.pop(context); + // } }, isConfirmEnabled: true, ), diff --git a/lib/pages/routiens/widgets/dragable_card.dart b/lib/pages/routiens/widgets/dragable_card.dart index 1eddf841..abea6593 100644 --- a/lib/pages/routiens/widgets/dragable_card.dart +++ b/lib/pages/routiens/widgets/dragable_card.dart @@ -32,15 +32,13 @@ class DraggableCard extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - final deviceFunctions = - state.selectedFunctions[deviceData['uniqueCustomId']] ?? []; + final deviceFunctions = state.selectedFunctions[deviceData['uniqueCustomId']] ?? []; return Draggable>( data: deviceData, feedback: Transform.rotate( angle: -0.1, - child: - _buildCardContent(context, deviceFunctions, padding: padding), + child: _buildCardContent(context, deviceFunctions, padding: padding), ), childWhenDragging: _buildGreyContainer(), child: _buildCardContent(context, deviceFunctions, padding: padding), @@ -49,8 +47,7 @@ class DraggableCard extends StatelessWidget { ); } - Widget _buildCardContent( - BuildContext context, List deviceFunctions, + Widget _buildCardContent(BuildContext context, List deviceFunctions, {EdgeInsetsGeometry? padding}) { return Stack( children: [ @@ -79,17 +76,13 @@ class DraggableCard extends StatelessWidget { ), ), padding: const EdgeInsets.all(8), - child: imagePath.contains('.svg') - ? SvgPicture.asset( - imagePath, + child: deviceData['type'] == 'tap_to_run' + ? Image.memory( + base64Decode(deviceData['icon']), ) - : imagePath.contains('.png') - ? Image.asset( - imagePath, - ) - : Image.memory( - base64Decode(imagePath), - ), + : SvgPicture.asset( + imagePath, + ), ), const SizedBox(height: 8), Padding( @@ -152,8 +145,7 @@ class DraggableCard extends StatelessWidget { } String _formatFunctionValue(DeviceFunctionData function) { - if (function.functionCode == 'temp_set' || - function.functionCode == 'temp_current') { + if (function.functionCode == 'temp_set' || function.functionCode == 'temp_current') { return '${(function.value / 10).toStringAsFixed(0)}°C'; } else if (function.functionCode.contains('countdown')) { final seconds = function.value.toInt(); diff --git a/lib/pages/routiens/widgets/routine_search_and_buttons.dart b/lib/pages/routiens/widgets/routine_search_and_buttons.dart index 4f4165d5..f10694b6 100644 --- a/lib/pages/routiens/widgets/routine_search_and_buttons.dart +++ b/lib/pages/routiens/widgets/routine_search_and_buttons.dart @@ -43,6 +43,13 @@ class _RoutineSearchAndButtonsState extends State { return Wrap( runSpacing: 16, children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + state.errorMessage ?? '', + style: const TextStyle(color: Colors.red), + ), + ), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -214,6 +221,7 @@ class _RoutineSearchAndButtonsState extends State { } // final result = // await + BlocProvider.of(context).add(ResetErrorMessage()); SaveRoutineHelper.showSaveRoutineDialog(context); // if (result != null && result) { // BlocProvider.of(context).add( @@ -341,6 +349,7 @@ class _RoutineSearchAndButtonsState extends State { } // final result = // await + BlocProvider.of(context).add(ResetErrorMessage()); SaveRoutineHelper.showSaveRoutineDialog(context); // if (result != null && result) { // BlocProvider.of(context).add( diff --git a/lib/pages/routiens/widgets/then_container.dart b/lib/pages/routiens/widgets/then_container.dart index d959c372..44d4aba8 100644 --- a/lib/pages/routiens/widgets/then_container.dart +++ b/lib/pages/routiens/widgets/then_container.dart @@ -26,9 +26,7 @@ class ThenContainer extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('THEN', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold)), + const Text('THEN', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 16), state.isLoading && state.isUpdate == true ? const Center( @@ -41,17 +39,12 @@ class ThenContainer extends StatelessWidget { state.thenItems.length, (index) => GestureDetector( onTap: () async { - if (state.thenItems[index] - ['deviceId'] == - 'delay') { - final result = await DelayHelper - .showDelayPickerDialog(context, - state.thenItems[index]); + if (state.thenItems[index]['deviceId'] == 'delay') { + final result = await DelayHelper.showDelayPickerDialog( + context, state.thenItems[index]); if (result != null) { - context - .read() - .add(AddToThenContainer({ + context.read().add(AddToThenContainer({ ...state.thenItems[index], 'imagePath': Assets.delay, 'title': 'Delay', @@ -60,76 +53,57 @@ class ThenContainer extends StatelessWidget { return; } - if (state.thenItems[index]['type'] == - 'automation') { + if (state.thenItems[index]['type'] == 'automation') { final result = await showDialog( context: context, - builder: (BuildContext context) => - AutomationDialog( + builder: (BuildContext context) => AutomationDialog( automationName: - state.thenItems[index] - ['name'] ?? - 'Automation', + state.thenItems[index]['name'] ?? 'Automation', automationId: - state.thenItems[index] - ['deviceId'] ?? - '', - uniqueCustomId: - state.thenItems[index] - ['uniqueCustomId'], + state.thenItems[index]['deviceId'] ?? '', + uniqueCustomId: state.thenItems[index] + ['uniqueCustomId'], ), ); if (result != null) { - context - .read() - .add(AddToThenContainer({ + context.read().add(AddToThenContainer({ ...state.thenItems[index], - 'imagePath': - Assets.automation, - 'title': state - .thenItems[index]['name'], + 'imagePath': Assets.automation, + 'title': state.thenItems[index]['name'], })); } return; } - final result = await DeviceDialogHelper - .showDeviceDialog( - context, state.thenItems[index], - removeComparetors: true); + final result = await DeviceDialogHelper.showDeviceDialog( + context, state.thenItems[index], + removeComparetors: true); if (result != null) { - context.read().add( - AddToThenContainer( - state.thenItems[index])); + context + .read() + .add(AddToThenContainer(state.thenItems[index])); } else if (!['AC', '1G', '2G', '3G'] - .contains(state.thenItems[index] - ['productType'])) { - context.read().add( - AddToThenContainer( - state.thenItems[index])); + .contains(state.thenItems[index]['productType'])) { + context + .read() + .add(AddToThenContainer(state.thenItems[index])); } }, child: DraggableCard( - imagePath: state.thenItems[index] - ['imagePath'] ?? - '', - title: state.thenItems[index] - ['title'] ?? - '', + imagePath: state.thenItems[index]['imagePath'] ?? '', + title: state.thenItems[index]['title'] ?? '', deviceData: state.thenItems[index], - padding: const EdgeInsets.symmetric( - horizontal: 4, vertical: 8), + padding: + const EdgeInsets.symmetric(horizontal: 4, vertical: 8), isFromThen: true, isFromIf: false, onRemove: () { - context.read().add( - RemoveDragCard( - index: index, - isFromThen: true, - key: state.thenItems[index] - ['uniqueCustomId'])); + context.read().add(RemoveDragCard( + index: index, + isFromThen: true, + key: state.thenItems[index]['uniqueCustomId'])); }, ), ))), @@ -149,6 +123,12 @@ class ThenContainer extends StatelessWidget { } if (mutableData['type'] == 'automation') { + int index = + state.thenItems.indexWhere((item) => item['deviceId'] == mutableData['deviceId']); + if (index != -1) { + return; + } + final result = await showDialog( context: context, builder: (BuildContext context) => AutomationDialog( @@ -169,6 +149,11 @@ class ThenContainer extends StatelessWidget { } if (mutableData['type'] == 'tap_to_run' && state.isAutomation) { + int index = + state.thenItems.indexWhere((item) => item['deviceId'] == mutableData['deviceId']); + if (index != -1) { + return; + } context.read().add(AddToThenContainer({ ...mutableData, 'imagePath': Assets.logo, @@ -183,8 +168,7 @@ class ThenContainer extends StatelessWidget { } if (mutableData['deviceId'] == 'delay') { - final result = - await DelayHelper.showDelayPickerDialog(context, mutableData); + final result = await DelayHelper.showDelayPickerDialog(context, mutableData); if (result != null) { context.read().add(AddToThenContainer({ @@ -196,13 +180,11 @@ class ThenContainer extends StatelessWidget { return; } - final result = await DeviceDialogHelper.showDeviceDialog( - context, mutableData, + final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData, removeComparetors: true); if (result != null) { context.read().add(AddToThenContainer(mutableData)); - } else if (!['AC', '1G', '2G', '3G'] - .contains(mutableData['productType'])) { + } else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) { context.read().add(AddToThenContainer(mutableData)); } }, diff --git a/lib/utils/snack_bar.dart b/lib/utils/snack_bar.dart index d50a4250..0a312e5a 100644 --- a/lib/utils/snack_bar.dart +++ b/lib/utils/snack_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/navigation_service.dart'; class CustomSnackBar { @@ -11,6 +12,35 @@ class CustomSnackBar { } } + static redSnackBar(String message) { + final key = NavigationService.snackbarKey; + BuildContext? currentContext = key?.currentContext; + if (key != null && currentContext != null) { + final snackBar = SnackBar( + padding: const EdgeInsets.all(16), + backgroundColor: ColorsManager.red, + content: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + const Icon( + Icons.check_circle, + color: ColorsManager.whiteColors, + size: 32, + ), + const SizedBox( + width: 8, + ), + Text( + message, + style: Theme.of(currentContext) + .textTheme + .bodySmall! + .copyWith(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.green), + ) + ]), + ); + key.currentState?.showSnackBar(snackBar); + } + } + static greenSnackBar(String message) { final key = NavigationService.snackbarKey; BuildContext? currentContext = key?.currentContext; @@ -29,8 +59,10 @@ class CustomSnackBar { ), Text( message, - style: Theme.of(currentContext).textTheme.bodySmall!.copyWith( - fontSize: 14, fontWeight: FontWeight.w500, color: Colors.green), + style: Theme.of(currentContext) + .textTheme + .bodySmall! + .copyWith(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.green), ) ]), );