connected all apis , create functionality is working

This commit is contained in:
ashrafzarkanisala
2024-06-27 02:35:50 +03:00
parent 9fe25b9bd3
commit 17881694e0
23 changed files with 793 additions and 154 deletions

View File

@ -3,21 +3,24 @@ 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/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';
part 'create_scene_event.dart'; part 'create_scene_event.dart';
part 'create_scene_state.dart'; part 'create_scene_state.dart';
class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState> { class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState> {
CreateSceneBloc() : super(CreateSceneInitial()) { CreateSceneBloc() : super(CreateSceneInitial()) {
on<CreateSceneEvent>((event, emit) => null as FutureOr<void>); on<CreateSceneWithTasksEvent>(_createSceneWithTasks);
on<AddTaskEvent>(_onAddSceneTask); on<AddTaskEvent>(_onAddSceneTask);
on<SelectedValueEvent>(_selectedValue); on<SelectedValueEvent>(_selectedValue);
on<RemoveTaskEvent>(_removeTaskById); on<RemoveTaskEvent>(_removeTaskById);
on<ClearTaskListEvent>(_clearTaskList);
} }
List<SceneStaticFunction> tasksList = []; List<SceneStaticFunction> tasksList = [];
String selectedValue = ''; dynamic selectedValue;
FutureOr<void> _onAddSceneTask( FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) { AddTaskEvent event, Emitter<CreateSceneState> emit) {
@ -58,4 +61,27 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState> {
} }
} }
} }
FutureOr<void> _createSceneWithTasks(
CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
try {
final response = await SceneApi.createScene(event.createSceneModel);
if (response['success'] == true) {
tasksList.clear();
emit(const CreateSceneWithTasks(success: true));
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
} catch (e) {
emit(CreateSceneError(message: e.toString()));
emit(AddSceneTask(tasksList: tasksList));
}
}
FutureOr<void> _clearTaskList(
ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
tasksList.clear();
emit(AddSceneTask(tasksList: tasksList));
}
} }

View File

