diff --git a/lib/pages/device_managment/all_devices/view/device_managment_page.dart b/lib/pages/device_managment/all_devices/view/device_managment_page.dart index 966d5361..ffc57131 100644 --- a/lib/pages/device_managment/all_devices/view/device_managment_page.dart +++ b/lib/pages/device_managment/all_devices/view/device_managment_page.dart @@ -88,32 +88,31 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { ); }), rightBody: const NavigateHomeGridView(), - scaffoldBody: CreateNewRoutineView(), - // BlocBuilder( - // builder: (context, state) { - // if (state is SelectedTabState && state.selectedTab) { - // return const RoutinesView(); - // } - // if (state is ShowCreateRoutineState && state.showCreateRoutine) { - // return const CreateNewRoutineView(); - // } + scaffoldBody: BlocBuilder( + builder: (context, state) { + if (state is SelectedTabState && state.selectedTab) { + return const RoutinesView(); + } + if (state is ShowCreateRoutineState && state.showCreateRoutine) { + return const CreateNewRoutineView(); + } - // return BlocBuilder( - // builder: (context, deviceState) { - // if (deviceState is DeviceManagementLoading) { - // return const Center(child: CircularProgressIndicator()); - // } else if (deviceState is DeviceManagementLoaded || - // deviceState is DeviceManagementFiltered) { - // final devices = (deviceState as dynamic).devices ?? - // (deviceState as DeviceManagementFiltered).filteredDevices; + return BlocBuilder( + builder: (context, deviceState) { + if (deviceState is DeviceManagementLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (deviceState is DeviceManagementLoaded || + deviceState is DeviceManagementFiltered) { + final devices = (deviceState as dynamic).devices ?? + (deviceState as DeviceManagementFiltered).filteredDevices; - // return DeviceManagementBody(devices: devices); - // } else { - // return const Center(child: Text('Error fetching Devices')); - // } - // }, - // ); - // }), + return DeviceManagementBody(devices: devices); + } else { + return const Center(child: Text('Error fetching Devices')); + } + }, + ); + }), ), ); } diff --git a/lib/pages/routiens/bloc/effective_period/effect_period_bloc.dart b/lib/pages/routiens/bloc/effective_period/effect_period_bloc.dart index b5a293a1..f4db836b 100644 --- a/lib/pages/routiens/bloc/effective_period/effect_period_bloc.dart +++ b/lib/pages/routiens/bloc/effective_period/effect_period_bloc.dart @@ -2,10 +2,7 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart'; import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart'; -import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; -import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart'; -import 'package:syncrow_web/utils/navigation_service.dart'; class EffectPeriodBloc extends Bloc { final daysMap = { @@ -52,10 +49,6 @@ class EffectPeriodBloc extends Bloc { break; } - BlocProvider.of(NavigationService.navigatorKey.currentContext!).add( - EffectiveTimePeriodEvent( - EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary))); - emit(state.copyWith( selectedPeriod: event.period, customStartTime: startTime, customEndTime: endTime)); } @@ -70,12 +63,6 @@ class EffectPeriodBloc extends Bloc { } final newDaysBinary = daysList.join(); emit(state.copyWith(selectedDaysBinary: newDaysBinary)); - - BlocProvider.of(NavigationService.navigatorKey.currentContext!).add( - EffectiveTimePeriodEvent(EffectiveTime( - start: state.customStartTime ?? '00:00', - end: state.customEndTime ?? '23:59', - loops: newDaysBinary))); } void _onSetCustomTime(SetCustomTime event, Emitter emit) { @@ -96,10 +83,6 @@ class EffectPeriodBloc extends Bloc { emit( state.copyWith(customStartTime: startTime, customEndTime: endTime, selectedPeriod: period)); - - BlocProvider.of(NavigationService.navigatorKey.currentContext!).add( - EffectiveTimePeriodEvent( - EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary))); } void _onResetEffectivePeriod(ResetEffectivePeriod event, Emitter emit) { @@ -108,9 +91,6 @@ class EffectPeriodBloc extends Bloc { 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) { diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart index 7694e8ec..6eb03160 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_bloc.dart @@ -15,9 +15,6 @@ part 'routine_state.dart'; const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; class RoutineBloc extends Bloc { - // bool isAutomation = false; - // bool isTabToRun = false; - RoutineBloc() : super(const RoutineState()) { on(_onAddToIfContainer); on(_onAddToThenContainer); @@ -32,29 +29,37 @@ class RoutineBloc extends Bloc { on(_onEffectiveTimeEvent); on(_onCreateAutomation); on(_onSetRoutineName); + on(_onResetRoutineState); // on(_onRemoveFunction); // on(_onClearFunctions); } void _onAddToIfContainer(AddToIfContainer event, Emitter emit) { - final updatedIfItems = List>.from(state.ifItems) - ..add(event.item); - if (event.isTabToRun) { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); + 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']); + // Replace the map if the index is valid + if (index != -1) { + updatedIfItems[index] = event.item; } else { - emit(state.copyWith( - ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); + updatedIfItems.add(event.item); + } + + if (event.isTabToRun) { + emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); + } else { + 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; @@ -65,21 +70,38 @@ 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; - final currentSelectedFunctions = - Map>.from(state.selectedFunctions); + List selectedFunction = List.from(event.functions); + Map> currentSelectedFunctions = + Map>.from(state.selectedFunctions); if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { - currentSelectedFunctions[event.uniqueCustomId] = - List.from(currentSelectedFunctions[event.uniqueCustomId]!) - ..addAll(event.functions); + List currentFunctions = + 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) { + currentFunctions[j] = selectedFunction[i]; + if (!functionCode.contains(currentFunctions[j].functionCode)) { + functionCode.add(currentFunctions[j].functionCode); + } + } + } + } + + for (int i = 0; i < functionCode.length; i++) { + selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]); + } + + 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)); @@ -88,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 { @@ -108,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, @@ -128,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)); } @@ -145,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)) { @@ -159,50 +186,54 @@ class RoutineBloc extends Bloc { emit(state.copyWith(isLoading: true)); - final actions = state.thenItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - if (item['deviceId'] == 'delay') { - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: 'delay', - executorProperty: CreateSceneExecutorProperty( - functionCode: '', - functionValue: '', - delaySeconds: function.value, - ), - ); - } - + final actions = state.thenItems.expand((item) { + final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; + return functions.map((function) { + if (function.functionCode == 'automation') { return CreateSceneAction( entityId: function.entityId, - actionExecutor: 'device_issue', + actionExecutor: function.value, + executorProperty: null, + ); + } + + if (item['deviceId'] == 'delay') { + return CreateSceneAction( + entityId: function.entityId, + actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( - functionCode: function.functionCode.toString(), - functionValue: function.value, - delaySeconds: 0, + functionCode: '', + functionValue: '', + delaySeconds: int.tryParse(function.value.toString()) ?? 0, ), ); - }) - .whereType() - .toList(); + } + + return CreateSceneAction( + entityId: function.entityId, + actionExecutor: 'device_issue', + executorProperty: CreateSceneExecutorProperty( + functionCode: function.functionCode, + functionValue: function.value, + delaySeconds: 0, + ), + ); + }); + }).toList(); final createSceneModel = CreateSceneModel( spaceUuid: spaceId, iconId: state.selectedIcon ?? '', showInDevice: true, - sceneName: state.routineName ?? '', + sceneName: state.routineName!, decisionExpr: 'and', actions: actions, ); final result = await SceneApi.createScene(createSceneModel); if (result['success']) { - emit(const RoutineState()); + emit(_resetState()); + add(const LoadScenes(spaceId)); } else { emit(state.copyWith( isLoading: false, @@ -212,13 +243,12 @@ class RoutineBloc extends Bloc { } catch (e) { emit(state.copyWith( isLoading: false, - errorMessage: e.toString(), + errorMessage: 'Something went wrong', )); } } - 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( @@ -229,26 +259,24 @@ class RoutineBloc extends Bloc { emit(state.copyWith(isLoading: true)); - final conditions = state.ifItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - return CreateCondition( - code: state.ifItems.indexOf(item) + 1, - entityId: function.entityId, - entityType: 'device_report', - expr: ConditionExpr( - statusCode: function.functionCode, - comparator: function.condition ?? '==', - statusValue: function.value, - ), - ); - }) - .whereType() - .toList(); + final conditions = state.ifItems.expand((item) { + final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; + return functions.map((function) { + return Condition( + code: state.selectedFunctions[item['uniqueCustomId']]!.indexOf( + function, + ) + + 1, + entityId: function.entityId, + entityType: 'device_report', + expr: ConditionExpr( + statusCode: function.functionCode, + comparator: function.condition ?? '==', + statusValue: function.value, + ), + ); + }); + }).toList(); if (conditions.isEmpty) { emit(state.copyWith( @@ -258,61 +286,54 @@ class RoutineBloc extends Bloc { return; } + final actions = state.thenItems.expand((item) { + final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; + return functions.map((function) { + if (function.functionCode == 'automation') { + return AutomationAction( + entityId: function.entityId, + actionExecutor: function.value, + ); + } + + if (item['deviceId'] == 'delay') { + return AutomationAction( + entityId: function.entityId, + actionExecutor: 'delay', + executorProperty: ExecutorProperty( + delaySeconds: int.tryParse(function.value.toString()) ?? 0, + ), + ); + } + + return AutomationAction( + entityId: function.entityId, + actionExecutor: 'device_issue', + executorProperty: ExecutorProperty( + functionCode: function.functionCode, + functionValue: function.value, + ), + ); + }); + }).toList(); + final createAutomationModel = CreateAutomationModel( - unitUuid: spaceId, + spaceUuid: spaceId, automationName: state.routineName!, decisionExpr: state.selectedAutomationOperator, - effectiveTime: state.effectiveTime ?? - EffectiveTime( - start: '00:00', - end: '23:59', - loops: '1111111', - ), + effectiveTime: EffectiveTime( + start: state.effectiveTime?.start ?? '00:00', + end: state.effectiveTime?.end ?? '23:59', + loops: state.effectiveTime?.loops ?? '1111111', + ), conditions: conditions, - actions: state.thenItems - .map((item) { - final functions = - state.selectedFunctions[item['uniqueCustomId']] ?? []; - if (functions.isEmpty) return null; - - final function = functions.first; - if (function.functionCode == 'automation') { - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: function.value, - executorProperty: null, - ); - } - - if (item['deviceId'] == 'delay') { - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: 'delay', - executorProperty: CreateSceneExecutorProperty( - functionCode: '', - functionValue: '', - delaySeconds: function.value, - ), - ); - } - - return CreateSceneAction( - entityId: function.entityId, - actionExecutor: 'device_issue', - executorProperty: CreateSceneExecutorProperty( - functionCode: function.functionCode, - functionValue: function.value, - delaySeconds: 0, - ), - ); - }) - .whereType() - .toList(), + actions: actions, ); final result = await SceneApi.createAutomation(createAutomationModel); if (result['success']) { - emit(const RoutineState()); + emit(_resetState()); + add(const LoadAutomation(spaceId)); } else { emit(state.copyWith( isLoading: false, @@ -322,21 +343,26 @@ class RoutineBloc extends Bloc { } catch (e) { emit(state.copyWith( isLoading: false, - errorMessage: e.toString(), + errorMessage: '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); + thenItems.removeAt(event.index); - emit(state.copyWith(thenItems: thenItems)); + selectedFunctions.remove(event.key); + emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions)); } else { final ifItems = List>.from(state.ifItems); + final selectedFunctions = Map>.from(state.selectedFunctions); + ifItems.removeAt(event.index); - emit(state.copyWith(ifItems: ifItems)); + selectedFunctions.remove(event.key); + emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions)); } } @@ -347,13 +373,36 @@ 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)); } + + RoutineState _resetState() { + return const RoutineState( + ifItems: [], + thenItems: [], + selectedFunctions: {}, + scenes: [], + automations: [], + isLoading: false, + errorMessage: null, + loadScenesErrorMessage: null, + loadAutomationErrorMessage: null, + searchText: '', + selectedIcon: null, + isTabToRun: false, + isAutomation: false, + selectedAutomationOperator: 'AND', + effectiveTime: null, + routineName: null, + ); + } + + FutureOr _onResetRoutineState(ResetRoutineState event, Emitter emit) { + emit(_resetState()); + } } diff --git a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart index 9337e88e..575f199d 100644 --- a/lib/pages/routiens/bloc/routine_bloc/routine_event.dart +++ b/lib/pages/routiens/bloc/routine_bloc/routine_event.dart @@ -82,9 +82,11 @@ class CreateSceneEvent extends RoutineEvent { class RemoveDragCard extends RoutineEvent { final int index; final bool isFromThen; - const RemoveDragCard({required this.index, required this.isFromThen}); + final String key; + const RemoveDragCard( + {required this.index, required this.isFromThen, required this.key}); @override - List get props => [index]; + List get props => [index, isFromThen, key]; } class ChangeAutomationOperator extends RoutineEvent { @@ -121,4 +123,7 @@ class SetRoutineName extends RoutineEvent { @override List get props => [name]; } + +class ResetRoutineState extends RoutineEvent {} + class ClearFunctions extends RoutineEvent {} diff --git a/lib/pages/routiens/helper/save_routine_helper.dart b/lib/pages/routiens/helper/save_routine_helper.dart index c6a8b2aa..2a57baa5 100644 --- a/lib/pages/routiens/helper/save_routine_helper.dart +++ b/lib/pages/routiens/helper/save_routine_helper.dart @@ -142,9 +142,16 @@ class SaveRoutineHelper { DialogFooter( onCancel: () => Navigator.pop(context), onConfirm: () { - context - .read() - .add(const CreateSceneEvent()); + if (state.isAutomation) { + context + .read() + .add(const CreateAutomationEvent()); + } else { + context + .read() + .add(const CreateSceneEvent()); + } + Navigator.pop(context); }, isConfirmEnabled: true, diff --git a/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart b/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart index f7bb1fb5..cd9a9c60 100644 --- a/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart +++ b/lib/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart @@ -1,18 +1,187 @@ - import 'dart:convert'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart'; +// class CreateAutomationModel { +// String unitUuid; +// String automationName; +// String decisionExpr; +// EffectiveTime effectiveTime; +// List conditions; +// List actions; + +// CreateAutomationModel({ +// required this.unitUuid, +// required this.automationName, +// required this.decisionExpr, +// required this.effectiveTime, +// required this.conditions, +// required this.actions, +// }); + +// CreateAutomationModel copyWith({ +// String? unitUuid, +// String? automationName, +// String? decisionExpr, +// EffectiveTime? effectiveTime, +// List? conditions, +// List? actions, +// }) { +// return CreateAutomationModel( +// unitUuid: unitUuid ?? this.unitUuid, +// automationName: automationName ?? this.automationName, +// decisionExpr: decisionExpr ?? this.decisionExpr, +// effectiveTime: effectiveTime ?? this.effectiveTime, +// conditions: conditions ?? this.conditions, +// actions: actions ?? this.actions, +// ); +// } + +// Map toMap([String? automationId]) { +// return { +// if (automationId == null) 'spaceUuid': unitUuid, +// 'automationName': automationName, +// 'decisionExpr': decisionExpr, +// 'effectiveTime': effectiveTime.toMap(), +// 'conditions': conditions.map((x) => x.toMap()).toList(), +// 'actions': actions.map((x) => x.toMap()).toList(), +// }; +// } + +// factory CreateAutomationModel.fromMap(Map map) { +// return CreateAutomationModel( +// unitUuid: map['spaceUuid'] ?? '', +// automationName: map['automationName'] ?? '', +// decisionExpr: map['decisionExpr'] ?? '', +// effectiveTime: EffectiveTime.fromMap(map['effectiveTime']), +// conditions: List.from( +// map['conditions']?.map((x) => CreateCondition.fromMap(x))), +// actions: List.from( +// map['actions']?.map((x) => CreateSceneAction.fromMap(x))), +// ); +// } + +// String toJson([String? automationId]) => json.encode(toMap(automationId)); + +// factory CreateAutomationModel.fromJson(String source) => +// CreateAutomationModel.fromMap(json.decode(source)); + +// @override +// String toString() { +// return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)'; +// } +// } + +// class EffectiveTime { +// String start; +// String end; +// String loops; + +// EffectiveTime({ +// required this.start, +// required this.end, +// required this.loops, +// }); + +// Map toMap() { +// return { +// 'start': start, +// 'end': end, +// 'loops': loops, +// }; +// } + +// factory EffectiveTime.fromMap(Map map) { +// return EffectiveTime( +// start: map['start'] ?? '', +// end: map['end'] ?? '', +// loops: map['loops'] ?? '', +// ); +// } + +// @override +// String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)'; +// } + +// class CreateCondition { +// int code; +// String entityId; +// String entityType; +// ConditionExpr expr; + +// CreateCondition({ +// required this.code, +// required this.entityId, +// required this.entityType, +// required this.expr, +// }); + +// Map toMap() { +// return { +// 'code': code, +// 'entityId': entityId, +// 'entityType': entityType, +// 'expr': expr.toMap(), +// }; +// } + +// factory CreateCondition.fromMap(Map map) { +// return CreateCondition( +// code: map['code'] ?? 0, +// entityId: map['entityId'] ?? '', +// entityType: map['entityType'] ?? '', +// expr: ConditionExpr.fromMap(map['expr']), +// ); +// } + +// @override +// String toString() => +// 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)'; +// } + +// class ConditionExpr { +// String statusCode; +// String comparator; +// dynamic statusValue; + +// ConditionExpr({ +// required this.statusCode, +// required this.comparator, +// required this.statusValue, +// }); + +// Map toMap() { +// return { +// 'statusCode': statusCode, +// 'comparator': comparator, +// 'statusValue': statusValue, +// }; +// } + +// factory ConditionExpr.fromMap(Map map) { +// return ConditionExpr( +// statusCode: map['statusCode'] ?? '', +// comparator: map['comparator'] ?? '', +// statusValue: map['statusValue'], +// ); +// } + +// @override +// String toString() => +// 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)'; +// } +import 'dart:convert'; + class CreateAutomationModel { - String unitUuid; + String spaceUuid; String automationName; String decisionExpr; EffectiveTime effectiveTime; - List conditions; - List actions; + List conditions; + List actions; CreateAutomationModel({ - required this.unitUuid, + required this.spaceUuid, required this.automationName, required this.decisionExpr, required this.effectiveTime, @@ -20,27 +189,9 @@ class CreateAutomationModel { required this.actions, }); - CreateAutomationModel copyWith({ - String? unitUuid, - String? automationName, - String? decisionExpr, - EffectiveTime? effectiveTime, - List? conditions, - List? actions, - }) { - return CreateAutomationModel( - unitUuid: unitUuid ?? this.unitUuid, - automationName: automationName ?? this.automationName, - decisionExpr: decisionExpr ?? this.decisionExpr, - effectiveTime: effectiveTime ?? this.effectiveTime, - conditions: conditions ?? this.conditions, - actions: actions ?? this.actions, - ); - } - - Map toMap([String? automationId]) { + Map toMap() { return { - if (automationId == null) 'spaceUuid': unitUuid, + 'spaceUuid': spaceUuid, 'automationName': automationName, 'decisionExpr': decisionExpr, 'effectiveTime': effectiveTime.toMap(), @@ -51,26 +202,21 @@ class CreateAutomationModel { factory CreateAutomationModel.fromMap(Map map) { return CreateAutomationModel( - unitUuid: map['spaceUuid'] ?? '', + spaceUuid: map['spaceUuid'] ?? '', automationName: map['automationName'] ?? '', decisionExpr: map['decisionExpr'] ?? '', effectiveTime: EffectiveTime.fromMap(map['effectiveTime']), - conditions: List.from( - map['conditions']?.map((x) => CreateCondition.fromMap(x))), - actions: List.from( - map['actions']?.map((x) => CreateSceneAction.fromMap(x))), + conditions: List.from( + map['conditions']?.map((x) => Condition.fromMap(x)) ?? []), + actions: List.from( + map['actions']?.map((x) => AutomationAction.fromMap(x)) ?? []), ); } - String toJson([String? automationId]) => json.encode(toMap(automationId)); + String toJson() => json.encode(toMap()); factory CreateAutomationModel.fromJson(String source) => CreateAutomationModel.fromMap(json.decode(source)); - - @override - String toString() { - return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)'; - } } class EffectiveTime { @@ -99,18 +245,15 @@ class EffectiveTime { loops: map['loops'] ?? '', ); } - - @override - String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)'; } -class CreateCondition { +class Condition { int code; String entityId; String entityType; ConditionExpr expr; - CreateCondition({ + Condition({ required this.code, required this.entityId, required this.entityType, @@ -126,18 +269,14 @@ class CreateCondition { }; } - factory CreateCondition.fromMap(Map map) { - return CreateCondition( - code: map['code'] ?? 0, + factory Condition.fromMap(Map map) { + return Condition( + code: map['code']?.toInt() ?? 0, entityId: map['entityId'] ?? '', entityType: map['entityType'] ?? '', expr: ConditionExpr.fromMap(map['expr']), ); } - - @override - String toString() => - 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)'; } class ConditionExpr { @@ -166,8 +305,62 @@ class ConditionExpr { statusValue: map['statusValue'], ); } - - @override - String toString() => - 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)'; +} + +class AutomationAction { + String entityId; + String actionExecutor; + ExecutorProperty? executorProperty; + + AutomationAction({ + required this.entityId, + required this.actionExecutor, + this.executorProperty, + }); + + Map toMap() { + return { + 'entityId': entityId, + 'actionExecutor': actionExecutor, + 'executorProperty': executorProperty?.toMap(), + }; + } + + factory AutomationAction.fromMap(Map map) { + return AutomationAction( + entityId: map['entityId'] ?? '', + actionExecutor: map['actionExecutor'] ?? '', + executorProperty: map['executorProperty'] != null + ? ExecutorProperty.fromMap(map['executorProperty']) + : null, + ); + } +} + +class ExecutorProperty { + String? functionCode; + dynamic functionValue; + int? delaySeconds; + + ExecutorProperty({ + this.functionCode, + this.functionValue, + this.delaySeconds, + }); + + Map toMap() { + return { + if (functionCode != null) 'functionCode': functionCode, + if (functionValue != null) 'functionValue': functionValue, + if (delaySeconds != null) 'delaySeconds': delaySeconds, + }; + } + + factory ExecutorProperty.fromMap(Map map) { + return ExecutorProperty( + functionCode: map['functionCode'], + functionValue: map['functionValue'], + delaySeconds: map['delaySeconds']?.toInt(), + ); + } } diff --git a/lib/pages/routiens/view/effective_period_view.dart b/lib/pages/routiens/view/effective_period_view.dart index d9d9bc2f..5e6c33da 100644 --- a/lib/pages/routiens/view/effective_period_view.dart +++ b/lib/pages/routiens/view/effective_period_view.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart'; import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.dart'; import 'package:syncrow_web/pages/routiens/widgets/period_option.dart'; import 'package:syncrow_web/pages/routiens/widgets/repeat_days.dart'; @@ -11,39 +9,36 @@ class EffectivePeriodView extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - create: (_) => EffectPeriodBloc(), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: ListView( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Spacer(), - Expanded( - child: Text( - 'Effective Period', - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: ColorsManager.textPrimaryColor, - fontWeight: FontWeight.w400, - fontSize: 14), - ), + return Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Spacer(), + Expanded( + child: Text( + 'Effective Period', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), ), - const Spacer(), - ], - ), - const Divider( - color: ColorsManager.backgroundColor, - ), - const PeriodOptions( - showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker, - ), - const SizedBox(height: 16), - const RepeatDays(), - const SizedBox(height: 24), - ], - ), + ), + const Spacer(), + ], + ), + const Divider( + color: ColorsManager.backgroundColor, + ), + const PeriodOptions( + showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker, + ), + const SizedBox(height: 16), + const RepeatDays(), + const SizedBox(height: 24), + ], ), ); } diff --git a/lib/pages/routiens/widgets/if_container.dart b/lib/pages/routiens/widgets/if_container.dart index 57577f64..d0273adc 100644 --- a/lib/pages/routiens/widgets/if_container.dart +++ b/lib/pages/routiens/widgets/if_container.dart @@ -26,9 +26,7 @@ class IfContainer extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text('IF', - style: TextStyle( - fontSize: 18, fontWeight: FontWeight.bold)), + const Text('IF', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), if (state.isAutomation) AutomationOperatorSelector( selectedOperator: state.selectedAutomationOperator), @@ -52,20 +50,38 @@ class IfContainer extends StatelessWidget { runSpacing: 8, children: List.generate( state.ifItems.length, - (index) => DraggableCard( - imagePath: - state.ifItems[index]['imagePath'] ?? '', - title: state.ifItems[index]['title'] ?? '', - deviceData: state.ifItems[index], - padding: const EdgeInsets.symmetric( - horizontal: 4, vertical: 8), - isFromThen: false, - isFromIf: true, - onRemove: () { - context.read().add( - RemoveDragCard( - index: index, isFromThen: false)); + (index) => GestureDetector( + onTap: () async { + if (!state.isTabToRun) { + final result = await DeviceDialogHelper.showDeviceDialog( + context, state.ifItems[index]); + + if (result != null) { + context + .read() + .add(AddToIfContainer(state.ifItems[index], false)); + } else if (!['AC', '1G', '2G', '3G'] + .contains(state.ifItems[index]['productType'])) { + context + .read() + .add(AddToIfContainer(state.ifItems[index], false)); + } + } }, + child: DraggableCard( + imagePath: state.ifItems[index]['imagePath'] ?? '', + title: state.ifItems[index]['title'] ?? '', + deviceData: state.ifItems[index], + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8), + isFromThen: false, + isFromIf: true, + onRemove: () { + context.read().add(RemoveDragCard( + index: index, + isFromThen: false, + key: state.ifItems[index]['uniqueCustomId'])); + }, + ), )), ), ], @@ -81,22 +97,14 @@ class IfContainer extends StatelessWidget { if (!state.isTabToRun) { if (mutableData['deviceId'] == 'tab_to_run') { - context - .read() - .add(AddToIfContainer(mutableData, true)); + context.read().add(AddToIfContainer(mutableData, true)); } else { - final result = await DeviceDialogHelper.showDeviceDialog( - context, mutableData); + final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData); if (result != null) { - context - .read() - .add(AddToIfContainer(mutableData, false)); - } else if (!['AC', '1G', '2G', '3G'] - .contains(mutableData['productType'])) { - context - .read() - .add(AddToIfContainer(mutableData, false)); + context.read().add(AddToIfContainer(mutableData, false)); + } else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) { + context.read().add(AddToIfContainer(mutableData, false)); } } } @@ -136,15 +144,12 @@ class AutomationOperatorSelector extends StatelessWidget { child: Text( 'Any condition is met', style: context.textTheme.bodyMedium?.copyWith( - color: selectedOperator == 'or' - ? ColorsManager.whiteColors - : ColorsManager.blackColor, + color: + selectedOperator == 'or' ? ColorsManager.whiteColors : ColorsManager.blackColor, ), ), onPressed: () { - context - .read() - .add(const ChangeAutomationOperator(operator: 'or')); + context.read().add(const ChangeAutomationOperator(operator: 'or')); }, ), Container( @@ -170,9 +175,7 @@ class AutomationOperatorSelector extends StatelessWidget { ), ), onPressed: () { - context - .read() - .add(const ChangeAutomationOperator(operator: 'and')); + context.read().add(const ChangeAutomationOperator(operator: 'and')); }, ), ], diff --git a/lib/pages/routiens/widgets/period_option.dart b/lib/pages/routiens/widgets/period_option.dart index 8a89e2f9..5c1c2d51 100644 --- a/lib/pages/routiens/widgets/period_option.dart +++ b/lib/pages/routiens/widgets/period_option.dart @@ -21,12 +21,9 @@ class PeriodOptions extends StatelessWidget { builder: (context, state) { return Column( children: [ - _buildRadioOption( - context, EnumEffectivePeriodOptions.allDay, '24 Hours'), - _buildRadioOption(context, EnumEffectivePeriodOptions.daytime, - 'Sunrise to Sunset'), - _buildRadioOption( - context, EnumEffectivePeriodOptions.night, 'Sunset to Sunrise'), + _buildRadioOption(context, EnumEffectivePeriodOptions.allDay, '24 Hours'), + _buildRadioOption(context, EnumEffectivePeriodOptions.daytime, 'Sunrise to Sunset'), + _buildRadioOption(context, EnumEffectivePeriodOptions.night, 'Sunset to Sunrise'), ListTile( contentPadding: EdgeInsets.zero, onTap: () => showCustomTimePicker(context), @@ -37,8 +34,7 @@ class PeriodOptions extends StatelessWidget { fontWeight: FontWeight.w400, fontSize: 14), ), - subtitle: state.customStartTime != null && - state.customEndTime != null + subtitle: state.customStartTime != null && state.customEndTime != null ? Text( '${"${state.customStartTime}"} - ${"${state.customEndTime}"}', style: Theme.of(context).textTheme.bodyMedium!.copyWith( @@ -83,9 +79,7 @@ class PeriodOptions extends StatelessWidget { subtitle: Text( subtitle, style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: ColorsManager.textPrimaryColor, - fontWeight: FontWeight.w400, - fontSize: 10), + color: ColorsManager.textPrimaryColor, fontWeight: FontWeight.w400, fontSize: 10), ), trailing: Radio( value: value, diff --git a/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart b/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart index c494622a..06995882 100644 --- a/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart +++ b/lib/pages/routiens/widgets/routine_dialogs/automation_dialog.dart @@ -74,7 +74,7 @@ class _AutomationDialogState extends State { DeviceFunctionData( entityId: widget.automationId, functionCode: 'automation', - value: _isEnabled, + value: _isEnabled ? 'rule_enable' : 'rule_disable', operationName: 'Automation', ), ], diff --git a/lib/pages/routiens/widgets/routine_dialogs/discard_dialog.dart b/lib/pages/routiens/widgets/routine_dialogs/discard_dialog.dart new file mode 100644 index 00000000..8b22a671 --- /dev/null +++ b/lib/pages/routiens/widgets/routine_dialogs/discard_dialog.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/common/custom_table.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart'; +import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; +import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class DiscardDialog { + static void show(BuildContext context) { + context.customAlertDialog( + alertBody: Container( + height: 150, + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'If you close, you will lose all the changes you have made.', + textAlign: TextAlign.center, + style: context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.red, + fontWeight: FontWeight.w400, + fontSize: 14, + ), + ), + const SizedBox( + height: 20, + ), + Text( + 'Are you sure you wish to close?', + style: context.textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.grayColor, + ), + ) + ], + )), + title: 'Discard', + titleStyle: context.textTheme.titleLarge!.copyWith( + color: ColorsManager.red, + fontWeight: FontWeight.bold, + ), + onDismissText: "Don’t Close", + onConfirmText: "Close", + onDismissColor: ColorsManager.grayColor, + onConfirmColor: ColorsManager.red.withOpacity(0.8), + onDismiss: () { + Navigator.pop(context); + }, + onConfirm: () { + context.read().add(ResetRoutineState()); + Navigator.pop(context); + BlocProvider.of(context).add( + const CreateNewRoutineViewEvent(false), + ); + BlocProvider.of(context).add( + const TriggerSwitchTabsEvent(true), + ); + }); + } +} diff --git a/lib/pages/routiens/widgets/routine_dialogs/setting_dialog.dart b/lib/pages/routiens/widgets/routine_dialogs/setting_dialog.dart index 4e2bdde6..7fc723af 100644 --- a/lib/pages/routiens/widgets/routine_dialogs/setting_dialog.dart +++ b/lib/pages/routiens/widgets/routine_dialogs/setting_dialog.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart'; +import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart'; import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart'; +import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart'; import 'package:syncrow_web/pages/routiens/models/icon_model.dart'; import 'package:syncrow_web/pages/routiens/view/effective_period_view.dart'; import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart'; @@ -19,444 +22,392 @@ class SettingHelper { context: context, builder: (BuildContext context) { final isAutomation = context.read().state.isAutomation; - return BlocProvider( - create: (_) => - SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')), + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (_) => EffectPeriodBloc(), + ), + BlocProvider( + create: (_) => SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? ''))), + ], child: AlertDialog( contentPadding: EdgeInsets.zero, - content: BlocBuilder( - builder: (context, state) { - String selectedIcon = ''; - List list = []; - if (state is TabToRunSettingLoaded) { - selectedIcon = state.selectedIcon; - list = state.iconList; - } - return Container( - width: context.read().isExpanded ? 800 : 400, - height: context.read().isExpanded && isAutomation - ? 500 - : 300, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - ), - padding: const EdgeInsets.only(top: 20), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const DialogHeader('Settings'), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 400, - child: isAutomation - ? Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.only( - top: 10, - left: 10, - right: 10, - bottom: 10), - child: Column( - children: [ - InkWell( - onTap: () {}, - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Validity', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight - .w400, - fontSize: 14), - ), - const Icon( - Icons - .arrow_forward_ios_outlined, - color: ColorsManager - .textGray, - size: 15, - ) - ], - ), - ), - const SizedBox( - height: 5, - ), - const Divider( - color: ColorsManager.graysColor, - ), - const SizedBox( - height: 5, - ), - InkWell( - onTap: () { - BlocProvider.of( - context) - .add(FetchIcons( - expanded: !context - .read< - SettingBloc>() - .isExpanded)); - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Effective Period', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight - .w400, - fontSize: 14), - ), - const Icon( - Icons - .arrow_forward_ios_outlined, - color: ColorsManager - .textGray, - size: 15, - ) - ], - ), - ), - const SizedBox( - height: 5, - ), - const Divider( - color: ColorsManager.graysColor, - ), - const SizedBox( - height: 5, - ), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Executed by', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight.w400, - fontSize: 14), - ), - Text('Cloud', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: - ColorsManager - .textGray, - fontWeight: - FontWeight - .w400, - fontSize: 14)), - ], - ), - ], - )), - ], - ) - : Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.only( - top: 10, - left: 10, - right: 10, - bottom: 10), - child: Column( - children: [ - InkWell( - onTap: () { - BlocProvider.of( - context) - .add(FetchIcons( - expanded: !context - .read< - SettingBloc>() - .isExpanded)); - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Icons', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight - .w400, - fontSize: 14), - ), - const Icon( - Icons - .arrow_forward_ios_outlined, - color: ColorsManager - .textGray, - size: 15, - ) - ], - ), - ), - const SizedBox( - height: 5, - ), - const Divider( - color: ColorsManager.graysColor, - ), - const SizedBox( - height: 5, - ), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Show on devices page', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight.w400, - fontSize: 14), - ), - Row( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - Container( - height: 30, - width: 1, - color: ColorsManager - .graysColor, - ), - Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: true, - onChanged: (value) {}, - applyTheme: true, - ), - ), - ], - ) - ], - ), - const SizedBox( - height: 5, - ), - const Divider( - color: ColorsManager.graysColor, - ), - const SizedBox( - height: 5, - ), - Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text( - 'Executed by', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .textPrimaryColor, - fontWeight: - FontWeight.w400, - fontSize: 14), - ), - Text('Cloud', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: - ColorsManager - .textGray, - fontWeight: - FontWeight - .w400, - fontSize: 14)), - ], - ), - ], - )), - ], - ), - ), - if (context.read().isExpanded && - !isAutomation) - SizedBox( - width: 400, - height: 150, - child: state is LoadingState - ? const Center( - child: CircularProgressIndicator()) - : GridView.builder( - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 6, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), - shrinkWrap: true, - itemCount: list.length, - itemBuilder: (context, index) { - final iconModel = list[index]; - return SizedBox( - width: 35, - height: 35, - child: InkWell( - onTap: () { - BlocProvider.of( - context) - .add(SelectIcon( - iconId: iconModel.uuid, - )); - selectedIcon = iconModel.uuid; - }, - child: SizedBox( - child: ClipOval( - child: Container( - padding: - const EdgeInsets.all(1), - decoration: BoxDecoration( - border: Border.all( - color: selectedIcon == - iconModel.uuid - ? ColorsManager - .primaryColorWithOpacity - : Colors - .transparent, - width: 2, - ), - shape: BoxShape.circle, - ), - child: Image.memory( - iconModel.iconBytes, - ), - ), - ), - ), - ), - ); - }, - )), - if (context.read().isExpanded && - isAutomation) - const SizedBox( - height: 350, - width: 400, - child: EffectivePeriodView()) - ], - ), - Container( - width: MediaQuery.sizeOf(context).width, - decoration: const BoxDecoration( - border: Border( - top: BorderSide( - color: ColorsManager.greyColor, - ), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + content: BlocBuilder( + builder: (context, effectPeriodState) { + return BlocBuilder( + builder: (context, settingState) { + String selectedIcon = ''; + List list = []; + if (settingState is TabToRunSettingLoaded) { + selectedIcon = settingState.selectedIcon; + list = settingState.iconList; + } + return Container( + width: context.read().isExpanded ? 800 : 400, + height: context.read().isExpanded && isAutomation ? 500 : 300, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.only(top: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const DialogHeader('Settings'), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: InkWell( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - alignment: AlignmentDirectional.center, - child: Text( - 'Cancel', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager.textGray, - ), - ), - ), - ), - ), - Container( - width: 1, - height: 50, - color: ColorsManager.greyColor), - Expanded( - child: InkWell( - onTap: () { - Navigator.of(context).pop(selectedIcon); - }, - child: Container( - alignment: AlignmentDirectional.center, - child: Text( - 'Confirm', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: ColorsManager - .primaryColorWithOpacity, - ), - ), - ), - ), + SizedBox( + width: 400, + child: isAutomation + ? Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.only( + top: 10, left: 10, right: 10, bottom: 10), + child: Column( + children: [ + InkWell( + onTap: () {}, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Validity', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: + ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + const Icon( + Icons.arrow_forward_ios_outlined, + color: ColorsManager.textGray, + size: 15, + ) + ], + ), + ), + const SizedBox( + height: 5, + ), + const Divider( + color: ColorsManager.graysColor, + ), + const SizedBox( + height: 5, + ), + InkWell( + onTap: () { + BlocProvider.of(context).add( + FetchIcons( + expanded: !context + .read() + .isExpanded)); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Effective Period', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: + ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + const Icon( + Icons.arrow_forward_ios_outlined, + color: ColorsManager.textGray, + size: 15, + ) + ], + ), + ), + const SizedBox( + height: 5, + ), + const Divider( + color: ColorsManager.graysColor, + ), + const SizedBox( + height: 5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Executed by', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + Text('Cloud', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: ColorsManager.textGray, + fontWeight: FontWeight.w400, + fontSize: 14)), + ], + ), + ], + )), + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.only( + top: 10, left: 10, right: 10, bottom: 10), + child: Column( + children: [ + InkWell( + onTap: () { + BlocProvider.of(context).add( + FetchIcons( + expanded: !context + .read() + .isExpanded)); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Icons', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: + ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + const Icon( + Icons.arrow_forward_ios_outlined, + color: ColorsManager.textGray, + size: 15, + ) + ], + ), + ), + const SizedBox( + height: 5, + ), + const Divider( + color: ColorsManager.graysColor, + ), + const SizedBox( + height: 5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Show on devices page', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + height: 30, + width: 1, + color: ColorsManager.graysColor, + ), + Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: true, + onChanged: (value) {}, + applyTheme: true, + ), + ), + ], + ) + ], + ), + const SizedBox( + height: 5, + ), + const Divider( + color: ColorsManager.graysColor, + ), + const SizedBox( + height: 5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Executed by', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: ColorsManager.textPrimaryColor, + fontWeight: FontWeight.w400, + fontSize: 14), + ), + Text('Cloud', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + color: ColorsManager.textGray, + fontWeight: FontWeight.w400, + fontSize: 14)), + ], + ), + ], + )), + ], + ), ), + if (context.read().isExpanded && !isAutomation) + SizedBox( + width: 400, + height: 150, + child: settingState is LoadingState + ? const Center(child: CircularProgressIndicator()) + : GridView.builder( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 6, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + shrinkWrap: true, + itemCount: list.length, + itemBuilder: (context, index) { + final iconModel = list[index]; + return SizedBox( + width: 35, + height: 35, + child: InkWell( + onTap: () { + BlocProvider.of(context) + .add(SelectIcon( + iconId: iconModel.uuid, + )); + selectedIcon = iconModel.uuid; + }, + child: SizedBox( + child: ClipOval( + child: Container( + padding: const EdgeInsets.all(1), + decoration: BoxDecoration( + border: Border.all( + color: selectedIcon == iconModel.uuid + ? ColorsManager + .primaryColorWithOpacity + : Colors.transparent, + width: 2, + ), + shape: BoxShape.circle, + ), + child: Image.memory( + iconModel.iconBytes, + ), + ), + ), + ), + ), + ); + }, + )), + if (context.read().isExpanded && isAutomation) + const SizedBox(height: 350, width: 400, child: EffectivePeriodView()) ], ), - ) - ], - ), - ); - }, - ), + Container( + width: MediaQuery.sizeOf(context).width, + decoration: const BoxDecoration( + border: Border( + top: BorderSide( + color: ColorsManager.greyColor, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + child: Container( + alignment: AlignmentDirectional.center, + child: Text( + 'Cancel', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: ColorsManager.textGray, + ), + ), + ), + ), + ), + Container(width: 1, height: 50, color: ColorsManager.greyColor), + Expanded( + child: InkWell( + onTap: () { + if (isAutomation) { + BlocProvider.of(context).add( + EffectiveTimePeriodEvent(EffectiveTime( + start: effectPeriodState.customStartTime!, + end: effectPeriodState.customEndTime!, + loops: effectPeriodState.selectedDaysBinary))); + Navigator.of(context).pop(); + } else { + Navigator.of(context).pop(selectedIcon); + } + }, + child: Container( + alignment: AlignmentDirectional.center, + child: Text( + 'Confirm', + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: ColorsManager.primaryColorWithOpacity, + ), + ), + ), + ), + ), + ], + ), + ) + ], + ), + ); + }, + ); + }), ), ); }, diff --git a/lib/pages/routiens/widgets/routine_search_and_buttons.dart b/lib/pages/routiens/widgets/routine_search_and_buttons.dart index 5bf9db8e..6696225f 100644 --- a/lib/pages/routiens/widgets/routine_search_and_buttons.dart +++ b/lib/pages/routiens/widgets/routine_search_and_buttons.dart @@ -1,11 +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 { @@ -15,88 +16,260 @@ class RoutineSearchAndButtons extends StatelessWidget { @override Widget build(BuildContext context) { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Wrap( - runSpacing: 16, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.end, + return BlocBuilder( + builder: (context, state) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Wrap( + runSpacing: 16, children: [ - Expanded( - child: Wrap( - spacing: 12, - runSpacing: 12, - crossAxisAlignment: WrapCrossAlignment.end, - 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)); - }, - ), - ), - (constraints.maxWidth <= 1000) - ? const SizedBox() - : SizedBox( - height: 40, - width: 200, - child: Center( - child: DefaultButton( - onPressed: () async { - final result = - await SettingHelper.showSettingDialog( - context: context, - ); - if (result != null) { - context - .read() - .add(AddSelectedIcon(result)); - } - }, - borderRadius: 15, - elevation: 0, - borderColor: ColorsManager.greyColor, - backgroundColor: ColorsManager.boxColor, - child: const Text( - 'Settings', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: ColorsManager.primaryColor, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Wrap( + spacing: 12, + runSpacing: 12, + crossAxisAlignment: WrapCrossAlignment.end, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + 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) + ? const SizedBox() + : SizedBox( + height: 40, + width: 200, + child: Center( + child: DefaultButton( + onPressed: state.isAutomation || state.isTabToRun + ? () async { + final result = await SettingHelper.showSettingDialog( + context: context, + ); + if (result != null) { + context + .read() + .add(AddSelectedIcon(result)); + } + } + : null, + borderRadius: 15, + elevation: 0, + borderColor: ColorsManager.greyColor, + backgroundColor: ColorsManager.boxColor, + child: const Text( + 'Settings', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: ColorsManager.primaryColor, + ), + ), + ), + ), + ), + ], + ), + ), + if (constraints.maxWidth > 1000) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 40, + width: 200, + child: Center( + child: DefaultButton( + onPressed: () { + DiscardDialog.show(context); + }, + borderRadius: 15, + elevation: 0, + borderColor: ColorsManager.greyColor, + backgroundColor: ColorsManager.boxColor, + child: const Text( + 'Cancel', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: ColorsManager.blackColor, ), ), ), ), - ], - ), + ), + const SizedBox(width: 12), + SizedBox( + height: 40, + width: 200, + 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, + elevation: 0, + backgroundColor: ColorsManager.primaryColor, + child: const Text( + 'Save', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: ColorsManager.whiteColors, + ), + ), + ), + ), + ), + ], + ), + ], ), - if (constraints.maxWidth > 1000) - Row( - mainAxisSize: MainAxisSize.min, + if (constraints.maxWidth <= 1000) + Wrap( + runSpacing: 12, children: [ SizedBox( height: 40, width: 200, child: Center( child: DefaultButton( - onPressed: () {}, + onPressed: state.isAutomation || state.isTabToRun + ? () async { + final result = await SettingHelper.showSettingDialog( + context: context, + ); + if (result != null) { + context.read().add(AddSelectedIcon(result)); + } + } + : null, + borderRadius: 15, + elevation: 0, + borderColor: ColorsManager.greyColor, + backgroundColor: ColorsManager.boxColor, + child: const Text( + 'Settings', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: ColorsManager.primaryColor, + ), + ), + ), + ), + ), + const SizedBox(width: 12), + SizedBox( + height: 40, + width: 200, + child: Center( + child: DefaultButton( + onPressed: () { + DiscardDialog.show(context); + }, borderRadius: 15, elevation: 0, borderColor: ColorsManager.greyColor, @@ -119,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, @@ -138,78 +344,8 @@ class RoutineSearchAndButtons extends StatelessWidget { ], ), ], - ), - if (constraints.maxWidth <= 1000) - Wrap( - runSpacing: 12, - children: [ - SizedBox( - height: 40, - width: 200, - child: Center( - child: DefaultButton( - onPressed: () {}, - borderRadius: 15, - elevation: 0, - borderColor: ColorsManager.greyColor, - backgroundColor: ColorsManager.boxColor, - child: const Text( - 'Settings', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: ColorsManager.primaryColor, - ), - ), - ), - ), - ), - const SizedBox(width: 12), - SizedBox( - height: 40, - width: 200, - child: Center( - child: DefaultButton( - onPressed: () {}, - borderRadius: 15, - elevation: 0, - borderColor: ColorsManager.greyColor, - backgroundColor: ColorsManager.boxColor, - child: const Text( - 'Cancel', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: ColorsManager.blackColor, - ), - ), - ), - ), - ), - const SizedBox(width: 12), - SizedBox( - height: 40, - width: 200, - child: Center( - child: DefaultButton( - onPressed: () {}, - borderRadius: 15, - elevation: 0, - backgroundColor: ColorsManager.primaryColor, - child: const Text( - 'Save', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - color: ColorsManager.whiteColors, - ), - ), - ), - ), - ), - ], - ), - ], + ); + }, ); }, ); 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, diff --git a/lib/pages/routiens/widgets/then_container.dart b/lib/pages/routiens/widgets/then_container.dart index 9d729327..52749851 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), Wrap( spacing: 8, @@ -37,16 +35,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', @@ -55,37 +49,32 @@ class ThenContainer extends StatelessWidget { return; } - final result = await DeviceDialogHelper - .showDeviceDialog( - context, state.thenItems[index]); + final result = await DeviceDialogHelper.showDeviceDialog( + context, state.thenItems[index]); 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)); + context.read().add(RemoveDragCard( + index: index, + isFromThen: true, + key: state.thenItems[index]['uniqueCustomId'])); }, ), ))), @@ -140,8 +129,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({ @@ -153,13 +141,11 @@ class ThenContainer extends StatelessWidget { return; } - final result = - await DeviceDialogHelper.showDeviceDialog(context, mutableData); + final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData); 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/services/routines_api.dart b/lib/services/routines_api.dart index f92f212f..756d533e 100644 --- a/lib/services/routines_api.dart +++ b/lib/services/routines_api.dart @@ -29,11 +29,13 @@ class SceneApi { rethrow; } } + // // create automation static Future> createAutomation( CreateAutomationModel createAutomationModel) async { try { + debugPrint("automation body ${createAutomationModel.toMap()}"); final response = await _httpService.post( path: ApiEndpoints.createAutomation, body: createAutomationModel.toMap(), @@ -42,8 +44,10 @@ class SceneApi { return json; }, ); + debugPrint('create automation response: $response'); return response; } catch (e) { + debugPrint(e.toString()); rethrow; } } diff --git a/lib/utils/extension/build_context_x.dart b/lib/utils/extension/build_context_x.dart index dbdbb347..0abd16a1 100644 --- a/lib/utils/extension/build_context_x.dart +++ b/lib/utils/extension/build_context_x.dart @@ -23,6 +23,11 @@ extension BuildContextExt on BuildContext { VoidCallback? onDismiss, bool? hideConfirmButton, final double? dialogWidth, + TextStyle? titleStyle, + String? onDismissText, + String? onConfirmText, + Color? onDismissColor, + Color? onConfirmColor, }) { showDialog( context: this, @@ -42,10 +47,11 @@ extension BuildContextExt on BuildContext { /// header widget Text( title, - style: context.textTheme.bodyMedium!.copyWith( - color: ColorsManager.primaryColorWithOpacity, - fontWeight: FontWeight.bold, - ), + style: titleStyle ?? + context.textTheme.bodyMedium!.copyWith( + color: ColorsManager.primaryColorWithOpacity, + fontWeight: FontWeight.bold, + ), ), Padding( padding: const EdgeInsets.symmetric( @@ -79,9 +85,10 @@ extension BuildContextExt on BuildContext { }, child: Center( child: Text( - 'Cancel', - style: context.textTheme.bodyMedium! - .copyWith(color: ColorsManager.greyColor), + onDismissText ?? 'Cancel', + style: context.textTheme.bodyMedium!.copyWith( + color: onDismissColor ?? + ColorsManager.greyColor), ), ), ), @@ -94,9 +101,9 @@ extension BuildContextExt on BuildContext { onTap: onConfirm, child: Center( child: Text( - 'Confirm', + onConfirmText ?? 'Confirm', style: context.textTheme.bodyMedium!.copyWith( - color: + color: onConfirmColor ?? ColorsManager.primaryColorWithOpacity), ), ),