mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
push connecting to automation api
This commit is contained in:
@ -88,31 +88,32 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
);
|
||||
}),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
builder: (context, state) {
|
||||
if (state is SelectedTabState && state.selectedTab) {
|
||||
return const RoutinesView();
|
||||
}
|
||||
if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
scaffoldBody: CreateNewRoutineView(),
|
||||
// BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
// builder: (context, state) {
|
||||
// if (state is SelectedTabState && state.selectedTab) {
|
||||
// return const RoutinesView();
|
||||
// }
|
||||
// if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
// return const CreateNewRoutineView();
|
||||
// }
|
||||
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
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<DeviceManagementBloc, DeviceManagementState>(
|
||||
// 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'));
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ 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<EffectPeriodEvent, EffectPeriodState> {
|
||||
final daysMap = {
|
||||
@ -49,9 +52,9 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
break;
|
||||
}
|
||||
|
||||
// BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
// EffectiveTimePeriodEvent(
|
||||
// EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(
|
||||
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedPeriod: event.period, customStartTime: startTime, customEndTime: endTime));
|
||||
@ -68,11 +71,11 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
final newDaysBinary = daysList.join();
|
||||
emit(state.copyWith(selectedDaysBinary: newDaysBinary));
|
||||
|
||||
// BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
// EffectiveTimePeriodEvent(EffectiveTime(
|
||||
// start: state.customStartTime ?? '00:00',
|
||||
// end: state.customEndTime ?? '23:59',
|
||||
// loops: newDaysBinary)));
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(EffectiveTime(
|
||||
start: state.customStartTime ?? '00:00',
|
||||
end: state.customEndTime ?? '23:59',
|
||||
loops: newDaysBinary)));
|
||||
}
|
||||
|
||||
void _onSetCustomTime(SetCustomTime event, Emitter<EffectPeriodState> emit) {
|
||||
@ -94,9 +97,9 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
emit(
|
||||
state.copyWith(customStartTime: startTime, customEndTime: endTime, selectedPeriod: period));
|
||||
|
||||
// BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
// EffectiveTimePeriodEvent(
|
||||
// EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(
|
||||
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
}
|
||||
|
||||
void _onResetEffectivePeriod(ResetEffectivePeriod event, Emitter<EffectPeriodState> emit) {
|
||||
@ -106,8 +109,8 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
customEndTime: '23:59',
|
||||
selectedDaysBinary: '1111111'));
|
||||
|
||||
// BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
// EffectiveTimePeriodEvent(EffectiveTime(start: '00:00', end: '23:59', loops: '1111111')));
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(EffectiveTime(start: '00:00', end: '23:59', loops: '1111111')));
|
||||
}
|
||||
|
||||
void _onResetDays(ResetDays event, Emitter<EffectPeriodState> emit) {
|
||||
|
@ -3,7 +3,8 @@ import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
@ -28,6 +29,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
on<CreateSceneEvent>(_onCreateScene);
|
||||
on<RemoveDragCard>(_onRemoveDragCard);
|
||||
on<ChangeAutomationOperator>(_changeOperatorOperator);
|
||||
on<EffectiveTimePeriodEvent>(_onEffectiveTimeEvent);
|
||||
on<CreateAutomationEvent>(_onCreateAutomation);
|
||||
// on<RemoveFunction>(_onRemoveFunction);
|
||||
// on<ClearFunctions>(_onClearFunctions);
|
||||
}
|
||||
@ -213,10 +216,119 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
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',
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
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<CreateCondition>()
|
||||
.toList();
|
||||
|
||||
if (conditions.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'At least one condition is required',
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
final createAutomationModel = CreateAutomationModel(
|
||||
unitUuid: spaceId,
|
||||
automationName: state.routineName!,
|
||||
decisionExpr: state.selectedAutomationOperator,
|
||||
effectiveTime: state.effectiveTime ??
|
||||
EffectiveTime(
|
||||
start: '00:00',
|
||||
end: '23:59',
|
||||
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<CreateSceneAction>()
|
||||
.toList(),
|
||||
);
|
||||
|
||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||
if (result['success']) {
|
||||
emit(const RoutineState());
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: result['message'],
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onRemoveDragCard(
|
||||
RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||
if (event.isFromThen) {
|
||||
/// remove element from thenItems at specific index
|
||||
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||
thenItems.removeAt(event.index);
|
||||
emit(state.copyWith(thenItems: thenItems));
|
||||
@ -233,4 +345,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
selectedAutomationOperator: event.operator,
|
||||
));
|
||||
}
|
||||
|
||||
FutureOr<void> _onEffectiveTimeEvent(
|
||||
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(effectiveTime: event.effectiveTime));
|
||||
}
|
||||
}
|
||||
|
@ -94,4 +94,25 @@ class ChangeAutomationOperator extends RoutineEvent {
|
||||
List<Object> get props => [operator];
|
||||
}
|
||||
|
||||
class EffectiveTimePeriodEvent extends RoutineEvent {
|
||||
final EffectiveTime effectiveTime;
|
||||
const EffectiveTimePeriodEvent(this.effectiveTime);
|
||||
@override
|
||||
List<Object> get props => [effectiveTime];
|
||||
}
|
||||
|
||||
class CreateAutomationEvent extends RoutineEvent {
|
||||
// final CreateAutomationModel createAutomationModel;
|
||||
final String? automationId;
|
||||
final bool updateAutomation;
|
||||
|
||||
const CreateAutomationEvent({
|
||||
//required this.createAutomationModel,
|
||||
this.automationId,
|
||||
this.updateAutomation = false,
|
||||
});
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class ClearFunctions extends RoutineEvent {}
|
||||
|
@ -17,6 +17,7 @@ class RoutineState extends Equatable {
|
||||
final bool isTabToRun;
|
||||
final bool isAutomation;
|
||||
final String selectedAutomationOperator;
|
||||
final EffectiveTime? effectiveTime;
|
||||
|
||||
const RoutineState({
|
||||
this.ifItems = const [],
|
||||
@ -35,43 +36,48 @@ class RoutineState extends Equatable {
|
||||
this.isTabToRun = false,
|
||||
this.isAutomation = false,
|
||||
this.selectedAutomationOperator = 'or',
|
||||
this.effectiveTime,
|
||||
});
|
||||
|
||||
RoutineState copyWith(
|
||||
{List<Map<String, dynamic>>? ifItems,
|
||||
List<Map<String, dynamic>>? thenItems,
|
||||
List<ScenesModel>? scenes,
|
||||
List<ScenesModel>? automations,
|
||||
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
String? routineName,
|
||||
String? selectedIcon,
|
||||
String? loadAutomationErrorMessage,
|
||||
String? loadScenesErrorMessage,
|
||||
String? searchText,
|
||||
bool? isTabToRun,
|
||||
bool? isAutomation,
|
||||
String? selectedAutomationOperator}) {
|
||||
RoutineState copyWith({
|
||||
List<Map<String, dynamic>>? ifItems,
|
||||
List<Map<String, dynamic>>? thenItems,
|
||||
List<ScenesModel>? scenes,
|
||||
List<ScenesModel>? automations,
|
||||
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
||||
bool? isLoading,
|
||||
String? errorMessage,
|
||||
String? routineName,
|
||||
String? selectedIcon,
|
||||
String? loadAutomationErrorMessage,
|
||||
String? loadScenesErrorMessage,
|
||||
String? searchText,
|
||||
bool? isTabToRun,
|
||||
bool? isAutomation,
|
||||
String? selectedAutomationOperator,
|
||||
EffectiveTime? effectiveTime,
|
||||
}) {
|
||||
return RoutineState(
|
||||
ifItems: ifItems ?? this.ifItems,
|
||||
thenItems: thenItems ?? this.thenItems,
|
||||
scenes: scenes ?? this.scenes,
|
||||
automations: automations ?? this.automations,
|
||||
selectedFunctions: selectedFunctions ?? this.selectedFunctions,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
routineName: routineName ?? this.routineName,
|
||||
selectedIcon: selectedIcon ?? this.selectedIcon,
|
||||
loadScenesErrorMessage:
|
||||
loadScenesErrorMessage ?? this.loadScenesErrorMessage,
|
||||
loadAutomationErrorMessage:
|
||||
loadAutomationErrorMessage ?? this.loadAutomationErrorMessage,
|
||||
searchText: searchText ?? this.searchText,
|
||||
isTabToRun: isTabToRun ?? this.isTabToRun,
|
||||
isAutomation: isAutomation ?? this.isAutomation,
|
||||
selectedAutomationOperator:
|
||||
selectedAutomationOperator ?? this.selectedAutomationOperator);
|
||||
ifItems: ifItems ?? this.ifItems,
|
||||
thenItems: thenItems ?? this.thenItems,
|
||||
scenes: scenes ?? this.scenes,
|
||||
automations: automations ?? this.automations,
|
||||
selectedFunctions: selectedFunctions ?? this.selectedFunctions,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
errorMessage: errorMessage ?? this.errorMessage,
|
||||
routineName: routineName ?? this.routineName,
|
||||
selectedIcon: selectedIcon ?? this.selectedIcon,
|
||||
loadScenesErrorMessage:
|
||||
loadScenesErrorMessage ?? this.loadScenesErrorMessage,
|
||||
loadAutomationErrorMessage:
|
||||
loadAutomationErrorMessage ?? this.loadAutomationErrorMessage,
|
||||
searchText: searchText ?? this.searchText,
|
||||
isTabToRun: isTabToRun ?? this.isTabToRun,
|
||||
isAutomation: isAutomation ?? this.isAutomation,
|
||||
selectedAutomationOperator:
|
||||
selectedAutomationOperator ?? this.selectedAutomationOperator,
|
||||
effectiveTime: effectiveTime ?? this.effectiveTime,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -90,6 +96,7 @@ class RoutineState extends Equatable {
|
||||
searchText,
|
||||
isTabToRun,
|
||||
isAutomation,
|
||||
selectedAutomationOperator
|
||||
selectedAutomationOperator,
|
||||
effectiveTime
|
||||
];
|
||||
}
|
||||
|
@ -52,6 +52,35 @@ class SaveRoutineHelper {
|
||||
),
|
||||
title: const Text('Tab to run'),
|
||||
),
|
||||
if (state.isAutomation)
|
||||
...state.ifItems.map((item) {
|
||||
final functions = state.selectedFunctions[
|
||||
item['uniqueCustomId']] ??
|
||||
[];
|
||||
return ListTile(
|
||||
leading: SvgPicture.asset(
|
||||
item['imagePath'],
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
title: Text(item['title'],
|
||||
style: const TextStyle(fontSize: 14)),
|
||||
subtitle: Wrap(
|
||||
children: functions
|
||||
.map((f) => Text(
|
||||
'${f.operationName}: ${f.value}, ',
|
||||
style: const TextStyle(
|
||||
color: ColorsManager
|
||||
.grayColor,
|
||||
fontSize: 8),
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
maxLines: 3,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -0,0 +1,173 @@
|
||||
|
||||
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<CreateCondition> conditions;
|
||||
List<CreateSceneAction> 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<CreateCondition>? conditions,
|
||||
List<CreateSceneAction>? 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<String, dynamic> 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<String, dynamic> map) {
|
||||
return CreateAutomationModel(
|
||||
unitUuid: map['spaceUuid'] ?? '',
|
||||
automationName: map['automationName'] ?? '',
|
||||
decisionExpr: map['decisionExpr'] ?? '',
|
||||
effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
|
||||
conditions: List<CreateCondition>.from(
|
||||
map['conditions']?.map((x) => CreateCondition.fromMap(x))),
|
||||
actions: List<CreateSceneAction>.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<String, dynamic> toMap() {
|
||||
return {
|
||||
'start': start,
|
||||
'end': end,
|
||||
'loops': loops,
|
||||
};
|
||||
}
|
||||
|
||||
factory EffectiveTime.fromMap(Map<String, dynamic> 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<String, dynamic> toMap() {
|
||||
return {
|
||||
'code': code,
|
||||
'entityId': entityId,
|
||||
'entityType': entityType,
|
||||
'expr': expr.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
factory CreateCondition.fromMap(Map<String, dynamic> 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<String, dynamic> toMap() {
|
||||
return {
|
||||
'statusCode': statusCode,
|
||||
'comparator': comparator,
|
||||
'statusValue': statusValue,
|
||||
};
|
||||
}
|
||||
|
||||
factory ConditionExpr.fromMap(Map<String, dynamic> map) {
|
||||
return ConditionExpr(
|
||||
statusCode: map['statusCode'] ?? '',
|
||||
comparator: map['comparator'] ?? '',
|
||||
statusValue: map['statusValue'],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)';
|
||||
}
|
@ -5,12 +5,14 @@ class DialogFooter extends StatelessWidget {
|
||||
final VoidCallback onCancel;
|
||||
final VoidCallback? onConfirm;
|
||||
final bool isConfirmEnabled;
|
||||
final int? dialogWidth;
|
||||
|
||||
const DialogFooter({
|
||||
Key? key,
|
||||
required this.onCancel,
|
||||
required this.onConfirm,
|
||||
required this.isConfirmEnabled,
|
||||
this.dialogWidth,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -26,24 +28,23 @@ class DialogFooter extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildFooterButton(
|
||||
context,
|
||||
'Cancel',
|
||||
onCancel,
|
||||
width: isConfirmEnabled ? 299 : 179,
|
||||
),
|
||||
if (isConfirmEnabled)
|
||||
Row(
|
||||
children: [
|
||||
Container(width: 1, height: 50, color: ColorsManager.greyColor),
|
||||
_buildFooterButton(
|
||||
context,
|
||||
'Confirm',
|
||||
onConfirm,
|
||||
width: 299,
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: _buildFooterButton(
|
||||
context,
|
||||
'Cancel',
|
||||
onCancel,
|
||||
),
|
||||
),
|
||||
if (isConfirmEnabled) ...[
|
||||
Container(width: 1, height: 50, color: ColorsManager.greyColor),
|
||||
Expanded(
|
||||
child: _buildFooterButton(
|
||||
context,
|
||||
'Confirm',
|
||||
onConfirm,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -52,14 +53,12 @@ class DialogFooter extends StatelessWidget {
|
||||
Widget _buildFooterButton(
|
||||
BuildContext context,
|
||||
String text,
|
||||
VoidCallback? onTap, {
|
||||
required double width,
|
||||
}) {
|
||||
VoidCallback? onTap,
|
||||
) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: 50,
|
||||
width: width,
|
||||
child: Center(
|
||||
child: Text(
|
||||
text,
|
||||
|
@ -124,34 +124,6 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: selectedOperator == 'and'
|
||||
? ColorsManager.dialogBlueTitle
|
||||
: ColorsManager.whiteColors,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'All condition is met',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: selectedOperator == 'and'
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
width: 3,
|
||||
height: 24,
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: selectedOperator == 'or'
|
||||
@ -175,6 +147,34 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
width: 3,
|
||||
height: 24,
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: selectedOperator == 'and'
|
||||
? ColorsManager.dialogBlueTitle
|
||||
: ColorsManager.whiteColors,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'All condition is met',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: selectedOperator == 'and'
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -5,18 +5,19 @@ import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
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';
|
||||
|
||||
class AutomationDialog extends StatefulWidget {
|
||||
final String automationName;
|
||||
final String automationId;
|
||||
final String uniqueCustomId;
|
||||
|
||||
const AutomationDialog({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.automationName,
|
||||
required this.automationId,
|
||||
}) : super(key: key);
|
||||
required this.uniqueCustomId,
|
||||
});
|
||||
|
||||
@override
|
||||
_AutomationDialogState createState() => _AutomationDialogState();
|
||||
@ -72,18 +73,19 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
||||
[
|
||||
DeviceFunctionData(
|
||||
entityId: widget.automationId,
|
||||
functionCode: '',
|
||||
functionCode: 'automation',
|
||||
value: _isEnabled,
|
||||
operationName: 'Automation',
|
||||
),
|
||||
],
|
||||
widget.automationId,
|
||||
widget.uniqueCustomId,
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
onCancel: () => Navigator.of(context).pop(false),
|
||||
isConfirmEnabled: true,
|
||||
dialogWidth: 400,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -94,20 +94,21 @@ class ThenContainer extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
},
|
||||
onWillAcceptWithDetails: (data) {
|
||||
if (data == null) return false;
|
||||
// onWillAcceptWithDetails: (data) {
|
||||
// if (data == null) return false;
|
||||
// return data.data;
|
||||
|
||||
if (state.isTabToRun) {
|
||||
return data.data['type'] == 'automation';
|
||||
}
|
||||
// // if (state.isTabToRun) {
|
||||
// // return data.data['type'] == 'automation';
|
||||
// // }
|
||||
|
||||
if (state.isAutomation) {
|
||||
return data.data['type'] == 'scene' ||
|
||||
data.data['type'] == 'automation';
|
||||
}
|
||||
// // if (state.isAutomation) {
|
||||
// // return data.data['type'] == 'scene' ||
|
||||
// // data.data['type'] == 'automation';
|
||||
// // }
|
||||
|
||||
return data.data['deviceId'] != null;
|
||||
},
|
||||
// // return data.data['deviceId'] != null;
|
||||
// },
|
||||
onAcceptWithDetails: (data) async {
|
||||
final uniqueCustomId = const Uuid().v4();
|
||||
final mutableData = Map<String, dynamic>.from(data.data);
|
||||
@ -124,13 +125,16 @@ class ThenContainer extends StatelessWidget {
|
||||
builder: (BuildContext context) => AutomationDialog(
|
||||
automationName: mutableData['name'] ?? 'Automation',
|
||||
automationId: mutableData['deviceId'] ?? '',
|
||||
uniqueCustomId: uniqueCustomId,
|
||||
),
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToThenContainer(mutableData));
|
||||
context.read<RoutineBloc>().add(AddToThenContainer({
|
||||
...mutableData,
|
||||
'imagePath': Assets.automation,
|
||||
'title': mutableData['name'],
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
|
||||
import 'package:syncrow_web/services/api/http_service.dart';
|
||||
@ -29,23 +30,23 @@ class SceneApi {
|
||||
}
|
||||
}
|
||||
//
|
||||
// // create automation
|
||||
// static Future<Map<String, dynamic>> createAutomation(
|
||||
// CreateAutomationModel createAutomationModel) async {
|
||||
// try {
|
||||
// final response = await _httpService.post(
|
||||
// path: ApiEndpoints.createAutomation,
|
||||
// body: createAutomationModel.toMap(),
|
||||
// showServerMessage: false,
|
||||
// expectedResponseModel: (json) {
|
||||
// return json;
|
||||
// },
|
||||
// );
|
||||
// return response;
|
||||
// } catch (e) {
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
// create automation
|
||||
static Future<Map<String, dynamic>> createAutomation(
|
||||
CreateAutomationModel createAutomationModel) async {
|
||||
try {
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.createAutomation,
|
||||
body: createAutomationModel.toMap(),
|
||||
showServerMessage: false,
|
||||
expectedResponseModel: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<IconModel>> getIcon() async {
|
||||
final response = await _httpService.get(
|
||||
|
@ -54,4 +54,5 @@ abstract class ApiEndpoints {
|
||||
static const String getSpaceAutomation = '/automation/{unitUuid}';
|
||||
static const String getIconScene = '/scene/icon';
|
||||
static const String createScene = '/scene/tap-to-run';
|
||||
static const String createAutomation = '/automation';
|
||||
}
|
||||
|
Reference in New Issue
Block a user