@ -28,12 +28,12 @@ class AddTaskEvent extends CreateSceneEvent {
} }
class SelectedValueEvent extends CreateSceneEvent { class SelectedValueEvent extends CreateSceneEvent {
final String value; final dynamic value;
const SelectedValueEvent({required this.value}); const SelectedValueEvent({this.value});
@override @override
List<Object> get props => [value]; List<Object> get props => [value!];
} }
class RemoveTaskEvent extends CreateSceneEvent { class RemoveTaskEvent extends CreateSceneEvent {
@ -44,3 +44,18 @@ class RemoveTaskEvent extends CreateSceneEvent {
@override @override
List<Object> get props => [taskId]; List<Object> get props => [taskId];
} }
class CreateSceneWithTasksEvent extends CreateSceneEvent {
final CreateSceneModel createSceneModel;
const CreateSceneWithTasksEvent({required this.createSceneModel});
@override
List<Object> get props => [createSceneModel];
}
class ClearTaskListEvent extends CreateSceneEvent {
const ClearTaskListEvent();
@override
List<Object> get props => [];
}

View File

@ -11,6 +11,14 @@ final class CreateSceneInitial extends CreateSceneState {}
class CreateSceneLoading extends CreateSceneState {} class CreateSceneLoading extends CreateSceneState {}
class CreateSceneError extends CreateSceneState {
final String message;
const CreateSceneError({required this.message});
@override
List<Object> get props => [message];
}
class AddSceneTask extends CreateSceneState { class AddSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tasksList; final List<SceneStaticFunction> tasksList;
const AddSceneTask({required this.tasksList}); const AddSceneTask({required this.tasksList});
@ -20,9 +28,17 @@ class AddSceneTask extends CreateSceneState {
} }
class SelectedTaskValueState extends CreateSceneState { class SelectedTaskValueState extends CreateSceneState {
final String value; final dynamic value;
const SelectedTaskValueState({required this.value}); const SelectedTaskValueState({required this.value});
@override @override
List<Object> get props => [value]; List<Object> get props => [value];
} }
class CreateSceneWithTasks extends CreateSceneState {
final bool success;
const CreateSceneWithTasks({required this.success});
@override
List<Object> get props => [success];
}

View File

@ -1,28 +1,48 @@
import 'dart:async';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/model/scene_model.dart'; import 'package:syncrow_app/features/scene/model/scene_model.dart';
import 'package:syncrow_app/services/api/scene_api.dart';
part 'scene_state.dart'; part 'scene_state.dart';
class SceneBloc extends Bloc<SceneEvent, SceneState> { class SceneBloc extends Bloc<SceneEvent, SceneState> {
SceneBloc() : super(SceneInitial()) { SceneBloc() : super(SceneInitial()) {
on<LoadScenes>(_onLoadScenes); on<LoadScenes>(_onLoadScenes);
on<SceneTrigger>(_sceneTrigger);
} }
void _onLoadScenes(LoadScenes event, Emitter<SceneState> emit) { FutureOr<void> _onLoadScenes(
LoadScenes event, Emitter<SceneState> emit) async {
emit(SceneLoading()); emit(SceneLoading());
try { try {
final scenes = _loadScenes(); final scenes = await SceneApi.getScenesByUnitId(event.unitId);
emit(SceneLoaded(scenes)); if (scenes.isNotEmpty) {
} catch (_) { emit(SceneLoaded(scenes));
emit(SceneError()); } else {
emit(SceneTriggerError(message: 'Something went wrong'));
}
} catch (e) {
emit(SceneError(message: e.toString()));
} }
} }
List<SceneModel> _loadScenes() { FutureOr<void> _sceneTrigger(
//TODO: Load scenes SceneTrigger event, Emitter<SceneState> emit) async {
return []; emit(SceneTriggerLoading());
try {
final success = await SceneApi.triggerScene(event.sceneId);
if (success) {
emit(SceneTriggerState(success: true));
} else {
emit(SceneTriggerError(message: 'Something went wrong'));
}
} catch (e) {
emit(SceneTriggerError(message: e.toString()));
}
} }
} }

View File

@ -1,4 +1,3 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
abstract class SceneEvent extends Equatable { abstract class SceneEvent extends Equatable {
@ -6,4 +5,20 @@ abstract class SceneEvent extends Equatable {
List<Object> get props => []; List<Object> get props => [];
} }
class LoadScenes extends SceneEvent {} class LoadScenes extends SceneEvent {
final String unitId;
LoadScenes(this.unitId);
@override
List<Object> get props => [unitId];
}
class SceneTrigger extends SceneEvent {
final String sceneId;
SceneTrigger(this.sceneId);
@override
List<Object> get props => [sceneId];
}

View File

@ -18,4 +18,31 @@ class SceneLoaded extends SceneState {
List<Object> get props => [scenes]; List<Object> get props => [scenes];
} }
class SceneError extends SceneState {} class SceneError extends SceneState {
final String message;
SceneError({required this.message});
@override
List<Object> get props => [message];
}
class SceneTriggerState extends SceneState {
final bool success;
SceneTriggerState({required this.success});
@override
List<Object> get props => [success];
}
class SceneTriggerLoading extends SceneState {}
class SceneTriggerError extends SceneState {
final String message;
SceneTriggerError({required this.message});
@override
List<Object> get props => [message];
}

View File

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
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/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/utils/context_extension.dart';
mixin SceneLogicHelper {
bool isOnlyDelayOrDelayLast(List<SceneStaticFunction> tasks) {
final lastTask = tasks.last;
return tasks.every((task) => task.code == 'delay') ||
lastTask.code == 'delay';
}
void handleSaveButtonPress(
BuildContext context,
TextEditingController sceneNameController,
List<SceneStaticFunction> tasks,
) {
if (isOnlyDelayOrDelayLast(tasks)) {
// Show snackbar indicating restriction
context.showCustomSnackbar(
message: 'Only a single delay or delay-last operations are allowed.',
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
} else {
final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
sceneName: sceneNameController.text,
decisionExpr: 'and',
actions: List.generate(
tasks.length,
(index) {
final task = tasks[index];
if (task.code == 'delay') {
return CreateSceneAction(
entityId: tasks[index].deviceId,
actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.operationalValues.first.value,
delaySeconds: 0,
),
);
}
return CreateSceneAction(
entityId: task.deviceId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.operationalValues.first.value,
delaySeconds: 0,
),
);
},
),
);
context
.read<CreateSceneBloc>()
.add(CreateSceneWithTasksEvent(createSceneModel: createSceneModel));
Navigator.pop(context);
}
}
}

View File

