push autoamtion api connect

This commit is contained in:
ashrafzarkanisala
2024-07-24 01:41:10 +03:00
parent 9a088353e0
commit 7a773f1653
20 changed files with 874 additions and 272 deletions

View File

@ -17,10 +17,15 @@ import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart'; import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart'; import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
@ -63,9 +68,12 @@ class HomeCubit extends Cubit<HomeState> {
selectedSpace = null; selectedSpace = null;
selectedRoom = null; selectedRoom = null;
pageIndex = 0; pageIndex = 0;
OneSignal.User.pushSubscription.removeObserver((stateChanges) => oneSignalSubscriptionObserver); OneSignal.User.pushSubscription
OneSignal.Notifications.removePermissionObserver((permission) => oneSignalPermissionObserver); .removeObserver((stateChanges) => oneSignalSubscriptionObserver);
OneSignal.Notifications.removeClickListener((event) => oneSignalClickListenerObserver); OneSignal.Notifications.removePermissionObserver(
(permission) => oneSignalPermissionObserver);
OneSignal.Notifications.removeClickListener(
(event) => oneSignalClickListenerObserver);
return super.close(); return super.close();
} }
@ -107,7 +115,9 @@ class HomeCubit extends Cubit<HomeState> {
return; return;
} }
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? ''; var userUuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
if (userUuid.isNotEmpty) { if (userUuid.isNotEmpty) {
await OneSignal.login(userUuid); await OneSignal.login(userUuid);
} }
@ -115,21 +125,24 @@ class HomeCubit extends Cubit<HomeState> {
await OneSignal.User.pushSubscription.optIn(); await OneSignal.User.pushSubscription.optIn();
//this function will be called once a user is subscribed //this function will be called once a user is subscribed
oneSignalSubscriptionObserver = OneSignal.User.pushSubscription.addObserver((state) async { oneSignalSubscriptionObserver =
OneSignal.User.pushSubscription.addObserver((state) async {
if (state.current.optedIn) { if (state.current.optedIn) {
await _sendSubscriptionId(); await _sendSubscriptionId();
} }
}); });
// Send the player id when a user allows notifications // Send the player id when a user allows notifications
oneSignalPermissionObserver = OneSignal.Notifications.addPermissionObserver((state) async { oneSignalPermissionObserver =
OneSignal.Notifications.addPermissionObserver((state) async {
await _sendSubscriptionId(); await _sendSubscriptionId();
}); });
//check if the player id is sent, if not send it again //check if the player id is sent, if not send it again
await _sendSubscriptionId(); await _sendSubscriptionId();
oneSignalClickListenerObserver = OneSignal.Notifications.addClickListener((event) async { oneSignalClickListenerObserver =
OneSignal.Notifications.addClickListener((event) async {
//Once the user clicks on the notification //Once the user clicks on the notification
}); });
} catch (err) { } catch (err) {
@ -216,7 +229,9 @@ class HomeCubit extends Cubit<HomeState> {
Future<bool> joinAUnit(String code) async { Future<bool> joinAUnit(String code) async {
try { try {
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? ''; var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
Map<String, String> body = {'userUuid': uuid, 'inviteCode': code}; Map<String, String> body = {'userUuid': uuid, 'inviteCode': code};
final success = await SpacesAPI.joinUnit(body); final success = await SpacesAPI.joinUnit(body);
@ -334,15 +349,25 @@ class HomeCubit extends Cubit<HomeState> {
size: 32, size: 32,
), ),
style: ButtonStyle( style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), foregroundColor:
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
), ),
onPressed: () { onPressed: () {
Navigator.push( Navigator.pushNamed(
NavigationService.navigatorKey.currentContext!, NavigationService.navigatorKey.currentContext!,
CustomPageRoute( Routes.sceneTasksRoute,
builder: (context) => const CreateSceneView(), arguments: SceneSettingsRouteArguments(
sceneType: '',
sceneId: '',
sceneName: '',
), ),
); );
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const ClearTaskListEvent());
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const SceneTypeEvent(CreateSceneEnum.none));
}, },
), ),
IconButton( IconButton(
@ -351,7 +376,8 @@ class HomeCubit extends Cubit<HomeState> {
size: 28, size: 28,
), ),
style: ButtonStyle( style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), foregroundColor:
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
), ),
onPressed: () {}, onPressed: () {},
), ),
@ -384,7 +410,8 @@ class HomeCubit extends Cubit<HomeState> {
}; };
static var bottomNavItems = [ static var bottomNavItems = [
defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'), defaultBottomNavBarItem(
icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
// defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'), // defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'), defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'), defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
@ -410,7 +437,8 @@ class HomeCubit extends Cubit<HomeState> {
void updateDevice(String deviceId) async { void updateDevice(String deviceId) async {
try { try {
final response = await DevicesAPI.firmwareDevice(deviceId: deviceId, firmwareVersion: '0'); final response = await DevicesAPI.firmwareDevice(
deviceId: deviceId, firmwareVersion: '0');
if (response['success'] ?? false) { if (response['success'] ?? false) {
CustomSnackBar.displaySnackBar('No updates available'); CustomSnackBar.displaySnackBar('No updates available');
} }
@ -418,7 +446,8 @@ class HomeCubit extends Cubit<HomeState> {
} }
} }
BottomNavigationBarItem defaultBottomNavBarItem({required String icon, required String label}) { BottomNavigationBarItem defaultBottomNavBarItem(
{required String icon, required String label}) {
return BottomNavigationBarItem( return BottomNavigationBarItem(
icon: SvgPicture.asset(icon), icon: SvgPicture.asset(icon),
activeIcon: SvgPicture.asset( activeIcon: SvgPicture.asset(

View File

@ -2,8 +2,10 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart'; import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart'; import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/services/api/scene_api.dart'; import 'package:syncrow_app/services/api/scene_api.dart';
@ -26,8 +28,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
on<RemoveFromSelectedValueById>(_removeFromSelectedValueById); on<RemoveFromSelectedValueById>(_removeFromSelectedValueById);
on<DeleteSceneEvent>(_deleteScene); on<DeleteSceneEvent>(_deleteScene);
on<UpdateTaskEvent>(_updateTaskValue); on<UpdateTaskEvent>(_updateTaskValue);
on<SelectConditionEvent>(_selectConditionRule);
on<SceneTypeEvent>(_sceneTypeEvent);
} }
CreateSceneEnum sceneType = CreateSceneEnum.none;
/// tab to run values and list /// tab to run values and list
List<SceneStaticFunction> tasksList = []; List<SceneStaticFunction> tasksList = [];
List<SceneStaticFunction> tempTasksList = []; List<SceneStaticFunction> tempTasksList = [];
@ -37,6 +43,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
List<SceneStaticFunction> automationTasksList = []; List<SceneStaticFunction> automationTasksList = [];
List<SceneStaticFunction> automationTempTasksList = []; List<SceneStaticFunction> automationTempTasksList = [];
final Map<String, dynamic> automationSelectedValues = {}; final Map<String, dynamic> automationSelectedValues = {};
final Map<String, String> automationComparatorValues = {};
String conditionRule = 'or';
FutureOr<void> _onAddSceneTask( FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) { AddTaskEvent event, Emitter<CreateSceneState> emit) {
@ -46,6 +54,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationTasksList.addAll(copyList); automationTasksList.addAll(copyList);
automationTempTasksList.clear(); automationTempTasksList.clear();
automationSelectedValues.clear(); automationSelectedValues.clear();
automationComparatorValues.clear();
emit(AddSceneTask( emit(AddSceneTask(
automationTasksList: automationTasksList, automationTasksList: automationTasksList,
tasksList: tasksList, tasksList: tasksList,
@ -144,6 +153,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '', icon: '',
), ),
], ],
comparator: automationComparatorValues[element.code],
); );
automationTempTasksList[automationTempTasksList.indexOf(element)] = automationTempTasksList[automationTempTasksList.indexOf(element)] =
updatedElement; updatedElement;
@ -168,6 +178,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '', icon: '',
), ),
], ],
comparator:
automationComparatorValues[event.deviceControlModel.code] ?? '==',
); );
automationTempTasksList.add(newElement); automationTempTasksList.add(newElement);
automationSelectedValues[newElement.code] = automationSelectedValues[newElement.code] =
@ -182,6 +194,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
emit(CreateSceneLoading()); emit(CreateSceneLoading());
if (event.isAutomation == true) { if (event.isAutomation == true) {
automationSelectedValues[event.code] = event.value; automationSelectedValues[event.code] = event.value;
automationComparatorValues[event.code] = event.comparator ?? '==';
emit(SelectedTaskValueState(value: event.value)); emit(SelectedTaskValueState(value: event.value));
emit(AddSceneTask( emit(AddSceneTask(
tasksList: tasksList, automationTasksList: automationTasksList)); tasksList: tasksList, automationTasksList: automationTasksList));
@ -248,13 +261,26 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async { CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
try { try {
final response = event.updateScene dynamic response;
? await SceneApi.updateScene(event.createSceneModel, event.sceneId) if (event.createSceneModel != null) {
: await SceneApi.createScene(event.createSceneModel); response = event.updateScene
? await SceneApi.updateScene(event.createSceneModel!, event.sceneId)
: await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) {
response =
await SceneApi.createAutomation(event.createAutomationModel!);
}
if (response['success'] == true) { if (response['success'] == true) {
tasksList.clear(); tasksList.clear();
tempTasksList.clear(); tempTasksList.clear();
selectedValues.clear(); selectedValues.clear();
automationTasksList.clear();
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
emit(const CreateSceneWithTasks(success: true)); emit(const CreateSceneWithTasks(success: true));
} else { } else {
emit(const CreateSceneError(message: 'Something went wrong')); emit(const CreateSceneError(message: 'Something went wrong'));
@ -301,6 +327,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
if (event.isAutomation == true) { if (event.isAutomation == true) {
automationTempTasksList.clear(); automationTempTasksList.clear();
automationSelectedValues.clear(); automationSelectedValues.clear();
automationComparatorValues.clear();
emit(AddSceneTask( emit(AddSceneTask(
tasksList: tasksList, automationTasksList: automationTasksList)); tasksList: tasksList, automationTasksList: automationTasksList));
} else { } else {
@ -317,6 +344,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
if (event.isAutomation == true) { if (event.isAutomation == true) {
if (automationSelectedValues.containsKey(event.code)) { if (automationSelectedValues.containsKey(event.code)) {
automationSelectedValues.remove(event.code); automationSelectedValues.remove(event.code);
automationComparatorValues.remove(event.code);
emit(const SelectedTaskValueState(value: null)); emit(const SelectedTaskValueState(value: null));
emit(AddSceneTask( emit(AddSceneTask(
tasksList: tasksList, automationTasksList: automationTasksList)); tasksList: tasksList, automationTasksList: automationTasksList));
@ -373,4 +401,31 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
emit(AddSceneTask( emit(AddSceneTask(
tasksList: tasksList, automationTasksList: automationTasksList)); tasksList: tasksList, automationTasksList: automationTasksList));
} }
FutureOr<void> _selectConditionRule(
SelectConditionEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.condition.contains('any')) {
conditionRule = 'or';
} else {
conditionRule = 'and';
}
emit(ConditionSelectedState(event.condition));
}
FutureOr<void> _sceneTypeEvent(
SceneTypeEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.type == CreateSceneEnum.tabToRun) {
sceneType = CreateSceneEnum.tabToRun;
} else if (event.type == CreateSceneEnum.deviceStatusChanges) {
sceneType = CreateSceneEnum.deviceStatusChanges;
} else {
sceneType = CreateSceneEnum.none;
}
emit(SceneTypeState(event.type));
}
} }

View File

@ -67,12 +67,14 @@ class SelectedValueEvent extends CreateSceneEvent {
final dynamic automationValue; final dynamic automationValue;
final String code; final String code;
final bool? isAutomation; final bool? isAutomation;
final String? comparator;
const SelectedValueEvent({ const SelectedValueEvent({
this.value, this.value,
required this.code, required this.code,
this.isAutomation, this.isAutomation,
this.automationValue, this.automationValue,
this.comparator,
}); });
@override @override
@ -110,19 +112,21 @@ class RemoveFromSelectedValueById extends CreateSceneEvent {
} }
class CreateSceneWithTasksEvent extends CreateSceneEvent { class CreateSceneWithTasksEvent extends CreateSceneEvent {
final CreateSceneModel createSceneModel; final CreateSceneModel? createSceneModel;
final bool updateScene; final bool updateScene;
final String sceneId; final String sceneId;
final CreateAutomationModel? createAutomationModel;
//final bool isAutomation; //final bool isAutomation;
const CreateSceneWithTasksEvent({ const CreateSceneWithTasksEvent({
required this.createSceneModel, required this.createSceneModel,
required this.updateScene, required this.updateScene,
required this.sceneId, required this.sceneId,
required this.createAutomationModel,
// required this.isAutomation, // required this.isAutomation,
}); });
@override @override
List<Object> get props => [createSceneModel]; List<Object> get props => [];
} }
class ClearTaskListEvent extends CreateSceneEvent { class ClearTaskListEvent extends CreateSceneEvent {
@ -160,3 +164,14 @@ class DeleteSceneEvent extends CreateSceneEvent {
@override @override
List<Object> get props => [sceneId, unitUuid]; List<Object> get props => [sceneId, unitUuid];
} }
class SelectConditionEvent extends CreateSceneEvent {
final String condition;
const SelectConditionEvent(this.condition);
}
class SceneTypeEvent extends CreateSceneEvent {
final CreateSceneEnum type;
const SceneTypeEvent(this.type);
}

View File

@ -71,3 +71,14 @@ class DeleteSceneError extends CreateSceneState {
} }
class DeleteSceneLoading extends CreateSceneState {} class DeleteSceneLoading extends CreateSceneState {}
class ConditionSelectedState extends CreateSceneState {
final String condition;
const ConditionSelectedState(this.condition);
}
class SceneTypeState extends CreateSceneState {
final CreateSceneEnum type;
const SceneTypeState(this.type);
}

View File

@ -1,4 +1,5 @@
enum CreateSceneEnum { enum CreateSceneEnum {
tabToRun, tabToRun,
deviceStatusChanges, deviceStatusChanges,
none,
} }

View File

@ -3,11 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart'; import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart'; import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart'; import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_functions_body.dart'; import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_functions_body.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_slider_steps.dart'; import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_slider_steps.dart';
@ -22,14 +20,19 @@ mixin SceneLogicHelper {
} }
void handleSaveButtonPress( void handleSaveButtonPress(
BuildContext context, BuildContext context, {
TextEditingController sceneNameController,
List<SceneStaticFunction> tasks, {
required bool updateScene, required bool updateScene,
required String sceneId, required String sceneId,
required bool isAutomation,
required TextEditingController sceneName,
required List<SceneStaticFunction> actions,
required List<SceneStaticFunction> conditions,
}) { }) {
if (isOnlyDelayOrDelayLast(tasks)) { final sceneBloc = context.read<CreateSceneBloc>();
// Show snackbar indicating restriction
if (isAutomation) {
// Handle Automation Creation
if (isOnlyDelayOrDelayLast(actions)) {
Navigator.pop(context); Navigator.pop(context);
context.showCustomSnackbar( context.showCustomSnackbar(
message: 'A single delay or delay-last operations are NOT allowed.', message: 'A single delay or delay-last operations are NOT allowed.',
@ -39,17 +42,65 @@ mixin SceneLogicHelper {
), ),
); );
} else { } else {
final createAutomationModel = CreateAutomationModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
automationName: sceneName.text,
decisionExpr: sceneBloc.conditionRule,
effectiveTime:
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'),
conditions: List.generate(
conditions.length,
(index) {
final task = conditions[index];
return CreateCondition(
code: index + 1,
entityId: task.deviceId,
entityType: 'device_report',
expr: ConditionExpr(
statusCode: task.code,
comparator: task.comparator ?? '==',
statusValue: task.functionValue,
),
);
},
),
actions: List.generate(
actions.length,
(index) {
final task = actions[index];
return CreateSceneAction(
entityId: task.deviceId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.functionValue,
delaySeconds: 0,
),
);
},
),
);
sceneBloc.add(CreateSceneWithTasksEvent(
createSceneModel: null,
updateScene: updateScene,
sceneId: sceneId,
createAutomationModel: createAutomationModel,
));
Navigator.pop(context);
}
} else {
// Handle Scene Creation
final createSceneModel = CreateSceneModel( final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '', unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
sceneName: sceneNameController.text, sceneName: sceneName.text,
decisionExpr: 'and', decisionExpr: 'and',
actions: List.generate( actions: List.generate(
tasks.length, actions.length,
(index) { (index) {
final task = tasks[index]; final task = actions[index];
if (task.deviceId == 'delay') { if (task.deviceId == 'delay') {
return CreateSceneAction( return CreateSceneAction(
entityId: tasks[index].deviceId, entityId: actions[index].deviceId,
actionExecutor: 'delay', actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty( executorProperty: CreateSceneExecutorProperty(
functionCode: '', functionCode: '',
@ -70,12 +121,12 @@ mixin SceneLogicHelper {
}, },
), ),
); );
context.read<CreateSceneBloc>().add(CreateSceneWithTasksEvent( sceneBloc.add(CreateSceneWithTasksEvent(
createSceneModel: createSceneModel, createSceneModel: createSceneModel,
createAutomationModel: null,
updateScene: updateScene, updateScene: updateScene,
sceneId: sceneId, sceneId: sceneId,
)); ));
Navigator.pop(context); Navigator.pop(context);
} }
} }

View File

@ -206,29 +206,9 @@ mixin SceneOperationsDataHelper {
} }
SceneStaticFunction _mapExecutorPropertyToSceneFunction( SceneStaticFunction _mapExecutorPropertyToSceneFunction(
Action action, bool isAutomation) { Action action, bool isAutomation,
{String? comparator}) {
ExecutorProperty executorProperty = action.executorProperty; ExecutorProperty executorProperty = action.executorProperty;
/*
if (type == DeviceType.LightBulb) {
tempIcon = Assets.assetsIconsLight;
} else if (type == DeviceType.CeilingSensor ||
type == DeviceType.WallSensor) {
tempIcon = Assets.assetsIconsSensors;
} else if (type == DeviceType.AC) {
tempIcon = Assets.assetsIconsAC;
} else if (type == DeviceType.DoorLock) {
tempIcon = Assets.assetsIconsDoorLock;
} else if (type == DeviceType.Curtain) {
tempIcon = Assets.assetsIconsCurtain;
} else if (type == DeviceType.ThreeGang) {
tempIcon = Assets.assetsIcons3GangSwitch;
} else if (type == DeviceType.Gateway) {
tempIcon = Assets.assetsIconsGateway;
} else {
tempIcon = Assets.assetsIconsLogo;
}
*/
switch (executorProperty.functionCode) { switch (executorProperty.functionCode) {
case 'sensitivity': case 'sensitivity':
@ -243,7 +223,8 @@ mixin SceneOperationsDataHelper {
isAutomation isAutomation
? _createIntegerStepsOptions() ? _createIntegerStepsOptions()
: _createSensitivityOptions(), : _createSensitivityOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'normal_open_switch': case 'normal_open_switch':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -252,7 +233,8 @@ mixin SceneOperationsDataHelper {
'Set Door lock Normal Open', 'Set Door lock Normal Open',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_fingerprint': case 'unlock_fingerprint':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -261,7 +243,8 @@ mixin SceneOperationsDataHelper {
'Fingerprint Unlock', 'Fingerprint Unlock',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createFingerprintUnlockOptions(), _createFingerprintUnlockOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_password': case 'unlock_password':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -270,7 +253,8 @@ mixin SceneOperationsDataHelper {
'Password Unlock', 'Password Unlock',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createPasswordUnlockOptions(), _createPasswordUnlockOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_card': case 'unlock_card':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -279,7 +263,8 @@ mixin SceneOperationsDataHelper {
'Card Unlock', 'Card Unlock',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createCardUnlockOptions(), _createCardUnlockOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'alarm_lock': case 'alarm_lock':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -288,7 +273,8 @@ mixin SceneOperationsDataHelper {
'Lock Alarm', 'Lock Alarm',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createLockAlarmOptions(), _createLockAlarmOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_request': case 'unlock_request':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -297,7 +283,8 @@ mixin SceneOperationsDataHelper {
'Remote Unlock Request', 'Remote Unlock Request',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createUnlockRequestOptions(), _createUnlockRequestOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'residual_electricity': case 'residual_electricity':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -306,7 +293,8 @@ mixin SceneOperationsDataHelper {
'Residual Electricity', 'Residual Electricity',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createResidualElectricityOptions(), _createResidualElectricityOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'reverse_lock': case 'reverse_lock':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -315,7 +303,8 @@ mixin SceneOperationsDataHelper {
'Double Lock', 'Double Lock',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_app': case 'unlock_app':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -324,7 +313,8 @@ mixin SceneOperationsDataHelper {
'Remote Unlock Via App', 'Remote Unlock Via App',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createUnlockAppOptions(), _createUnlockAppOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'hijack': case 'hijack':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -333,7 +323,8 @@ mixin SceneOperationsDataHelper {
'Hijack Alarm', 'Hijack Alarm',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'doorbell': case 'doorbell':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -342,7 +333,8 @@ mixin SceneOperationsDataHelper {
'Doorbell', 'Doorbell',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'unlock_temporary': case 'unlock_temporary':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -351,7 +343,8 @@ mixin SceneOperationsDataHelper {
'Temporary Password Unlock', 'Temporary Password Unlock',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createTemporaryPasswordUnlockOptions(), _createTemporaryPasswordUnlockOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'far_detection': case 'far_detection':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -360,7 +353,8 @@ mixin SceneOperationsDataHelper {
'Far Detection', 'Far Detection',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createFarDetectionOptions(), _createFarDetectionOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'motion_sensitivity_value': case 'motion_sensitivity_value':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -369,7 +363,8 @@ mixin SceneOperationsDataHelper {
'Motion Detection Sensitivity', 'Motion Detection Sensitivity',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createSensitivityOptions(), _createSensitivityOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'motionless_sensitivity': case 'motionless_sensitivity':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -378,7 +373,8 @@ mixin SceneOperationsDataHelper {
'Motionless Detection Sensitivity', 'Motionless Detection Sensitivity',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createSensitivityOptions(), _createSensitivityOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'indicator': case 'indicator':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -387,7 +383,8 @@ mixin SceneOperationsDataHelper {
'Indicator', 'Indicator',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'presence_time': case 'presence_time':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -396,7 +393,8 @@ mixin SceneOperationsDataHelper {
'Nobody Time', 'Nobody Time',
OperationDialogType.countdown, OperationDialogType.countdown,
_createCountdownOptions(), _createCountdownOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'presence_state': case 'presence_state':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -405,7 +403,8 @@ mixin SceneOperationsDataHelper {
'Presence State', 'Presence State',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createPresenceStateOptions(), _createPresenceStateOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'dis_current': case 'dis_current':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -414,7 +413,8 @@ mixin SceneOperationsDataHelper {
'Current Distance', 'Current Distance',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createCurrentDistanceOptions(), _createCurrentDistanceOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'illuminance_value': case 'illuminance_value':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -423,7 +423,8 @@ mixin SceneOperationsDataHelper {
'Illuminance Value', 'Illuminance Value',
OperationDialogType.integerSteps, OperationDialogType.integerSteps,
_createIlluminanceValueOptions(), _createIlluminanceValueOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'checking_result': case 'checking_result':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -432,7 +433,8 @@ mixin SceneOperationsDataHelper {
'Self-Test Result', 'Self-Test Result',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createSelfTestResultOptions(), _createSelfTestResultOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'switch': case 'switch':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -441,7 +443,8 @@ mixin SceneOperationsDataHelper {
'Power', 'Power',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'temp_set': case 'temp_set':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -454,7 +457,19 @@ mixin SceneOperationsDataHelper {
isAutomation isAutomation
? _createAutomationTemperatureOptions() ? _createAutomationTemperatureOptions()
: _createTemperatureOptions(), : _createTemperatureOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'temp_current':
return _createSceneFunction(
action,
'Smart AC Thermostat - Grey - Model A',
Assets.assetsIconsAC,
'Current Temperature',
OperationDialogType.integerSteps,
_createCurrentTemperatureOptions(),
isAutomation,
comparator ?? '==');
case 'mode': case 'mode':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -463,7 +478,8 @@ mixin SceneOperationsDataHelper {
'Mode', 'Mode',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createAcModeOptions(), _createAcModeOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'level': case 'level':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -472,7 +488,8 @@ mixin SceneOperationsDataHelper {
'Fan Speed', 'Fan Speed',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createFanSpeedOptions(), _createFanSpeedOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'child_lock': case 'child_lock':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -481,7 +498,8 @@ mixin SceneOperationsDataHelper {
'Child Lock', 'Child Lock',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'switch_1': case 'switch_1':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -490,7 +508,8 @@ mixin SceneOperationsDataHelper {
'Light 1 Switch', 'Light 1 Switch',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'switch_2': case 'switch_2':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -499,7 +518,8 @@ mixin SceneOperationsDataHelper {
'Light 2 Switch', 'Light 2 Switch',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'switch_3': case 'switch_3':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -508,7 +528,8 @@ mixin SceneOperationsDataHelper {
'Light 3 Switch', 'Light 3 Switch',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'countdown_1': case 'countdown_1':
return _createSceneFunction( return _createSceneFunction(
@ -522,7 +543,8 @@ mixin SceneOperationsDataHelper {
isAutomation isAutomation
? _createAutomationCountDownOptions() ? _createAutomationCountDownOptions()
: _createCountdownOptions(), : _createCountdownOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'countdown_2': case 'countdown_2':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -535,7 +557,8 @@ mixin SceneOperationsDataHelper {
isAutomation isAutomation
? _createAutomationCountDownOptions() ? _createAutomationCountDownOptions()
: _createCountdownOptions(), : _createCountdownOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'countdown_3': case 'countdown_3':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -548,7 +571,8 @@ mixin SceneOperationsDataHelper {
isAutomation isAutomation
? _createAutomationCountDownOptions() ? _createAutomationCountDownOptions()
: _createCountdownOptions(), : _createCountdownOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'switch_alarm_sound': case 'switch_alarm_sound':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -557,7 +581,8 @@ mixin SceneOperationsDataHelper {
'Switch Alarm Sound', 'Switch Alarm Sound',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'master_state': case 'master_state':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -566,7 +591,8 @@ mixin SceneOperationsDataHelper {
'Master State', 'Master State',
OperationDialogType.listOfOptions, OperationDialogType.listOfOptions,
_createMasterStateOptions(), _createMasterStateOptions(),
isAutomation); isAutomation,
comparator ?? '==');
case 'factory_reset': case 'factory_reset':
return _createSceneFunction( return _createSceneFunction(
action, action,
@ -575,7 +601,8 @@ mixin SceneOperationsDataHelper {
'Factory Reset', 'Factory Reset',
OperationDialogType.onOff, OperationDialogType.onOff,
_createOnOffOptions(), _createOnOffOptions(),
isAutomation); isAutomation,
comparator ?? '==');
default: default:
throw ArgumentError( throw ArgumentError(
'Unsupported function code: ${executorProperty.functionCode}'); 'Unsupported function code: ${executorProperty.functionCode}');
@ -778,7 +805,8 @@ mixin SceneOperationsDataHelper {
String operationName, String operationName,
OperationDialogType operationDialogType, OperationDialogType operationDialogType,
List<SceneOperationalValue> operationalValues, List<SceneOperationalValue> operationalValues,
bool isAutomation) { bool isAutomation,
String comparator) {
final functionValue = action.executorProperty.functionValue; final functionValue = action.executorProperty.functionValue;
return SceneStaticFunction( return SceneStaticFunction(
deviceId: action.entityId, deviceId: action.entityId,
@ -790,6 +818,7 @@ mixin SceneOperationsDataHelper {
code: action.executorProperty.functionCode ?? '', code: action.executorProperty.functionCode ?? '',
operationDialogType: operationDialogType, operationDialogType: operationDialogType,
operationalValues: operationalValues, operationalValues: operationalValues,
comparator: comparator,
); );
} }
@ -913,7 +942,22 @@ mixin SceneOperationsDataHelper {
functionCode: taskItem.code, functionCode: taskItem.code,
functionValue: taskItem.functionValue), functionValue: taskItem.functionValue),
actionExecutor: ''), actionExecutor: ''),
isAutomation) isAutomation,
comparator: taskItem.comparator,
)
];
}
List<SceneOperationalValue> _createCurrentTemperatureOptions() {
return [
SceneOperationalValue(
icon: Assets.assetsCelsiusDegrees,
value: 0.0,
description: '°C',
minValue: -9.9,
maxValue: 99.9,
stepValue: 0.1,
),
]; ];
} }
} }

View File

@ -0,0 +1,172 @@
import 'dart:convert';
import 'package:syncrow_app/features/scene/model/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() {
return {
'unitUuid': 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['unitUuid'] ?? '',
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() => 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 {
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)';
}

View File

@ -15,6 +15,7 @@ class SceneStaticFunction {
final dynamic functionValue; final dynamic functionValue;
final String? deviceIcon; final String? deviceIcon;
final OperationDialogType operationDialogType; final OperationDialogType operationDialogType;
final String? comparator;
SceneStaticFunction({ SceneStaticFunction({
required this.icon, required this.icon,
@ -26,6 +27,7 @@ class SceneStaticFunction {
required this.functionValue, required this.functionValue,
this.deviceIcon, this.deviceIcon,
required this.operationDialogType, required this.operationDialogType,
this.comparator,
}) : uniqueCustomId = const Uuid().v4(); }) : uniqueCustomId = const Uuid().v4();
SceneStaticFunction copyWith({ SceneStaticFunction copyWith({
@ -39,6 +41,7 @@ class SceneStaticFunction {
String? deviceIcon, String? deviceIcon,
String? deviceName, String? deviceName,
OperationDialogType? operationDialogType, OperationDialogType? operationDialogType,
String? comparator,
}) { }) {
return SceneStaticFunction( return SceneStaticFunction(
icon: icon ?? this.icon, icon: icon ?? this.icon,
@ -50,6 +53,7 @@ class SceneStaticFunction {
functionValue: functionValue ?? this.functionValue, functionValue: functionValue ?? this.functionValue,
deviceIcon: deviceIcon ?? this.deviceIcon, deviceIcon: deviceIcon ?? this.deviceIcon,
operationDialogType: operationDialogType ?? this.operationDialogType, operationDialogType: operationDialogType ?? this.operationDialogType,
comparator: comparator ?? this.comparator,
); );
} }
@ -63,7 +67,8 @@ class SceneStaticFunction {
'operationName': operationName, 'operationName': operationName,
'functionValue': functionValue, 'functionValue': functionValue,
'deviceIcon': deviceIcon, 'deviceIcon': deviceIcon,
'operationDialogType': operationDialogType.name 'operationDialogType': operationDialogType.name,
'comparator': comparator
}; };
} }
@ -82,6 +87,7 @@ class SceneStaticFunction {
operationDialogType: map['operationDialogType'] != null operationDialogType: map['operationDialogType'] != null
? OperationDialogType.values.byName(map['operationDialogType']) ? OperationDialogType.values.byName(map['operationDialogType'])
: OperationDialogType.none, : OperationDialogType.none,
comparator: map['comparator'],
); );
} }
@ -92,7 +98,7 @@ class SceneStaticFunction {
@override @override
String toString() { String toString() {
return 'SceneStaticFunction(icon: $icon, name: $deviceName, code: $code, operationalValues: $operationalValues, deviceId: $deviceId, operationName: $operationName, functionValue: $functionValue, deviceIcon: $deviceIcon, operationDialogType: $operationDialogType)'; return 'SceneStaticFunction(icon: $icon, name: $deviceName, code: $code, operationalValues: $operationalValues, deviceId: $deviceId, operationName: $operationName, functionValue: $functionValue, deviceIcon: $deviceIcon, operationDialogType: $operationDialogType, comparator: $comparator)';
} }
@override @override
@ -106,6 +112,7 @@ class SceneStaticFunction {
other.operationName == operationName && other.operationName == operationName &&
other.functionValue == functionValue && other.functionValue == functionValue &&
other.deviceIcon == deviceIcon && other.deviceIcon == deviceIcon &&
other.comparator == comparator &&
other.operationDialogType == operationDialogType && other.operationDialogType == operationDialogType &&
listEquals(other.operationalValues, operationalValues) && listEquals(other.operationalValues, operationalValues) &&
other.deviceId == deviceId; other.deviceId == deviceId;
@ -120,6 +127,7 @@ class SceneStaticFunction {
operationName.hashCode ^ operationName.hashCode ^
functionValue.hashCode ^ functionValue.hashCode ^
deviceIcon.hashCode ^ deviceIcon.hashCode ^
comparator.hashCode ^
operationDialogType.hashCode ^ operationDialogType.hashCode ^
operationalValues.hashCode; operationalValues.hashCode;
} }

View File

@ -6,10 +6,9 @@ import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class CreateSceneView extends StatelessWidget { class CreateSceneView extends StatelessWidget {
@ -22,7 +21,7 @@ class CreateSceneView extends StatelessWidget {
padding: const EdgeInsets.only(top: 24), padding: const EdgeInsets.only(top: 24),
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
Navigator.pop(context); navigateToRoute(context, Routes.sceneTasksRoute);
}, },
icon: const Icon( icon: const Icon(
Icons.arrow_back_ios, Icons.arrow_back_ios,
@ -48,6 +47,9 @@ class CreateSceneView extends StatelessWidget {
), ),
); );
context.read<CreateSceneBloc>().add(const ClearTaskListEvent()); context.read<CreateSceneBloc>().add(const ClearTaskListEvent());
context
.read<CreateSceneBloc>()
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
}, },
), ),
DefaultContainer( DefaultContainer(
@ -71,6 +73,8 @@ class CreateSceneView extends StatelessWidget {
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(const ClearTaskListEvent(isAutomation: true)); .add(const ClearTaskListEvent(isAutomation: true));
context.read<CreateSceneBloc>().add(
const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges));
}, },
), ),
], ],

View File

@ -12,6 +12,7 @@ import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/light_divider.dart'; import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
@ -53,9 +54,7 @@ class DeviceFunctionsView extends StatelessWidget
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(AddTaskEvent(isAutomation: isAutomation)); .add(AddTaskEvent(isAutomation: isAutomation));
Navigator.popUntil(context, (route) { navigateToRoute(context, Routes.sceneTasksRoute);
return route.settings.name == Routes.sceneTasksRoute;
});
}, },
child: BodyMedium( child: BodyMedium(
text: 'Save', text: 'Save',

View File

@ -8,6 +8,8 @@ import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart
import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_body.dart'; import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_body.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@ -16,10 +18,12 @@ class SceneRoomsTabBarDevicesView extends StatefulWidget {
const SceneRoomsTabBarDevicesView({super.key}); const SceneRoomsTabBarDevicesView({super.key});
@override @override
State<SceneRoomsTabBarDevicesView> createState() => _SceneRoomsTabBarDevicesViewState(); State<SceneRoomsTabBarDevicesView> createState() =>
_SceneRoomsTabBarDevicesViewState();
} }
class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesView> class _SceneRoomsTabBarDevicesViewState
extends State<SceneRoomsTabBarDevicesView>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late final TabController _tabController; late final TabController _tabController;
List<RoomModel>? rooms = []; List<RoomModel>? rooms = [];
@ -41,7 +45,8 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
} }
} }
_tabController = TabController(length: rooms!.length, vsync: this, initialIndex: 0); _tabController =
TabController(length: rooms!.length, vsync: this, initialIndex: 0);
_tabController.addListener(_handleTabSwitched); _tabController.addListener(_handleTabSwitched);
super.initState(); super.initState();
} }
@ -51,9 +56,8 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
final value = _tabController.index; final value = _tabController.index;
/// select tab /// select tab
context context.read<TabBarBloc>().add(
.read<TabBarBloc>() TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
.add(TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
return; return;
} }
} }
@ -72,8 +76,7 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
Navigator.pop(context); navigateToRoute(context, Routes.sceneTasksRoute);
Navigator.pop(context);
}, },
icon: const Icon( icon: const Icon(
Icons.arrow_back_ios, Icons.arrow_back_ios,

View File

@ -24,7 +24,7 @@ class AlertDialogSliderSteps extends StatefulWidget {
class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> { class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
double? groupValue; double? groupValue;
int selectedToggleIndex = 0; int selectedToggleIndex = 1;
@override @override
void didChangeDependencies() { void didChangeDependencies() {
@ -33,23 +33,53 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
if (widget.isAutomation) { if (widget.isAutomation) {
final automationTempTaskList = final automationTempTaskList =
context.read<CreateSceneBloc>().automationTempTasksList; context.read<CreateSceneBloc>().automationTempTasksList;
final automationComparatorValues =
context.read<CreateSceneBloc>().automationComparatorValues;
if (automationTempTaskList.isNotEmpty) { if (automationTempTaskList.isNotEmpty) {
for (var element in automationTempTaskList) { for (var element in automationTempTaskList) {
if (element.code == widget.taskItem.code) { if (element.code == widget.taskItem.code) {
groupValue = element.functionValue; groupValue = element.functionValue;
} else { selectedToggleIndex =
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById( _comparatorToIndex(automationComparatorValues[element.code]);
code: widget.taskItem.code, isAutomation: widget.isAutomation));
} }
} }
} }
if (widget.functionValue != null) { if (widget.functionValue != null) {
setState(() {
groupValue = widget.functionValue; groupValue = widget.functionValue;
});
} else { } else {
groupValue = widget.taskItem.operationalValues[0].minValue; groupValue = widget.taskItem.operationalValues[0].minValue;
} }
if (widget.taskItem.comparator != null) {
selectedToggleIndex = _comparatorToIndex(widget.taskItem.comparator);
}
setState(() {});
}
}
int _comparatorToIndex(String? comparator) {
switch (comparator) {
case "<=":
return 0;
case "==":
return 1;
case ">=":
return 2;
default:
return 1;
}
}
String _indexToComparator(int index) {
switch (index) {
case 0:
return "<=";
case 1:
return "==";
case 2:
return ">=";
default:
return "==";
} }
} }
@ -68,6 +98,10 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
setState(() { setState(() {
selectedToggleIndex = index; selectedToggleIndex = index;
}); });
context.read<CreateSceneBloc>().add(SelectedValueEvent(
code: widget.taskItem.code,
isAutomation: widget.isAutomation,
comparator: _indexToComparator(selectedToggleIndex)));
}, },
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
selectedColor: Colors.white, selectedColor: Colors.white,
@ -164,7 +198,9 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
context.read<CreateSceneBloc>().add(SelectedValueEvent( context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: groupValue, value: groupValue,
code: widget.taskItem.code, code: widget.taskItem.code,
isAutomation: widget.isAutomation)); isAutomation: widget.isAutomation,
comparator:
_indexToComparator(selectedToggleIndex)));
}, },
), ),
), ),

View File

@ -1,9 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart'; import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -43,8 +46,7 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
listener: (context, state) { listener: (context, state) {
if (state is CreateSceneWithTasks) { if (state is CreateSceneWithTasks) {
if (state.success == true) { if (state.success == true) {
Navigator.pop(context); navigateToRoute(context, Routes.homeRoute);
Navigator.pop(context);
context.showCustomSnackbar( context.showCustomSnackbar(
message: 'Scene created successfully', message: 'Scene created successfully',
icon: const Icon( icon: const Icon(
@ -66,29 +68,31 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
}, },
builder: (context, state) { builder: (context, state) {
return DefaultButton( return DefaultButton(
onPressed: widget.sceneName.isNotEmpty onPressed: () {
? () { final sceneBloc = context.read<CreateSceneBloc>();
final tasks = context.read<CreateSceneBloc>().tasksList; final isAutomation =
sceneBloc.sceneType == CreateSceneEnum.deviceStatusChanges;
if (widget.sceneName.isNotEmpty) {
handleSaveButtonPress( handleSaveButtonPress(
context, context,
sceneNameController, sceneName: sceneNameController,
tasks, actions: sceneBloc.tasksList,
updateScene: true, updateScene: true,
sceneId: widget.sceneId, sceneId: widget.sceneId,
isAutomation: isAutomation,
conditions: sceneBloc.automationTasksList,
); );
} } else {
: () {
context.customAlertDialog( context.customAlertDialog(
alertBody: Padding( alertBody: Padding(
padding: padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
const EdgeInsets.only(left: 8, right: 8, bottom: 8),
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: SearchBar( child: SearchBar(
controller: sceneNameController, controller: sceneNameController,
elevation: WidgetStateProperty.all(0), elevation: WidgetStateProperty.all(0),
textStyle: textStyle: WidgetStateProperty.all(context.bodyMedium),
WidgetStateProperty.all(context.bodyMedium),
hintStyle: WidgetStateProperty.all( hintStyle: WidgetStateProperty.all(
context.bodyMedium.copyWith( context.bodyMedium.copyWith(
fontSize: 14, fontSize: 14,
@ -103,17 +107,19 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
title: 'Scene Name', title: 'Scene Name',
onConfirm: () { onConfirm: () {
if (sceneNameController.text.isNotEmpty) { if (sceneNameController.text.isNotEmpty) {
final tasks = context.read<CreateSceneBloc>().tasksList;
handleSaveButtonPress( handleSaveButtonPress(
context, context,
sceneNameController, sceneName: sceneNameController,
tasks, actions: sceneBloc.tasksList,
updateScene: false, updateScene: false,
sceneId: widget.sceneId, sceneId: widget.sceneId,
isAutomation: isAutomation,
conditions: sceneBloc.automationTasksList,
); );
} }
}, },
); );
}
}, },
customButtonStyle: ButtonStyle( customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>( backgroundColor: WidgetStateProperty.all<Color>(

View File

@ -1,18 +1,24 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart'; import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart'; import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart'; import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/light_divider.dart'; import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class IFDefaultContainer extends StatelessWidget { class IFDefaultContainer extends StatelessWidget {
const IFDefaultContainer({ const IFDefaultContainer({
@ -27,30 +33,101 @@ class IFDefaultContainer extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SceneListTile( SceneListTile(
leadingWidget: BodyLarge( leadingWidget: InkWell(
onTap: () {
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name ==
CreateSceneEnum.deviceStatusChanges.name) {
context.customAlertDialog(
hideConfirmButton: true,
alertBody: Column(
children: [
ListTile(
title: const BodyMedium(
text: "When all conditions are met"),
onTap: () {
context.read<CreateSceneBloc>().add(
const SelectConditionEvent(
"When all conditions are met"));
Navigator.pop(context);
},
),
ListTile(
title: const BodyMedium(
text: "When any condition is met"),
onTap: () {
context.read<CreateSceneBloc>().add(
const SelectConditionEvent(
"When any condition is met"));
Navigator.pop(context);
},
),
],
),
title: 'Conditions Rule',
onConfirm: () {},
);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
BodyLarge(
text: 'IF', text: 'IF',
style: context.bodyLarge.copyWith( style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: ColorsManager.primaryTextColor, color: ColorsManager.primaryTextColor,
), ),
), ),
trailingWidget: GestureDetector( BlocBuilder<CreateSceneBloc, CreateSceneState>(
onTap: () => Navigator.pushNamed( builder: (context, state) {
String conditionText = "When any condition is met";
if (state is ConditionSelectedState) {
conditionText = state.condition;
}
return SizedBox(
width: context.width * 0.6,
child: Row(children: [
BodySmall(text: conditionText),
const Icon(Icons.keyboard_arrow_down)
]),
);
},
),
],
),
),
trailingWidget: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
bool isClickable = false;
if (state is AddSceneTask) {
isClickable = state.automationTasksList?.isNotEmpty ?? false;
}
return GestureDetector(
onTap: isClickable
? () => Navigator.pushNamed(
context, context,
Routes.sceneControlDevicesRoute, Routes.sceneControlDevicesRoute,
arguments: SceneSettingsRouteArguments( arguments: SceneSettingsRouteArguments(
sceneType: CreateSceneEnum.deviceStatusChanges.name, sceneType:
CreateSceneEnum.deviceStatusChanges.name,
sceneId: '', sceneId: '',
sceneName: '', sceneName: '',
), ),
), )
: null,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.addIcon, Assets.addIcon,
colorFilter: const ColorFilter.mode( colorFilter: ColorFilter.mode(
ColorsManager.primaryColor, isClickable
? ColorsManager.primaryColor
: ColorsManager.greyColor,
BlendMode.srcIn, BlendMode.srcIn,
), ),
), ),
);
},
), ),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
@ -74,10 +151,26 @@ class IFDefaultContainer extends StatelessWidget {
); );
} }
} }
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.tabToRun.name) {
return const SceneListTile(
assetPath: Assets.handClickIcon,
titleString: StringsManager.tapToRun,
subtitleString: '',
);
}
return SceneListTile( return SceneListTile(
titleString: '+ Add Condition', titleString: '+ Add Condition',
textAlign: TextAlign.center, textAlign: TextAlign.center,
onPressed: () => Navigator.pushNamed( onPressed: () {
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.none.name) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => const CreateSceneView()));
} else {
Navigator.pushNamed(
context, context,
Routes.sceneControlDevicesRoute, Routes.sceneControlDevicesRoute,
arguments: SceneSettingsRouteArguments( arguments: SceneSettingsRouteArguments(
@ -85,8 +178,9 @@ class IFDefaultContainer extends StatelessWidget {
sceneId: '', sceneId: '',
sceneName: '', sceneName: '',
), ),
),
); );
}
});
}, },
) )
], ],

View File

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart'; import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart'; import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/scene/widgets/bottom_sheet_widget.dart'; import 'package:syncrow_app/features/scene/widgets/bottom_sheet_widget.dart';
@ -10,6 +12,7 @@ import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class ThenDefaultContainer extends StatelessWidget { class ThenDefaultContainer extends StatelessWidget {
@ -35,17 +38,29 @@ class ThenDefaultContainer extends StatelessWidget {
color: ColorsManager.primaryTextColor, color: ColorsManager.primaryTextColor,
), ),
), ),
trailingWidget: GestureDetector( trailingWidget: BlocBuilder<CreateSceneBloc, CreateSceneState>(
onTap: () => context.customBottomSheet( builder: (context, state) {
bool isClickable = false;
if (state is AddSceneTask) {
isClickable = state.tasksList.isNotEmpty;
}
return GestureDetector(
onTap: isClickable
? () => context.customBottomSheet(
child: const CustomBottomSheetWidget(), child: const CustomBottomSheetWidget(),
), )
: null,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.addIcon, Assets.addIcon,
colorFilter: const ColorFilter.mode( colorFilter: ColorFilter.mode(
ColorsManager.primaryColor, isClickable
? ColorsManager.primaryColor
: ColorsManager.greyColor,
BlendMode.srcIn, BlendMode.srcIn,
), ),
), ),
);
},
), ),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
@ -71,20 +86,23 @@ class ThenDefaultContainer extends StatelessWidget {
}, },
); );
} }
return SceneListTile(
titleString: '+ Add Task',
textAlign: TextAlign.center,
onPressed: () => context.customBottomSheet(
child: const CustomBottomSheetWidget(),
),
);
} }
return SceneListTile( return SceneListTile(
titleString: '+ Add Task', titleString: '+ Add Task',
textAlign: TextAlign.center, textAlign: TextAlign.center,
onPressed: () => context.customBottomSheet( onPressed: () {
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.none.name) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => const CreateSceneView()));
} else {
context.customBottomSheet(
child: const CustomBottomSheetWidget(), child: const CustomBottomSheetWidget(),
), );
}
},
); );
}, },
) )

