mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-15 09:45:22 +00:00
push autoamtion api connect
This commit is contained in:
@ -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/devices_view_body.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/scene_tasks_view.dart';
|
||||
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
||||
import 'package:syncrow_app/generated/assets.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/spaces_api.dart';
|
||||
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
|
||||
@ -63,9 +68,12 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
selectedSpace = null;
|
||||
selectedRoom = null;
|
||||
pageIndex = 0;
|
||||
OneSignal.User.pushSubscription.removeObserver((stateChanges) => oneSignalSubscriptionObserver);
|
||||
OneSignal.Notifications.removePermissionObserver((permission) => oneSignalPermissionObserver);
|
||||
OneSignal.Notifications.removeClickListener((event) => oneSignalClickListenerObserver);
|
||||
OneSignal.User.pushSubscription
|
||||
.removeObserver((stateChanges) => oneSignalSubscriptionObserver);
|
||||
OneSignal.Notifications.removePermissionObserver(
|
||||
(permission) => oneSignalPermissionObserver);
|
||||
OneSignal.Notifications.removeClickListener(
|
||||
(event) => oneSignalClickListenerObserver);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@ -107,7 +115,9 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
return;
|
||||
}
|
||||
|
||||
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
|
||||
var userUuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
|
||||
'';
|
||||
if (userUuid.isNotEmpty) {
|
||||
await OneSignal.login(userUuid);
|
||||
}
|
||||
@ -115,21 +125,24 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
await OneSignal.User.pushSubscription.optIn();
|
||||
|
||||
//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) {
|
||||
await _sendSubscriptionId();
|
||||
}
|
||||
});
|
||||
|
||||
// Send the player id when a user allows notifications
|
||||
oneSignalPermissionObserver = OneSignal.Notifications.addPermissionObserver((state) async {
|
||||
oneSignalPermissionObserver =
|
||||
OneSignal.Notifications.addPermissionObserver((state) async {
|
||||
await _sendSubscriptionId();
|
||||
});
|
||||
|
||||
//check if the player id is sent, if not send it again
|
||||
await _sendSubscriptionId();
|
||||
|
||||
oneSignalClickListenerObserver = OneSignal.Notifications.addClickListener((event) async {
|
||||
oneSignalClickListenerObserver =
|
||||
OneSignal.Notifications.addClickListener((event) async {
|
||||
//Once the user clicks on the notification
|
||||
});
|
||||
} catch (err) {
|
||||
@ -216,7 +229,9 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
|
||||
Future<bool> joinAUnit(String code) async {
|
||||
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};
|
||||
|
||||
final success = await SpacesAPI.joinUnit(body);
|
||||
@ -334,15 +349,25 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
size: 32,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
|
||||
foregroundColor:
|
||||
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
Navigator.pushNamed(
|
||||
NavigationService.navigatorKey.currentContext!,
|
||||
CustomPageRoute(
|
||||
builder: (context) => const CreateSceneView(),
|
||||
Routes.sceneTasksRoute,
|
||||
arguments: SceneSettingsRouteArguments(
|
||||
sceneType: '',
|
||||
sceneId: '',
|
||||
sceneName: '',
|
||||
),
|
||||
);
|
||||
NavigationService.navigatorKey.currentContext!
|
||||
.read<CreateSceneBloc>()
|
||||
.add(const ClearTaskListEvent());
|
||||
NavigationService.navigatorKey.currentContext!
|
||||
.read<CreateSceneBloc>()
|
||||
.add(const SceneTypeEvent(CreateSceneEnum.none));
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
@ -351,7 +376,8 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
size: 28,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
|
||||
foregroundColor:
|
||||
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
|
||||
),
|
||||
onPressed: () {},
|
||||
),
|
||||
@ -384,7 +410,8 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
};
|
||||
|
||||
static var bottomNavItems = [
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
|
||||
defaultBottomNavBarItem(
|
||||
icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
|
||||
// defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
|
||||
defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
|
||||
@ -410,7 +437,8 @@ class HomeCubit extends Cubit<HomeState> {
|
||||
|
||||
void updateDevice(String deviceId) async {
|
||||
try {
|
||||
final response = await DevicesAPI.firmwareDevice(deviceId: deviceId, firmwareVersion: '0');
|
||||
final response = await DevicesAPI.firmwareDevice(
|
||||
deviceId: deviceId, firmwareVersion: '0');
|
||||
if (response['success'] ?? false) {
|
||||
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(
|
||||
icon: SvgPicture.asset(icon),
|
||||
activeIcon: SvgPicture.asset(
|
||||
|
@ -2,8 +2,10 @@ import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.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/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/scene_static_function.dart';
|
||||
import 'package:syncrow_app/services/api/scene_api.dart';
|
||||
@ -26,8 +28,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
on<RemoveFromSelectedValueById>(_removeFromSelectedValueById);
|
||||
on<DeleteSceneEvent>(_deleteScene);
|
||||
on<UpdateTaskEvent>(_updateTaskValue);
|
||||
on<SelectConditionEvent>(_selectConditionRule);
|
||||
on<SceneTypeEvent>(_sceneTypeEvent);
|
||||
}
|
||||
|
||||
CreateSceneEnum sceneType = CreateSceneEnum.none;
|
||||
|
||||
/// tab to run values and list
|
||||
List<SceneStaticFunction> tasksList = [];
|
||||
List<SceneStaticFunction> tempTasksList = [];
|
||||
@ -37,6 +43,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
List<SceneStaticFunction> automationTasksList = [];
|
||||
List<SceneStaticFunction> automationTempTasksList = [];
|
||||
final Map<String, dynamic> automationSelectedValues = {};
|
||||
final Map<String, String> automationComparatorValues = {};
|
||||
String conditionRule = 'or';
|
||||
|
||||
FutureOr<void> _onAddSceneTask(
|
||||
AddTaskEvent event, Emitter<CreateSceneState> emit) {
|
||||
@ -46,6 +54,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
automationTasksList.addAll(copyList);
|
||||
automationTempTasksList.clear();
|
||||
automationSelectedValues.clear();
|
||||
automationComparatorValues.clear();
|
||||
emit(AddSceneTask(
|
||||
automationTasksList: automationTasksList,
|
||||
tasksList: tasksList,
|
||||
@ -144,6 +153,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
icon: '',
|
||||
),
|
||||
],
|
||||
comparator: automationComparatorValues[element.code],
|
||||
);
|
||||
automationTempTasksList[automationTempTasksList.indexOf(element)] =
|
||||
updatedElement;
|
||||
@ -168,6 +178,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
icon: '',
|
||||
),
|
||||
],
|
||||
comparator:
|
||||
automationComparatorValues[event.deviceControlModel.code] ?? '==',
|
||||
);
|
||||
automationTempTasksList.add(newElement);
|
||||
automationSelectedValues[newElement.code] =
|
||||
@ -182,6 +194,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
emit(CreateSceneLoading());
|
||||
if (event.isAutomation == true) {
|
||||
automationSelectedValues[event.code] = event.value;
|
||||
automationComparatorValues[event.code] = event.comparator ?? '==';
|
||||
emit(SelectedTaskValueState(value: event.value));
|
||||
emit(AddSceneTask(
|
||||
tasksList: tasksList, automationTasksList: automationTasksList));
|
||||
@ -248,13 +261,26 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async {
|
||||
emit(CreateSceneLoading());
|
||||
try {
|
||||
final response = event.updateScene
|
||||
? await SceneApi.updateScene(event.createSceneModel, event.sceneId)
|
||||
: await SceneApi.createScene(event.createSceneModel);
|
||||
dynamic response;
|
||||
if (event.createSceneModel != null) {
|
||||
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) {
|
||||
tasksList.clear();
|
||||
tempTasksList.clear();
|
||||
selectedValues.clear();
|
||||
automationTasksList.clear();
|
||||
automationTempTasksList.clear();
|
||||
automationSelectedValues.clear();
|
||||
automationComparatorValues.clear();
|
||||
sceneType = CreateSceneEnum.none;
|
||||
conditionRule = 'or';
|
||||
emit(const CreateSceneWithTasks(success: true));
|
||||
} else {
|
||||
emit(const CreateSceneError(message: 'Something went wrong'));
|
||||
@ -301,6 +327,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
if (event.isAutomation == true) {
|
||||
automationTempTasksList.clear();
|
||||
automationSelectedValues.clear();
|
||||
automationComparatorValues.clear();
|
||||
emit(AddSceneTask(
|
||||
tasksList: tasksList, automationTasksList: automationTasksList));
|
||||
} else {
|
||||
@ -317,6 +344,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
if (event.isAutomation == true) {
|
||||
if (automationSelectedValues.containsKey(event.code)) {
|
||||
automationSelectedValues.remove(event.code);
|
||||
automationComparatorValues.remove(event.code);
|
||||
emit(const SelectedTaskValueState(value: null));
|
||||
emit(AddSceneTask(
|
||||
tasksList: tasksList, automationTasksList: automationTasksList));
|
||||
@ -373,4 +401,31 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
|
||||
emit(AddSceneTask(
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -67,12 +67,14 @@ class SelectedValueEvent extends CreateSceneEvent {
|
||||
final dynamic automationValue;
|
||||
final String code;
|
||||
final bool? isAutomation;
|
||||
final String? comparator;
|
||||
|
||||
const SelectedValueEvent({
|
||||
this.value,
|
||||
required this.code,
|
||||
this.isAutomation,
|
||||
this.automationValue,
|
||||
this.comparator,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -110,19 +112,21 @@ class RemoveFromSelectedValueById extends CreateSceneEvent {
|
||||
}
|
||||
|
||||
class CreateSceneWithTasksEvent extends CreateSceneEvent {
|
||||
final CreateSceneModel createSceneModel;
|
||||
final CreateSceneModel? createSceneModel;
|
||||
final bool updateScene;
|
||||
final String sceneId;
|
||||
final CreateAutomationModel? createAutomationModel;
|
||||
//final bool isAutomation;
|
||||
const CreateSceneWithTasksEvent({
|
||||
required this.createSceneModel,
|
||||
required this.updateScene,
|
||||
required this.sceneId,
|
||||
required this.createAutomationModel,
|
||||
// required this.isAutomation,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [createSceneModel];
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class ClearTaskListEvent extends CreateSceneEvent {
|
||||
@ -160,3 +164,14 @@ class DeleteSceneEvent extends CreateSceneEvent {
|
||||
@override
|
||||
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);
|
||||
}
|
||||
|
@ -71,3 +71,14 @@ class DeleteSceneError 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);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
enum CreateSceneEnum {
|
||||
tabToRun,
|
||||
deviceStatusChanges,
|
||||
none,
|
||||
}
|
||||
|
@ -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/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/model/create_automation_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/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_slider_steps.dart';
|
||||
@ -22,14 +20,19 @@ mixin SceneLogicHelper {
|
||||
}
|
||||
|
||||
void handleSaveButtonPress(
|
||||
BuildContext context,
|
||||
TextEditingController sceneNameController,
|
||||
List<SceneStaticFunction> tasks, {
|
||||
BuildContext context, {
|
||||
required bool updateScene,
|
||||
required String sceneId,
|
||||
required bool isAutomation,
|
||||
required TextEditingController sceneName,
|
||||
required List<SceneStaticFunction> actions,
|
||||
required List<SceneStaticFunction> conditions,
|
||||
}) {
|
||||
if (isOnlyDelayOrDelayLast(tasks)) {
|
||||
// Show snackbar indicating restriction
|
||||
final sceneBloc = context.read<CreateSceneBloc>();
|
||||
|
||||
if (isAutomation) {
|
||||
// Handle Automation Creation
|
||||
if (isOnlyDelayOrDelayLast(actions)) {
|
||||
Navigator.pop(context);
|
||||
context.showCustomSnackbar(
|
||||
message: 'A single delay or delay-last operations are NOT allowed.',
|
||||
@ -39,17 +42,65 @@ mixin SceneLogicHelper {
|
||||
),
|
||||
);
|
||||
} 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(
|
||||
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
|
||||
sceneName: sceneNameController.text,
|
||||
sceneName: sceneName.text,
|
||||
decisionExpr: 'and',
|
||||
actions: List.generate(
|
||||
tasks.length,
|
||||
actions.length,
|
||||
(index) {
|
||||
final task = tasks[index];
|
||||
final task = actions[index];
|
||||
if (task.deviceId == 'delay') {
|
||||
return CreateSceneAction(
|
||||
entityId: tasks[index].deviceId,
|
||||
entityId: actions[index].deviceId,
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: '',
|
||||
@ -70,12 +121,12 @@ mixin SceneLogicHelper {
|
||||
},
|
||||
),
|
||||
);
|
||||
context.read<CreateSceneBloc>().add(CreateSceneWithTasksEvent(
|
||||
sceneBloc.add(CreateSceneWithTasksEvent(
|
||||
createSceneModel: createSceneModel,
|
||||
createAutomationModel: null,
|
||||
updateScene: updateScene,
|
||||
sceneId: sceneId,
|
||||
));
|
||||
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
@ -206,29 +206,9 @@ mixin SceneOperationsDataHelper {
|
||||
}
|
||||
|
||||
SceneStaticFunction _mapExecutorPropertyToSceneFunction(
|
||||
Action action, bool isAutomation) {
|
||||
Action action, bool isAutomation,
|
||||
{String? comparator}) {
|
||||
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) {
|
||||
case 'sensitivity':
|
||||
@ -243,7 +223,8 @@ mixin SceneOperationsDataHelper {
|
||||
isAutomation
|
||||
? _createIntegerStepsOptions()
|
||||
: _createSensitivityOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'normal_open_switch':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -252,7 +233,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Set Door lock Normal Open',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_fingerprint':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -261,7 +243,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Fingerprint Unlock',
|
||||
OperationDialogType.integerSteps,
|
||||
_createFingerprintUnlockOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_password':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -270,7 +253,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Password Unlock',
|
||||
OperationDialogType.integerSteps,
|
||||
_createPasswordUnlockOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_card':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -279,7 +263,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Card Unlock',
|
||||
OperationDialogType.integerSteps,
|
||||
_createCardUnlockOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'alarm_lock':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -288,7 +273,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Lock Alarm',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createLockAlarmOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_request':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -297,7 +283,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Remote Unlock Request',
|
||||
OperationDialogType.integerSteps,
|
||||
_createUnlockRequestOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'residual_electricity':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -306,7 +293,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Residual Electricity',
|
||||
OperationDialogType.integerSteps,
|
||||
_createResidualElectricityOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'reverse_lock':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -315,7 +303,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Double Lock',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_app':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -324,7 +313,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Remote Unlock Via App',
|
||||
OperationDialogType.integerSteps,
|
||||
_createUnlockAppOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'hijack':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -333,7 +323,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Hijack Alarm',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'doorbell':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -342,7 +333,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Doorbell',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'unlock_temporary':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -351,7 +343,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Temporary Password Unlock',
|
||||
OperationDialogType.integerSteps,
|
||||
_createTemporaryPasswordUnlockOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'far_detection':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -360,7 +353,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Far Detection',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createFarDetectionOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'motion_sensitivity_value':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -369,7 +363,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Motion Detection Sensitivity',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createSensitivityOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'motionless_sensitivity':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -378,7 +373,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Motionless Detection Sensitivity',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createSensitivityOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'indicator':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -387,7 +383,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Indicator',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'presence_time':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -396,7 +393,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Nobody Time',
|
||||
OperationDialogType.countdown,
|
||||
_createCountdownOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'presence_state':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -405,7 +403,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Presence State',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createPresenceStateOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'dis_current':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -414,7 +413,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Current Distance',
|
||||
OperationDialogType.integerSteps,
|
||||
_createCurrentDistanceOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'illuminance_value':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -423,7 +423,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Illuminance Value',
|
||||
OperationDialogType.integerSteps,
|
||||
_createIlluminanceValueOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'checking_result':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -432,7 +433,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Self-Test Result',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createSelfTestResultOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'switch':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -441,7 +443,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Power',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'temp_set':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -454,7 +457,19 @@ mixin SceneOperationsDataHelper {
|
||||
isAutomation
|
||||
? _createAutomationTemperatureOptions()
|
||||
: _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':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -463,7 +478,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Mode',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createAcModeOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'level':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -472,7 +488,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Fan Speed',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createFanSpeedOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'child_lock':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -481,7 +498,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Child Lock',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'switch_1':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -490,7 +508,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Light 1 Switch',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'switch_2':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -499,7 +518,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Light 2 Switch',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'switch_3':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -508,7 +528,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Light 3 Switch',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
|
||||
case 'countdown_1':
|
||||
return _createSceneFunction(
|
||||
@ -522,7 +543,8 @@ mixin SceneOperationsDataHelper {
|
||||
isAutomation
|
||||
? _createAutomationCountDownOptions()
|
||||
: _createCountdownOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'countdown_2':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -535,7 +557,8 @@ mixin SceneOperationsDataHelper {
|
||||
isAutomation
|
||||
? _createAutomationCountDownOptions()
|
||||
: _createCountdownOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'countdown_3':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -548,7 +571,8 @@ mixin SceneOperationsDataHelper {
|
||||
isAutomation
|
||||
? _createAutomationCountDownOptions()
|
||||
: _createCountdownOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'switch_alarm_sound':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -557,7 +581,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Switch Alarm Sound',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'master_state':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -566,7 +591,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Master State',
|
||||
OperationDialogType.listOfOptions,
|
||||
_createMasterStateOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
case 'factory_reset':
|
||||
return _createSceneFunction(
|
||||
action,
|
||||
@ -575,7 +601,8 @@ mixin SceneOperationsDataHelper {
|
||||
'Factory Reset',
|
||||
OperationDialogType.onOff,
|
||||
_createOnOffOptions(),
|
||||
isAutomation);
|
||||
isAutomation,
|
||||
comparator ?? '==');
|
||||
default:
|
||||
throw ArgumentError(
|
||||
'Unsupported function code: ${executorProperty.functionCode}');
|
||||
@ -778,7 +805,8 @@ mixin SceneOperationsDataHelper {
|
||||
String operationName,
|
||||
OperationDialogType operationDialogType,
|
||||
List<SceneOperationalValue> operationalValues,
|
||||
bool isAutomation) {
|
||||
bool isAutomation,
|
||||
String comparator) {
|
||||
final functionValue = action.executorProperty.functionValue;
|
||||
return SceneStaticFunction(
|
||||
deviceId: action.entityId,
|
||||
@ -790,6 +818,7 @@ mixin SceneOperationsDataHelper {
|
||||
code: action.executorProperty.functionCode ?? '',
|
||||
operationDialogType: operationDialogType,
|
||||
operationalValues: operationalValues,
|
||||
comparator: comparator,
|
||||
);
|
||||
}
|
||||
|
||||
@ -913,7 +942,22 @@ mixin SceneOperationsDataHelper {
|
||||
functionCode: taskItem.code,
|
||||
functionValue: taskItem.functionValue),
|
||||
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,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
172
lib/features/scene/model/create_automation_model.dart
Normal file
172
lib/features/scene/model/create_automation_model.dart
Normal 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)';
|
||||
}
|
@ -15,6 +15,7 @@ class SceneStaticFunction {
|
||||
final dynamic functionValue;
|
||||
final String? deviceIcon;
|
||||
final OperationDialogType operationDialogType;
|
||||
final String? comparator;
|
||||
|
||||
SceneStaticFunction({
|
||||
required this.icon,
|
||||
@ -26,6 +27,7 @@ class SceneStaticFunction {
|
||||
required this.functionValue,
|
||||
this.deviceIcon,
|
||||
required this.operationDialogType,
|
||||
this.comparator,
|
||||
}) : uniqueCustomId = const Uuid().v4();
|
||||
|
||||
SceneStaticFunction copyWith({
|
||||
@ -39,6 +41,7 @@ class SceneStaticFunction {
|
||||
String? deviceIcon,
|
||||
String? deviceName,
|
||||
OperationDialogType? operationDialogType,
|
||||
String? comparator,
|
||||
}) {
|
||||
return SceneStaticFunction(
|
||||
icon: icon ?? this.icon,
|
||||
@ -50,6 +53,7 @@ class SceneStaticFunction {
|
||||
functionValue: functionValue ?? this.functionValue,
|
||||
deviceIcon: deviceIcon ?? this.deviceIcon,
|
||||
operationDialogType: operationDialogType ?? this.operationDialogType,
|
||||
comparator: comparator ?? this.comparator,
|
||||
);
|
||||
}
|
||||
|
||||
@ -63,7 +67,8 @@ class SceneStaticFunction {
|
||||
'operationName': operationName,
|
||||
'functionValue': functionValue,
|
||||
'deviceIcon': deviceIcon,
|
||||
'operationDialogType': operationDialogType.name
|
||||
'operationDialogType': operationDialogType.name,
|
||||
'comparator': comparator
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,6 +87,7 @@ class SceneStaticFunction {
|
||||
operationDialogType: map['operationDialogType'] != null
|
||||
? OperationDialogType.values.byName(map['operationDialogType'])
|
||||
: OperationDialogType.none,
|
||||
comparator: map['comparator'],
|
||||
);
|
||||
}
|
||||
|
||||
@ -92,7 +98,7 @@ class SceneStaticFunction {
|
||||
|
||||
@override
|
||||
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
|
||||
@ -106,6 +112,7 @@ class SceneStaticFunction {
|
||||
other.operationName == operationName &&
|
||||
other.functionValue == functionValue &&
|
||||
other.deviceIcon == deviceIcon &&
|
||||
other.comparator == comparator &&
|
||||
other.operationDialogType == operationDialogType &&
|
||||
listEquals(other.operationalValues, operationalValues) &&
|
||||
other.deviceId == deviceId;
|
||||
@ -120,6 +127,7 @@ class SceneStaticFunction {
|
||||
operationName.hashCode ^
|
||||
functionValue.hashCode ^
|
||||
deviceIcon.hashCode ^
|
||||
comparator.hashCode ^
|
||||
operationDialogType.hashCode ^
|
||||
operationalValues.hashCode;
|
||||
}
|
||||
|
@ -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/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.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/utils/resource_manager/strings_manager.dart';
|
||||
|
||||
class CreateSceneView extends StatelessWidget {
|
||||
@ -22,7 +21,7 @@ class CreateSceneView extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(top: 24),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
navigateToRoute(context, Routes.sceneTasksRoute);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios,
|
||||
@ -48,6 +47,9 @@ class CreateSceneView extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
context.read<CreateSceneBloc>().add(const ClearTaskListEvent());
|
||||
context
|
||||
.read<CreateSceneBloc>()
|
||||
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
|
||||
},
|
||||
),
|
||||
DefaultContainer(
|
||||
@ -71,6 +73,8 @@ class CreateSceneView extends StatelessWidget {
|
||||
context
|
||||
.read<CreateSceneBloc>()
|
||||
.add(const ClearTaskListEvent(isAutomation: true));
|
||||
context.read<CreateSceneBloc>().add(
|
||||
const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges));
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -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/light_divider.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/utils/context_extension.dart';
|
||||
|
||||
@ -53,9 +54,7 @@ class DeviceFunctionsView extends StatelessWidget
|
||||
context
|
||||
.read<CreateSceneBloc>()
|
||||
.add(AddTaskEvent(isAutomation: isAutomation));
|
||||
Navigator.popUntil(context, (route) {
|
||||
return route.settings.name == Routes.sceneTasksRoute;
|
||||
});
|
||||
navigateToRoute(context, Routes.sceneTasksRoute);
|
||||
},
|
||||
child: BodyMedium(
|
||||
text: 'Save',
|
||||
|
@ -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/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/strings_manager.dart';
|
||||
@ -16,10 +18,12 @@ class SceneRoomsTabBarDevicesView extends StatefulWidget {
|
||||
const SceneRoomsTabBarDevicesView({super.key});
|
||||
|
||||
@override
|
||||
State<SceneRoomsTabBarDevicesView> createState() => _SceneRoomsTabBarDevicesViewState();
|
||||
State<SceneRoomsTabBarDevicesView> createState() =>
|
||||
_SceneRoomsTabBarDevicesViewState();
|
||||
}
|
||||
|
||||
class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesView>
|
||||
class _SceneRoomsTabBarDevicesViewState
|
||||
extends State<SceneRoomsTabBarDevicesView>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController _tabController;
|
||||
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);
|
||||
super.initState();
|
||||
}
|
||||
@ -51,9 +56,8 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
|
||||
final value = _tabController.index;
|
||||
|
||||
/// select tab
|
||||
context
|
||||
.read<TabBarBloc>()
|
||||
.add(TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
|
||||
context.read<TabBarBloc>().add(
|
||||
TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -72,8 +76,7 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
|
||||
padding: EdgeInsets.zero,
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context);
|
||||
navigateToRoute(context, Routes.sceneTasksRoute);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.arrow_back_ios,
|
||||
|
@ -24,7 +24,7 @@ class AlertDialogSliderSteps extends StatefulWidget {
|
||||
|
||||
class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
|
||||
double? groupValue;
|
||||
int selectedToggleIndex = 0;
|
||||
int selectedToggleIndex = 1;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
@ -33,23 +33,53 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
|
||||
if (widget.isAutomation) {
|
||||
final automationTempTaskList =
|
||||
context.read<CreateSceneBloc>().automationTempTasksList;
|
||||
final automationComparatorValues =
|
||||
context.read<CreateSceneBloc>().automationComparatorValues;
|
||||
|
||||
if (automationTempTaskList.isNotEmpty) {
|
||||
for (var element in automationTempTaskList) {
|
||||
if (element.code == widget.taskItem.code) {
|
||||
groupValue = element.functionValue;
|
||||
} else {
|
||||
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
|
||||
code: widget.taskItem.code, isAutomation: widget.isAutomation));
|
||||
selectedToggleIndex =
|
||||
_comparatorToIndex(automationComparatorValues[element.code]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widget.functionValue != null) {
|
||||
setState(() {
|
||||
groupValue = widget.functionValue;
|
||||
});
|
||||
} else {
|
||||
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(() {
|
||||
selectedToggleIndex = index;
|
||||
});
|
||||
context.read<CreateSceneBloc>().add(SelectedValueEvent(
|
||||
code: widget.taskItem.code,
|
||||
isAutomation: widget.isAutomation,
|
||||
comparator: _indexToComparator(selectedToggleIndex)));
|
||||
},
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
selectedColor: Colors.white,
|
||||
@ -164,7 +198,9 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
|
||||
context.read<CreateSceneBloc>().add(SelectedValueEvent(
|
||||
value: groupValue,
|
||||
code: widget.taskItem.code,
|
||||
isAutomation: widget.isAutomation));
|
||||
isAutomation: widget.isAutomation,
|
||||
comparator:
|
||||
_indexToComparator(selectedToggleIndex)));
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1,9 +1,12 @@
|
||||
import 'package:flutter/material.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/enum/create_scene_enum.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/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/resource_manager/color_manager.dart';
|
||||
|
||||
@ -43,8 +46,7 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
|
||||
listener: (context, state) {
|
||||
if (state is CreateSceneWithTasks) {
|
||||
if (state.success == true) {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(context);
|
||||
navigateToRoute(context, Routes.homeRoute);
|
||||
context.showCustomSnackbar(
|
||||
message: 'Scene created successfully',
|
||||
icon: const Icon(
|
||||
@ -66,29 +68,31 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
|
||||
},
|
||||
builder: (context, state) {
|
||||
return DefaultButton(
|
||||
onPressed: widget.sceneName.isNotEmpty
|
||||
? () {
|
||||
final tasks = context.read<CreateSceneBloc>().tasksList;
|
||||
onPressed: () {
|
||||
final sceneBloc = context.read<CreateSceneBloc>();
|
||||
final isAutomation =
|
||||
sceneBloc.sceneType == CreateSceneEnum.deviceStatusChanges;
|
||||
|
||||
if (widget.sceneName.isNotEmpty) {
|
||||
handleSaveButtonPress(
|
||||
context,
|
||||
sceneNameController,
|
||||
tasks,
|
||||
sceneName: sceneNameController,
|
||||
actions: sceneBloc.tasksList,
|
||||
updateScene: true,
|
||||
sceneId: widget.sceneId,
|
||||
isAutomation: isAutomation,
|
||||
conditions: sceneBloc.automationTasksList,
|
||||
);
|
||||
}
|
||||
: () {
|
||||
} else {
|
||||
context.customAlertDialog(
|
||||
alertBody: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||
padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: SearchBar(
|
||||
controller: sceneNameController,
|
||||
elevation: WidgetStateProperty.all(0),
|
||||
textStyle:
|
||||
WidgetStateProperty.all(context.bodyMedium),
|
||||
textStyle: WidgetStateProperty.all(context.bodyMedium),
|
||||
hintStyle: WidgetStateProperty.all(
|
||||
context.bodyMedium.copyWith(
|
||||
fontSize: 14,
|
||||
@ -103,17 +107,19 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
|
||||
title: 'Scene Name',
|
||||
onConfirm: () {
|
||||
if (sceneNameController.text.isNotEmpty) {
|
||||
final tasks = context.read<CreateSceneBloc>().tasksList;
|
||||
handleSaveButtonPress(
|
||||
context,
|
||||
sceneNameController,
|
||||
tasks,
|
||||
sceneName: sceneNameController,
|
||||
actions: sceneBloc.tasksList,
|
||||
updateScene: false,
|
||||
sceneId: widget.sceneId,
|
||||
isAutomation: isAutomation,
|
||||
conditions: sceneBloc.automationTasksList,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
customButtonStyle: ButtonStyle(
|
||||
backgroundColor: WidgetStateProperty.all<Color>(
|
||||
|
@ -1,18 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/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/widgets/if_then_containers/then_added_tasks.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/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_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/navigation/routing_constants.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/strings_manager.dart';
|
||||
|
||||
class IFDefaultContainer extends StatelessWidget {
|
||||
const IFDefaultContainer({
|
||||
@ -27,30 +33,101 @@ class IFDefaultContainer extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
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',
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ColorsManager.primaryTextColor,
|
||||
),
|
||||
),
|
||||
trailingWidget: GestureDetector(
|
||||
onTap: () => Navigator.pushNamed(
|
||||
BlocBuilder<CreateSceneBloc, CreateSceneState>(
|
||||
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,
|
||||
Routes.sceneControlDevicesRoute,
|
||||
arguments: SceneSettingsRouteArguments(
|
||||
sceneType: CreateSceneEnum.deviceStatusChanges.name,
|
||||
sceneType:
|
||||
CreateSceneEnum.deviceStatusChanges.name,
|
||||
sceneId: '',
|
||||
sceneName: '',
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: SvgPicture.asset(
|
||||
Assets.addIcon,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
ColorsManager.primaryColor,
|
||||
colorFilter: ColorFilter.mode(
|
||||
isClickable
|
||||
? ColorsManager.primaryColor
|
||||
: ColorsManager.greyColor,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
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(
|
||||
titleString: '+ Add Condition',
|
||||
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,
|
||||
Routes.sceneControlDevicesRoute,
|
||||
arguments: SceneSettingsRouteArguments(
|
||||
@ -85,8 +178,9 @@ class IFDefaultContainer extends StatelessWidget {
|
||||
sceneId: '',
|
||||
sceneName: '',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
|
@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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/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/scene_list_tile.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/generated/assets.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';
|
||||
|
||||
class ThenDefaultContainer extends StatelessWidget {
|
||||
@ -35,17 +38,29 @@ class ThenDefaultContainer extends StatelessWidget {
|
||||
color: ColorsManager.primaryTextColor,
|
||||
),
|
||||
),
|
||||
trailingWidget: GestureDetector(
|
||||
onTap: () => context.customBottomSheet(
|
||||
trailingWidget: BlocBuilder<CreateSceneBloc, CreateSceneState>(
|
||||
builder: (context, state) {
|
||||
bool isClickable = false;
|
||||
if (state is AddSceneTask) {
|
||||
isClickable = state.tasksList.isNotEmpty;
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: isClickable
|
||||
? () => context.customBottomSheet(
|
||||
child: const CustomBottomSheetWidget(),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: SvgPicture.asset(
|
||||
Assets.addIcon,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
ColorsManager.primaryColor,
|
||||
colorFilter: ColorFilter.mode(
|
||||
isClickable
|
||||
? ColorsManager.primaryColor
|
||||
: ColorsManager.greyColor,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
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(
|
||||
titleString: '+ Add Task',
|
||||
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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
|
17
lib/navigation/navigate_to_route.dart
Normal file
17
lib/navigation/navigate_to_route.dart
Normal 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);
|
||||
}
|
||||
}
|
@ -135,6 +135,8 @@ abstract class ApiEndpoints {
|
||||
static const String triggerScene =
|
||||
'$baseUrl/scene/tap-to-run/trigger/{sceneId}';
|
||||
|
||||
static const String createAutomation = '$baseUrl/automation';
|
||||
|
||||
/// GET
|
||||
static const String getUnitScenes = '$baseUrl/scene/tap-to-run/{unitUuid}';
|
||||
|
||||
|
@ -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/scene_details_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 {
|
||||
try {
|
||||
final response = await _httpService.get(
|
||||
|
@ -65,6 +65,7 @@ extension ContextExtension on BuildContext {
|
||||
required String title,
|
||||
required VoidCallback onConfirm,
|
||||
VoidCallback? onDismiss,
|
||||
bool? hideConfirmButton,
|
||||
}) {
|
||||
showDialog(
|
||||
context: this,
|
||||
@ -110,7 +111,8 @@ extension ContextExtension on BuildContext {
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
Row(
|
||||
hideConfirmButton != true
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
GestureDetector(
|
||||
@ -137,12 +139,29 @@ extension ContextExtension on BuildContext {
|
||||
child: BodyMedium(
|
||||
text: 'Confirm',
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
Reference in New Issue
Block a user