@ -4,7 +4,7 @@ import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
mixin SceneHelper { mixin SceneOperationsDataHelper {
List<SceneStaticFunction> getFunctionsWithIcons({ List<SceneStaticFunction> getFunctionsWithIcons({
DeviceType? type, DeviceType? type,
required List<FunctionModel> functions, required List<FunctionModel> functions,
@ -79,25 +79,25 @@ mixin SceneHelper {
code: 'sensitivity', code: 'sensitivity',
operationalValues: [ operationalValues: [
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "1"), icon: Assets.assetsSensitivityOperationIcon, value: 1),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "2"), icon: Assets.assetsSensitivityOperationIcon, value: 2),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "3"), icon: Assets.assetsSensitivityOperationIcon, value: 3),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "4"), icon: Assets.assetsSensitivityOperationIcon, value: 4),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "5"), icon: Assets.assetsSensitivityOperationIcon, value: 5),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "6"), icon: Assets.assetsSensitivityOperationIcon, value: 6),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "7"), icon: Assets.assetsSensitivityOperationIcon, value: 7),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "8"), icon: Assets.assetsSensitivityOperationIcon, value: 8),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "9"), icon: Assets.assetsSensitivityOperationIcon, value: 9),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon, value: "10"), icon: Assets.assetsSensitivityOperationIcon, value: 10),
], ],
), ),
]; ];
@ -151,10 +151,15 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 1 Switch', operationName: 'Light 1 Switch',
code: 'switch_1', code: 'switch_1',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: Assets.assetsAcPower, value: "ON"),
SceneOperationalValue(icon: Assets.assetsAcPowerOFF, value: "OFF"),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSceneRefresh, value: "Reverse Switch"), icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
SceneOperationalValue(
icon: Assets.assetsSceneRefresh,
description: "Reverse Switch",
value: false,
),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -164,10 +169,15 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 2 Switch', operationName: 'Light 2 Switch',
code: 'switch_2', code: 'switch_2',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: Assets.assetsAcPower, value: "ON"),
SceneOperationalValue(icon: Assets.assetsAcPowerOFF, value: "OFF"),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSceneRefresh, value: "Reverse Switch"), icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
SceneOperationalValue(
icon: Assets.assetsSceneRefresh,
description: "Reverse Switch",
value: false,
),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -177,10 +187,15 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 3 Switch', operationName: 'Light 3 Switch',
code: 'switch_3', code: 'switch_3',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: Assets.assetsAcPower, value: "ON"),
SceneOperationalValue(icon: Assets.assetsAcPowerOFF, value: "OFF"),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSceneRefresh, value: "Reverse Switch"), icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
SceneOperationalValue(
icon: Assets.assetsSceneRefresh,
description: "Reverse Switch",
value: false,
),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -190,7 +205,7 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 1 CountDown', operationName: 'Light 1 CountDown',
code: 'countdown_1', code: 'countdown_1',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: '', value: "0"), SceneOperationalValue(icon: '', value: 0),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -200,7 +215,7 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 2 CountDown', operationName: 'Light 2 CountDown',
code: 'countdown_1', code: 'countdown_1',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: '', value: "0"), SceneOperationalValue(icon: '', value: 0),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -210,7 +225,7 @@ List<SceneStaticFunction> threeGangFunctions(
operationName: 'Light 3 CountDown', operationName: 'Light 3 CountDown',
code: 'countdown_1', code: 'countdown_1',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: '', value: "0"), SceneOperationalValue(icon: '', value: 0),
], ],
), ),
]; ];
@ -229,8 +244,16 @@ List<SceneStaticFunction> acFunctions(
operationName: 'Power', operationName: 'Power',
code: 'switch', code: 'switch',
operationalValues: [ operationalValues: [
SceneOperationalValue(icon: Assets.assetsAcPower, value: "ON"), SceneOperationalValue(
SceneOperationalValue(icon: Assets.assetsAcPowerOFF, value: "OFF"), icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -242,15 +265,18 @@ List<SceneStaticFunction> acFunctions(
operationalValues: [ operationalValues: [
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcCooling, icon: Assets.assetsAcCooling,
value: AcValuesEnums.Cooling.name, description: AcValuesEnums.Cooling.name,
value: TempModes.cold.name,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcHeating, icon: Assets.assetsAcHeating,
value: AcValuesEnums.Heating.name, description: AcValuesEnums.Heating.name,
value: TempModes.hot.name,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsFanSpeed, icon: Assets.assetsFanSpeed,
value: AcValuesEnums.Ventilation.name, description: AcValuesEnums.Ventilation.name,
value: TempModes.wind.name,
), ),
], ],
), ),
@ -262,7 +288,10 @@ List<SceneStaticFunction> acFunctions(
code: 'temp_set', code: 'temp_set',
operationalValues: [ operationalValues: [
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsCelsiusDegrees, value: "COOL TO"), icon: Assets.assetsCelsiusDegrees,
value: 0,
description: 'COOL TO',
),
], ],
), ),
SceneStaticFunction( SceneStaticFunction(
@ -274,19 +303,23 @@ List<SceneStaticFunction> acFunctions(
operationalValues: [ operationalValues: [
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcFanLow, icon: Assets.assetsAcFanLow,
value: ValueACRange.LOW.name, description: ValueACRange.LOW.name,
value: FanSpeeds.low.name,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcFanMiddle, icon: Assets.assetsAcFanMiddle,
value: ValueACRange.MIDDLE.name, description: ValueACRange.MIDDLE.name,
value: FanSpeeds.middle.name,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcFanHigh, icon: Assets.assetsAcFanHigh,
value: ValueACRange.HIGH.name, description: ValueACRange.HIGH.name,
value: FanSpeeds.high.name,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsAcFanAuto, icon: Assets.assetsAcFanAuto,
value: ValueACRange.AUTO.name, description: ValueACRange.AUTO.name,
value: FanSpeeds.auto.name,
), ),
], ],
), ),
@ -299,11 +332,13 @@ List<SceneStaticFunction> acFunctions(
operationalValues: [ operationalValues: [
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSceneChildLock, icon: Assets.assetsSceneChildLock,
value: 'Lock', description: 'Lock',
value: true,
), ),
SceneOperationalValue( SceneOperationalValue(
icon: Assets.assetsSceneChildUnlock, icon: Assets.assetsSceneChildUnlock,
value: 'Unlock', description: 'Unlock',
value: false,
), ),
], ],
), ),

