push temp list logic before saving

This commit is contained in:
ashrafzarkanisala
2024-06-30 21:22:33 +03:00
parent 6699866ff0
commit cc6b754845
16 changed files with 282 additions and 72 deletions

View File

@ -291,4 +291,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: cf86fcba3fb3dbd505936bc190bb0b8fe3dd2498
COCOAPODS: 1.15.2
COCOAPODS: 1.14.3

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -17,18 +16,34 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
on<CreateSceneWithTasksEvent>(_createSceneWithTasks);
on<AddTaskEvent>(_onAddSceneTask);
on<SelectedValueEvent>(_selectedValue);
on<RemoveTaskEvent>(_removeTaskById);
on<RemoveTaskByIdEvent>(_removeTaskById);
on<ClearTaskListEvent>(_clearTaskList);
on<FetchSceneTasks>(_fetchSceneTasks);
on<ClearTempTaskListEvent>(_clearTempTaskList);
on<FetchSceneTasksEvent>(_fetchSceneTasks);
on<TempHoldSceneTasksEvent>(_onTempHoldSceneTask);
on<RemoveTempTaskByIdEvent>(_removeTempTaskById);
on<RemoveFromSelectedValueById>(_removeFromSelectedValueById);
}
List<SceneStaticFunction> tasksList = [];
dynamic selectedValue;
List<SceneStaticFunction> tempTasksList = [];
final Map<String, dynamic> selectedValues = {};
FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) {
tasksList.add(
SceneStaticFunction(
tasksList = List<SceneStaticFunction>.from(tempTasksList);
emit(AddSceneTask(tasksList: tasksList));
tempTasksList.clear();
emit(TempHoldSceneTask(tempTasksList: tempTasksList));
}
FutureOr<void> _onTempHoldSceneTask(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
bool updated = false;
for (var element in tempTasksList) {
if (element.code == event.deviceControlModel.code) {
// Update the existing function with new values
var updatedElement = element.copyWith(
operationName: event.operation,
deviceName: event.deviceName,
icon: event.icon,
@ -41,19 +56,44 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
icon: '',
),
],
),
);
emit(AddSceneTask(tasksList: tasksList));
tempTasksList[tempTasksList.indexOf(element)] = updatedElement;
selectedValues[updatedElement.code] = event.deviceControlModel.value;
updated = true;
break;
}
}
if (!updated) {
// Add new function if not found
var newElement = SceneStaticFunction(
operationName: event.operation,
deviceName: event.deviceName,
icon: event.icon,
code: event.deviceControlModel.code ?? '',
deviceId: event.deviceId,
functionValue: event.deviceControlModel.value,
operationalValues: [
SceneOperationalValue(
value: event.deviceControlModel.value,
icon: '',
),
],
);
tempTasksList.add(newElement);
selectedValues[newElement.code] = event.deviceControlModel.value;
}
emit(TempHoldSceneTask(tempTasksList: tempTasksList));
}
FutureOr<void> _selectedValue(
SelectedValueEvent event, Emitter<CreateSceneState> emit) {
selectedValue = event.value;
selectedValues[event.code] = event.value;
emit(SelectedTaskValueState(value: event.value));
}
FutureOr<void> _removeTaskById(
RemoveTaskEvent event, Emitter<CreateSceneState> emit) {
RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
for (var element in tasksList) {
@ -66,6 +106,18 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
FutureOr<void> _removeTempTaskById(
RemoveTempTaskByIdEvent event, Emitter<CreateSceneState> emit) {
for (var element in tempTasksList) {
if (element.code == event.code) {
tempTasksList.remove(element);
emit(TempHoldSceneTask(tempTasksList: tempTasksList));
break;
}
}
}
FutureOr<void> _createSceneWithTasks(
CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
@ -73,6 +125,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
final response = await SceneApi.createScene(event.createSceneModel);
if (response['success'] == true) {
tasksList.clear();
tempTasksList.clear();
emit(const CreateSceneWithTasks(success: true));
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
@ -90,14 +143,14 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
FutureOr<void> _fetchSceneTasks(
FetchSceneTasks event, Emitter<CreateSceneState> emit) async {
FetchSceneTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
try {
final response = await SceneApi.getSceneDetails(event.sceneId);
if (response.id.isNotEmpty) {
tasksList = getTaskListFunctionsFromApi(
actions: response.actions, deviceId: response.id);
tasksList = List.from(getTaskListFunctionsFromApi(
actions: response.actions, deviceId: response.id));
emit(AddSceneTask(tasksList: tasksList));
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
@ -106,4 +159,19 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
emit(CreateSceneError(message: e.toString()));
}
}
FutureOr<void> _clearTempTaskList(
ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
tempTasksList.clear();
selectedValues.clear();
emit(TempHoldSceneTask(tempTasksList: tempTasksList));
}
FutureOr<void> _removeFromSelectedValueById(
RemoveFromSelectedValueById event, Emitter<CreateSceneState> emit) {
if (selectedValues.containsKey(event.code)) {
selectedValues.remove(event.code);
emit(const SelectedTaskValueState(value: null));
}
}
}

View File

@ -8,43 +8,76 @@ sealed class CreateSceneEvent extends Equatable {
}
class AddTaskEvent extends CreateSceneEvent {
@override
List<Object> get props => [];
}
class TempHoldSceneTasksEvent extends CreateSceneEvent {
final DeviceControlModel deviceControlModel;
final String deviceId;
final String icon;
final String operation;
final String deviceName;
final String uniqueId;
const AddTaskEvent({
const TempHoldSceneTasksEvent({
required this.deviceControlModel,
required this.deviceId,
required this.icon,
required this.operation,
required this.deviceName,
required this.uniqueId,
});
@override
List<Object> get props =>
[deviceControlModel, deviceId, deviceName, icon, operation];
List<Object> get props => [
deviceControlModel,
deviceId,
deviceName,
icon,
operation,
uniqueId,
deviceName,
icon
];
}
class SelectedValueEvent extends CreateSceneEvent {
final dynamic value;
final String code;
const SelectedValueEvent({this.value});
const SelectedValueEvent({this.value, required this.code});
@override
List<Object> get props => [value!];
List<Object> get props => [value!, code];
}
class RemoveTaskEvent extends CreateSceneEvent {
class RemoveTaskByIdEvent extends CreateSceneEvent {
final String taskId;
const RemoveTaskEvent({required this.taskId});
const RemoveTaskByIdEvent({required this.taskId});
@override
List<Object> get props => [taskId];
}
class RemoveTempTaskByIdEvent extends CreateSceneEvent {
final String code;
const RemoveTempTaskByIdEvent({required this.code});
@override
List<Object> get props => [code];
}
class RemoveFromSelectedValueById extends CreateSceneEvent {
final String code;
const RemoveFromSelectedValueById({required this.code});
@override
List<Object> get props => [code];
}
class CreateSceneWithTasksEvent extends CreateSceneEvent {
final CreateSceneModel createSceneModel;
const CreateSceneWithTasksEvent({required this.createSceneModel});
@ -60,9 +93,16 @@ class ClearTaskListEvent extends CreateSceneEvent {
List<Object> get props => [];
}
class FetchSceneTasks extends CreateSceneEvent {
final String sceneId;
const FetchSceneTasks({required this.sceneId});
class ClearTempTaskListEvent extends CreateSceneEvent {
const ClearTempTaskListEvent();
@override
List<Object> get props => [];
}
class FetchSceneTasksEvent extends CreateSceneEvent {
final String sceneId;
const FetchSceneTasksEvent({required this.sceneId});
@override
List<Object> get props => [];

View File

@ -27,6 +27,14 @@ class AddSceneTask extends CreateSceneState {
List<Object> get props => [tasksList];
}
class TempHoldSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tempTasksList;
const TempHoldSceneTask({required this.tempTasksList});
@override
List<Object> get props => [tempTasksList];
}
class SelectedTaskValueState extends CreateSceneState {
final dynamic value;
const SelectedTaskValueState({required this.value});

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:equatable/equatable.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/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/services/api/scene_api.dart';

View File

@ -3,8 +3,7 @@ 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_details_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/utils/context_extension.dart';

View File

@ -1,8 +1,6 @@
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/features/scene/enum/ac_values.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_details_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';

View File

@ -34,6 +34,7 @@ class SceneStaticFunction {
String? operationName,
dynamic functionValue,
String? deviceIcon,
String? deviceName,
}) {
return SceneStaticFunction(
icon: icon ?? this.icon,
@ -57,6 +58,7 @@ class SceneStaticFunction {
'operationName': operationName,
'functionValue': functionValue,
'deviceIcon': deviceIcon
};
}

View File

@ -46,6 +46,7 @@ class DeviceFunctionsView extends StatelessWidget
actions: [
TextButton(
onPressed: () {
context.read<CreateSceneBloc>().add(AddTaskEvent());
Navigator.popUntil(context, (route) {
return route.settings.name == Routes.sceneTasksRoute;
});
@ -58,7 +59,10 @@ class DeviceFunctionsView extends StatelessWidget
),
],
leading: TextButton(
onPressed: () => Navigator.pop(context),
onPressed: () {
context.read<CreateSceneBloc>().add(const ClearTaskListEvent());
Navigator.pop(context);
},
child: BodyMedium(
text: 'Cancel',
fontWeight: FontWeight.normal,
@ -114,10 +118,16 @@ class DeviceFunctionsView extends StatelessWidget
],
),
onPressed: () {
final functionValues = context
.read<CreateSceneBloc>()
.selectedValues[functions[index].code];
context.customAlertDialog(
alertBody: functions[index].code == 'temp_set'
? AlertDialogTemperatureBody(
index: index, functions: functions,)
index: index,
functions: functions,
functionValue: functionValues,
)
: (functions[index]
.code
.contains('countdown') ||
@ -128,17 +138,23 @@ class DeviceFunctionsView extends StatelessWidget
durationValue: functions[index]
.operationalValues
.first
.value)
.value,
function: functions[index],
functionValue: functionValues,
)
: AlertDialogFunctionsOperationsBody(
index: index, functions: functions),
index: index,
functions: functions,
functionValue: functionValues,
),
title: functions[index].operationName,
onConfirm: () {
final selectedValue = context
.read<CreateSceneBloc>()
.selectedValue;
.selectedValues[functions[index].code];
context
.read<CreateSceneBloc>()
.add(AddTaskEvent(
.add(TempHoldSceneTasksEvent(
deviceControlModel: DeviceControlModel(
deviceId: device.uuid,
code: functions[index].code,
@ -148,9 +164,32 @@ class DeviceFunctionsView extends StatelessWidget
operation: functions[index].operationName,
icon: device.icon ?? '',
deviceName: device.name ?? '',
uniqueId: functions[index].uniqueCustomId,
));
Navigator.pop(context);
},
onDismiss: () {
final tempTaskList = context
.read<CreateSceneBloc>()
.tempTasksList;
if (tempTaskList.isEmpty) {
context
.read<CreateSceneBloc>()
.add(const ClearTempTaskListEvent());
} else {
for (var element in tempTaskList) {
if (element.code == functions[index].code) {
context.read<CreateSceneBloc>().add(
RemoveTempTaskByIdEvent(
code: functions[index].code));
context.read<CreateSceneBloc>().add(
RemoveFromSelectedValueById(
code: functions[index].code));
}
}
}
Navigator.pop(context);
},
);
},
);

View File

@ -1,14 +1,22 @@
// ignore_for_file: must_be_immutable
import 'package:flutter/cupertino.dart';
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/model/scene_static_function.dart';
class AlertDialogCountdown extends StatefulWidget {
AlertDialogCountdown(
{super.key, required this.durationValue, this.functionValue});
AlertDialogCountdown({
super.key,
required this.durationValue,
this.functionValue,
required this.function,
});
final int durationValue;
dynamic functionValue;
SceneStaticFunction function;
@override
State<AlertDialogCountdown> createState() => _AlertDialogCountdownState();
@ -18,6 +26,17 @@ class _AlertDialogCountdownState extends State<AlertDialogCountdown> {
@override
didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
for (var element in tempTaskList) {
if (element.code == widget.function.code) {
durationInSeconds = element.functionValue;
} else {
context
.read<CreateSceneBloc>()
.add(RemoveFromSelectedValueById(code: widget.function.code));
}
}
if (widget.functionValue != null) {
setState(() {
durationInSeconds = widget.functionValue;
@ -41,9 +60,8 @@ class _AlertDialogCountdownState extends State<AlertDialogCountdown> {
setState(() {
durationInSeconds = newDuration.inSeconds;
});
context
.read<CreateSceneBloc>()
.add(SelectedValueEvent(value: newDuration.inSeconds));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: newDuration.inSeconds, code: widget.function.code));
},
),
);

View File

@ -1,3 +1,5 @@
// ignore_for_file: must_be_immutable
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';
@ -26,6 +28,19 @@ class _AlertDialogFunctionsOperationsBodyState
@override
didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
if (tempTaskList.isEmpty) {
context.read<CreateSceneBloc>().add(const ClearTempTaskListEvent());
}
for (var element in tempTaskList) {
if (element.code == widget.functions[widget.index].code) {
groupValue = element.functionValue;
} else {
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
code: widget.functions[widget.index].code));
}
}
if (widget.functionValue != null) {
setState(() {
groupValue = widget.functionValue;
@ -60,18 +75,18 @@ class _AlertDialogFunctionsOperationsBodyState
setState(() {
groupValue = value;
});
context
.read<CreateSceneBloc>()
.add(SelectedValueEvent(value: value!));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: value!,
code: widget.functions[widget.index].code));
},
),
onPressed: () {
setState(() {
groupValue = operation.value;
});
context
.read<CreateSceneBloc>()
.add(SelectedValueEvent(value: groupValue));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: groupValue,
code: widget.functions[widget.index].code));
},
);
},

View File

@ -1,3 +1,5 @@
// ignore_for_file: must_be_immutable
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -31,6 +33,16 @@ class _AlertDialogTemperatureBodyState
@override
didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
for (var element in tempTaskList) {
if (element.code == widget.functions[widget.index].code) {
temperature = element.functionValue;
} else {
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
code: widget.functions[widget.index].code));
}
}
if (widget.functionValue != null) {
setState(() {
temperature = widget.functionValue;
@ -50,9 +62,9 @@ class _AlertDialogTemperatureBodyState
temperature--;
}
});
context
.read<CreateSceneBloc>()
.add(SelectedValueEvent(value: temperature * 10));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: temperature * 10,
code: widget.functions[widget.index].code));
},
icon: const Icon(
Icons.remove,
@ -93,9 +105,9 @@ class _AlertDialogTemperatureBodyState
temperature++;
}
});
context
.read<CreateSceneBloc>()
.add(SelectedValueEvent(value: temperature * 10));
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: temperature * 10,
code: widget.functions[widget.index].code));
},
icon: const Icon(
Icons.add,

View File

@ -1,3 +1,5 @@
// ignore_for_file: must_be_immutable
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -61,6 +63,7 @@ class ThenAddedTasksContainer extends StatelessWidget {
durationValue:
listOfSceneStaticFunction![index!].functionValue,
functionValue: taskList.functionValue,
function: listOfSceneStaticFunction![index!],
)
: AlertDialogFunctionsOperationsBody(
index: index!,
@ -69,7 +72,7 @@ class ThenAddedTasksContainer extends StatelessWidget {
title: listOfSceneStaticFunction![index!].operationName,
onConfirm: () {
// final selectedValue = context.read<CreateSceneBloc>().selectedValue;
// context.read<CreateSceneBloc>().add(AddTaskEvent(
// context.read<CreateSceneBloc>().add(TempHoldSceneTasksEvent(
// deviceControlModel: DeviceControlModel(
// deviceId: device.uuid,
// code: functions[index].code,
@ -111,7 +114,7 @@ class ThenAddedTasksContainer extends StatelessWidget {
context
.read<CreateSceneBloc>()
.add(RemoveTaskEvent(taskId: removeFunctionById));
.add(RemoveTaskByIdEvent(taskId: removeFunctionById));
String removeFunction =
"${taskList.operationName} with value ${taskList.operationalValues.first.value}";

View File

@ -52,8 +52,8 @@ class ThenDefaultContainer extends StatelessWidget {
const LightDivider(),
sceneId.isNotEmpty
? BlocProvider(
create: (context) =>
CreateSceneBloc()..add(FetchSceneTasks(sceneId: sceneId)),
create: (context) => CreateSceneBloc()
..add(FetchSceneTasksEvent(sceneId: sceneId)),
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
if (state is CreateSceneLoading) {

View File

@ -69,13 +69,15 @@ class SceneItem extends StatelessWidget {
],
),
const SizedBox(height: 10),
BodyMedium(
FittedBox(
child: BodyMedium(
text: scene.name,
maxLines: 1,
overflow: TextOverflow.fade,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
);

View File

@ -14,7 +14,8 @@ extension ContextExtension on BuildContext {
double get height => MediaQuery.sizeOf(this).height;
InputDecorationTheme get inputDecoration => Theme.of(this).inputDecorationTheme;
InputDecorationTheme get inputDecoration =>
Theme.of(this).inputDecorationTheme;
TextStyle get displayLarge => Theme.of(this).textTheme.displayLarge!;
@ -59,8 +60,12 @@ extension ContextExtension on BuildContext {
);
}
void customAlertDialog(
{required Widget alertBody, required String title, required VoidCallback onConfirm}) {
void customAlertDialog({
required Widget alertBody,
required String title,
required VoidCallback onConfirm,
VoidCallback? onDismiss,
}) {
showDialog(
context: this,
builder: (BuildContext context) {
@ -109,13 +114,15 @@ extension ContextExtension on BuildContext {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
onTap: onDismiss ??
() {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
),
),
),
@ -129,8 +136,8 @@ extension ContextExtension on BuildContext {
child: Center(
child: BodyMedium(
text: 'Confirm',
style: context.bodyMedium
.copyWith(color: ColorsManager.primaryColorWithOpacity),
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity),
),
),
),