Implemented tab to run setting

This commit is contained in:
Abdullah Alassaf
2024-10-28 16:45:59 +03:00
parent 20fdfdde87
commit 3d56f33ec3
18 changed files with 734 additions and 718 deletions

View File

@ -370,6 +370,9 @@ class HomeCubit extends Cubit<HomeState> {
.add(const SmartSceneClearEvent());
BlocProvider.of<EffectPeriodBloc>(NavigationService.navigatorKey.currentState!.context)
.add(ResetEffectivePeriod());
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const ClearTabToRunSetting());
},
),
IconButton(

View File

@ -40,13 +40,10 @@ class SceneListview extends StatelessWidget {
sceneName: scene.name,
),
);
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
BlocProvider.of<CreateSceneBloc>(context).add(
FetchSceneTasksEvent(
sceneId: scene.id, isAutomation: false));
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
/// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context)
@ -59,11 +56,13 @@ class SceneListview extends StatelessWidget {
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
child: Image.memory(
height: 32,
width: 32,
Assets.assetsIconsLogo,
scene.iconInBytes,
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) => Image.asset(
height: 32, width: 32, fit: BoxFit.fill, Assets.assetsIconsLogo),
),
),
Expanded(

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -38,6 +37,9 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
on<SceneTypeEvent>(_sceneTypeEvent);
on<EffectiveTimePeriodEvent>(_onEffectiveTimeEvent);
on<SceneIconEvent>(_fetchIconScene);
on<IconSelected>(_iconSelected);
on<ShowOnDeviceClicked>(_showInDeviceClicked);
on<ClearTabToRunSetting>(_clearTabToRunSetting);
}
CreateSceneEnum sceneType = CreateSceneEnum.none;
@ -54,9 +56,11 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
final Map<String, String> automationComparatorValues = {};
String conditionRule = 'or';
EffectiveTime? effectiveTime;
List<IconModel> iconModelList = [];
String selectedIcon = '';
bool showInDeviceScreen = false;
FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _onAddSceneTask(AddTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
final copyList = List<SceneStaticFunction>.from(automationTempTasksList);
@ -91,8 +95,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
void addToTempTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
void addToTempTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
@ -177,8 +180,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
void addToTempAutomationTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
void addToTempAutomationTaskList(TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
for (var element in automationTempTasksList) {
@ -200,10 +202,8 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
],
comparator: automationComparatorValues[element.code],
);
automationTempTasksList[automationTempTasksList.indexOf(element)] =
updatedElement;
automationSelectedValues[updatedElement.code] =
event.deviceControlModel.value;
automationTempTasksList[automationTempTasksList.indexOf(element)] = updatedElement;
automationSelectedValues[updatedElement.code] = event.deviceControlModel.value;
updated = true;
break;
}
@ -223,12 +223,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '',
),
],
comparator:
automationComparatorValues[event.deviceControlModel.code] ?? '==',
comparator: automationComparatorValues[event.deviceControlModel.code] ?? '==',
);
automationTempTasksList.add(newElement);
automationSelectedValues[newElement.code] =
event.deviceControlModel.value;
automationSelectedValues[newElement.code] = event.deviceControlModel.value;
}
emit(AddSceneTask(
tasksList: tasksList,
@ -237,8 +235,7 @@ 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) {
automationSelectedValues[event.code] = event.value;
automationComparatorValues[event.code] = event.comparator ?? '==';
@ -275,8 +272,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _removeTaskById(
RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _removeTaskById(RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var element in automationTasksList) {
@ -349,8 +345,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) {
response = event.updateScene
? await SceneApi.updateAutomation(
event.createAutomationModel!, event.sceneId)
? await SceneApi.updateAutomation(event.createAutomationModel!, event.sceneId)
: await SceneApi.createAutomation(event.createAutomationModel!);
}
@ -362,14 +357,14 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
selectedIcon = '';
showInDeviceScreen = false;
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
emit(const CreateSceneWithTasks(success: true));
CustomSnackBar.greenSnackBar(event.updateScene
? 'Scene updated successfully'
: 'Scene created successfully');
CustomSnackBar.greenSnackBar(
event.updateScene ? 'Scene updated successfully' : 'Scene created successfully');
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
@ -383,8 +378,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _clearTaskList(
ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _clearTaskList(ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
automationTasksList.clear();
tasksList.clear();
@ -395,6 +389,19 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _clearTabToRunSetting(ClearTabToRunSetting event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
selectedIcon = '';
showInDeviceScreen = false;
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
showInDevice: showInDeviceScreen,
selectedIcon: selectedIcon,
iconModels: iconModelList));
}
FutureOr<void> _fetchSceneTasks(
FetchSceneTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
@ -407,8 +414,9 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
effectiveTime =
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
selectedIcon = '';
showInDeviceScreen = false;
effectiveTime = EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
@ -417,14 +425,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: await SceneApi.getSceneDetails(event.sceneId);
if (response.id.isNotEmpty) {
if (event.isAutomation) {
automationTasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: [],
isAutomation: true,
conditions: response.conditions));
automationTasksList = List<SceneStaticFunction>.from(getTaskListFunctionsFromApi(
actions: [], isAutomation: true, conditions: response.conditions));
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false));
conditionRule = response.decisionExpr ?? conditionRule;
@ -437,28 +441,31 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
: EffectiveTime(start: '00:00', end: '23:59', loops: '1111111');
// 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'));
// 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));
emit(AddSceneTask(
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
));
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
iconModels: iconModelList,
selectedIcon: selectedIcon,
showInDevice: showInDeviceScreen));
} else {
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
getTaskListFunctionsFromApi(actions: response.actions, isAutomation: false));
selectedIcon = response.icon!;
showInDeviceScreen = response.showInDevice!;
emit(AddSceneTask(
tasksList: tasksList,
condition: conditionRule,
));
tasksList: tasksList,
condition: conditionRule,
iconModels: iconModelList,
selectedIcon: selectedIcon,
showInDevice: showInDeviceScreen));
}
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
@ -468,19 +475,52 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
List<IconModel> iconModel = [];
FutureOr<void> _fetchIconScene(
SceneIconEvent event, Emitter<CreateSceneState> emit) async {
FutureOr<void> _fetchIconScene(SceneIconEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
try {
final response = await SceneApi.getIcon();
iconModel = (response as List<dynamic>)
.map((iconJson) =>
IconModel.fromJson(iconJson as Map<String, dynamic>))
.toList();
print(iconModel[0].iconBase64.toString());
emit(CreateSceneLoaded(iconModel));
iconModelList = await SceneApi.getIcon();
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
showInDevice: showInDeviceScreen,
selectedIcon: selectedIcon,
iconModels: iconModelList));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
}
FutureOr<void> _iconSelected(IconSelected event, Emitter<CreateSceneState> emit) async {
try {
if (event.confirmSelection) {
selectedIcon = event.iconId;
}
emit(CreateSceneLoading());
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
showInDevice: showInDeviceScreen,
condition: conditionRule,
selectedIcon: event.iconId,
iconModels: iconModelList));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
}
FutureOr<void> _showInDeviceClicked(
ShowOnDeviceClicked event, Emitter<CreateSceneState> emit) async {
try {
emit(CreateSceneLoading());
showInDeviceScreen = event.value;
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
selectedIcon: selectedIcon,
iconModels: iconModelList,
showInDevice: showInDeviceScreen));
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
}
@ -491,8 +531,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
return days[index];
}
FutureOr<void> _clearTempTaskList(
ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _clearTempTaskList(ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
automationTempTasksList.clear();
@ -536,17 +575,13 @@ 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());
try {
final response =
sceneType.name == CreateSceneEnum.deviceStatusChanges.name
? await SceneApi.deleteAutomation(
automationId: event.sceneId, unitUuid: event.unitUuid)
: await SceneApi.deleteScene(
sceneId: event.sceneId, unitUuid: event.unitUuid);
final response = sceneType.name == CreateSceneEnum.deviceStatusChanges.name
? await SceneApi.deleteAutomation(automationId: event.sceneId, unitUuid: event.unitUuid)
: await SceneApi.deleteScene(sceneId: event.sceneId, unitUuid: event.unitUuid);
if (response == true) {
emit(const DeleteSceneSuccess(true));
} else {
@ -557,8 +592,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _updateTaskValue(
UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _updateTaskValue(UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var i = 0; i < automationTasksList.length; i++) {
@ -594,8 +628,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _selectConditionRule(
SelectConditionEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _selectConditionRule(SelectConditionEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.condition.contains('any')) {
conditionRule = 'or';
@ -610,8 +643,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
));
}
FutureOr<void> _sceneTypeEvent(
SceneTypeEvent event, Emitter<CreateSceneState> emit) {
FutureOr<void> _sceneTypeEvent(SceneTypeEvent event, Emitter<CreateSceneState> emit) {
// emit(CreateSceneInitial());
if (event.type == CreateSceneEnum.tabToRun) {

View File

@ -149,8 +149,7 @@ class FetchSceneTasksEvent extends CreateSceneEvent {
final String sceneId;
final bool isAutomation;
const FetchSceneTasksEvent(
{this.isAutomation = false, required this.sceneId});
const FetchSceneTasksEvent({this.isAutomation = false, required this.sceneId});
@override
List<Object> get props => [sceneId, isAutomation];
@ -185,3 +184,31 @@ class EffectiveTimePeriodEvent extends CreateSceneEvent {
}
class SceneIconEvent extends CreateSceneEvent {}
class IconSelected extends CreateSceneEvent {
final String iconId;
final bool confirmSelection;
const IconSelected({required this.iconId, required this.confirmSelection});
@override
List<Object> get props => [iconId];
}
class ShowOnDeviceClicked extends CreateSceneEvent {
final bool value;
const ShowOnDeviceClicked({
required this.value,
});
@override
List<Object> get props => [value];
}
class ClearTabToRunSetting extends CreateSceneEvent {
const ClearTabToRunSetting();
@override
List<Object> get props => [];
}

View File

@ -23,8 +23,16 @@ class AddSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tasksList;
final List<SceneStaticFunction>? automationTasksList;
final String? condition;
final String? selectedIcon;
final List<IconModel>? iconModels;
final bool? showInDevice;
const AddSceneTask(
{required this.tasksList, this.automationTasksList, this.condition});
{required this.tasksList,
this.automationTasksList,
this.condition,
this.iconModels,
this.selectedIcon,
this.showInDevice});
@override
List<Object> get props => [tasksList];
@ -33,8 +41,7 @@ class AddSceneTask extends CreateSceneState {
class TempHoldSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tempTasksList;
final List<SceneStaticFunction>? automationTempTasksList;
const TempHoldSceneTask(
{required this.tempTasksList, this.automationTempTasksList});
const TempHoldSceneTask({required this.tempTasksList, this.automationTempTasksList});
@override
List<Object> get props => [tempTasksList];
@ -84,8 +91,3 @@ class SceneTypeState extends CreateSceneState {
final CreateSceneEnum type;
const SceneTypeState(this.type);
}
class CreateSceneLoaded extends CreateSceneState {
final List<IconModel> iconModels;
CreateSceneLoaded(this.iconModels);
}

View File

@ -24,7 +24,7 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
try {
if (event.unitId.isNotEmpty) {
scenes = await SceneApi.getScenesByUnitId(event.unitId);
scenes = await SceneApi.getScenesByUnitId(event.unitId, showInDevice: event.showInDevice);
emit(SceneLoaded(scenes, automationList));
} else {
emit(const SceneError(message: 'Unit ID is empty'));
@ -34,8 +34,7 @@ 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());
try {
@ -50,8 +49,7 @@ 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;
if (currentState is SceneLoaded) {
emit(SceneLoaded(
@ -78,9 +76,8 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
UpdateAutomationStatus event, Emitter<SceneState> emit) async {
final currentState = state;
if (currentState is SceneLoaded) {
final newLoadingStates =
Map<String, bool>.from(currentState.loadingStates)
..[event.automationId] = true;
final newLoadingStates = Map<String, bool>.from(currentState.loadingStates)
..[event.automationId] = true;
emit(SceneLoaded(
currentState.scenes,
@ -89,11 +86,11 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
));
try {
final success = await SceneApi.updateAutomationStatus(
event.automationId, event.automationStatusUpdate);
final success =
await SceneApi.updateAutomationStatus(event.automationId, event.automationStatusUpdate);
if (success) {
automationList = await SceneApi.getAutomationByUnitId(
event.automationStatusUpdate.unitUuid);
automationList =
await SceneApi.getAutomationByUnitId(event.automationStatusUpdate.unitUuid);
newLoadingStates[event.automationId] = false;
emit(SceneLoaded(
currentState.scenes,

View File

@ -10,11 +10,12 @@ abstract class SceneEvent extends Equatable {
class LoadScenes extends SceneEvent {
final String unitId;
final bool showInDevice;
const LoadScenes(this.unitId);
const LoadScenes(this.unitId, {this.showInDevice = false});
@override
List<Object> get props => [unitId];
List<Object> get props => [unitId, showInDevice];
}
class LoadAutomation extends SceneEvent {
@ -41,8 +42,7 @@ class UpdateAutomationStatus extends SceneEvent {
final String automationId;
final AutomationStatusUpdate automationStatusUpdate;
const UpdateAutomationStatus(
{required this.automationStatusUpdate, required this.automationId});
const UpdateAutomationStatus({required this.automationStatusUpdate, required this.automationId});
@override
List<Object> get props => [automationStatusUpdate];

View File

@ -125,6 +125,8 @@ mixin SceneLogicHelper {
} else {
final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
iconId: sceneBloc.selectedIcon,
showInDevice: sceneBloc.showInDeviceScreen,
sceneName: sceneName.text,
decisionExpr: 'and',
actions: [
@ -171,24 +173,21 @@ mixin SceneLogicHelper {
}
}
Widget getTheCorrectDialogBody(
SceneStaticFunction taskItem, dynamic functionValue,
Widget getTheCorrectDialogBody(SceneStaticFunction taskItem, dynamic functionValue,
{required bool isAutomation}) {
if (taskItem.operationDialogType == OperationDialogType.temperature) {
return AlertDialogTemperatureBody(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,
);
} else if ((taskItem.operationDialogType ==
OperationDialogType.countdown) ||
} else if ((taskItem.operationDialogType == OperationDialogType.countdown) ||
(taskItem.operationDialogType == OperationDialogType.delay)) {
return AlertDialogCountdown(
durationValue: taskItem.functionValue ?? 0,
functionValue: functionValue ?? taskItem.functionValue,
function: taskItem,
);
} else if (taskItem.operationDialogType ==
OperationDialogType.integerSteps) {
} else if (taskItem.operationDialogType == OperationDialogType.integerSteps) {
return AlertDialogSliderSteps(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,

View File

@ -4,12 +4,16 @@ import 'package:flutter/foundation.dart';
class CreateSceneModel {
String unitUuid;
String iconId;
bool showInDevice;
String sceneName;
String decisionExpr;
List<CreateSceneAction> actions;
CreateSceneModel({
required this.unitUuid,
required this.iconId,
required this.showInDevice,
required this.sceneName,
required this.decisionExpr,
required this.actions,
@ -17,12 +21,16 @@ class CreateSceneModel {
CreateSceneModel copyWith({
String? unitUuid,
String? iconId,
bool? showInDevice,
String? sceneName,
String? decisionExpr,
List<CreateSceneAction>? actions,
}) {
return CreateSceneModel(
unitUuid: unitUuid ?? this.unitUuid,
iconId: iconId ?? this.iconId,
showInDevice: showInDevice ?? this.showInDevice,
sceneName: sceneName ?? this.sceneName,
decisionExpr: decisionExpr ?? this.decisionExpr,
actions: actions ?? this.actions,
@ -32,6 +40,8 @@ class CreateSceneModel {
Map<String, dynamic> toMap([String? sceneId]) {
return {
if (sceneId == null) 'unitUuid': unitUuid,
if (iconId.isNotEmpty) 'iconUuid': iconId,
'showInHomePage': showInDevice,
'sceneName': sceneName,
'decisionExpr': decisionExpr,
'actions': actions.map((x) => x.toMap()).toList(),
@ -41,17 +51,18 @@ class CreateSceneModel {
factory CreateSceneModel.fromMap(Map<String, dynamic> map) {
return CreateSceneModel(
unitUuid: map['unitUuid'] ?? '',
iconId: map['iconUuid'] ?? '',
showInDevice: map['showInHomePage'] ?? false,
sceneName: map['sceneName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
actions: List<CreateSceneAction>.from(
map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
actions:
List<CreateSceneAction>.from(map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
);
}
String toJson([String? sceneId]) => json.encode(toMap(sceneId));
factory CreateSceneModel.fromJson(String source) =>
CreateSceneModel.fromMap(json.decode(source));
factory CreateSceneModel.fromJson(String source) => CreateSceneModel.fromMap(json.decode(source));
@override
String toString() {
@ -64,6 +75,8 @@ class CreateSceneModel {
return other is CreateSceneModel &&
other.unitUuid == unitUuid &&
other.iconId == iconId &&
other.showInDevice == showInDevice &&
other.sceneName == sceneName &&
other.decisionExpr == decisionExpr &&
listEquals(other.actions, actions);
@ -71,10 +84,7 @@ class CreateSceneModel {
@override
int get hashCode {
return unitUuid.hashCode ^
sceneName.hashCode ^
decisionExpr.hashCode ^
actions.hashCode;
return unitUuid.hashCode ^ sceneName.hashCode ^ decisionExpr.hashCode ^ actions.hashCode;
}
}
@ -120,8 +130,7 @@ class CreateSceneAction {
return CreateSceneAction(
entityId: map['entityId'] ?? '',
actionExecutor: map['actionExecutor'] ?? '',
executorProperty:
CreateSceneExecutorProperty.fromMap(map['executorProperty']),
executorProperty: CreateSceneExecutorProperty.fromMap(map['executorProperty']),
);
}
@ -145,8 +154,7 @@ class CreateSceneAction {
}
@override
int get hashCode =>
entityId.hashCode ^ actionExecutor.hashCode ^ executorProperty.hashCode;
int get hashCode => entityId.hashCode ^ actionExecutor.hashCode ^ executorProperty.hashCode;
}
class CreateSceneExecutorProperty {
@ -210,6 +218,5 @@ class CreateSceneExecutorProperty {
}
@override
int get hashCode =>
functionCode.hashCode ^ functionValue.hashCode ^ delaySeconds.hashCode;
int get hashCode => functionCode.hashCode ^ functionValue.hashCode ^ delaySeconds.hashCode;
}

View File

@ -4,6 +4,8 @@ class SceneDetailsModel {
final String id;
final String name;
final String status;
final String? icon;
final bool? showInDevice;
final String type;
final List<Action> actions;
final List<Condition>? conditions;
@ -16,48 +18,44 @@ class SceneDetailsModel {
required this.status,
required this.type,
required this.actions,
this.icon,
this.showInDevice,
this.conditions,
this.decisionExpr,
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());
factory SceneDetailsModel.fromJson(Map<String, dynamic> json) =>
SceneDetailsModel(
id: json["id"],
name: json["name"],
status: json["status"],
type: json["type"],
actions: (json["actions"] as List)
.map((x) => Action.fromJson(x))
.where((x) => x != null)
.toList()
.cast<Action>(),
conditions: json["conditions"] != null
? (json["conditions"] as List)
.map((x) => Condition.fromJson(x))
.toList()
: null,
decisionExpr: json["decisionExpr"],
effectiveTime: json["effectiveTime"] != null
? EffectiveTime.fromJson(json["effectiveTime"])
: null,
);
factory SceneDetailsModel.fromJson(Map<String, dynamic> json) => SceneDetailsModel(
id: json["id"],
name: json["name"],
status: json["status"],
type: json["type"],
actions: (json["actions"] as List)
.map((x) => Action.fromJson(x))
.where((x) => x != null)
.toList()
.cast<Action>(),
conditions: json["conditions"] != null
? (json["conditions"] as List).map((x) => Condition.fromJson(x)).toList()
: null,
decisionExpr: json["decisionExpr"],
effectiveTime:
json["effectiveTime"] != null ? EffectiveTime.fromJson(json["effectiveTime"]) : null,
icon: json["iconUuid"] != null ? json["iconUuid"] ?? '' : '',
showInDevice: json['showInHome'] != null ? json['showInHome'] ?? false : false);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"status": status,
"type": type,
"actions": List<dynamic>.from(actions.map((x) => x.toJson())),
"conditions": conditions != null
? List<dynamic>.from(conditions!.map((x) => x.toJson()))
: null,
"conditions":
conditions != null ? List<dynamic>.from(conditions!.map((x) => x.toJson())) : null,
"decisionExpr": decisionExpr,
"effectiveTime": effectiveTime?.toJson(),
};
@ -90,7 +88,7 @@ class Action {
);
}
if (json["executorProperty"] == null) {
return null;
return null;
}
return Action(
@ -118,8 +116,7 @@ class ExecutorProperty {
this.delaySeconds,
});
factory ExecutorProperty.fromJson(Map<String, dynamic> json) =>
ExecutorProperty(
factory ExecutorProperty.fromJson(Map<String, dynamic> json) => ExecutorProperty(
functionCode: json["functionCode"] ?? '',
functionValue: json["functionValue"] ?? '',
delaySeconds: json["delaySeconds"] ?? 0,
@ -145,8 +142,7 @@ class Condition {
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());
@ -204,8 +200,7 @@ class EffectiveTime {
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());

View File

@ -1,29 +1,31 @@
import 'dart:convert';
import 'dart:typed_data';
class ScenesModel {
final String id;
final String name;
final String status;
final String type;
final String icon;
ScenesModel({
required this.id,
required this.name,
required this.status,
required this.type,
});
ScenesModel(
{required this.id,
required this.name,
required this.status,
required this.type,
required 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());
Uint8List get iconInBytes => base64Decode(icon);
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
id: json["id"],
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
);
id: json["id"],
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
icon: json["icon"] ?? '');
Map<String, dynamic> toJson() => {
"id": id,

View File

@ -1,15 +1,16 @@
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.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/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/icons_dialog.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/effective_period_bottom_sheet.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_scaffold.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/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SceneAutoSettings extends StatelessWidget {
@ -17,14 +18,13 @@ class SceneAutoSettings extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sceneSettings =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>? ??
{};
final sceneSettings = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>? ?? {};
final sceneId = sceneSettings['sceneId'] as String? ?? '';
final isAutomation = context.read<CreateSceneBloc>().sceneType ==
CreateSceneEnum.deviceStatusChanges;
final isAutomation =
context.read<CreateSceneBloc>().sceneType == CreateSceneEnum.deviceStatusChanges;
final sceneName = sceneSettings['sceneName'] as String? ?? '';
bool showInDevice = context.read<CreateSceneBloc>().showInDeviceScreen;
String selectedIcon = '';
return DefaultScaffold(
title: 'Settings',
padding: EdgeInsets.zero,
@ -35,44 +35,81 @@ class SceneAutoSettings extends StatelessWidget {
icon: const Icon(
Icons.arrow_back_ios,
)),
child: BlocProvider(
create: (BuildContext context) =>
CreateSceneBloc()..add(SceneIconEvent()),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
return SizedBox(
height: MediaQuery.sizeOf(context).height,
child: Column(
children: [
DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 10),
child: Column(
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
return SecondDialog(
WidgetList: BlocBuilder<CreateSceneBloc,
CreateSceneState>(
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(builder: (context, state) {
if (state is AddSceneTask) {
showInDevice = state.showInDevice ?? false;
}
return SizedBox(
height: MediaQuery.sizeOf(context).height,
child: Column(
children: [
if (!isAutomation)
DefaultContainer(
child: Padding(
padding: const EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 10),
child: Column(
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
BlocProvider.of<CreateSceneBloc>(context).add(SceneIconEvent());
return IconsDialog(
widgetList: Container(
height: MediaQuery.sizeOf(context).height * 0.4,
width: MediaQuery.sizeOf(context).width,
padding: const EdgeInsets.all(24),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
if (state is CreateSceneLoading) {
return CircularProgressIndicator();
} else if (state is CreateSceneLoaded) {
return Container(
child: ListView.builder(
itemCount:
state.iconModels.length,
itemBuilder: (context, index) {
final iconModel =
state.iconModels[index];
return Image.memory(
iconModel.iconBytes);
},
return const Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator()),
);
} else if (state is AddSceneTask) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: state.iconModels?.length ?? 0,
itemBuilder: (context, index) {
final iconModel = state.iconModels![index];
return InkWell(
onTap: () {
BlocProvider.of<CreateSceneBloc>(context).add(
IconSelected(
iconId: iconModel.uuid,
confirmSelection: false));
selectedIcon = iconModel.uuid;
},
child: ClipOval(
child: Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
border: Border.all(
color: state.selectedIcon == iconModel.uuid
? ColorsManager.primaryColorWithOpacity
: Colors.transparent,
width: 2,
),
shape: BoxShape.circle,
),
child: Image.memory(
iconModel.iconBytes,
width: 35,
height: 35,
),
),
),
);
},
);
} else if (state is CreateSceneError) {
return Text(state.message);
@ -81,258 +118,140 @@ class SceneAutoSettings extends StatelessWidget {
}
},
),
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: (v) {
Navigator.of(context).pop();
},
title: 'Icons',
onTapLabel1: (selected) {},
);
},
);
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(text: 'Icons'),
Icon(
Icons.arrow_forward_ios_outlined,
color: ColorsManager.textGray,
size: 15,
)
],
),
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(
height: 5,
),
Row(
),
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
BlocProvider.of<CreateSceneBloc>(context).add(
IconSelected(iconId: selectedIcon, confirmSelection: true));
Navigator.of(context).pop();
},
title: 'Icons',
);
},
);
},
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Show on devices page'),
Container(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 30,
width: 1,
color: ColorsManager.graysColor,
),
Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: true,
onChanged: (value) {},
applyTheme: true,
),
),
],
),
BodyMedium(text: 'Icons'),
Icon(
Icons.arrow_forward_ios_outlined,
color: ColorsManager.textGray,
size: 15,
)
],
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
SizedBox(
height: 5,
),
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//Cloud
BodyMedium(text: 'Executed by'),
Text('Cloud',
style: TextStyle(
color: ColorsManager.textGray,
)),
],
),
],
),
)),
// Padding(
// padding: const EdgeInsets.symmetric(vertical: 16),
// child: DefaultContainer(
// child: Column(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// const SizedBox(
// height: 8,
// ),
// Visibility(
// visible: isAutomation,
// child: SceneListTile(
// padding: const EdgeInsets.symmetric(
// horizontal: 16, vertical: 8),
// titleString: "Effective Period",
// trailingWidget:
// const Icon(Icons.arrow_forward_ios_rounded),
// onPressed: () {
// context.customBottomSheet(
// child: const EffectPeriodBottomSheetContent(),
// );
// },
// ),
// ),
// Visibility(
// visible: sceneName.isNotEmpty && isAutomation,
// child: SizedBox(
// width: context.width * 0.9,
// child: const Divider(
// color: ColorsManager.greyColor,
// ),
// ),
// ),
// Visibility(
// visible: sceneName.isNotEmpty,
// child: DeleteBottomSheetContent(
// isAutomation: isAutomation,
// sceneId: sceneId,
// ),
// ),
// const SizedBox(
// height: 16,
// ),
// ],
// ),
// ),
// ),
],
),
);
})));
}
}
class SecondDialog extends StatefulWidget {
final String title;
Widget WidgetList;
final Function(String)? onTapLabel1;
final Function()? cancelTab;
final Function(int selectedSecond)? confirmTab;
SecondDialog({
required this.WidgetList,
required this.title,
this.onTapLabel1,
required this.cancelTab,
required this.confirmTab,
});
@override
_SecondDialogState createState() => _SecondDialogState();
}
class _SecondDialogState extends State<SecondDialog> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: widget.title,
fontWeight: FontWeight.w700,
fontColor: ColorsManager.primaryColor,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
Expanded(child: widget.WidgetList),
Row(
children: [
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const BodyMedium(text: 'Show on devices page'),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 30,
width: 1,
color: ColorsManager.graysColor,
),
Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: showInDevice,
onChanged: (value) {
BlocProvider.of<CreateSceneBloc>(context)
.add(ShowOnDeviceClicked(value: value));
},
applyTheme: true,
),
),
],
)
],
),
const SizedBox(
height: 5,
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(
height: 5,
),
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//Cloud
BodyMedium(text: 'Executed by'),
Text('Cloud',
style: TextStyle(
color: ColorsManager.textGray,
)),
],
),
],
),
)),
child: SizedBox(
child: InkWell(
onTap: widget.cancelTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Cancel',
style: TextStyle(
color: ColorsManager.textGray,
fontSize: 14,
fontWeight: FontWeight.w400),
if (isAutomation)
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 8,
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
height: 8,
),
Visibility(
visible: isAutomation,
child: SceneListTile(
titleString: "Effective Period",
trailingWidget: const Icon(Icons.arrow_forward_ios_rounded),
onPressed: () {
context.customBottomSheet(
child: const EffectPeriodBottomSheetContent(),
);
},
),
),
),
Visibility(
visible: sceneName.isNotEmpty && isAutomation,
child: SizedBox(
width: context.width * 0.9,
child: const Divider(
color: ColorsManager.greyColor,
),
),
),
Visibility(
visible: sceneName.isNotEmpty,
child: DeleteBottomSheetContent(
isAutomation: isAutomation,
sceneId: sceneId,
),
),
const SizedBox(
height: 16,
),
],
),
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: InkWell(
onTap: () {},
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Confirm',
style: TextStyle(
color: ColorsManager.primaryColor,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
],
),
);
}));
}
}

View File

@ -21,35 +21,32 @@ class SceneView extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SceneBloc()
..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? ''))
..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? '', showInDevice: pageType))
..add(LoadAutomation(HomeCubit.getInstance().selectedSpace?.id ?? '')),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
if (state is DeleteSceneSuccess) {
if (state.success) {
BlocProvider.of<SceneBloc>(context)
.add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!, showInDevice: pageType));
BlocProvider.of<SceneBloc>(context)
.add(LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
}
}
if (state is CreateSceneWithTasks) {
if (state.success == true) {
BlocProvider.of<SceneBloc>(context)
.add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!, showInDevice: pageType));
BlocProvider.of<SceneBloc>(context)
.add(LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
}
}
return BlocListener<SceneBloc, SceneState>(
listener: (context, state) {
if (state is SceneTriggerSuccess) {
context.showCustomSnackbar(
message:
'Scene ${state.sceneName} triggered successfully!');
message: 'Scene ${state.sceneName} triggered successfully!');
}
},
child: HomeCubit.getInstance().spaces?.isEmpty ?? true
@ -86,30 +83,25 @@ class SceneView extends StatelessWidget {
child: ListView(
children: [
Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent),
data: ThemeData()
.copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
tilePadding:
const EdgeInsets.symmetric(
horizontal: 6),
tilePadding: const EdgeInsets.symmetric(horizontal: 6),
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
title: const BodyMedium(
text: 'Tap to run routines'),
title: const BodyMedium(text: 'Tap to run routines'),
children: [
scenes.isNotEmpty
? SceneGrid(
scenes: scenes,
loadingSceneId:
state.loadingSceneId,
loadingSceneId: state.loadingSceneId,
disablePlayButton: false,
loadingStates: state
.loadingStates, // Add this line
loadingStates:
state.loadingStates, // Add this line
)
: const Center(
child: BodyMedium(
text:
'No scenes have been added yet',
text: 'No scenes have been added yet',
),
),
const SizedBox(
@ -119,30 +111,25 @@ class SceneView extends StatelessWidget {
),
),
Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent),
data: ThemeData()
.copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
tilePadding:
const EdgeInsets.symmetric(
horizontal: 6),
title: const BodyMedium(
text: 'Automation'),
tilePadding: const EdgeInsets.symmetric(horizontal: 6),
title: const BodyMedium(text: 'Automation'),
children: [
automationList.isNotEmpty
? SceneGrid(
scenes: automationList,
loadingSceneId:
state.loadingSceneId,
loadingSceneId: state.loadingSceneId,
disablePlayButton: true,
loadingStates: state
.loadingStates, // Add this line
loadingStates:
state.loadingStates, // Add this line
)
: const Center(
child: BodyMedium(
text:
'No automations have been added yet',
text: 'No automations have been added yet',
),
),
const SizedBox(

View File

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class IconsDialog extends StatelessWidget {
final String title;
final Widget widgetList;
final Function()? cancelTab;
final Function()? confirmTab;
const IconsDialog({
super.key,
required this.widgetList,
required this.title,
required this.cancelTab,
required this.confirmTab,
});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: title,
fontWeight: FontWeight.w700,
fontColor: ColorsManager.primaryColor,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
widgetList,
Row(
children: [
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: SizedBox(
child: InkWell(
onTap: cancelTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Cancel',
style: TextStyle(
color: ColorsManager.textGray,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
),
),
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: InkWell(
onTap: confirmTab!,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Confirm',
style: TextStyle(
color: ColorsManager.primaryColor,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
@ -37,8 +38,8 @@ class SceneItem extends StatelessWidget {
onTap: () {
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent());
if (disablePlayButton == false) {
BlocProvider.of<CreateSceneBloc>(context).add(
FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
/// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context)
@ -72,19 +73,22 @@ class SceneItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
height: 32,
width: 32,
Assets.assetsIconsLogo,
fit: BoxFit.fill,
),
if (!disablePlayButton)
Image.memory(
height: 32,
width: 32,
scene.iconInBytes,
fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) =>
Image.asset(height: 32, width: 32, fit: BoxFit.fill, Assets.assetsIconsLogo),
),
if (disablePlayButton)
SvgPicture.asset(height: 32, width: 32, fit: BoxFit.fill, Assets.automationIcon),
disablePlayButton == false
? IconButton(
padding: EdgeInsets.zero,
onPressed: () {
context
.read<SceneBloc>()
.add(SceneTrigger(scene.id, scene.name));
context.read<SceneBloc>().add(SceneTrigger(scene.id, scene.name));
},
icon: isLoading
? const Center(
@ -106,15 +110,11 @@ class SceneItem extends StatelessWidget {
activeColor: ColorsManager.primaryColor,
value: scene.status == 'enable' ? true : false,
onChanged: (value) {
context.read<SceneBloc>().add(
UpdateAutomationStatus(
automationStatusUpdate:
AutomationStatusUpdate(
isEnable: value,
unitUuid: HomeCubit.getInstance()
.selectedSpace!
.id!),
automationId: scene.id));
context.read<SceneBloc>().add(UpdateAutomationStatus(
automationStatusUpdate: AutomationStatusUpdate(
isEnable: value,
unitUuid: HomeCubit.getInstance().selectedSpace!.id!),
automationId: scene.id));
},
),
],