View File

@ -0,0 +1,222 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
class CreateSceneModel {
/*
{
"unitUuid": "string",
"sceneName": "string",
"decisionExpr": "string",
"actions": [
{
"entityId": "string",
"actionExecutor": "string",
"executorProperty": {
"functionCode": "string",
"functionValue": {},
"delaySeconds": 0
}
}
]
}
*/
String unitUuid;
String sceneName;
String decisionExpr;
List<CreateSceneAction> actions;
CreateSceneModel({
required this.unitUuid,
required this.sceneName,
required this.decisionExpr,
required this.actions,
});
CreateSceneModel copyWith({
String? unitUuid,
String? sceneName,
String? decisionExpr,
List<CreateSceneAction>? actions,
}) {
return CreateSceneModel(
unitUuid: unitUuid ?? this.unitUuid,
sceneName: sceneName ?? this.sceneName,
decisionExpr: decisionExpr ?? this.decisionExpr,
actions: actions ?? this.actions,
);
}
Map<String, dynamic> toMap() {
return {
'unitUuid': unitUuid,
'sceneName': sceneName,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
};
}
factory CreateSceneModel.fromMap(Map<String, dynamic> map) {
return CreateSceneModel(
unitUuid: map['unitUuid'] ?? '',
sceneName: map['sceneName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<CreateSceneAction>.from(
map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
);
}
String toJson() => json.encode(toMap());
factory CreateSceneModel.fromJson(String source) =>
CreateSceneModel.fromMap(json.decode(source));
@override
String toString() {
return 'CreateSceneModel(unitUuid: $unitUuid, sceneName: $sceneName, decisionExpr: $decisionExpr, actions: $actions)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneModel &&
other.unitUuid == unitUuid &&
other.sceneName == sceneName &&
other.decisionExpr == decisionExpr &&
listEquals(other.actions, actions);
}
@override
int get hashCode {
return unitUuid.hashCode ^
sceneName.hashCode ^
decisionExpr.hashCode ^
actions.hashCode;
}
}
class CreateSceneAction {
String entityId;
String actionExecutor;
CreateSceneExecutorProperty executorProperty;
CreateSceneAction({
required this.entityId,
required this.actionExecutor,
required this.executorProperty,
});
CreateSceneAction copyWith({
String? entityId,
String? actionExecutor,
CreateSceneExecutorProperty? executorProperty,
}) {
return CreateSceneAction(
entityId: entityId ?? this.entityId,
actionExecutor: actionExecutor ?? this.actionExecutor,
executorProperty: executorProperty ?? this.executorProperty,
);
}
Map<String, dynamic> toMap() {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
'executorProperty': executorProperty.toMap(),
};
}
factory CreateSceneAction.fromMap(Map<String, dynamic> map) {
return CreateSceneAction(
entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '',
executorProperty:
CreateSceneExecutorProperty.fromMap(map['executorProperty']),
);
}
String toJson() => json.encode(toMap());
factory CreateSceneAction.fromJson(String source) =>
CreateSceneAction.fromMap(json.decode(source));
@override
String toString() =>
'CreateSceneAction(entityId: $entityId, actionExecutor: $actionExecutor, executorProperty: $executorProperty)';
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneAction &&
other.entityId == entityId &&
other.actionExecutor == actionExecutor &&
other.executorProperty == executorProperty;
}
@override
int get hashCode =>
entityId.hashCode ^ actionExecutor.hashCode ^ executorProperty.hashCode;
}
class CreateSceneExecutorProperty {
String functionCode;
dynamic functionValue;
int delaySeconds;
CreateSceneExecutorProperty({
required this.functionCode,
required this.functionValue,
required this.delaySeconds,
});
CreateSceneExecutorProperty copyWith({
String? functionCode,
dynamic functionValue,
int? delaySeconds,
}) {
return CreateSceneExecutorProperty(
functionCode: functionCode ?? this.functionCode,
functionValue: functionValue ?? this.functionValue,
delaySeconds: delaySeconds ?? this.delaySeconds,
);
}
Map<String, dynamic> toMap() {
return {
'functionCode': functionCode,
'functionValue': functionValue,
'delaySeconds': delaySeconds,
};
}
factory CreateSceneExecutorProperty.fromMap(Map<String, dynamic> map) {
return CreateSceneExecutorProperty(
functionCode: map['functionCode'] ?? '',
functionValue: map['functionValue'] ?? '',
delaySeconds: map['delaySeconds']?.toInt() ?? 0,
);
}
String toJson() => json.encode(toMap());
factory CreateSceneExecutorProperty.fromJson(String source) =>
CreateSceneExecutorProperty.fromMap(json.decode(source));
@override
String toString() =>
'CreateSceneExecutorProperty(functionCode: $functionCode, functionValue: $functionValue, delaySeconds: $delaySeconds)';
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CreateSceneExecutorProperty &&
other.functionCode == functionCode &&
other.functionValue == functionValue &&
other.delaySeconds == delaySeconds;
}
@override
int get hashCode =>
functionCode.hashCode ^ functionValue.hashCode ^ delaySeconds.hashCode;
}

