Bug fixes

This commit is contained in:
Abdullah Alassaf
2024-12-03 00:02:52 +03:00
parent 2f5c5d7da1
commit 4e94d2df89
7 changed files with 245 additions and 254 deletions

View File

@ -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<RoutineEvent, RoutineState> {
on<SetAutomationActionExecutor>(_onSetAutomationActionExecutor);
on<TriggerSwitchTabsEvent>(_triggerSwitchTabsEvent);
on<CreateNewRoutineViewEvent>(_createNewRoutineViewEvent);
on<ResetErrorMessage>(_resetErrorMessage);
}
FutureOr<void> _triggerSwitchTabsEvent(
TriggerSwitchTabsEvent event,
Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
}
}
_resetErrorMessage(
ResetErrorMessage event,
Emitter<RoutineState> emit,
) {
emit(state.copyWith(errorMessage: ''));
}
FutureOr<void> _createNewRoutineViewEvent(
CreateNewRoutineViewEvent event,
Emitter<RoutineState> emit,
@ -73,8 +81,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final updatedIfItems = List<Map<String, dynamic>>.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<RoutineEvent, RoutineState> {
}
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<RoutineState> emit) {
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
final currentItems = List<Map<String, dynamic>>.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<RoutineEvent, RoutineState> {
emit(state.copyWith(thenItems: currentItems));
}
void _onAddFunctionsToRoutine(
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
try {
if (event.functions.isEmpty) return;
List<DeviceFunctionData> selectedFunction =
List<DeviceFunctionData>.from(event.functions);
List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
List<DeviceFunctionData> currentFunctions =
List<DeviceFunctionData>.from(
currentSelectedFunctions[event.uniqueCustomId] ?? []);
List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
List<String> 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<RoutineEvent, RoutineState> {
}
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<RoutineEvent, RoutineState> {
}
}
Future<void> _onLoadScenes(
LoadScenes event, Emitter<RoutineState> emit) async {
Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
}
}
Future<void> _onLoadAutomation(
LoadAutomation event, Emitter<RoutineState> emit) async {
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null));
try {
@ -204,44 +200,41 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onSearchRoutines(
SearchRoutines event, Emitter<RoutineState> emit) async {
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> 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<void> _onAddSelectedIcon(
AddSelectedIcon event, Emitter<RoutineState> emit) {
FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
emit(state.copyWith(selectedIcon: event.icon));
}
bool _isFirstActionDelay(List<Map<String, dynamic>> actions) {
if (actions.isEmpty) return false;
return actions.first['deviceId'] == 'delay';
}
// bool _isFirstActionDelay(List<Map<String, dynamic>> actions) {
// if (actions.isEmpty) return false;
// return actions.first['deviceId'] == 'delay';
// }
bool _isLastActionDelay(List<Map<String, dynamic>> actions) {
if (actions.isEmpty) return false;
return actions.last['deviceId'] == 'delay';
}
Future<void> _onCreateScene(
CreateSceneEvent event, Emitter<RoutineState> emit) async {
Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
}
}
Future<void> _onCreateAutomation(
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
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<void> _onRemoveDragCard(
RemoveDragCard event, Emitter<RoutineState> emit) {
FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
if (event.isFromThen) {
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
final selectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
final selectedFunctions = Map<String, List<DeviceFunctionData>>.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<Map<String, dynamic>>.from(state.ifItems);
final selectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
ifItems.removeAt(event.index);
selectedFunctions.remove(event.key);
@ -464,8 +458,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
));
}
FutureOr<void> _onEffectiveTimeEvent(
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
emit(state.copyWith(effectiveTime: event.effectiveTime));
}
FutureOr<void> _onSetRoutineName(
SetRoutineName event, Emitter<RoutineState> emit) {
FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
emit(state.copyWith(
routineName: event.name,
));
}
(
List<Map<String, dynamic>>,
List<Map<String, dynamic>>,
Map<String, List<DeviceFunctionData>>
) _createCardData(
(List<Map<String, dynamic>>, List<Map<String, dynamic>>, Map<String, List<DeviceFunctionData>>)
_createCardData(
List<RoutineAction> actions,
List<RoutineCondition>? conditions,
Map<String, List<DeviceFunctionData>> currentFunctions,
@ -526,8 +514,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
'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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
return (thenItems, ifItems, currentFunctions);
}
Future<void> _onGetSceneDetails(
GetSceneDetails event, Emitter<RoutineState> emit) async {
Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
try {
emit(state.copyWith(
isLoading: true,
@ -659,12 +642,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
),
);
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<RoutineEvent, RoutineState> {
thenItems: [],
));
final automationDetails =
await SceneApi.getAutomationDetails(event.automationId);
final automationDetails = await SceneApi.getAutomationDetails(event.automationId);
final List<Map<String, dynamic>> thenItems;
final List<Map<String, dynamic>> ifItems;
@ -805,16 +784,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onResetRoutineState(
ResetRoutineState event, Emitter<RoutineState> emit) {
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
emit(state.copyWith(
ifItems: [],
thenItems: [],
@ -955,8 +926,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
// }
// }
FutureOr<void> _fetchDevices(
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true));
try {
final devices = await DevicesManagementApi().fetchDevices();
@ -997,22 +966,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onUpdateScene(
UpdateScene event, Emitter<RoutineState> emit) async {
FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
}
}
FutureOr<void> _onUpdateAutomation(
UpdateAutomation event, Emitter<RoutineState> emit) async {
if (_isFirstActionDelay(state.thenItems)) {
emit(state.copyWith(
errorMessage: 'Cannot have delay as the first action',
isLoading: false,
));
return;
}
FutureOr<void> _onUpdateAutomation(UpdateAutomation event, Emitter<RoutineState> 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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
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<RoutineEvent, RoutineState> {
FutureOr<void> _onSetAutomationActionExecutor(
SetAutomationActionExecutor event, Emitter<RoutineState> emit) {
emit(state.copyWith(
automationActionExecutor: event.automationActionExecutor));
emit(state.copyWith(automationActionExecutor: event.automationActionExecutor));
}
}

View File

@ -206,3 +206,5 @@ class FetchDevicesInRoutine extends RoutineEvent {}
class ResetRoutineState extends RoutineEvent {}
class ClearFunctions extends RoutineEvent {}
class ResetErrorMessage extends RoutineEvent {}

View File

@ -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<void> 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<RoutineBloc>().add(const UpdateAutomation());
@ -148,10 +162,9 @@ class SaveRoutineHelper {
context.read<RoutineBloc>().add(const CreateSceneEvent());
}
}
if (context.read<RoutineBloc>().state.errorMessage == null ||
context.read<RoutineBloc>().state.errorMessage!.isEmpty) {
Navigator.pop(context);
}
// if (state.errorMessage == null || state.errorMessage!.isEmpty) {
Navigator.pop(context);
// }
},
isConfirmEnabled: true,
),

View File

@ -32,15 +32,13 @@ class DraggableCard extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) {
final deviceFunctions =
state.selectedFunctions[deviceData['uniqueCustomId']] ?? [];
final deviceFunctions = state.selectedFunctions[deviceData['uniqueCustomId']] ?? [];
return Draggable<Map<String, dynamic>>(
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<DeviceFunctionData> deviceFunctions,
Widget _buildCardContent(BuildContext context, List<DeviceFunctionData> 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();

View File

@ -43,6 +43,13 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
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<RoutineSearchAndButtons> {
}
// final result =
// await
BlocProvider.of<RoutineBloc>(context).add(ResetErrorMessage());
SaveRoutineHelper.showSaveRoutineDialog(context);
// if (result != null && result) {
// BlocProvider.of<RoutineBloc>(context).add(
@ -341,6 +349,7 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
}
// final result =
// await
BlocProvider.of<RoutineBloc>(context).add(ResetErrorMessage());
SaveRoutineHelper.showSaveRoutineDialog(context);
// if (result != null && result) {
// BlocProvider.of<RoutineBloc>(context).add(

View File

@ -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<RoutineBloc>()
.add(AddToThenContainer({
context.read<RoutineBloc>().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<bool>(
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<RoutineBloc>()
.add(AddToThenContainer({
context.read<RoutineBloc>().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<RoutineBloc>().add(
AddToThenContainer(
state.thenItems[index]));
context
.read<RoutineBloc>()
.add(AddToThenContainer(state.thenItems[index]));
} else if (!['AC', '1G', '2G', '3G']
.contains(state.thenItems[index]
['productType'])) {
context.read<RoutineBloc>().add(
AddToThenContainer(
state.thenItems[index]));
.contains(state.thenItems[index]['productType'])) {
context
.read<RoutineBloc>()
.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<RoutineBloc>().add(
RemoveDragCard(
index: index,
isFromThen: true,
key: state.thenItems[index]
['uniqueCustomId']));
context.read<RoutineBloc>().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<bool>(
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<RoutineBloc>().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<RoutineBloc>().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<RoutineBloc>().add(AddToThenContainer(mutableData));
} else if (!['AC', '1G', '2G', '3G']
.contains(mutableData['productType'])) {
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
}
},

View File

@ -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),
)
]),
);