fixed automation

This commit is contained in:
hannathkadher
2024-11-02 23:10:24 +04:00
parent dcccc4db3a
commit 87a4a88417
13 changed files with 240 additions and 132 deletions

View File

@ -32,6 +32,7 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
final allDevices = await HomeManagementAPI.fetchDevicesByUnitId(); final allDevices = await HomeManagementAPI.fetchDevicesByUnitId();
emit(state.copyWith(devices: allDevices, loading: false)); emit(state.copyWith(devices: allDevices, loading: false));
} catch (e) { } catch (e) {
print(e);
emit(state.copyWith(error: e.toString(), loading: false)); emit(state.copyWith(error: e.toString(), loading: false));
} }
} }

View File

@ -60,7 +60,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
String selectedIcon = ''; String selectedIcon = '';
bool showInDeviceScreen = false; bool showInDeviceScreen = false;
FutureOr<void> _onAddSceneTask(AddTaskEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
if (event.isAutomation == true) { if (event.isAutomation == true) {
final copyList = List<SceneStaticFunction>.from(automationTempTasksList); final copyList = List<SceneStaticFunction>.from(automationTempTasksList);
@ -95,7 +96,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
void addToTempTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) { void addToTempTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
bool updated = false; bool updated = false;
@ -180,7 +182,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
void addToTempAutomationTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) { void addToTempAutomationTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
bool updated = false; bool updated = false;
for (var element in automationTempTasksList) { for (var element in automationTempTasksList) {
@ -202,8 +205,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
], ],
comparator: automationComparatorValues[element.code], comparator: automationComparatorValues[element.code],
); );
automationTempTasksList[automationTempTasksList.indexOf(element)] = updatedElement; automationTempTasksList[automationTempTasksList.indexOf(element)] =
automationSelectedValues[updatedElement.code] = event.deviceControlModel.value; updatedElement;
automationSelectedValues[updatedElement.code] =
event.deviceControlModel.value;
updated = true; updated = true;
break; break;
} }
@ -223,10 +228,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '', icon: '',
), ),
], ],
comparator: automationComparatorValues[event.deviceControlModel.code] ?? '==', comparator:
automationComparatorValues[event.deviceControlModel.code] ?? '==',
); );
automationTempTasksList.add(newElement); automationTempTasksList.add(newElement);
automationSelectedValues[newElement.code] = event.deviceControlModel.value; automationSelectedValues[newElement.code] =
event.deviceControlModel.value;
} }
emit(AddSceneTask( emit(AddSceneTask(
tasksList: tasksList, tasksList: tasksList,
@ -235,7 +242,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
FutureOr<void> _selectedValue(SelectedValueEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _selectedValue(
SelectedValueEvent event, Emitter<CreateSceneState> emit) {
if (event.isAutomation == true) { if (event.isAutomation == true) {
automationSelectedValues[event.code] = event.value; automationSelectedValues[event.code] = event.value;
automationComparatorValues[event.code] = event.comparator ?? '=='; automationComparatorValues[event.code] = event.comparator ?? '==';
@ -272,7 +280,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
FutureOr<void> _removeTaskById(RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _removeTaskById(
RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
if (event.isAutomation == true) { if (event.isAutomation == true) {
for (var element in automationTasksList) { for (var element in automationTasksList) {
@ -345,7 +354,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.createScene(event.createSceneModel!); : await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) { } else if (event.createAutomationModel != null) {
response = event.updateScene response = event.updateScene
? await SceneApi.updateAutomation(event.createAutomationModel!, event.sceneId) ? await SceneApi.updateAutomation(
event.createAutomationModel!, event.sceneId)
: await SceneApi.createAutomation(event.createAutomationModel!); : await SceneApi.createAutomation(event.createAutomationModel!);
} }
@ -359,12 +369,14 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationComparatorValues.clear(); automationComparatorValues.clear();
selectedIcon = ''; selectedIcon = '';
showInDeviceScreen = false; showInDeviceScreen = false;
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none; sceneType = CreateSceneEnum.none;
conditionRule = 'or'; conditionRule = 'or';
emit(const CreateSceneWithTasks(success: true)); emit(const CreateSceneWithTasks(success: true));
CustomSnackBar.greenSnackBar( CustomSnackBar.greenSnackBar(event.updateScene
event.updateScene ? 'Scene updated successfully' : 'Scene created successfully'); ? 'Scene updated successfully'
: 'Scene created successfully');
} else { } else {
emit(const CreateSceneError(message: 'Something went wrong')); emit(const CreateSceneError(message: 'Something went wrong'));
} }
@ -378,7 +390,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
FutureOr<void> _clearTaskList(ClearTaskListEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _clearTaskList(
ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
automationTasksList.clear(); automationTasksList.clear();
tasksList.clear(); tasksList.clear();
@ -389,7 +402,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
FutureOr<void> _clearTabToRunSetting(ClearTabToRunSetting event, Emitter<CreateSceneState> emit) { FutureOr<void> _clearTabToRunSetting(
ClearTabToRunSetting event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
selectedIcon = ''; selectedIcon = '';
showInDeviceScreen = false; showInDeviceScreen = false;
@ -416,7 +430,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationComparatorValues.clear(); automationComparatorValues.clear();
selectedIcon = ''; selectedIcon = '';
showInDeviceScreen = false; showInDeviceScreen = false;
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none; sceneType = CreateSceneEnum.none;
conditionRule = 'or'; conditionRule = 'or';
@ -425,10 +440,14 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.getSceneDetails(event.sceneId); : await SceneApi.getSceneDetails(event.sceneId);
if (response.id.isNotEmpty) { if (response.id.isNotEmpty) {
if (event.isAutomation) { if (event.isAutomation) {
automationTasksList = List<SceneStaticFunction>.from(getTaskListFunctionsFromApi( automationTasksList = List<SceneStaticFunction>.from(
actions: [], isAutomation: true, conditions: response.conditions)); getTaskListFunctionsFromApi(
actions: [],
isAutomation: true,
conditions: response.conditions));
tasksList = List<SceneStaticFunction>.from( tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false)); getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
conditionRule = response.decisionExpr ?? conditionRule; conditionRule = response.decisionExpr ?? conditionRule;
@ -441,11 +460,13 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'); : EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
// Set the days directly from the API response // Set the days directly from the API response
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentContext!) BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentContext!)
.add(SetDays(response.effectiveTime?.loops ?? '1111111')); .add(SetDays(response.effectiveTime?.loops ?? '1111111'));
// Set Custom Time and reset days first // Set Custom Time and reset days first
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentContext!) BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentContext!)
.add(SetCustomTime(effectiveTime!.start, effectiveTime!.end)); .add(SetCustomTime(effectiveTime!.start, effectiveTime!.end));
emit(AddSceneTask( emit(AddSceneTask(
@ -457,7 +478,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
showInDevice: showInDeviceScreen)); showInDevice: showInDeviceScreen));
} else { } else {
tasksList = List<SceneStaticFunction>.from( tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false)); getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
selectedIcon = response.icon!; selectedIcon = response.icon!;
showInDeviceScreen = response.showInDevice!; showInDeviceScreen = response.showInDevice!;
emit(AddSceneTask( emit(AddSceneTask(
@ -475,7 +497,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
FutureOr<void> _fetchIconScene(SceneIconEvent event, Emitter<CreateSceneState> emit) async { FutureOr<void> _fetchIconScene(
SceneIconEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
try { try {
iconModelList = await SceneApi.getIcon(); iconModelList = await SceneApi.getIcon();
@ -491,7 +514,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
FutureOr<void> _iconSelected(IconSelected event, Emitter<CreateSceneState> emit) async { FutureOr<void> _iconSelected(
IconSelected event, Emitter<CreateSceneState> emit) async {
try { try {
if (event.confirmSelection) { if (event.confirmSelection) {
selectedIcon = event.iconId; selectedIcon = event.iconId;
@ -531,7 +555,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
return days[index]; return days[index];
} }
FutureOr<void> _clearTempTaskList(ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _clearTempTaskList(
ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
if (event.isAutomation == true) { if (event.isAutomation == true) {
automationTempTasksList.clear(); automationTempTasksList.clear();
@ -575,13 +600,18 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
FutureOr<void> _deleteScene(DeleteSceneEvent event, Emitter<CreateSceneState> emit) async { FutureOr<void> _deleteScene(
DeleteSceneEvent event, Emitter<CreateSceneState> emit) async {
emit(DeleteSceneLoading()); emit(DeleteSceneLoading());
try { try {
final response = sceneType.name == CreateSceneEnum.deviceStatusChanges.name final response =
? await SceneApi.deleteAutomation(automationId: event.sceneId, unitUuid: event.unitUuid) sceneType.name == CreateSceneEnum.deviceStatusChanges.name
: await SceneApi.deleteScene(sceneId: event.sceneId, unitUuid: event.unitUuid); ? await SceneApi.deleteAutomation(
automationId: event.sceneId, unitUuid: event.unitUuid)
: await SceneApi.deleteScene(
sceneId: event.sceneId,
);
if (response == true) { if (response == true) {
emit(const DeleteSceneSuccess(true)); emit(const DeleteSceneSuccess(true));
} else { } else {
@ -592,7 +622,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
} }
} }
FutureOr<void> _updateTaskValue(UpdateTaskEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _updateTaskValue(
UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading()); emit(CreateSceneLoading());
if (event.isAutomation == true) { if (event.isAutomation == true) {
for (var i = 0; i < automationTasksList.length; i++) { for (var i = 0; i < automationTasksList.length; i++) {
@ -628,7 +659,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
FutureOr<void> _selectConditionRule(SelectConditionEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _selectConditionRule(
SelectConditionEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial()); emit(CreateSceneInitial());
if (event.condition.contains('any')) { if (event.condition.contains('any')) {
conditionRule = 'or'; conditionRule = 'or';
@ -643,7 +675,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
)); ));
} }
FutureOr<void> _sceneTypeEvent(SceneTypeEvent event, Emitter<CreateSceneState> emit) { FutureOr<void> _sceneTypeEvent(
SceneTypeEvent event, Emitter<CreateSceneState> emit) {
// emit(CreateSceneInitial()); // emit(CreateSceneInitial());
if (event.type == CreateSceneEnum.tabToRun) { if (event.type == CreateSceneEnum.tabToRun) {

View File

@ -24,7 +24,9 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
try { try {
if (event.unitId.isNotEmpty) { if (event.unitId.isNotEmpty) {
scenes = await SceneApi.getScenesByUnitId(event.unitId, showInDevice: event.showInDevice); scenes = await SceneApi.getScenesByUnitId(
event.unitId, event.unit.community.uuid,
showInDevice: event.showInDevice);
emit(SceneLoaded(scenes, automationList)); emit(SceneLoaded(scenes, automationList));
} else { } else {
emit(const SceneError(message: 'Unit ID is empty')); emit(const SceneError(message: 'Unit ID is empty'));
@ -34,7 +36,8 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
} }
} }
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<SceneState> emit) async { Future<void> _onLoadAutomation(
LoadAutomation event, Emitter<SceneState> emit) async {
emit(SceneLoading()); emit(SceneLoading());
try { try {
@ -49,7 +52,8 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
} }
} }
Future<void> _onSceneTrigger(SceneTrigger event, Emitter<SceneState> emit) async { Future<void> _onSceneTrigger(
SceneTrigger event, Emitter<SceneState> emit) async {
final currentState = state; final currentState = state;
if (currentState is SceneLoaded) { if (currentState is SceneLoaded) {
emit(SceneLoaded( emit(SceneLoaded(
@ -76,7 +80,8 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
UpdateAutomationStatus event, Emitter<SceneState> emit) async { UpdateAutomationStatus event, Emitter<SceneState> emit) async {
final currentState = state; final currentState = state;
if (currentState is SceneLoaded) { if (currentState is SceneLoaded) {
final newLoadingStates = Map<String, bool>.from(currentState.loadingStates) final newLoadingStates =
Map<String, bool>.from(currentState.loadingStates)
..[event.automationId] = true; ..[event.automationId] = true;
emit(SceneLoaded( emit(SceneLoaded(
@ -86,11 +91,11 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
)); ));
try { try {
final success = final success = await SceneApi.updateAutomationStatus(
await SceneApi.updateAutomationStatus(event.automationId, event.automationStatusUpdate); event.automationId, event.automationStatusUpdate);
if (success) { if (success) {
automationList = automationList = await SceneApi.getAutomationByUnitId(
await SceneApi.getAutomationByUnitId(event.automationStatusUpdate.unitUuid); event.automationStatusUpdate.unitUuid);
newLoadingStates[event.automationId] = false; newLoadingStates[event.automationId] = false;
emit(SceneLoaded( emit(SceneLoaded(
currentState.scenes, currentState.scenes,

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/scene/model/update_automation.dart'; import 'package:syncrow_app/features/scene/model/update_automation.dart';
abstract class SceneEvent extends Equatable { abstract class SceneEvent extends Equatable {
@ -11,8 +12,9 @@ abstract class SceneEvent extends Equatable {
class LoadScenes extends SceneEvent { class LoadScenes extends SceneEvent {
final String unitId; final String unitId;
final bool showInDevice; final bool showInDevice;
final SpaceModel unit;
const LoadScenes(this.unitId, {this.showInDevice = false}); const LoadScenes(this.unitId, this.unit, {this.showInDevice = false});
@override @override
List<Object> get props => [unitId, showInDevice]; List<Object> get props => [unitId, showInDevice];

View File

@ -39,7 +39,7 @@ class CreateAutomationModel {
Map<String, dynamic> toMap([String? automationId]) { Map<String, dynamic> toMap([String? automationId]) {
return { return {
if (automationId == null) 'unitUuid': unitUuid, if (automationId == null) 'spaceUuid': unitUuid,
'automationName': automationName, 'automationName': automationName,
'decisionExpr': decisionExpr, 'decisionExpr': decisionExpr,
'effectiveTime': effectiveTime.toMap(), 'effectiveTime': effectiveTime.toMap(),
@ -50,7 +50,7 @@ class CreateAutomationModel {
factory CreateAutomationModel.fromMap(Map<String, dynamic> map) { factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
return CreateAutomationModel( return CreateAutomationModel(
unitUuid: map['unitUuid'] ?? '', unitUuid: map['spaceUuid'] ?? '',
automationName: map['automationName'] ?? '', automationName: map['automationName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '', decisionExpr: map['decisionExpr'] ?? '',
effectiveTime: EffectiveTime.fromMap(map['effectiveTime']), effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),

View File

@ -25,12 +25,14 @@ class SceneDetailsModel {
this.effectiveTime, this.effectiveTime,
}); });
factory SceneDetailsModel.fromRawJson(String str) => SceneDetailsModel.fromJson(json.decode(str)); factory SceneDetailsModel.fromRawJson(String str) =>
SceneDetailsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
factory SceneDetailsModel.fromJson(Map<String, dynamic> json) => SceneDetailsModel( factory SceneDetailsModel.fromJson(Map<String, dynamic> json) =>
id: json["id"], SceneDetailsModel(
id: json["uuid"],
name: json["name"], name: json["name"],
status: json["status"], status: json["status"],
type: json["type"], type: json["type"],
@ -40,13 +42,17 @@ class SceneDetailsModel {
.toList() .toList()
.cast<Action>(), .cast<Action>(),
conditions: json["conditions"] != null conditions: json["conditions"] != null
? (json["conditions"] as List).map((x) => Condition.fromJson(x)).toList() ? (json["conditions"] as List)
.map((x) => Condition.fromJson(x))
.toList()
: null, : null,
decisionExpr: json["decisionExpr"], decisionExpr: json["decisionExpr"],
effectiveTime: effectiveTime: json["effectiveTime"] != null
json["effectiveTime"] != null ? EffectiveTime.fromJson(json["effectiveTime"]) : null, ? EffectiveTime.fromJson(json["effectiveTime"])
: null,
icon: json["iconUuid"] != null ? json["iconUuid"] ?? '' : '', icon: json["iconUuid"] != null ? json["iconUuid"] ?? '' : '',
showInDevice: json['showInHome'] != null ? json['showInHome'] ?? false : false); showInDevice:
json['showInHome'] != null ? json['showInHome'] ?? false : false);
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id, "id": id,
@ -54,8 +60,9 @@ class SceneDetailsModel {
"status": status, "status": status,
"type": type, "type": type,
"actions": List<dynamic>.from(actions.map((x) => x.toJson())), "actions": List<dynamic>.from(actions.map((x) => x.toJson())),
"conditions": "conditions": conditions != null
conditions != null ? List<dynamic>.from(conditions!.map((x) => x.toJson())) : null, ? List<dynamic>.from(conditions!.map((x) => x.toJson()))
: null,
"decisionExpr": decisionExpr, "decisionExpr": decisionExpr,
"effectiveTime": effectiveTime?.toJson(), "effectiveTime": effectiveTime?.toJson(),
}; };
@ -116,7 +123,8 @@ class ExecutorProperty {
this.delaySeconds, this.delaySeconds,
}); });
factory ExecutorProperty.fromJson(Map<String, dynamic> json) => ExecutorProperty( factory ExecutorProperty.fromJson(Map<String, dynamic> json) =>
ExecutorProperty(
functionCode: json["functionCode"] ?? '', functionCode: json["functionCode"] ?? '',
functionValue: json["functionValue"] ?? '', functionValue: json["functionValue"] ?? '',
delaySeconds: json["delaySeconds"] ?? 0, delaySeconds: json["delaySeconds"] ?? 0,
@ -142,7 +150,8 @@ class Condition {
required this.expr, required this.expr,
}); });
factory Condition.fromRawJson(String str) => Condition.fromJson(json.decode(str)); factory Condition.fromRawJson(String str) =>
Condition.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
@ -200,7 +209,8 @@ class EffectiveTime {
required this.loops, required this.loops,
}); });
factory EffectiveTime.fromRawJson(String str) => EffectiveTime.fromJson(json.decode(str)); factory EffectiveTime.fromRawJson(String str) =>
EffectiveTime.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());

View File

@ -3,32 +3,40 @@ import 'dart:typed_data';
class ScenesModel { class ScenesModel {
final String id; final String id;
final String? sceneTuyaId;
final String name; final String name;
final String status; final String status;
final String type; final String type;
final String icon; final String? icon;
ScenesModel( ScenesModel(
{required this.id, {required this.id,
this.sceneTuyaId,
required this.name, required this.name,
required this.status, required this.status,
required this.type, required this.type,
required this.icon}); this.icon});
factory ScenesModel.fromRawJson(String str) => ScenesModel.fromJson(json.decode(str)); factory ScenesModel.fromRawJson(String str) =>
ScenesModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson()); String toRawJson() => json.encode(toJson());
Uint8List get iconInBytes => base64Decode(icon); Uint8List get iconInBytes => base64Decode(icon ?? '');
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
id: json["uuid"],
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
icon: json["icon"] ?? '');
factory ScenesModel.fromJson(Map<String, dynamic> json) {
return ScenesModel(
id: json["id"] ?? json["uuid"] ?? '', // Fallback to empty string if id is null
sceneTuyaId: json["sceneTuyaId"] as String?, // Nullable
name: json["name"] ?? '', // Fallback to empty string if name is null
status:
json["status"] ?? '', // Fallback to empty string if status is null
type: json["type"] ?? '', // Fallback to empty string if type is null
icon: json["icon"] as String?, // Nullable
);
}
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
"id": id, "id": id,
"sceneTuyaId": sceneTuyaId ?? '',
"name": name, "name": name,
"status": status, "status": status,
"type": type, "type": type,

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/app_layout/model/community_model.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/scene_listview.dart'; import 'package:syncrow_app/features/devices/view/widgets/scene_listview.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/bloc/scene_bloc/scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
@ -21,32 +23,47 @@ class SceneView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (BuildContext context) => SceneBloc() create: (BuildContext context) => SceneBloc()
..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? '', showInDevice: pageType)) ..add(LoadScenes(
HomeCubit.getInstance().selectedSpace?.id ?? '',
HomeCubit.getInstance().selectedSpace ??
SpaceModel(
id: '-1',
name: '',
community: Community(
uuid: '-1',
name: '',
)),
showInDevice: pageType))
..add(LoadAutomation(HomeCubit.getInstance().selectedSpace?.id ?? '')), ..add(LoadAutomation(HomeCubit.getInstance().selectedSpace?.id ?? '')),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>( child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) { builder: (context, state) {
if (state is DeleteSceneSuccess) { if (state is DeleteSceneSuccess) {
if (state.success) { if (state.success) {
BlocProvider.of<SceneBloc>(context).add(LoadScenes(
HomeCubit.getInstance().selectedSpace!.id!,HomeCubit.getInstance().selectedSpace!,
showInDevice: pageType));
BlocProvider.of<SceneBloc>(context).add( BlocProvider.of<SceneBloc>(context).add(
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!, showInDevice: pageType)); LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context)
.add(LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
} }
} }
if (state is CreateSceneWithTasks) { if (state is CreateSceneWithTasks) {
if (state.success == true) { if (state.success == true) {
BlocProvider.of<SceneBloc>(context).add(LoadScenes(
HomeCubit.getInstance().selectedSpace!.id!,HomeCubit.getInstance().selectedSpace!,
showInDevice: pageType));
BlocProvider.of<SceneBloc>(context).add( BlocProvider.of<SceneBloc>(context).add(
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!, showInDevice: pageType)); LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context) context
.add(LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!)); .read<SmartSceneSelectBloc>()
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent()); .add(const SmartSceneClearEvent());
} }
} }
return BlocListener<SceneBloc, SceneState>( return BlocListener<SceneBloc, SceneState>(
listener: (context, state) { listener: (context, state) {
if (state is SceneTriggerSuccess) { if (state is SceneTriggerSuccess) {
context.showCustomSnackbar( context.showCustomSnackbar(
message: 'Scene ${state.sceneName} triggered successfully!'); message:
'Scene ${state.sceneName} triggered successfully!');
} }
}, },
child: HomeCubit.getInstance().spaces?.isEmpty ?? true child: HomeCubit.getInstance().spaces?.isEmpty ?? true
@ -83,25 +100,30 @@ class SceneView extends StatelessWidget {
child: ListView( child: ListView(
children: [ children: [
Theme( Theme(
data: ThemeData() data: ThemeData().copyWith(
.copyWith(dividerColor: Colors.transparent), dividerColor: Colors.transparent),
child: ExpansionTile( child: ExpansionTile(
tilePadding: const EdgeInsets.symmetric(horizontal: 6), tilePadding:
const EdgeInsets.symmetric(
horizontal: 6),
initiallyExpanded: true, initiallyExpanded: true,
iconColor: ColorsManager.grayColor, iconColor: ColorsManager.grayColor,
title: const BodyMedium(text: 'Tap to run routines'), title: const BodyMedium(
text: 'Tap to run routines'),
children: [ children: [
scenes.isNotEmpty scenes.isNotEmpty
? SceneGrid( ? SceneGrid(
scenes: scenes, scenes: scenes,
loadingSceneId: state.loadingSceneId, loadingSceneId:
state.loadingSceneId,
disablePlayButton: false, disablePlayButton: false,
loadingStates: loadingStates: state
state.loadingStates, // Add this line .loadingStates, // Add this line
) )
: const Center( : const Center(
child: BodyMedium( child: BodyMedium(
text: 'No scenes have been added yet', text:
'No scenes have been added yet',
), ),
), ),
const SizedBox( const SizedBox(
@ -111,25 +133,30 @@ class SceneView extends StatelessWidget {
), ),
), ),
Theme( Theme(
data: ThemeData() data: ThemeData().copyWith(
.copyWith(dividerColor: Colors.transparent), dividerColor: Colors.transparent),
child: ExpansionTile( child: ExpansionTile(
initiallyExpanded: true, initiallyExpanded: true,
iconColor: ColorsManager.grayColor, iconColor: ColorsManager.grayColor,
tilePadding: const EdgeInsets.symmetric(horizontal: 6), tilePadding:
title: const BodyMedium(text: 'Automation'), const EdgeInsets.symmetric(
horizontal: 6),
title: const BodyMedium(
text: 'Automation'),
children: [ children: [
automationList.isNotEmpty automationList.isNotEmpty
? SceneGrid( ? SceneGrid(
scenes: automationList, scenes: automationList,
loadingSceneId: state.loadingSceneId, loadingSceneId:
state.loadingSceneId,
disablePlayButton: true, disablePlayButton: true,
loadingStates: loadingStates: state
state.loadingStates, // Add this line .loadingStates, // Add this line
) )
: const Center( : const Center(
child: BodyMedium( child: BodyMedium(
text: 'No automations have been added yet', text:
'No automations have been added yet',
), ),
), ),
const SizedBox( const SizedBox(

View File

@ -24,7 +24,7 @@ class DeleteRoutineButton extends StatelessWidget {
if (state.success) { if (state.success) {
navigateToRoute(context, Routes.homeRoute); navigateToRoute(context, Routes.homeRoute);
BlocProvider.of<SceneBloc>(context) BlocProvider.of<SceneBloc>(context)
.add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!)); .add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!,HomeCubit.getInstance().selectedSpace!));
BlocProvider.of<SceneBloc>(context).add( BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!)); LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
} }

View File

@ -17,7 +17,7 @@ class SmartEnableTabRun extends StatelessWidget {
width: double.infinity, width: double.infinity,
child: BlocBuilder<SceneBloc, SceneState>( child: BlocBuilder<SceneBloc, SceneState>(
bloc: context.read<SceneBloc>() bloc: context.read<SceneBloc>()
..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? '')), ..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? '',HomeCubit.getInstance().selectedSpace!)),
builder: (context, state) { builder: (context, state) {
if (state is SceneLoading) { if (state is SceneLoading) {
return const Align( return const Align(

View File

@ -150,9 +150,9 @@ class DevicesAPI {
}) async { }) async {
try { try {
final String path = ApiEndpoints.deviceByRoom final String path = ApiEndpoints.deviceByRoom
.replaceAll(':communityUuid', communityUuid) .replaceAll('{communityUuid}', communityUuid)
.replaceAll(':spaceUuid', spaceUuid) .replaceAll('{spaceUuid}', spaceUuid)
.replaceAll(':subSpaceUuid', roomId); .replaceAll('{subSpaceUuid}', roomId);
final response = await _httpService.get( final response = await _httpService.get(
path: path, path: path,

View File

@ -37,15 +37,17 @@ class HomeManagementAPI {
// Ensure both placeholders are replaced // Ensure both placeholders are replaced
final path = ApiEndpoints.spaceDevices final path = ApiEndpoints.spaceDevices
.replaceAll("{communityUuid}", communityUuid) .replaceAll('{communityUuid}', communityUuid)
.replaceAll("{spaceUuid}", spaceUuid); .replaceAll('{spaceUuid}', spaceUuid);
await _httpService.get( await _httpService.get(
path: path, path: path,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
json.forEach((value) { if (json['data'] != null) {
json['data'].forEach((value) {
list.add(DeviceModel.fromJson(value)); list.add(DeviceModel.fromJson(value));
}); });
}
}, },
); );

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart'; import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart'; import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/icon_model.dart'; import 'package:syncrow_app/features/scene/model/icon_model.dart';
@ -11,7 +13,8 @@ class SceneApi {
static final HTTPService _httpService = HTTPService(); static final HTTPService _httpService = HTTPService();
//create scene //create scene
static Future<Map<String, dynamic>> createScene(CreateSceneModel createSceneModel) async { static Future<Map<String, dynamic>> createScene(
CreateSceneModel createSceneModel) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.createScene, path: ApiEndpoints.createScene,
@ -47,15 +50,21 @@ class SceneApi {
//get scene by unit id //get scene by unit id
static Future<List<ScenesModel>> getScenesByUnitId(String unitId, {showInDevice = false}) async { static Future<List<ScenesModel>> getScenesByUnitId(
String unitId, String communityId,
{showInDevice = false}) async {
try { try {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getUnitScenes.replaceAll('{unitUuid}', unitId), path: ApiEndpoints.getUnitScenes
.replaceAll('{spaceUuid}', unitId)
.replaceAll('{communityUuid}', communityId),
queryParameters: {'showInHomePage': showInDevice}, queryParameters: {'showInHomePage': showInDevice},
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
final scenesJson = json['data'] as List;
List<ScenesModel> scenes = []; List<ScenesModel> scenes = [];
for (var scene in json) { for (var scene in scenesJson) {
scenes.add(ScenesModel.fromJson(scene)); scenes.add(ScenesModel.fromJson(scene));
} }
return scenes; return scenes;
@ -102,10 +111,12 @@ class SceneApi {
} }
//automation details //automation details
static Future<SceneDetailsModel> getAutomationDetails(String automationId) async { static Future<SceneDetailsModel> getAutomationDetails(
String automationId) async {
try { try {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getAutomationDetails.replaceAll('{automationId}', automationId), path: ApiEndpoints.getAutomationDetails
.replaceAll('{automationId}', automationId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => SceneDetailsModel.fromJson(json), expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
); );
@ -116,11 +127,12 @@ class SceneApi {
} }
//updateAutomationStatus //updateAutomationStatus
static Future<bool> updateAutomationStatus( static Future<bool> updateAutomationStatus(String automationId,
String automationId, AutomationStatusUpdate createAutomationEnable) async { AutomationStatusUpdate createAutomationEnable) async {
try { try {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.updateAutomationStatus.replaceAll('{automationId}', automationId), path: ApiEndpoints.updateAutomationStatus
.replaceAll('{automationId}', automationId),
body: createAutomationEnable.toMap(), body: createAutomationEnable.toMap(),
expectedResponseModel: (json) => json['success'], expectedResponseModel: (json) => json['success'],
); );
@ -135,7 +147,13 @@ class SceneApi {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId), path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => SceneDetailsModel.fromJson(json), expectedResponseModel: (json) {
if (json != null && json['data'] != null) {
return SceneDetailsModel.fromJson(json['data']);
} else {
throw Exception('Data field is null');
}
},
); );
return response; return response;
} catch (e) { } catch (e) {
@ -163,7 +181,8 @@ class SceneApi {
try { try {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId), path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId),
body: createSceneModel.toJson(sceneId.isNotEmpty == true ? sceneId : null), body: createSceneModel
.toJson(sceneId.isNotEmpty == true ? sceneId : null),
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
}, },
@ -175,11 +194,14 @@ class SceneApi {
} }
//update automation //update automation
static updateAutomation(CreateAutomationModel createAutomationModel, String automationId) async { static updateAutomation(
CreateAutomationModel createAutomationModel, String automationId) async {
try { try {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.updateAutomation.replaceAll('{automationId}', automationId), path: ApiEndpoints.updateAutomation
body: createAutomationModel.toJson(automationId.isNotEmpty == true ? automationId : null), .replaceAll('{automationId}', automationId),
body: createAutomationModel
.toJson(automationId.isNotEmpty == true ? automationId : null),
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
}, },
@ -192,12 +214,10 @@ class SceneApi {
//delete Scene //delete Scene
static Future<bool> deleteScene({required String unitUuid, required String sceneId}) async { static Future<bool> deleteScene({required String sceneId}) async {
try { try {
final response = await _httpService.delete( final response = await _httpService.delete(
path: ApiEndpoints.deleteScene path: ApiEndpoints.deleteScene.replaceAll('{sceneId}', sceneId),
.replaceAll('{sceneId}', sceneId)
.replaceAll('{unitUuid}', unitUuid),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => json['statusCode'] == 200, expectedResponseModel: (json) => json['statusCode'] == 200,
); );