View File

@ -1,46 +1,54 @@
import 'dart:convert';
class SceneModel { class SceneModel {
final String id; final String id;
final String name; final String name;
final String description; final Status status;
final String imageUrl; final Type type;
final String location;
final String type;
final String rating;
final String price;
final String duration;
final String date;
final String time;
final String status;
SceneModel({ SceneModel({
required this.id, required this.id,
required this.name, required this.name,
required this.description,
required this.imageUrl,
required this.location,
required this.type,
required this.rating,
required this.price,
required this.duration,
required this.date,
required this.time,
required this.status, required this.status,
required this.type,
}); });
factory SceneModel.fromJson(Map<String, dynamic> json) { factory SceneModel.fromRawJson(String str) =>
return SceneModel( SceneModel.fromJson(json.decode(str));
id: json['id'],
name: json['name'], String toRawJson() => json.encode(toJson());
description: json['description'],
imageUrl: json['imageUrl'], factory SceneModel.fromJson(Map<String, dynamic> json) => SceneModel(
location: json['location'], id: json["id"],
type: json['type'], name: json["name"],
rating: json['rating'], status: statusValues.map[json["status"]]!,
price: json['price'], type: typeValues.map[json["type"]]!,
duration: json['duration'], );
date: json['date'],
time: json['time'], Map<String, dynamic> toJson() => {
status: json['status'], "id": id,
); "name": name,
"status": statusValues.reverse[status],
"type": typeValues.reverse[type],
};
}
enum Status { ENABLE }
final statusValues = EnumValues({"enable": Status.ENABLE});
enum Type { TAP_TO_RUN }
final typeValues = EnumValues({"tap_to_run": Type.TAP_TO_RUN});
class EnumValues<T> {
Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
reverseMap = map.map((k, v) => MapEntry(v, k));
return reverseMap;
} }
} }

View File

@ -99,34 +99,36 @@ class SceneStaticFunction {
class SceneOperationalValue { class SceneOperationalValue {
final String icon; final String icon;
final String value; final dynamic value;
final String? description;
SceneOperationalValue({ SceneOperationalValue({
required this.icon, required this.icon,
required this.value, required this.value,
this.description,
}); });
SceneOperationalValue copyWith({ SceneOperationalValue copyWith({
String? icon, String? icon,
String? value, dynamic value,
String? description,
}) { }) {
return SceneOperationalValue( return SceneOperationalValue(
icon: icon ?? this.icon, icon: icon ?? this.icon,
value: value ?? this.value, value: value ?? this.value,
description: description ?? this.description,
); );
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {'icon': icon, 'value': value, 'description': description};
'icon': icon,
'value': value,
};
} }
factory SceneOperationalValue.fromMap(Map<String, dynamic> map) { factory SceneOperationalValue.fromMap(Map<String, dynamic> map) {
return SceneOperationalValue( return SceneOperationalValue(
icon: map['icon'] ?? '', icon: map['icon'] ?? '',
value: map['value'] ?? '', value: map['value'],
description: map['description'],
); );
} }
@ -137,7 +139,7 @@ class SceneOperationalValue {
@override @override
String toString() => String toString() =>
'StaticFunctionOperationHelper(icon: $icon, value: $value)'; 'StaticFunctionOperationHelper(icon: $icon, value: $value, description: $description)';
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
@ -145,9 +147,10 @@ class SceneOperationalValue {
return other is SceneOperationalValue && return other is SceneOperationalValue &&
other.icon == icon && other.icon == icon &&
other.description == description &&
other.value == value; other.value == value;
} }
@override @override
int get hashCode => icon.hashCode ^ value.hashCode; int get hashCode => icon.hashCode ^ value.hashCode ^ description.hashCode;
} }

View File