View File

@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
void navigateToRoute(BuildContext context, String targetRoute) {
bool routeFound = false;
Navigator.popUntil(context, (route) {
if (route.settings.name == targetRoute) {
routeFound = true;
return true;
}
return route.isFirst;
});
if (!routeFound) {
Navigator.pushNamed(context, targetRoute);
}
}

View File

@ -135,6 +135,8 @@ abstract class ApiEndpoints {
static const String triggerScene = static const String triggerScene =
'$baseUrl/scene/tap-to-run/trigger/{sceneId}'; '$baseUrl/scene/tap-to-run/trigger/{sceneId}';
static const String createAutomation = '$baseUrl/automation';
/// GET /// GET
static const String getUnitScenes = '$baseUrl/scene/tap-to-run/{unitUuid}'; static const String getUnitScenes = '$baseUrl/scene/tap-to-run/{unitUuid}';

View File

@ -1,3 +1,4 @@
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_details_model.dart'; import 'package:syncrow_app/features/scene/model/scene_details_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart'; import 'package:syncrow_app/features/scene/model/scenes_model.dart';
@ -24,6 +25,23 @@ class SceneApi {
} }
} }
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<ScenesModel>> getScenesByUnitId(String unitId) async { static Future<List<ScenesModel>> getScenesByUnitId(String unitId) async {
try { try {
final response = await _httpService.get( final response = await _httpService.get(

View File

@ -65,6 +65,7 @@ extension ContextExtension on BuildContext {
required String title, required String title,
required VoidCallback onConfirm, required VoidCallback onConfirm,
VoidCallback? onDismiss, VoidCallback? onDismiss,
bool? hideConfirmButton,
}) { }) {
showDialog( showDialog(
context: this, context: this,
@ -110,7 +111,8 @@ extension ContextExtension on BuildContext {
width: double.infinity, width: double.infinity,
color: ColorsManager.greyColor, color: ColorsManager.greyColor,
), ),
Row( hideConfirmButton != true
? Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
GestureDetector( GestureDetector(
@ -137,12 +139,29 @@ extension ContextExtension on BuildContext {
child: BodyMedium( child: BodyMedium(
text: 'Confirm', text: 'Confirm',
style: context.bodyMedium.copyWith( style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity), color:
ColorsManager.primaryColorWithOpacity),
), ),
), ),
), ),
], ],
) )
: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: GestureDetector(
onTap: onDismiss ??
() {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
),
),
),
),
], ],
), ),
), ),