@ -1,16 +0,0 @@
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
class SceneRepo {
Future<bool> deviceControl({
required DeviceControlModel controlModel,
required String deviceId,
}) async {
final response = await DevicesAPI.controlDevice(controlModel, deviceId);
if (response['success'] == true) {
return true;
} else {
return false;
}
}
}

View File

@ -35,7 +35,7 @@ class CreateSceneView extends StatelessWidget {
Routes.sceneTasksRoute, Routes.sceneTasksRoute,
arguments: CreateSceneEnum.tabToRun, arguments: CreateSceneEnum.tabToRun,
); );
context.read<CreateSceneBloc>().tasksList.clear(); context.read<CreateSceneBloc>().add(ClearTaskListEvent());
}, },
), ),
DefaultContainer( DefaultContainer(
@ -53,3 +53,5 @@ class CreateSceneView extends StatelessWidget {
); );
} }
} }

View File

@ -3,11 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.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/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.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/helper/scene_helper.dart'; import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.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_dialog_countdown.dart'; import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart';
import 'package:syncrow_app/features/scene/widgets/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_dialog_temperature_body.dart'; import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_temperature_body.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/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
@ -18,12 +18,13 @@ 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';
class DeviceFunctionsView extends StatelessWidget with SceneHelper { class DeviceFunctionsView extends StatelessWidget
with SceneOperationsDataHelper {
const DeviceFunctionsView({super.key}); const DeviceFunctionsView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
/// this whole widget i need to revamp it later /// this whole widget needs a refactor later
/// ///
/// static functions based on type /// static functions based on type
final device = ModalRoute.of(context)?.settings.arguments as DeviceModel; final device = ModalRoute.of(context)?.settings.arguments as DeviceModel;

View File

@ -1,10 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/widgets/create_scene_save_button.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/if_container.dart'; import 'package:syncrow_app/features/scene/widgets/if_then_containers/if_container.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_container.dart'; import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.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/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/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -60,18 +59,7 @@ class SceneTasksView extends StatelessWidget {
left: 40, left: 40,
child: SizedBox( child: SizedBox(
width: context.width * 0.8, width: context.width * 0.8,
child: DefaultButton( child: const CreateSceneSaveButton(),
onPressed: () {},
customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
ColorsManager.primaryColorWithOpacity,
),
),
child: BodyLarge(
text: 'Save',
style: context.bodyLarge.copyWith(color: Colors.white),
),
),
), ),
) )
], ],

View File

@ -48,8 +48,10 @@ class SceneView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.spaceBetween, CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Image.asset( Image.asset(
height: 50, height: 50,
@ -85,8 +87,10 @@ class SceneView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.spaceBetween, CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Image.asset( Image.asset(
height: 50, height: 50,

View File

@ -6,7 +6,7 @@ import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.d
class AlertDialogCountdown extends StatefulWidget { class AlertDialogCountdown extends StatefulWidget {
const AlertDialogCountdown({super.key, required this.durationValue}); const AlertDialogCountdown({super.key, required this.durationValue});
final String durationValue; final int durationValue;
@override @override
State<AlertDialogCountdown> createState() => _AlertDialogCountdownState(); State<AlertDialogCountdown> createState() => _AlertDialogCountdownState();
@ -16,7 +16,7 @@ class _AlertDialogCountdownState extends State<AlertDialogCountdown> {
int durationInSeconds = 0; int durationInSeconds = 0;
// Convert seconds to Duration. // Convert seconds to Duration.
Duration get duration => Duration get duration =>
Duration(seconds: int.tryParse(widget.durationValue) ?? 0); Duration(seconds: widget.durationValue) ;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
@ -32,7 +32,7 @@ class _AlertDialogCountdownState extends State<AlertDialogCountdown> {
}); });
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(SelectedValueEvent(value: newDuration.inSeconds.toString())); .add(SelectedValueEvent(value: newDuration.inSeconds));
}, },
), ),
); );

View File

@ -21,7 +21,7 @@ class AlertDialogFunctionsOperationsBody extends StatefulWidget {
class _AlertDialogFunctionsOperationsBodyState class _AlertDialogFunctionsOperationsBodyState
extends State<AlertDialogFunctionsOperationsBody> { extends State<AlertDialogFunctionsOperationsBody> {
String? groupValue = ""; dynamic groupValue;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( return SingleChildScrollView(
@ -36,7 +36,7 @@ class _AlertDialogFunctionsOperationsBodyState
minLeadingWidth: 15, minLeadingWidth: 15,
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
assetPath: operation.icon, assetPath: operation.icon,
titleString: operation.value, titleString: operation.description.toString(),
textAlign: TextAlign.start, textAlign: TextAlign.start,
trailingWidget: Radio( trailingWidget: Radio(
value: operation.value, value: operation.value,
@ -58,7 +58,7 @@ class _AlertDialogFunctionsOperationsBodyState
}); });
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(SelectedValueEvent(value: groupValue!)); .add(SelectedValueEvent(value: groupValue));
}, },
); );
}, },

View File

@ -40,7 +40,7 @@ class _AlertDialogTemperatureBodyState
}); });
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(SelectedValueEvent(value: temperature.toString())); .add(SelectedValueEvent(value: temperature * 10));
}, },
icon: const Icon( icon: const Icon(
Icons.remove, Icons.remove,
@ -70,7 +70,8 @@ class _AlertDialogTemperatureBodyState
], ],
), ),
subtitle: BodyLarge( subtitle: BodyLarge(
text: widget.functions[widget.index].operationalValues[0].value, text: widget.functions[widget.index].operationalValues[0].description
.toString(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
trailing: IconButton( trailing: IconButton(
@ -82,7 +83,7 @@ class _AlertDialogTemperatureBodyState
}); });
context context
.read<CreateSceneBloc>() .read<CreateSceneBloc>()
.add(SelectedValueEvent(value: temperature.toString())); .add(SelectedValueEvent(value: temperature * 10));
}, },
icon: const Icon( icon: const Icon(
Icons.add, Icons.add,

View File

@ -0,0 +1,106 @@
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/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/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CreateSceneSaveButton extends StatefulWidget {
const CreateSceneSaveButton({
super.key,
});
@override
State<CreateSceneSaveButton> createState() => _CreateSceneSaveButtonState();
}
class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
with SceneLogicHelper {
late TextEditingController sceneNameController;
@override
void initState() {
sceneNameController = TextEditingController();
super.initState();
}
@override
void dispose() {
sceneNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<CreateSceneBloc, CreateSceneState>(
listener: (context, state) {
if (state is CreateSceneWithTasks) {
if (state.success == true) {
context.showCustomSnackbar(
message: 'Scene created successfully',
icon: const Icon(
Icons.check,
color: Colors.green,
),
);
sceneNameController.text = '';
}
} else if (state is CreateSceneError) {
context.showCustomSnackbar(
message: state.message,
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
}
},
builder: (context, state) {
return DefaultButton(
onPressed: () {
context.customAlertDialog(
alertBody: Padding(
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),
hintStyle: WidgetStateProperty.all(
context.bodyMedium.copyWith(
fontSize: 14,
color: ColorsManager.secondaryTextColor),
),
hintText: 'Enter scene name',
backgroundColor:
WidgetStateProperty.all(ColorsManager.backgroundColor),
),
),
),
title: 'Scene Name',
onConfirm: () {
if (sceneNameController.text.isNotEmpty) {
final tasks = context.read<CreateSceneBloc>().tasksList;
handleSaveButtonPress(context, sceneNameController, tasks);
}
},
);
},
customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
ColorsManager.primaryColorWithOpacity,
),
),
isLoading: state is CreateSceneLoading,
child: BodyLarge(
text: 'Save',
style: context.bodyLarge.copyWith(color: Colors.white),
),
);
},
);
}
}

View File

@ -9,7 +9,8 @@ abstract class ApiEndpoints {
static const String deleteUser = '$baseUrl/authentication/user/delete/{id}'; static const String deleteUser = '$baseUrl/authentication/user/delete/{id}';
static const String sendOtp = '$baseUrl/authentication/user/send-otp'; static const String sendOtp = '$baseUrl/authentication/user/send-otp';
static const String verifyOtp = '$baseUrl/authentication/user/verify-otp'; static const String verifyOtp = '$baseUrl/authentication/user/verify-otp';
static const String forgetPassword = '$baseUrl/authentication/user/forget-password'; static const String forgetPassword =
'$baseUrl/authentication/user/forget-password';
////////////////////////////////////// Spaces /////////////////////////////////////// ////////////////////////////////////// Spaces ///////////////////////////////////////
@ -19,10 +20,12 @@ abstract class ApiEndpoints {
static const String addCommunityToUser = '$baseUrl/community/user'; static const String addCommunityToUser = '$baseUrl/community/user';
//GET //GET
static const String communityByUuid = '$baseUrl/community/{communityUuid}'; static const String communityByUuid = '$baseUrl/community/{communityUuid}';
static const String communityChild = '$baseUrl/community/child/{communityUuid}'; static const String communityChild =
'$baseUrl/community/child/{communityUuid}';
static const String communityUser = '$baseUrl/community/user/{userUuid}'; static const String communityUser = '$baseUrl/community/user/{userUuid}';
//PUT //PUT
static const String renameCommunity = '$baseUrl/community/rename/{communityUuid}'; static const String renameCommunity =
'$baseUrl/community/rename/{communityUuid}';
///Building Module ///Building Module
//POST //POST
@ -31,10 +34,12 @@ abstract class ApiEndpoints {
//GET //GET
static const String buildingByUuid = '$baseUrl/building/{buildingUuid}'; static const String buildingByUuid = '$baseUrl/building/{buildingUuid}';
static const String buildingChild = '$baseUrl/building/child/{buildingUuid}'; static const String buildingChild = '$baseUrl/building/child/{buildingUuid}';
static const String buildingParent = '$baseUrl/building/parent/{buildingUuid}'; static const String buildingParent =
'$baseUrl/building/parent/{buildingUuid}';
static const String buildingUser = '$baseUrl/building/user/{userUuid}'; static const String buildingUser = '$baseUrl/building/user/{userUuid}';
//PUT //PUT
static const String renameBuilding = '$baseUrl/building/rename/{buildingUuid}'; static const String renameBuilding =
'$baseUrl/building/rename/{buildingUuid}';
///Floor Module ///Floor Module
//POST //POST
@ -57,7 +62,8 @@ abstract class ApiEndpoints {
static const String unitChild = '$baseUrl/unit/child/'; static const String unitChild = '$baseUrl/unit/child/';
static const String unitParent = '$baseUrl/unit/parent/{unitUuid}'; static const String unitParent = '$baseUrl/unit/parent/{unitUuid}';
static const String unitUser = '$baseUrl/unit/user/'; static const String unitUser = '$baseUrl/unit/user/';
static const String invitationCode = '$baseUrl/unit/{unitUuid}/invitation-code'; static const String invitationCode =
'$baseUrl/unit/{unitUuid}/invitation-code';
static const String verifyInvitationCode = '$baseUrl/unit/user/verify-code'; static const String verifyInvitationCode = '$baseUrl/unit/user/verify-code';
//PUT //PUT
@ -95,8 +101,10 @@ abstract class ApiEndpoints {
//GET //GET
static const String deviceByRoom = '$baseUrl/device/room'; static const String deviceByRoom = '$baseUrl/device/room';
static const String deviceByUuid = '$baseUrl/device/{deviceUuid}'; static const String deviceByUuid = '$baseUrl/device/{deviceUuid}';
static const String deviceFunctions = '$baseUrl/device/{deviceUuid}/functions'; static const String deviceFunctions =
static const String deviceFunctionsStatus = '$baseUrl/device/{deviceUuid}/functions/status'; '$baseUrl/device/{deviceUuid}/functions';
static const String deviceFunctionsStatus =
'$baseUrl/device/{deviceUuid}/functions/status';
///Device Permission Module ///Device Permission Module
//POST //POST
@ -104,7 +112,26 @@ abstract class ApiEndpoints {
//GET //GET
static const String devicePermissionList = '$baseUrl/device-permission/list'; static const String devicePermissionList = '$baseUrl/device-permission/list';
//PUT //PUT
static const String editDevicePermission = '$baseUrl/device-permission/edit/{userId}'; static const String editDevicePermission =
'$baseUrl/device-permission/edit/{userId}';
static const String assignDeviceToRoom = '$baseUrl/device/room'; static const String assignDeviceToRoom = '$baseUrl/device/room';
/// Scene API ////////////////////
/// POST
static const String createScene = '$baseUrl/scene/tap-to-run';
static const String triggerScene =
'$baseUrl/scene/tap-to-run/trigger/{sceneId}';
/// GET
static const String getUnitScenes = '$baseUrl/scene/tap-to-run/{unitUuid}';
static const String getScene = '$baseUrl/scene/tap-to-run/details/{sceneId}';
/// PUT
static const String updateScene = '$baseUrl/scene/{sceneId}';
/// DELETE
static const String deleteScene =
'$baseUrl/scene/tap-to-run/{sceneUuid}/{sceneId}';
} }

View File

@ -0,0 +1,57 @@
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_model.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
class SceneApi {
static final HTTPService _httpService = HTTPService();
static Future<Map<String, dynamic>> createScene(
CreateSceneModel createSceneModel) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.createScene,
body: createSceneModel.toJson(),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<List<SceneModel>> getScenesByUnitId(String unitId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getUnitScenes.replaceAll('{unitUuid}', unitId),
showServerMessage: false,
expectedResponseModel: (json) {
List<SceneModel> scenes = [];
for (var scene in json) {
scenes.add(SceneModel.fromJson(scene));
}
return scenes;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<bool> triggerScene(String sceneId) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.triggerScene.replaceAll('{sceneUuid}', sceneId),
showServerMessage: false,
expectedResponseModel: (json) => json['success'],
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -47,6 +47,19 @@ extension ContextExtension on BuildContext {
); );
} }
void showCustomSnackbar({required String message, Widget? icon}) {
ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Row(
children: [
Expanded(child: Text(message)),
icon ?? const SizedBox.shrink(),
],
),
),
);
}
void customAlertDialog( void customAlertDialog(
{required Widget alertBody, {required Widget alertBody,
required String title, required String title,