Merge pull request #39 from SyncrowIOT/automation

Automation
This commit is contained in:
Abdullah
2024-07-29 12:42:09 +03:00
committed by GitHub
90 changed files with 6822 additions and 2563 deletions
+52 -20
View File
@@ -17,10 +17,16 @@ import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
@@ -52,13 +58,12 @@ class HomeCubit extends Cubit<HomeState> {
return _instance!;
}
Future fetchUserInfo() async {
Future fetchUserInfo() async {
try {
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await ProfileApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
} catch (e) {
return;
}
@@ -77,9 +82,12 @@ class HomeCubit extends Cubit<HomeState> {
selectedSpace = null;
selectedRoom = null;
pageIndex = 0;
OneSignal.User.pushSubscription.removeObserver((stateChanges) => oneSignalSubscriptionObserver);
OneSignal.Notifications.removePermissionObserver((permission) => oneSignalPermissionObserver);
OneSignal.Notifications.removeClickListener((event) => oneSignalClickListenerObserver);
OneSignal.User.pushSubscription
.removeObserver((stateChanges) => oneSignalSubscriptionObserver);
OneSignal.Notifications.removePermissionObserver(
(permission) => oneSignalPermissionObserver);
OneSignal.Notifications.removeClickListener(
(event) => oneSignalClickListenerObserver);
return super.close();
}
@@ -121,7 +129,9 @@ class HomeCubit extends Cubit<HomeState> {
return;
}
var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
var userUuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
if (userUuid.isNotEmpty) {
await OneSignal.login(userUuid);
}
@@ -129,21 +139,24 @@ class HomeCubit extends Cubit<HomeState> {
await OneSignal.User.pushSubscription.optIn();
//this function will be called once a user is subscribed
oneSignalSubscriptionObserver = OneSignal.User.pushSubscription.addObserver((state) async {
oneSignalSubscriptionObserver =
OneSignal.User.pushSubscription.addObserver((state) async {
if (state.current.optedIn) {
await _sendSubscriptionId();
}
});
// Send the player id when a user allows notifications
oneSignalPermissionObserver = OneSignal.Notifications.addPermissionObserver((state) async {
oneSignalPermissionObserver =
OneSignal.Notifications.addPermissionObserver((state) async {
await _sendSubscriptionId();
});
//check if the player id is sent, if not send it again
await _sendSubscriptionId();
oneSignalClickListenerObserver = OneSignal.Notifications.addClickListener((event) async {
oneSignalClickListenerObserver =
OneSignal.Notifications.addClickListener((event) async {
//Once the user clicks on the notification
});
} catch (err) {
@@ -230,7 +243,9 @@ class HomeCubit extends Cubit<HomeState> {
Future<bool> joinAUnit(String code) async {
try {
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ??
'';
Map<String, String> body = {'userUuid': uuid, 'inviteCode': code};
final success = await SpacesAPI.joinUnit(body);
@@ -348,15 +363,28 @@ class HomeCubit extends Cubit<HomeState> {
size: 32,
),
style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
foregroundColor:
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {
Navigator.push(
Navigator.pushNamed(
NavigationService.navigatorKey.currentContext!,
CustomPageRoute(
builder: (context) => const CreateSceneView(),
Routes.sceneTasksRoute,
arguments: SceneSettingsRouteArguments(
sceneType: '',
sceneId: '',
sceneName: '',
),
);
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const ClearTaskListEvent());
NavigationService.navigatorKey.currentContext!
.read<CreateSceneBloc>()
.add(const SceneTypeEvent(CreateSceneEnum.none));
NavigationService.navigatorKey.currentContext!
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
},
),
IconButton(
@@ -365,7 +393,8 @@ class HomeCubit extends Cubit<HomeState> {
size: 28,
),
style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
foregroundColor:
WidgetStateProperty.all(ColorsManager.textPrimaryColor),
),
onPressed: () {},
),
@@ -398,7 +427,8 @@ class HomeCubit extends Cubit<HomeState> {
};
static var bottomNavItems = [
defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
defaultBottomNavBarItem(
icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
// defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
@@ -424,7 +454,8 @@ class HomeCubit extends Cubit<HomeState> {
void updateDevice(String deviceId) async {
try {
final response = await DevicesAPI.firmwareDevice(deviceId: deviceId, firmwareVersion: '0');
final response = await DevicesAPI.firmwareDevice(
deviceId: deviceId, firmwareVersion: '0');
if (response['success'] ?? false) {
CustomSnackBar.displaySnackBar('No updates available');
}
@@ -432,7 +463,8 @@ class HomeCubit extends Cubit<HomeState> {
}
}
BottomNavigationBarItem defaultBottomNavBarItem({required String icon, required String label}) {
BottomNavigationBarItem defaultBottomNavBarItem(
{required String icon, required String label}) {
return BottomNavigationBarItem(
icon: SvgPicture.asset(icon),
activeIcon: SvgPicture.asset(
+4 -2
View File
@@ -45,7 +45,8 @@ class DeviceModel {
if (type == DeviceType.LightBulb) {
tempIcon = Assets.assetsIconsLight;
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
} else if (type == DeviceType.CeilingSensor ||
type == DeviceType.WallSensor) {
tempIcon = Assets.assetsIconsSensors;
} else if (type == DeviceType.AC) {
tempIcon = Assets.assetsIconsAC;
@@ -93,5 +94,6 @@ class DeviceModel {
};
}
List<FunctionModel> getFunctions(DeviceType type) => devicesFunctionsMap[productType] ?? [];
List<FunctionModel> getFunctions(DeviceType type) =>
devicesFunctionsMap[productType] ?? [];
}
@@ -1,6 +1,3 @@
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';
@@ -12,7 +9,6 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
class SceneListview extends StatelessWidget {
final List<ScenesModel> scenes;
final String? loadingSceneId;
@@ -24,8 +20,7 @@ class SceneListview extends StatelessWidget {
@override
Widget build(BuildContext context) {
return
ListView.builder(
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: scenes.length,
@@ -34,7 +29,7 @@ class SceneListview extends StatelessWidget {
final isLoading = loadingSceneId == scene.id;
return Container(
padding: const EdgeInsets.only(right: 10),
child:DefaultContainer(
child: DefaultContainer(
onTap: () {
Navigator.pushNamed(
context,
@@ -45,10 +40,11 @@ class SceneListview extends StatelessWidget {
sceneName: scene.name,
),
);
BlocProvider.of<CreateSceneBloc>(context).add(FetchSceneTasksEvent(sceneId: scene.id));
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id));
},
child:SizedBox(
width: MediaQuery.of(context).size.width*0.4,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@@ -73,8 +69,7 @@ class SceneListview extends StatelessWidget {
],
),
),
)
);
));
},
);
}
@@ -1,10 +1,17 @@
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';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/services/api/scene_api.dart';
part 'create_scene_event.dart';
@@ -25,23 +32,65 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
on<RemoveFromSelectedValueById>(_removeFromSelectedValueById);
on<DeleteSceneEvent>(_deleteScene);
on<UpdateTaskEvent>(_updateTaskValue);
on<SelectConditionEvent>(_selectConditionRule);
on<SceneTypeEvent>(_sceneTypeEvent);
on<EffectiveTimePeriodEvent>(_onEffectiveTimeEvent);
}
CreateSceneEnum sceneType = CreateSceneEnum.none;
/// tab to run values and list
List<SceneStaticFunction> tasksList = [];
List<SceneStaticFunction> tempTasksList = [];
final Map<String, dynamic> selectedValues = {};
/// automation values and list
List<SceneStaticFunction> automationTasksList = [];
List<SceneStaticFunction> automationTempTasksList = [];
final Map<String, dynamic> automationSelectedValues = {};
final Map<String, String> automationComparatorValues = {};
String conditionRule = 'or';
EffectiveTime? effectiveTime;
FutureOr<void> _onAddSceneTask(
AddTaskEvent event, Emitter<CreateSceneState> emit) {
final copyList = List<SceneStaticFunction>.from(tempTasksList);
tasksList.addAll(copyList);
tempTasksList.clear();
selectedValues.clear();
emit(AddSceneTask(tasksList: tasksList));
emit(CreateSceneLoading());
if (event.isAutomation == true) {
final copyList = List<SceneStaticFunction>.from(automationTempTasksList);
automationTasksList.addAll(copyList);
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
emit(AddSceneTask(
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
));
} else {
final copyList = List<SceneStaticFunction>.from(tempTasksList);
tasksList.addAll(copyList);
tempTasksList.clear();
selectedValues.clear();
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
}
FutureOr<void> _onTempHoldSceneTask(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
if (event.isAutomation == true) {
addToTempAutomationTaskList(event, emit);
} else {
addToTempTaskList(event, emit);
}
}
void addToTempTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
for (var element in tempTasksList) {
if (element.code == event.deviceControlModel.code) {
@@ -53,6 +102,7 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
code: event.deviceControlModel.code ?? '',
deviceId: event.deviceId,
functionValue: event.deviceControlModel.value,
operationDialogType: event.operationType,
operationalValues: [
SceneOperationalValue(
value: event.deviceControlModel.value,
@@ -67,12 +117,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
}
}
if (!updated) {
// Add new function if not found
var newElement = SceneStaticFunction(
operationName: event.operation,
deviceName: event.deviceName,
icon: event.icon,
code: event.deviceControlModel.code ?? '',
operationDialogType: event.operationType,
deviceId: event.deviceId,
functionValue: event.deviceControlModel.value,
operationalValues: [
@@ -86,40 +136,161 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
selectedValues[newElement.code] = event.deviceControlModel.value;
}
emit(TempHoldSceneTask(tempTasksList: tempTasksList));
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
void addToTempAutomationTaskList(
TempHoldSceneTasksEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
bool updated = false;
for (var element in automationTempTasksList) {
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,
code: event.deviceControlModel.code ?? '',
deviceId: event.deviceId,
functionValue: event.deviceControlModel.value,
operationDialogType: event.operationType,
operationalValues: [
SceneOperationalValue(
value: event.deviceControlModel.value,
icon: '',
),
],
comparator: automationComparatorValues[element.code],
);
automationTempTasksList[automationTempTasksList.indexOf(element)] =
updatedElement;
automationSelectedValues[updatedElement.code] =
event.deviceControlModel.value;
updated = true;
break;
}
}
if (!updated) {
var newElement = SceneStaticFunction(
operationName: event.operation,
deviceName: event.deviceName,
icon: event.icon,
code: event.deviceControlModel.code ?? '',
operationDialogType: event.operationType,
deviceId: event.deviceId,
functionValue: event.deviceControlModel.value,
operationalValues: [
SceneOperationalValue(
value: event.deviceControlModel.value,
icon: '',
),
],
comparator:
automationComparatorValues[event.deviceControlModel.code] ?? '==',
);
automationTempTasksList.add(newElement);
automationSelectedValues[newElement.code] =
event.deviceControlModel.value;
}
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
FutureOr<void> _selectedValue(
SelectedValueEvent event, Emitter<CreateSceneState> emit) {
selectedValues[event.code] = event.value;
if (event.isAutomation == true) {
automationSelectedValues[event.code] = event.value;
automationComparatorValues[event.code] = event.comparator ?? '==';
// Update the comparator value for the specific task in automationTasksList
for (int i = 0; i < automationTasksList.length; i++) {
if (automationTasksList[i].code == event.code) {
automationTasksList[i] = automationTasksList[i].copyWith(
comparator: event.comparator ?? '==',
functionValue: event.value,
);
break;
}
}
} else {
selectedValues[event.code] = event.value;
}
emit(SelectedTaskValueState(value: event.value));
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: List.from(tasksList),
automationTasksList: List.from(
automationTasksList,
),
condition: conditionRule,
));
}
FutureOr<void> _removeTaskById(
RemoveTaskByIdEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var element in automationTasksList) {
if (element.uniqueCustomId == event.taskId) {
automationTasksList.remove(element);
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
break;
}
}
} else {
for (var element in tasksList) {
if (element.uniqueCustomId == event.taskId) {
tasksList.remove(element);
for (var element in tasksList) {
if (element.uniqueCustomId == event.taskId) {
tasksList.remove(element);
emit(AddSceneTask(tasksList: tasksList));
break;
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
break;
}
}
}
}
FutureOr<void> _removeTempTaskById(
RemoveTempTaskByIdEvent event, Emitter<CreateSceneState> emit) {
for (var element in tempTasksList) {
if (element.code == event.code) {
tempTasksList.remove(element);
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var element in automationTempTasksList) {
if (element.uniqueCustomId == event.code) {
automationTempTasksList.remove(element);
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
break;
}
}
} else {
for (var element in tempTasksList) {
if (element.code == event.code) {
tempTasksList.remove(element);
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
break;
break;
}
}
}
}
@@ -128,27 +299,53 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
CreateSceneWithTasksEvent event, Emitter<CreateSceneState> emit) async {
emit(CreateSceneLoading());
try {
final response = event.updateScene
? await SceneApi.updateScene(event.createSceneModel, event.sceneId)
: await SceneApi.createScene(event.createSceneModel);
dynamic response;
if (event.createSceneModel != null) {
response = event.updateScene
? await SceneApi.updateScene(event.createSceneModel!, event.sceneId)
: await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) {
response = event.updateScene
? await SceneApi.updateAutomation(
event.createAutomationModel!, event.sceneId)
: await SceneApi.createAutomation(event.createAutomationModel!);
}
if (response['success'] == true) {
tasksList.clear();
tempTasksList.clear();
selectedValues.clear();
automationTasksList.clear();
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
effectiveTime = null;
sceneType = CreateSceneEnum.none;
conditionRule = 'or';
emit(const CreateSceneWithTasks(success: true));
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
} catch (e) {
emit(const CreateSceneError(message: 'Something went wrong'));
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
}
FutureOr<void> _clearTaskList(
ClearTaskListEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneLoading());
automationTasksList.clear();
tasksList.clear();
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
FutureOr<void> _fetchSceneTasks(
@@ -156,13 +353,46 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
emit(CreateSceneLoading());
try {
final response = await SceneApi.getSceneDetails(event.sceneId);
final response = event.isAutomation
? await SceneApi.getAutomationDetails(event.sceneId)
: await SceneApi.getSceneDetails(event.sceneId);
if (response.id.isNotEmpty) {
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(actions: response.actions));
emit(AddSceneTask(
tasksList: tasksList,
));
if (event.isAutomation) {
automationTasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: [],
isAutomation: true,
conditions: response.conditions));
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
conditionRule = response.decisionExpr ?? conditionRule;
if (response.effectiveTime != null) {
BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(SetCustomTime(response.effectiveTime!.start,
response.effectiveTime!.end));
BlocProvider.of<EffectPeriodBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(ToggleDay(response.effectiveTime!.loops));
}
emit(AddSceneTask(
automationTasksList: automationTasksList,
tasksList: tasksList,
condition: conditionRule,
));
} else {
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
emit(AddSceneTask(
tasksList: tasksList,
condition: conditionRule,
));
}
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
@@ -173,17 +403,51 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
FutureOr<void> _clearTempTaskList(
ClearTempTaskListEvent event, Emitter<CreateSceneState> emit) {
tempTasksList.clear();
selectedValues.clear();
emit(AddSceneTask(tasksList: tempTasksList));
emit(CreateSceneLoading());
if (event.isAutomation == true) {
automationTempTasksList.clear();
automationSelectedValues.clear();
automationComparatorValues.clear();
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
} else {
tempTasksList.clear();
selectedValues.clear();
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
}
FutureOr<void> _removeFromSelectedValueById(
RemoveFromSelectedValueById event, Emitter<CreateSceneState> emit) {
if (selectedValues.containsKey(event.code)) {
selectedValues.remove(event.code);
emit(const SelectedTaskValueState(value: null));
emit(AddSceneTask(tasksList: tasksList));
emit(CreateSceneLoading());
if (event.isAutomation == true) {
if (automationSelectedValues.containsKey(event.code)) {
automationSelectedValues.remove(event.code);
automationComparatorValues.remove(event.code);
emit(const SelectedTaskValueState(value: null));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
} else {
if (selectedValues.containsKey(event.code)) {
selectedValues.remove(event.code);
emit(const SelectedTaskValueState(value: null));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
}
}
@@ -192,8 +456,12 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
emit(DeleteSceneLoading());
try {
final response = 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 {
@@ -206,14 +474,66 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
FutureOr<void> _updateTaskValue(
UpdateTaskEvent event, Emitter<CreateSceneState> emit) {
for (var i = 0; i < tasksList.length; i++) {
if (tasksList[i].uniqueCustomId == event.taskId) {
tasksList[i] = tasksList[i].copyWith(
functionValue: event.newValue,
);
break;
emit(CreateSceneLoading());
if (event.isAutomation == true) {
for (var i = 0; i < automationTasksList.length; i++) {
if (automationTasksList[i].uniqueCustomId == event.taskId) {
automationTasksList[i] = automationTasksList[i].copyWith(
functionValue: event.newValue,
);
break;
}
}
} else {
for (var i = 0; i < tasksList.length; i++) {
if (tasksList[i].uniqueCustomId == event.taskId) {
tasksList[i] = tasksList[i].copyWith(
functionValue: event.newValue,
);
break;
}
}
}
emit(AddSceneTask(tasksList: tasksList));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
FutureOr<void> _selectConditionRule(
SelectConditionEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.condition.contains('any')) {
conditionRule = 'or';
} else {
conditionRule = 'and';
}
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
FutureOr<void> _sceneTypeEvent(
SceneTypeEvent event, Emitter<CreateSceneState> emit) {
emit(CreateSceneInitial());
if (event.type == CreateSceneEnum.tabToRun) {
sceneType = CreateSceneEnum.tabToRun;
} else if (event.type == CreateSceneEnum.deviceStatusChanges) {
sceneType = CreateSceneEnum.deviceStatusChanges;
} else {
sceneType = CreateSceneEnum.none;
}
emit(SceneTypeState(event.type));
}
FutureOr<void> _onEffectiveTimeEvent(
EffectiveTimePeriodEvent event, Emitter<CreateSceneState> emit) {
effectiveTime = event.period;
}
}
@@ -8,6 +8,9 @@ sealed class CreateSceneEvent extends Equatable {
}
class AddTaskEvent extends CreateSceneEvent {
const AddTaskEvent({this.isAutomation});
final bool? isAutomation;
@override
List<Object> get props => [];
}
@@ -19,6 +22,8 @@ class TempHoldSceneTasksEvent extends CreateSceneEvent {
final String operation;
final String deviceName;
final String uniqueId;
final bool? isAutomation;
final OperationDialogType operationType;
const TempHoldSceneTasksEvent({
required this.deviceControlModel,
@@ -27,6 +32,8 @@ class TempHoldSceneTasksEvent extends CreateSceneEvent {
required this.operation,
required this.deviceName,
required this.uniqueId,
this.isAutomation,
required this.operationType,
});
@override
@@ -38,23 +45,37 @@ class TempHoldSceneTasksEvent extends CreateSceneEvent {
operation,
uniqueId,
deviceName,
icon
icon,
];
}
class UpdateTaskEvent extends CreateSceneEvent {
final String taskId;
final dynamic newValue;
const UpdateTaskEvent({required this.taskId, required this.newValue});
final bool? isAutomation;
const UpdateTaskEvent({
required this.taskId,
required this.newValue,
this.isAutomation,
});
@override
List<Object> get props => [taskId, newValue];
}
class SelectedValueEvent extends CreateSceneEvent {
final dynamic value;
final dynamic automationValue;
final String code;
final bool? isAutomation;
final String? comparator;
const SelectedValueEvent({this.value, required this.code});
const SelectedValueEvent({
this.value,
required this.code,
this.isAutomation,
this.automationValue,
this.comparator,
});
@override
List<Object> get props => [value!, code];
@@ -62,8 +83,11 @@ class SelectedValueEvent extends CreateSceneEvent {
class RemoveTaskByIdEvent extends CreateSceneEvent {
final String taskId;
const RemoveTaskByIdEvent({required this.taskId});
final bool? isAutomation;
const RemoveTaskByIdEvent({
required this.taskId,
this.isAutomation,
});
@override
List<Object> get props => [taskId];
@@ -71,7 +95,8 @@ class RemoveTaskByIdEvent extends CreateSceneEvent {
class RemoveTempTaskByIdEvent extends CreateSceneEvent {
final String code;
const RemoveTempTaskByIdEvent({required this.code});
final bool? isAutomation;
const RemoveTempTaskByIdEvent({required this.code, this.isAutomation});
@override
List<Object> get props => [code];
@@ -79,36 +104,42 @@ class RemoveTempTaskByIdEvent extends CreateSceneEvent {
class RemoveFromSelectedValueById extends CreateSceneEvent {
final String code;
const RemoveFromSelectedValueById({required this.code});
final bool? isAutomation;
const RemoveFromSelectedValueById({required this.code, this.isAutomation});
@override
List<Object> get props => [code];
}
class CreateSceneWithTasksEvent extends CreateSceneEvent {
final CreateSceneModel createSceneModel;
final CreateSceneModel? createSceneModel;
final bool updateScene;
final String sceneId;
final CreateAutomationModel? createAutomationModel;
//final bool isAutomation;
const CreateSceneWithTasksEvent({
required this.createSceneModel,
required this.updateScene,
required this.sceneId,
required this.createAutomationModel,
// required this.isAutomation,
});
@override
List<Object> get props => [createSceneModel];
List<Object> get props => [];
}
class ClearTaskListEvent extends CreateSceneEvent {
const ClearTaskListEvent();
const ClearTaskListEvent({this.isAutomation});
final bool? isAutomation;
@override
List<Object> get props => [];
}
class ClearTempTaskListEvent extends CreateSceneEvent {
const ClearTempTaskListEvent();
const ClearTempTaskListEvent({this.isAutomation});
final bool? isAutomation;
@override
List<Object> get props => [];
@@ -116,10 +147,13 @@ class ClearTempTaskListEvent extends CreateSceneEvent {
class FetchSceneTasksEvent extends CreateSceneEvent {
final String sceneId;
const FetchSceneTasksEvent({required this.sceneId});
final bool isAutomation;
const FetchSceneTasksEvent(
{this.isAutomation = false, required this.sceneId});
@override
List<Object> get props => [];
List<Object> get props => [sceneId, isAutomation];
}
class DeleteSceneEvent extends CreateSceneEvent {
@@ -133,3 +167,19 @@ class DeleteSceneEvent extends CreateSceneEvent {
@override
List<Object> get props => [sceneId, unitUuid];
}
class SelectConditionEvent extends CreateSceneEvent {
final String condition;
const SelectConditionEvent(this.condition);
}
class SceneTypeEvent extends CreateSceneEvent {
final CreateSceneEnum type;
const SceneTypeEvent(this.type);
}
class EffectiveTimePeriodEvent extends CreateSceneEvent {
final EffectiveTime period;
const EffectiveTimePeriodEvent(this.period);
}
@@ -21,7 +21,10 @@ class CreateSceneError extends CreateSceneState {
class AddSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tasksList;
const AddSceneTask({required this.tasksList});
final List<SceneStaticFunction>? automationTasksList;
final String? condition;
const AddSceneTask(
{required this.tasksList, this.automationTasksList, this.condition});
@override
List<Object> get props => [tasksList];
@@ -29,7 +32,9 @@ class AddSceneTask extends CreateSceneState {
class TempHoldSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tempTasksList;
const TempHoldSceneTask({required this.tempTasksList});
final List<SceneStaticFunction>? automationTempTasksList;
const TempHoldSceneTask(
{required this.tempTasksList, this.automationTempTasksList});
@override
List<Object> get props => [tempTasksList];
@@ -68,3 +73,14 @@ class DeleteSceneError extends CreateSceneState {
}
class DeleteSceneLoading extends CreateSceneState {}
class ConditionSelectedState extends CreateSceneState {
final String condition;
const ConditionSelectedState(this.condition);
}
class SceneTypeState extends CreateSceneState {
final CreateSceneEnum type;
const SceneTypeState(this.type);
}
@@ -0,0 +1,86 @@
import 'package:bloc/bloc.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/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/scene/enum/effective_period_options.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
EffectPeriodBloc() : super(EffectPeriodState.initial()) {
on<SetPeriod>(_onSetPeriod);
on<ToggleDay>(_onToggleDay);
on<SetCustomTime>(_onSetCustomTime);
}
void _onSetPeriod(SetPeriod event, Emitter<EffectPeriodState> emit) {
String startTime = '';
String endTime = '';
switch (event.period) {
case EnumEffectivePeriodOptions.allDay:
startTime = '00:00';
endTime = '23:59';
break;
case EnumEffectivePeriodOptions.daytime:
startTime = '06:00';
endTime = '18:00';
break;
case EnumEffectivePeriodOptions.night:
startTime = '18:00';
endTime = '06:00';
break;
case EnumEffectivePeriodOptions.custom:
startTime = state.customStartTime ?? '00:00';
endTime = state.customEndTime ?? '23:59';
break;
default:
break;
}
// Update CreateSceneBloc
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(EffectiveTimePeriodEvent(EffectiveTime(
start: startTime, end: endTime, loops: state.selectedDaysBinary)));
emit(state.copyWith(selectedPeriod: event.period));
}
void _onToggleDay(ToggleDay event, Emitter<EffectPeriodState> emit) {
final daysList = state.selectedDaysBinary.split('');
final dayIndex = _getDayIndex(event.day);
if (daysList[dayIndex] == '1') {
daysList[dayIndex] = '0';
} else {
daysList[dayIndex] = '1';
}
final newDaysBinary = daysList.join();
emit(state.copyWith(selectedDaysBinary: newDaysBinary));
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(EffectiveTimePeriodEvent(EffectiveTime(
start: state.customStartTime ?? '00:00',
end: state.customEndTime ?? '23:59',
loops: newDaysBinary)));
}
void _onSetCustomTime(SetCustomTime event, Emitter<EffectPeriodState> emit) {
emit(state.copyWith(
customStartTime: event.startTime, customEndTime: event.endTime));
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentState!.context)
.add(EffectiveTimePeriodEvent(EffectiveTime(
start: event.startTime,
end: event.endTime,
loops: state.selectedDaysBinary)));
}
int _getDayIndex(String day) {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return days.indexOf(day);
}
}
@@ -0,0 +1,37 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/scene/enum/effective_period_options.dart';
abstract class EffectPeriodEvent extends Equatable {
const EffectPeriodEvent();
@override
List<Object> get props => [];
}
class SetPeriod extends EffectPeriodEvent {
final EnumEffectivePeriodOptions period;
const SetPeriod(this.period);
@override
List<Object> get props => [period];
}
class ToggleDay extends EffectPeriodEvent {
final String day;
const ToggleDay(this.day);
@override
List<Object> get props => [day];
}
class SetCustomTime extends EffectPeriodEvent {
final String startTime;
final String endTime;
const SetCustomTime(this.startTime, this.endTime);
@override
List<Object> get props => [startTime, endTime];
}
@@ -0,0 +1,43 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/scene/enum/effective_period_options.dart';
class EffectPeriodState extends Equatable {
final EnumEffectivePeriodOptions selectedPeriod;
final String selectedDaysBinary;
final String? customStartTime;
final String? customEndTime;
const EffectPeriodState({
required this.selectedPeriod,
required this.selectedDaysBinary,
this.customStartTime,
this.customEndTime,
});
factory EffectPeriodState.initial() {
return const EffectPeriodState(
selectedPeriod: EnumEffectivePeriodOptions.allDay,
selectedDaysBinary: "1111111", // All days selected
customStartTime: "00:00",
customEndTime: "23:59",
);
}
EffectPeriodState copyWith({
EnumEffectivePeriodOptions? selectedPeriod,
String? selectedDaysBinary,
String? customStartTime,
String? customEndTime,
}) {
return EffectPeriodState(
selectedPeriod: selectedPeriod ?? this.selectedPeriod,
selectedDaysBinary: selectedDaysBinary ?? this.selectedDaysBinary,
customStartTime: customStartTime ?? this.customStartTime,
customEndTime: customEndTime ?? this.customEndTime,
);
}
@override
List<Object?> get props =>
[selectedPeriod, selectedDaysBinary, customStartTime, customEndTime];
}
@@ -11,34 +11,95 @@ part 'scene_state.dart';
class SceneBloc extends Bloc<SceneEvent, SceneState> {
SceneBloc() : super(SceneInitial()) {
on<LoadScenes>(_onLoadScenes);
on<LoadAutomation>(_onLoadAutomation);
on<SceneTrigger>(_onSceneTrigger);
on<UpdateAutomationStatus>(_onUpdateAutomationStatus);
}
List<ScenesModel> scenes = [];
List<ScenesModel> automationList = [];
Future<void> _onLoadScenes(LoadScenes event, Emitter<SceneState> emit) async {
emit(SceneLoading());
try {
if (event.unitId.isNotEmpty) {
final scenes = await SceneApi.getScenesByUnitId(event.unitId);
emit(SceneLoaded(scenes));
scenes = await SceneApi.getScenesByUnitId(event.unitId);
emit(SceneLoaded(scenes, automationList));
} else {
const SceneError(message: '');
emit(const SceneError(message: 'Unit ID is empty'));
}
} catch (e) {
emit(const SceneError(message: 'Something went wrong'));
}
}
Future<void> _onSceneTrigger(SceneTrigger event, Emitter<SceneState> emit) async {
Future<void> _onLoadAutomation(
LoadAutomation event, Emitter<SceneState> emit) async {
emit(SceneLoading());
try {
if (event.unitId.isNotEmpty) {
automationList = await SceneApi.getAutomationByUnitId(event.unitId);
emit(SceneLoaded(scenes, automationList));
} else {
emit(const SceneError(message: 'Unit ID is empty'));
}
} catch (e) {
emit(const SceneError(message: 'Something went wrong'));
}
}
Future<void> _onSceneTrigger(
SceneTrigger event, Emitter<SceneState> emit) async {
final currentState = state;
if (currentState is SceneLoaded) {
emit(SceneLoaded(currentState.scenes, loadingSceneId: event.sceneId));
emit(SceneLoaded(
currentState.scenes,
currentState.automationList,
loadingSceneId: event.sceneId,
));
try {
final success = await SceneApi.triggerScene(event.sceneId);
if (success) {
emit(SceneTriggerSuccess(event.name));
emit(SceneLoaded(currentState.scenes));
emit(SceneLoaded(currentState.scenes, currentState.automationList));
} else {
emit(const SceneError(message: 'Something went wrong'));
}
} catch (e) {
emit(const SceneError(message: 'Something went wrong'));
}
}
}
Future<void> _onUpdateAutomationStatus(
UpdateAutomationStatus event, Emitter<SceneState> emit) async {
final currentState = state;
if (currentState is SceneLoaded) {
final newLoadingStates =
Map<String, bool>.from(currentState.loadingStates)
..[event.automationId] = true;
emit(SceneLoaded(
currentState.scenes,
currentState.automationList,
loadingStates: newLoadingStates,
));
try {
final success = await SceneApi.updateAutomationStatus(
event.automationId, event.automationStatusUpdate);
if (success) {
automationList = await SceneApi.getAutomationByUnitId(
event.automationStatusUpdate.unitUuid);
newLoadingStates[event.automationId] = false;
emit(SceneLoaded(
currentState.scenes,
automationList,
loadingStates: newLoadingStates,
));
} else {
emit(const SceneError(message: 'Something went wrong'));
}
@@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/scene/model/update_automation.dart';
abstract class SceneEvent extends Equatable {
const SceneEvent();
@@ -16,6 +17,15 @@ class LoadScenes extends SceneEvent {
List<Object> get props => [unitId];
}
class LoadAutomation extends SceneEvent {
final String unitId;
const LoadAutomation(this.unitId);
@override
List<Object> get props => [unitId];
}
class SceneTrigger extends SceneEvent {
final String sceneId;
final String name;
@@ -25,3 +35,15 @@ class SceneTrigger extends SceneEvent {
@override
List<Object> get props => [sceneId];
}
//updateAutomationStatus
class UpdateAutomationStatus extends SceneEvent {
final String automationId;
final AutomationStatusUpdate automationStatusUpdate;
const UpdateAutomationStatus(
{required this.automationStatusUpdate, required this.automationId});
@override
List<Object> get props => [automationStatusUpdate];
}
@@ -13,12 +13,16 @@ class SceneLoading extends SceneState {}
class SceneLoaded extends SceneState {
final List<ScenesModel> scenes;
final List<ScenesModel> automationList;
final String? loadingSceneId;
final Map<String, bool> loadingStates;
const SceneLoaded(this.scenes, {this.loadingSceneId});
const SceneLoaded(this.scenes, this.automationList,
{this.loadingSceneId, this.loadingStates = const {}});
@override
List<Object?> get props => [scenes, loadingSceneId];
List<Object?> get props =>
[scenes, loadingSceneId, automationList, loadingStates];
}
class SceneError extends SceneState {
@@ -38,3 +42,7 @@ class SceneTriggerSuccess extends SceneState {
@override
List<Object> get props => [sceneName];
}
class UpdateAutomationStatusLoading extends SceneState {
const UpdateAutomationStatusLoading();
}
@@ -0,0 +1,30 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/scene/model/smart_scene_enable.dart';
part 'smart_scene_select_dart_event.dart';
part 'smart_scene_select_dart_state.dart';
class SmartSceneSelectBloc
extends Bloc<SmartSceneSelectEvent, SmartSceneSelectState> {
SmartSceneSelectBloc() : super(SmartSceneSelectInitial()) {
on<SmartSceneEnableEvent>(_onSmartSceneEnable);
on<SmartSceneClearEvent>(_smartSceneClear);
}
SmartSceneEnable? smartSceneEnable;
FutureOr<void> _onSmartSceneEnable(
SmartSceneEnableEvent event, Emitter<SmartSceneSelectState> emit) {
smartSceneEnable = event.smartSceneEnable;
emit(SmartSceneSelected(smartSceneEnable: smartSceneEnable!));
}
FutureOr<void> _smartSceneClear(
SmartSceneClearEvent event, Emitter<SmartSceneSelectState> emit) {
smartSceneEnable = null;
emit(SmartSceneSelectInitial());
}
}
@@ -0,0 +1,21 @@
part of 'smart_scene_select_dart_bloc.dart';
sealed class SmartSceneSelectEvent extends Equatable {
const SmartSceneSelectEvent();
@override
List<Object> get props => [];
}
class SmartSceneEnableEvent extends SmartSceneSelectEvent {
final SmartSceneEnable smartSceneEnable;
const SmartSceneEnableEvent(this.smartSceneEnable);
@override
List<Object> get props => [smartSceneEnable];
}
class SmartSceneClearEvent extends SmartSceneSelectEvent {
const SmartSceneClearEvent();
}
@@ -0,0 +1,19 @@
part of 'smart_scene_select_dart_bloc.dart';
sealed class SmartSceneSelectState extends Equatable {
const SmartSceneSelectState();
@override
List<Object> get props => [];
}
final class SmartSceneSelectInitial extends SmartSceneSelectState {}
class SmartSceneSelected extends SmartSceneSelectState {
final SmartSceneEnable smartSceneEnable;
const SmartSceneSelected({required this.smartSceneEnable});
@override
List<Object> get props => [smartSceneEnable];
}
@@ -1,4 +1,5 @@
enum CreateSceneEnum {
tabToRun,
deviceStatusChanges,
none,
}
@@ -0,0 +1,7 @@
enum EnumEffectivePeriodOptions {
allDay,
daytime,
night,
custom,
none,
}
@@ -0,0 +1,9 @@
enum OperationDialogType {
countdown,
delay,
temperature,
onOff,
integerSteps,
listOfOptions,
none,
}
@@ -0,0 +1,150 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/enum/effective_period_options.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';
import 'package:time_picker_spinner/time_picker_spinner.dart';
class EffectPeriodHelper {
static Future<List<String>?> showCustomTimePicker(
BuildContext context) async {
String selectedStartTime = "00:00";
String selectedEndTime = "23:59";
PageController pageController = PageController(initialPage: 0);
DateTime startDateTime = DateTime(2022, 1, 1, 0, 0);
DateTime endDateTime = DateTime(2022, 1, 1, 23, 59);
context.customAlertDialog(
alertBody: SizedBox(
height: 250,
child: PageView(
controller: pageController,
physics: const NeverScrollableScrollPhysics(),
children: [
_buildTimePickerPage(
context: context,
pageController: pageController,
isStartTime: true,
time: startDateTime,
onTimeChange: (time) {
selectedStartTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
_buildTimePickerPage(
context: context,
pageController: pageController,
isStartTime: false,
time: endDateTime,
onTimeChange: (time) {
selectedEndTime =
"${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}";
},
),
],
),
),
title: "Custom",
onConfirm: () {
context.read<EffectPeriodBloc>().add(
SetCustomTime(selectedStartTime, selectedEndTime),
);
context.read<EffectPeriodBloc>().add(
const SetPeriod(EnumEffectivePeriodOptions.custom),
);
Navigator.of(context).pop();
},
);
return null;
}
static Widget _buildTimePickerPage({
required BuildContext context,
required PageController pageController,
required bool isStartTime,
required DateTime time,
required Function(DateTime) onTimeChange,
}) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (!isStartTime)
TextButton(
onPressed: () {
pageController.previousPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(text: "Start"),
),
TextButton(
onPressed: () {},
child: BodyMedium(
text: isStartTime ? "Start" : "End",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColor,
),
),
),
if (isStartTime)
TextButton(
onPressed: () {
pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
},
child: const BodyMedium(text: "End"),
),
],
),
),
TimePickerSpinner(
is24HourMode: false,
normalTextStyle: const TextStyle(
fontSize: 24,
color: Colors.grey,
),
highlightedTextStyle: const TextStyle(
fontSize: 24,
color: ColorsManager.primaryColor,
),
spacing: 20,
itemHeight: 50,
isForce2Digits: true,
time: time,
onTimeChange: onTimeChange,
),
const SizedBox(height: 16),
],
);
}
static String formatEnumValue(EnumEffectivePeriodOptions value) {
switch (value) {
case EnumEffectivePeriodOptions.allDay:
return "All Day";
case EnumEffectivePeriodOptions.daytime:
return "Daytime";
case EnumEffectivePeriodOptions.night:
return "Night";
case EnumEffectivePeriodOptions.custom:
return "Custom";
case EnumEffectivePeriodOptions.none:
return "None";
default:
return "";
}
}
}
@@ -0,0 +1,271 @@
import 'package:syncrow_app/features/scene/enum/ac_values.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.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';
class ACFunctionsHelper {
static List<SceneStaticFunction> tabToRunAcFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Power',
code: 'switch',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFreezing,
operationName: 'Mode',
code: 'mode',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcCooling,
description: AcValuesEnums.Cooling.name,
value: TempModes.cold.name,
),
SceneOperationalValue(
icon: Assets.assetsAcHeating,
description: AcValuesEnums.Heating.name,
value: TempModes.hot.name,
),
SceneOperationalValue(
icon: Assets.assetsFanSpeed,
description: AcValuesEnums.Ventilation.name,
value: TempModes.wind.name,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsTempreture,
operationName: 'Set Temperature',
code: 'temp_set',
functionValue: functionValue,
operationDialogType: OperationDialogType.temperature,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsCelsiusDegrees,
value: 0,
description: 'COOL TO',
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFanSpeed,
operationName: 'Fan Speed',
code: 'level',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcFanLow,
description: ValueACRange.LOW.name,
value: FanSpeeds.low.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanMiddle,
description: ValueACRange.MIDDLE.name,
value: FanSpeeds.middle.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanHigh,
description: ValueACRange.HIGH.name,
value: FanSpeeds.high.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanAuto,
description: ValueACRange.AUTO.name,
value: FanSpeeds.auto.name,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsChildLock,
operationName: 'Child Lock',
code: 'child_lock',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSceneChildLock,
description: 'Lock',
value: true,
),
SceneOperationalValue(
icon: Assets.assetsSceneChildUnlock,
description: 'Unlock',
value: false,
),
],
),
];
}
static List<SceneStaticFunction> automationAcFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Power',
code: 'switch',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFreezing,
operationName: 'Mode',
code: 'mode',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcCooling,
description: AcValuesEnums.Cooling.name,
value: TempModes.cold.name,
),
SceneOperationalValue(
icon: Assets.assetsAcHeating,
description: AcValuesEnums.Heating.name,
value: TempModes.hot.name,
),
SceneOperationalValue(
icon: Assets.assetsFanSpeed,
description: AcValuesEnums.Ventilation.name,
value: TempModes.wind.name,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsTempreture,
operationName: 'Set Temperature',
code: 'temp_set',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsCelsiusDegrees,
value: 0.0,
description: '°C',
minValue: 20,
maxValue: 30,
stepValue: 0.5,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsCurrentTemp,
operationName: 'Current Temperature',
code: 'temp_current',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsCelsiusDegrees,
value: 0.0,
description: '°C',
minValue: -9.9,
maxValue: 99.9,
stepValue: 0.1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFanSpeed,
operationName: 'Fan Speed',
code: 'level',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcFanLow,
description: ValueACRange.LOW.name,
value: FanSpeeds.low.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanMiddle,
description: ValueACRange.MIDDLE.name,
value: FanSpeeds.middle.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanHigh,
description: ValueACRange.HIGH.name,
value: FanSpeeds.high.name,
),
SceneOperationalValue(
icon: Assets.assetsAcFanAuto,
description: ValueACRange.AUTO.name,
value: FanSpeeds.auto.name,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsChildLock,
operationName: 'Child Lock',
code: 'child_lock',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSceneChildLock,
description: 'Lock',
value: true,
),
SceneOperationalValue(
icon: Assets.assetsSceneChildUnlock,
description: 'Unlock',
value: false,
),
],
),
];
}
}
@@ -0,0 +1,267 @@
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
class DoorLockHelperFunctions {
/// tab to run functions
static List<SceneStaticFunction> doorLockTapToRunFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIconsDoorLock,
operationName: 'Set Door lock Normal Open',
functionValue: functionValue,
code: 'normal_open_switch',
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
];
}
//// automation functions
static List<SceneStaticFunction> doorLockAutomationFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFingerprintUnlock,
operationName: 'Fingerprint Unlock',
functionValue: functionValue,
code: 'unlock_fingerprint',
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0.0,
maxValue: 999,
stepValue: 1.0,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsPasswordUnlock,
operationName: 'Password Unlock',
functionValue: functionValue,
code: 'unlock_password',
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0.0,
maxValue: 999,
stepValue: 1.0,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsCardUnlock,
operationName: 'Card Unlock',
functionValue: functionValue,
code: 'unlock_card',
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0.0,
maxValue: 999,
stepValue: 1.0,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLockAlarm,
operationName: 'Lock Alarm',
functionValue: functionValue,
code: 'alarm_lock',
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsFingerprintUnlock,
description: "Fingerprint Mismatch",
value: 0,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsRemoteUnlockReq,
operationName: 'Remote Unlock Request',
functionValue: functionValue,
code: 'unlock_request',
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0,
maxValue: 90,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsResidualElectricity,
operationName: 'Residual Electricity',
functionValue: functionValue,
code: 'residual_electricity',
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0,
maxValue: 100,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsDoubleLock,
operationName: 'Double Lock',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
code: 'reverse_lock',
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsRemoteUnlockViaApp,
operationName: 'Remote Unlock Via App',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
code: 'unlock_app',
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0,
maxValue: 999,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsHijackAlarm,
operationName: 'Hijack Alarm',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
code: 'hijack',
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsDoorlockNormalOpen,
operationName: 'Set Door Lock Normal Open',
functionValue: functionValue,
code: 'normal_open_switch',
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsDoorlockNormalOpen,
operationName: 'Doorbell',
functionValue: functionValue,
code: 'doorbell',
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "ON",
value: true,
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "OFF",
value: false,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsTempPasswordUnlock,
operationName: 'Temporary Password Unlock',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
code: 'unlock_temporary',
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0,
maxValue: 999,
stepValue: 1,
),
],
),
];
}
}
@@ -0,0 +1,62 @@
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
class GatewayHelperFunctions {
static List<SceneStaticFunction> tabToRunGatewayFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsSwitchAlarmSound,
operationName: 'Switch Alarm Sound',
code: 'switch_alarm_sound',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsMasterState,
operationName: 'Master State',
code: 'master_state',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: "Alarm",
value: 'alarm',
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: "Normal",
value: 'normal',
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFactoryReset,
operationName: 'Factory Reset',
code: 'factory_reset',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSceneRefresh, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsResetOff, description: "OFF", value: false),
],
),
];
}
}
@@ -0,0 +1,260 @@
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
class HumanPresenceHelperFunctions {
static List<SceneStaticFunction> tabToRunHumanPresenceFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsFarDetection,
operationName: 'Far Detection',
code: 'far_detection',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 75,
description: '75cm',
iconValue: '75',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 150,
description: '150cm',
iconValue: '150',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 225,
description: '225cm',
iconValue: '225',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 300,
description: '300cm',
iconValue: '300',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 375,
description: '375cm',
iconValue: '375',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 450,
description: '450cm',
iconValue: '450',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 525,
description: '525cm',
iconValue: '525',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 600,
description: '600cm',
iconValue: '600',
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsMotionDetection,
operationName: 'Motion Detection Sensitivity',
code: 'motion_sensitivity_value',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 1,
description: 1.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 2,
description: 2.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 3,
description: 3.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 4,
description: 4.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 5,
description: 5.toString(),
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsMotionlessDetection,
operationName: 'Motionless Detection Sensitivity',
code: 'motionless_sensitivity',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
iconValue: '1',
icon: Assets.assetsFarDetectionFunction,
value: 1,
description: '1',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 2,
description: '2',
iconValue: '2',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 3,
description: '3',
iconValue: '3',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 4,
description: '4',
iconValue: '4',
),
SceneOperationalValue(
icon: Assets.assetsFarDetectionFunction,
value: 5,
description: '5',
iconValue: '5',
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIndicator,
operationName: 'Indicator',
code: 'indicator',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
];
}
static List<SceneStaticFunction> automationHumanPresenceFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsPresenceState,
operationName: 'Presence State',
code: 'presence_state',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsIconsPresenceSensorAssetsEmpty,
value: 'none',
description: 'None',
),
SceneOperationalValue(
icon: Assets.assetsPresence,
value: 'presence',
description: 'Presence',
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIconsPresenceSensorAssetsDistance,
operationName: 'Current Distance',
code: 'dis_current',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
value: 0.0,
description: "CM",
minValue: 1,
maxValue: 600,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIconsPresenceSensorAssetsIlluminanceValue,
operationName: 'Illuminance Value',
code: 'illuminance_value',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
value: 0.0,
description: "Lux",
minValue: 0,
maxValue: 10000,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIndicator,
operationName: 'Indicator',
code: 'indicator',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIconsPresenceSensorAssetsTime,
operationName: 'Presence Time',
code: 'presence_time',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
value: 0.0,
minValue: 0.0,
maxValue: 65535,
stepValue: 1,
description: 'min'),
],
),
];
}
}
@@ -0,0 +1,139 @@
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
class PresenceSensorHelperFunctions {
static List<SceneStaticFunction> tabToRunPresenceSensorFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsSensitivityFunction,
operationName: 'Sensitivity',
code: 'sensitivity',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 1,
description: 1.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 2,
description: 2.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 3,
description: 3.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 4,
description: 4.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 5,
description: 5.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 6,
description: 6.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 7,
description: 7.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 8,
description: 8.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 9,
description: 9.toString(),
),
SceneOperationalValue(
icon: Assets.assetsSensitivityOperationIcon,
value: 10,
description: 10.toString(),
),
],
),
];
}
static List<SceneStaticFunction> automationPresenceSensorFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsIconsSensors,
operationName: 'Presence Status',
code: 'presence_state',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsIconsPresenceSensorAssetsEmpty,
value: 'none',
description: 'None',
),
// SceneOperationalValue(
// icon: Assets.assetsPresence,
// value: 'presence',
// description: 'Presence',
// ),
// SceneOperationalValue(
// icon: Assets.assetsMotion,
// value: 'motion',
// description: 'Motion',
// ),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsSensitivityFunction,
operationName: 'Sensitivity',
code: 'sensitivity',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "",
value: 0.0,
minValue: 0,
maxValue: 10,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsSelfTestResult,
operationName: 'Self-Test Result',
code: 'checking_result',
functionValue: functionValue,
operationDialogType: OperationDialogType.listOfOptions,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsSelfTestResult,
value: 'check_success',
description: 'Self Testing Success',
),
],
),
];
}
}
@@ -0,0 +1,200 @@
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/generated/assets.dart';
class ThreeGangHelperFunctions {
static List<SceneStaticFunction> threeGangHelperFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 1 Switch',
code: 'switch_1',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 2 Switch',
code: 'switch_2',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 3 Switch',
code: 'switch_3',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 1 CountDown',
code: 'countdown_1',
functionValue: functionValue,
operationDialogType: OperationDialogType.countdown,
operationalValues: [
SceneOperationalValue(icon: '', value: 0),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 2 CountDown',
code: 'countdown_2',
functionValue: functionValue,
operationDialogType: OperationDialogType.countdown,
operationalValues: [
SceneOperationalValue(icon: '', value: 0),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 3 CountDown',
code: 'countdown_3',
functionValue: functionValue,
operationDialogType: OperationDialogType.countdown,
operationalValues: [
SceneOperationalValue(icon: '', value: 0),
],
),
];
}
static List<SceneStaticFunction> threeGangAutomationFunctions(
String deviceId, String deviceName, functionValue) {
return [
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 1 Switch',
code: 'switch_1',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 2 Switch',
code: 'switch_2',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsAcPower,
operationName: 'Light 3 Switch',
code: 'switch_3',
functionValue: functionValue,
operationDialogType: OperationDialogType.onOff,
operationalValues: [
SceneOperationalValue(
icon: Assets.assetsAcPower, description: "ON", value: true),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF, description: "OFF", value: false),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 1 CountDown',
code: 'countdown_1',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "sec",
value: 0.0,
minValue: 0,
maxValue: 43200,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 2 CountDown',
code: 'countdown_2',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "sec",
value: 0.0,
minValue: 0,
maxValue: 43200,
stepValue: 1,
),
],
),
SceneStaticFunction(
deviceId: deviceId,
deviceName: deviceName,
icon: Assets.assetsLightCountdown,
operationName: 'Light 3 CountDown',
code: 'countdown_3',
functionValue: functionValue,
operationDialogType: OperationDialogType.integerSteps,
operationalValues: [
SceneOperationalValue(
icon: '',
description: "sec",
value: 0.0,
minValue: 0,
maxValue: 43200,
stepValue: 1,
),
],
),
];
}
}
+164 -62
View File
@@ -2,13 +2,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_functions_body.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_slider_steps.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_temperature_body.dart';
import 'package:syncrow_app/utils/context_extension.dart';
@@ -20,84 +21,185 @@ mixin SceneLogicHelper {
}
void handleSaveButtonPress(
BuildContext context,
TextEditingController sceneNameController,
List<SceneStaticFunction> tasks, {
BuildContext context, {
required bool updateScene,
required String sceneId,
required bool isAutomation,
required TextEditingController sceneName,
required List<SceneStaticFunction> actions,
required List<SceneStaticFunction> conditions,
}) {
if (isOnlyDelayOrDelayLast(tasks)) {
// Show snackbar indicating restriction
Navigator.pop(context);
context.showCustomSnackbar(
message: 'A single delay or delay-last operations are NOT allowed.',
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
} else {
final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
sceneName: sceneNameController.text,
decisionExpr: 'and',
actions: List.generate(
tasks.length,
(index) {
final task = tasks[index];
if (task.deviceId == 'delay') {
return CreateSceneAction(
entityId: tasks[index].deviceId,
actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty(
functionCode: '',
functionValue: '',
delaySeconds: task.functionValue,
final sceneBloc = context.read<CreateSceneBloc>();
final smartSceneBloc = context.read<SmartSceneSelectBloc>();
if (isAutomation) {
// Handle Automation Creation
if (isOnlyDelayOrDelayLast(actions)) {
Navigator.pop(context);
context.showCustomSnackbar(
message: 'A single delay or delay-last operations are NOT allowed.',
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
} else {
final createAutomationModel = CreateAutomationModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
automationName: sceneName.text,
decisionExpr: sceneBloc.conditionRule,
effectiveTime: sceneBloc.effectiveTime ??
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111'),
conditions: List.generate(
conditions.length,
(index) {
final task = conditions[index];
return CreateCondition(
code: index + 1,
entityId: task.deviceId,
entityType: 'device_report',
expr: ConditionExpr(
statusCode: task.code,
comparator: task.comparator ?? '==',
statusValue: task.functionValue,
),
);
}
return CreateSceneAction(
entityId: task.deviceId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.functionValue,
delaySeconds: 0,
),
);
},
),
);
context.read<CreateSceneBloc>().add(CreateSceneWithTasksEvent(
createSceneModel: createSceneModel,
updateScene: updateScene,
sceneId: sceneId,
));
Navigator.pop(context);
},
),
actions: [
...List.generate(
actions.length,
(index) {
final task = actions[index];
if (task.deviceId == 'delay') {
return CreateSceneAction(
entityId: actions[index].deviceId,
actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty(
functionCode: '',
functionValue: '',
delaySeconds: task.functionValue,
),
);
}
return CreateSceneAction(
entityId: task.deviceId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.functionValue,
delaySeconds: 0,
),
);
},
),
if (smartSceneBloc.smartSceneEnable != null)
CreateSceneAction(
entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '',
actionExecutor:
smartSceneBloc.smartSceneEnable?.actionExecutor ?? '',
executorProperty: null)
],
);
sceneBloc.add(CreateSceneWithTasksEvent(
createSceneModel: null,
updateScene: updateScene,
sceneId: sceneId,
createAutomationModel: createAutomationModel,
));
Navigator.pop(context);
}
} else {
if (isOnlyDelayOrDelayLast(actions)) {
Navigator.pop(context);
context.showCustomSnackbar(
message: 'A single delay or delay-last operations are NOT allowed.',
icon: const Icon(
Icons.error,
color: Colors.red,
),
);
} else {
// Handle Scene Creation
final createSceneModel = CreateSceneModel(
unitUuid: HomeCubit.getInstance().selectedSpace!.id ?? '',
sceneName: sceneName.text,
decisionExpr: 'and',
actions: [
...List.generate(
actions.length,
(index) {
final task = actions[index];
if (task.deviceId == 'delay') {
return CreateSceneAction(
entityId: actions[index].deviceId,
actionExecutor: 'delay',
executorProperty: CreateSceneExecutorProperty(
functionCode: '',
functionValue: '',
delaySeconds: task.functionValue,
),
);
}
return CreateSceneAction(
entityId: task.deviceId,
actionExecutor: 'device_issue',
executorProperty: CreateSceneExecutorProperty(
functionCode: task.code,
functionValue: task.functionValue,
delaySeconds: 0,
),
);
},
),
if (smartSceneBloc.smartSceneEnable != null)
CreateSceneAction(
entityId: smartSceneBloc.smartSceneEnable?.entityId ?? '',
actionExecutor:
smartSceneBloc.smartSceneEnable?.actionExecutor ?? '',
executorProperty: null)
],
);
sceneBloc.add(CreateSceneWithTasksEvent(
createSceneModel: createSceneModel,
createAutomationModel: null,
updateScene: updateScene,
sceneId: sceneId,
));
Navigator.pop(context);
}
}
}
Widget getTheCorrectDialogBody(
SceneStaticFunction taskItem,
) {
if (taskItem.code.contains('temp_set')) {
SceneStaticFunction taskItem, dynamic functionValue,
{required bool isAutomation}) {
if (taskItem.operationDialogType == OperationDialogType.temperature) {
return AlertDialogTemperatureBody(
taskItem: taskItem,
functionValue: taskItem.functionValue,
functionValue: functionValue ?? taskItem.functionValue,
);
} else if (taskItem.code.contains('countdown') ||
taskItem.deviceId.contains('delay')) {
} else if ((taskItem.operationDialogType ==
OperationDialogType.countdown) ||
(taskItem.operationDialogType == OperationDialogType.delay)) {
return AlertDialogCountdown(
durationValue: taskItem.functionValue,
functionValue: taskItem.functionValue,
durationValue: taskItem.functionValue ?? 0,
functionValue: functionValue ?? taskItem.functionValue,
function: taskItem,
);
} else if (taskItem.operationDialogType ==
OperationDialogType.integerSteps) {
return AlertDialogSliderSteps(
taskItem: taskItem,
functionValue: functionValue ?? taskItem.functionValue,
isAutomation: isAutomation,
);
}
return AlertDialogFunctionsOperationsBody(
taskItem: taskItem,
functionValue: taskItem.functionValue,
functionValue: functionValue ?? taskItem.functionValue,
isAutomation: isAutomation,
);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,172 @@
import 'dart:convert';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
class CreateAutomationModel {
String unitUuid;
String automationName;
String decisionExpr;
EffectiveTime effectiveTime;
List<CreateCondition> conditions;
List<CreateSceneAction> actions;
CreateAutomationModel({
required this.unitUuid,
required this.automationName,
required this.decisionExpr,
required this.effectiveTime,
required this.conditions,
required this.actions,
});
CreateAutomationModel copyWith({
String? unitUuid,
String? automationName,
String? decisionExpr,
EffectiveTime? effectiveTime,
List<CreateCondition>? conditions,
List<CreateSceneAction>? actions,
}) {
return CreateAutomationModel(
unitUuid: unitUuid ?? this.unitUuid,
automationName: automationName ?? this.automationName,
decisionExpr: decisionExpr ?? this.decisionExpr,
effectiveTime: effectiveTime ?? this.effectiveTime,
conditions: conditions ?? this.conditions,
actions: actions ?? this.actions,
);
}
Map<String, dynamic> toMap([String? automationId]) {
return {
if (automationId == null) 'unitUuid': unitUuid,
'automationName': automationName,
'decisionExpr': decisionExpr,
'effectiveTime': effectiveTime.toMap(),
'conditions': conditions.map((x) => x.toMap()).toList(),
'actions': actions.map((x) => x.toMap()).toList(),
};
}
factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
return CreateAutomationModel(
unitUuid: map['unitUuid'] ?? '',
automationName: map['automationName'] ?? '',
decisionExpr: map['decisionExpr'] ?? '',
effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
conditions: List<CreateCondition>.from(
map['conditions']?.map((x) => CreateCondition.fromMap(x))),
actions: List<CreateSceneAction>.from(
map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
);
}
String toJson([String? automationId]) => json.encode(toMap(automationId));
factory CreateAutomationModel.fromJson(String source) =>
CreateAutomationModel.fromMap(json.decode(source));
@override
String toString() {
return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)';
}
}
class EffectiveTime {
String start;
String end;
String loops;
EffectiveTime({
required this.start,
required this.end,
required this.loops,
});
Map<String, dynamic> toMap() {
return {
'start': start,
'end': end,
'loops': loops,
};
}
factory EffectiveTime.fromMap(Map<String, dynamic> map) {
return EffectiveTime(
start: map['start'] ?? '',
end: map['end'] ?? '',
loops: map['loops'] ?? '',
);
}
@override
String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)';
}
class CreateCondition {
int code;
String entityId;
String entityType;
ConditionExpr expr;
CreateCondition({
required this.code,
required this.entityId,
required this.entityType,
required this.expr,
});
Map<String, dynamic> toMap() {
return {
'code': code,
'entityId': entityId,
'entityType': entityType,
'expr': expr.toMap(),
};
}
factory CreateCondition.fromMap(Map<String, dynamic> map) {
return CreateCondition(
code: map['code'] ?? 0,
entityId: map['entityId'] ?? '',
entityType: map['entityType'] ?? '',
expr: ConditionExpr.fromMap(map['expr']),
);
}
@override
String toString() =>
'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)';
}
class ConditionExpr {
String statusCode;
String comparator;
dynamic statusValue;
ConditionExpr({
required this.statusCode,
required this.comparator,
required this.statusValue,
});
Map<String, dynamic> toMap() {
return {
'statusCode': statusCode,
'comparator': comparator,
'statusValue': statusValue,
};
}
factory ConditionExpr.fromMap(Map<String, dynamic> map) {
return ConditionExpr(
statusCode: map['statusCode'] ?? '',
comparator: map['comparator'] ?? '',
statusValue: map['statusValue'],
);
}
@override
String toString() =>
'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)';
}
@@ -3,29 +3,11 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
class CreateSceneModel {
/*
{
"unitUuid": "string",
"sceneName": "string",
"decisionExpr": "string",
"actions": [
{
"entityId": "string",
"actionExecutor": "string",
"executorProperty": {
"functionCode": "string",
"functionValue": {},
"delaySeconds": 0
}
}
]
}
*/
String unitUuid;
String sceneName;
String decisionExpr;
List<CreateSceneAction> actions;
CreateSceneModel({
required this.unitUuid,
required this.sceneName,
@@ -99,7 +81,8 @@ class CreateSceneModel {
class CreateSceneAction {
String entityId;
String actionExecutor;
CreateSceneExecutorProperty executorProperty;
CreateSceneExecutorProperty? executorProperty;
CreateSceneAction({
required this.entityId,
required this.actionExecutor,
@@ -122,7 +105,8 @@ class CreateSceneAction {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
'executorProperty': executorProperty.toMap(),
if (executorProperty != null)
'executorProperty': executorProperty?.toMap(actionExecutor),
};
}
@@ -163,6 +147,7 @@ class CreateSceneExecutorProperty {
String functionCode;
dynamic functionValue;
int delaySeconds;
CreateSceneExecutorProperty({
required this.functionCode,
required this.functionValue,
@@ -181,12 +166,14 @@ class CreateSceneExecutorProperty {
);
}
Map<String, dynamic> toMap() {
return {
if (functionCode.isNotEmpty == true) 'functionCode': functionCode,
if (functionValue != '') 'functionValue': functionValue,
if (delaySeconds > 0) 'delaySeconds': delaySeconds,
};
Map<String, dynamic> toMap(String actionExecutor) {
final map = <String, dynamic>{};
if (functionCode.isNotEmpty) map['functionCode'] = functionCode;
if (functionValue != null) map['functionValue'] = functionValue;
if (actionExecutor == 'delay' && delaySeconds > 0) {
map['delaySeconds'] = delaySeconds;
}
return map;
}
factory CreateSceneExecutorProperty.fromMap(Map<String, dynamic> map) {
@@ -197,7 +184,7 @@ class CreateSceneExecutorProperty {
);
}
String toJson() => json.encode(toMap());
String toJson(String actionExecutor) => json.encode(toMap(actionExecutor));
factory CreateSceneExecutorProperty.fromJson(String source) =>
CreateSceneExecutorProperty.fromMap(json.decode(source));
@@ -6,6 +6,9 @@ class SceneDetailsModel {
final String status;
final String type;
final List<Action> actions;
final List<Condition>? conditions;
final String? decisionExpr;
final EffectiveTime? effectiveTime;
SceneDetailsModel({
required this.id,
@@ -13,6 +16,9 @@ class SceneDetailsModel {
required this.status,
required this.type,
required this.actions,
this.conditions,
this.decisionExpr,
this.effectiveTime,
});
factory SceneDetailsModel.fromRawJson(String str) =>
@@ -26,8 +32,20 @@ class SceneDetailsModel {
name: json["name"],
status: json["status"],
type: json["type"],
actions:
List<Action>.from(json["actions"].map((x) => Action.fromJson(x))),
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,
);
Map<String, dynamic> toJson() => {
@@ -36,6 +54,11 @@ class SceneDetailsModel {
"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,
"decisionExpr": decisionExpr,
"effectiveTime": effectiveTime?.toJson(),
};
}
@@ -50,15 +73,19 @@ class Action {
required this.executorProperty,
});
factory Action.fromRawJson(String str) => Action.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Action.fromJson(Map<String, dynamic> json) => Action(
actionExecutor: json["actionExecutor"],
entityId: json["entityId"],
executorProperty: ExecutorProperty.fromJson(json["executorProperty"]),
);
static Action? fromJson(Map<String, dynamic> json) {
if (json["executorProperty"] == null) {
return null; // Return null if executorProperty is not present
}
return Action(
actionExecutor: json["actionExecutor"],
entityId: json["entityId"],
executorProperty: ExecutorProperty.fromJson(json["executorProperty"]),
);
}
Map<String, dynamic> toJson() => {
"actionExecutor": actionExecutor,
@@ -91,3 +118,93 @@ class ExecutorProperty {
"delaySeconds": delaySeconds,
};
}
class Condition {
final int code;
final String entityId;
final String entityType;
final Expr expr;
Condition({
required this.code,
required this.entityId,
required this.entityType,
required this.expr,
});
factory Condition.fromRawJson(String str) =>
Condition.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Condition.fromJson(Map<String, dynamic> json) => Condition(
code: json["code"],
entityId: json["entityId"],
entityType: json["entityType"],
expr: Expr.fromJson(json["expr"]),
);
Map<String, dynamic> toJson() => {
"code": code,
"entityId": entityId,
"entityType": entityType,
"expr": expr.toJson(),
};
}
class Expr {
final String comparator;
final String statusCode;
final dynamic statusValue;
Expr({
required this.comparator,
required this.statusCode,
required this.statusValue,
});
factory Expr.fromRawJson(String str) => Expr.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Expr.fromJson(Map<String, dynamic> json) => Expr(
comparator: json["comparator"],
statusCode: json["statusCode"],
statusValue: json["statusValue"],
);
Map<String, dynamic> toJson() => {
"comparator": comparator,
"statusCode": statusCode,
"statusValue": statusValue,
};
}
class EffectiveTime {
final String start;
final String end;
final String loops;
EffectiveTime({
required this.start,
required this.end,
required this.loops,
});
factory EffectiveTime.fromRawJson(String str) =>
EffectiveTime.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EffectiveTime.fromJson(Map<String, dynamic> json) => EffectiveTime(
start: json["start"],
end: json["end"],
loops: json["loops"],
);
Map<String, dynamic> toJson() => {
"start": start,
"end": end,
"loops": loops,
};
}
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:uuid/uuid.dart';
class SceneStaticFunction {
@@ -13,6 +14,8 @@ class SceneStaticFunction {
final String uniqueCustomId;
final dynamic functionValue;
final String? deviceIcon;
final OperationDialogType operationDialogType;
final String? comparator;
SceneStaticFunction({
required this.icon,
@@ -23,6 +26,8 @@ class SceneStaticFunction {
required this.operationName,
required this.functionValue,
this.deviceIcon,
required this.operationDialogType,
this.comparator,
}) : uniqueCustomId = const Uuid().v4();
SceneStaticFunction copyWith({
@@ -35,6 +40,8 @@ class SceneStaticFunction {
dynamic functionValue,
String? deviceIcon,
String? deviceName,
OperationDialogType? operationDialogType,
String? comparator,
}) {
return SceneStaticFunction(
icon: icon ?? this.icon,
@@ -45,6 +52,8 @@ class SceneStaticFunction {
operationName: operationName ?? this.operationName,
functionValue: functionValue ?? this.functionValue,
deviceIcon: deviceIcon ?? this.deviceIcon,
operationDialogType: operationDialogType ?? this.operationDialogType,
comparator: comparator ?? this.comparator,
);
}
@@ -57,8 +66,9 @@ class SceneStaticFunction {
'deviceId': deviceId,
'operationName': operationName,
'functionValue': functionValue,
'deviceIcon': deviceIcon
'deviceIcon': deviceIcon,
'operationDialogType': operationDialogType.name,
'comparator': comparator
};
}
@@ -74,6 +84,10 @@ class SceneStaticFunction {
operationName: map['operationName'] ?? '',
functionValue: map['functionValue'] ?? '',
deviceIcon: map['deviceIcon'] ?? '',
operationDialogType: map['operationDialogType'] != null
? OperationDialogType.values.byName(map['operationDialogType'])
: OperationDialogType.none,
comparator: map['comparator'],
);
}
@@ -84,7 +98,7 @@ class SceneStaticFunction {
@override
String toString() {
return 'SceneStaticFunction(icon: $icon, name: $deviceName, code: $code, operationalValues: $operationalValues, deviceId: $deviceId, operationName: $operationName, functionValue: $functionValue, deviceIcon: $deviceIcon)';
return 'SceneStaticFunction(icon: $icon, name: $deviceName, code: $code, operationalValues: $operationalValues, deviceId: $deviceId, operationName: $operationName, functionValue: $functionValue, deviceIcon: $deviceIcon, operationDialogType: $operationDialogType, comparator: $comparator)';
}
@override
@@ -98,6 +112,8 @@ class SceneStaticFunction {
other.operationName == operationName &&
other.functionValue == functionValue &&
other.deviceIcon == deviceIcon &&
other.comparator == comparator &&
other.operationDialogType == operationDialogType &&
listEquals(other.operationalValues, operationalValues) &&
other.deviceId == deviceId;
}
@@ -111,6 +127,8 @@ class SceneStaticFunction {
operationName.hashCode ^
functionValue.hashCode ^
deviceIcon.hashCode ^
comparator.hashCode ^
operationDialogType.hashCode ^
operationalValues.hashCode;
}
}
@@ -120,12 +138,18 @@ class SceneOperationalValue {
final dynamic value;
final String? description;
final String? iconValue;
final double? minValue;
final double? maxValue;
final double? stepValue;
SceneOperationalValue({
required this.icon,
required this.value,
this.description,
this.iconValue,
this.minValue,
this.maxValue,
this.stepValue,
});
SceneOperationalValue copyWith({
@@ -133,12 +157,18 @@ class SceneOperationalValue {
dynamic value,
String? description,
String? iconValue,
double? minValue,
double? maxValue,
double? stepValue,
}) {
return SceneOperationalValue(
icon: icon ?? this.icon,
value: value ?? this.value,
description: description ?? this.description,
iconValue: iconValue ?? this.iconValue,
minValue: minValue ?? this.minValue,
maxValue: maxValue ?? this.maxValue,
stepValue: stepValue ?? this.stepValue,
);
}
@@ -147,7 +177,10 @@ class SceneOperationalValue {
'icon': icon,
'value': value,
'description': description,
'iconValue': iconValue
'iconValue': iconValue,
'minValue': minValue,
'maxValue': maxValue,
'stepValue': stepValue
};
}
@@ -157,6 +190,9 @@ class SceneOperationalValue {
value: map['value'],
description: map['description'],
iconValue: map['iconValue'] ?? '',
minValue: map['minValue'],
maxValue: map['maxValue'],
stepValue: map['stepValue'],
);
}
@@ -167,7 +203,7 @@ class SceneOperationalValue {
@override
String toString() =>
'StaticFunctionOperationHelper(icon: $icon, value: $value, description: $description, iconValue: $iconValue)';
'StaticFunctionOperationHelper(icon: $icon, value: $value, description: $description, iconValue: $iconValue, minValue: $minValue, maxValue: $maxValue, stepValue: $stepValue)';
@override
bool operator ==(Object other) {
@@ -177,6 +213,9 @@ class SceneOperationalValue {
other.icon == icon &&
other.description == description &&
other.iconValue == iconValue &&
other.minValue == minValue &&
other.maxValue == maxValue &&
other.stepValue == stepValue &&
other.value == value;
}
@@ -186,5 +225,8 @@ class SceneOperationalValue {
value.hashCode ^
description.hashCode ^
iconValue.hashCode ^
minValue.hashCode ^
maxValue.hashCode ^
stepValue.hashCode ^
description.hashCode;
}
+7 -27
View File
@@ -3,8 +3,8 @@ import 'dart:convert';
class ScenesModel {
final String id;
final String name;
final Status status;
final Type type;
final String status;
final String type;
ScenesModel({
required this.id,
@@ -20,35 +20,15 @@ class ScenesModel {
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
id: json["id"],
name: json["name"],
status: statusValues.map[json["status"]]!,
type: typeValues.map[json["type"]]!,
name: json["name"] ?? '',
status: json["status"] ?? '',
type: json["type"] ?? '',
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"status": statusValues.reverse[status],
"type": typeValues.reverse[type],
"status": status,
"type": type,
};
}
enum Status { ENABLE }
final statusValues = EnumValues({"enable": Status.ENABLE});
enum Type { TAP_TO_RUN }
final typeValues = EnumValues({"tap_to_run": Type.TAP_TO_RUN});
class EnumValues<T> {
Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
reverseMap = map.map((k, v) => MapEntry(v, k));
return reverseMap;
}
}
@@ -0,0 +1,23 @@
class SmartSceneEnable {
final String entityId;
final String actionExecutor;
SmartSceneEnable({
required this.entityId,
required this.actionExecutor,
});
factory SmartSceneEnable.fromJson(Map<String, dynamic> json) {
return SmartSceneEnable(
entityId: json['entityId'],
actionExecutor: json['actionExecutor'],
);
}
Map<String, dynamic> toJson() {
return {
'entityId': entityId,
'actionExecutor': actionExecutor,
};
}
}
@@ -0,0 +1,38 @@
import 'dart:convert';
class AutomationStatusUpdate {
final String unitUuid;
final bool isEnable;
AutomationStatusUpdate({
required this.unitUuid,
required this.isEnable,
});
factory AutomationStatusUpdate.fromRawJson(String str) =>
AutomationStatusUpdate.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AutomationStatusUpdate.fromJson(Map<String, dynamic> json) =>
AutomationStatusUpdate(
unitUuid: json["unitUuid"],
isEnable: json["isEnable"],
);
Map<String, dynamic> toJson() => {
"unitUuid": unitUuid,
"isEnable": isEnable,
};
factory AutomationStatusUpdate.fromMap(Map<String, dynamic> map) =>
AutomationStatusUpdate(
unitUuid: map["unitUuid"],
isEnable: map["isEnable"],
);
Map<String, dynamic> toMap() => {
"unitUuid": unitUuid,
"isEnable": isEnable,
};
}
+21 -4
View File
@@ -6,10 +6,9 @@ import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class CreateSceneView extends StatelessWidget {
@@ -22,7 +21,7 @@ class CreateSceneView extends StatelessWidget {
padding: const EdgeInsets.only(top: 24),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
navigateToRoute(context, Routes.sceneTasksRoute);
},
icon: const Icon(
Icons.arrow_back_ios,
@@ -48,6 +47,9 @@ class CreateSceneView extends StatelessWidget {
),
);
context.read<CreateSceneBloc>().add(const ClearTaskListEvent());
context
.read<CreateSceneBloc>()
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
},
),
DefaultContainer(
@@ -58,7 +60,22 @@ class CreateSceneView extends StatelessWidget {
titleString: StringsManager.whenDeviceStatusChanges,
subtitleString: StringsManager.whenUnusualActivityIsDetected,
),
onTap: () {},
onTap: () {
Navigator.pushNamed(
context,
Routes.sceneControlDevicesRoute,
arguments: SceneSettingsRouteArguments(
sceneType: CreateSceneEnum.deviceStatusChanges.name,
sceneId: '',
sceneName: '',
),
);
context
.read<CreateSceneBloc>()
.add(const ClearTaskListEvent(isAutomation: true));
context.read<CreateSceneBloc>().add(
const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges));
},
),
],
),
+197 -138
View File
@@ -1,33 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart';
import 'package:syncrow_app/features/scene/helper/scene_operations_data_helper.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_functions_body.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_temperature_body.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/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DeviceFunctionsView extends StatelessWidget
with SceneOperationsDataHelper {
const DeviceFunctionsView({super.key});
with SceneOperationsDataHelper, SceneLogicHelper {
DeviceFunctionsView({super.key});
@override
Widget build(BuildContext context) {
/// this whole widget needs a refactor later
///
/// static functions based on type
final device = ModalRoute.of(context)?.settings.arguments as DeviceModel;
final device = (ModalRoute.of(context)?.settings.arguments as Map)['device']
as DeviceModel;
final isAutomation = (ModalRoute.of(context)?.settings.arguments
as Map)['isAutomationDeviceStatus'] as bool;
/// static custom functions based on type
/// used for now until later backend fixes
@@ -38,6 +42,7 @@ class DeviceFunctionsView extends StatelessWidget
functions: device.functions,
deviceId: device.uuid ?? '',
deviceName: device.name ?? '',
isAutomation: isAutomation,
);
}
@@ -46,10 +51,10 @@ class DeviceFunctionsView extends StatelessWidget
actions: [
TextButton(
onPressed: () {
context.read<CreateSceneBloc>().add(AddTaskEvent());
Navigator.popUntil(context, (route) {
return route.settings.name == Routes.sceneTasksRoute;
});
context
.read<CreateSceneBloc>()
.add(AddTaskEvent(isAutomation: isAutomation));
navigateToRoute(context, Routes.sceneTasksRoute);
},
child: BodyMedium(
text: 'Save',
@@ -60,6 +65,16 @@ class DeviceFunctionsView extends StatelessWidget
],
leading: TextButton(
onPressed: () {
final automationSelectedValue =
context.read<CreateSceneBloc>().automationSelectedValues;
for (var element in device.functions) {
if (automationSelectedValue.containsKey(element.code)) {
context.read<CreateSceneBloc>().add(RemoveTempTaskByIdEvent(
code: element.code!, isAutomation: true));
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
code: element.code!, isAutomation: true));
}
}
final selectedValue =
context.read<CreateSceneBloc>().selectedValues;
for (var element in device.functions) {
@@ -83,136 +98,180 @@ class DeviceFunctionsView extends StatelessWidget
),
leadingWidth: 80,
padding: EdgeInsets.zero,
child: Padding(
child: ListView.builder(
shrinkWrap: true,
itemCount: functions.length,
padding: const EdgeInsets.only(top: 24.0),
child: ListView.builder(
shrinkWrap: true,
itemCount: functions.length,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return DefaultContainer(
padding: index == 0
? const EdgeInsets.only(top: 8)
: index == functions.length - 1
? const EdgeInsets.only(bottom: 8)
: EdgeInsets.zero,
margin: EdgeInsets.zero,
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))
: index == functions.length - 1
? const BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20))
: BorderRadius.zero,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
return SceneListTile(
iconsSize: 22,
minLeadingWidth: 20,
assetPath: functions[index].icon,
titleString: functions[index].operationName,
trailingWidget: const Row(
mainAxisSize: MainAxisSize.min,
children: [
/// selected value or the default value
// BodyMedium(text: ),
Icon(
Icons.arrow_forward_ios_rounded,
color: ColorsManager.greyColor,
size: 16,
),
],
),
onPressed: () {
final functionValues = context
.read<CreateSceneBloc>()
.selectedValues[functions[index].code];
context.customAlertDialog(
alertBody: functions[index].code == 'temp_set'
? AlertDialogTemperatureBody(
taskItem: functions[index],
functionValue: functionValues,
)
: (functions[index]
.code
.contains('countdown') ||
functions[index]
.code
.contains('presence_time'))
? AlertDialogCountdown(
durationValue: functions[index]
.operationalValues
.first
.value,
function: functions[index],
functionValue: functionValues,
)
: AlertDialogFunctionsOperationsBody(
taskItem: functions[index],
functionValue: functionValues,
),
title: functions[index].operationName,
onConfirm: () {
final selectedValue = context
.read<CreateSceneBloc>()
.selectedValues[functions[index].code];
if (selectedValue == null) {
return;
}
context
.read<CreateSceneBloc>()
.add(TempHoldSceneTasksEvent(
deviceControlModel: DeviceControlModel(
deviceId: device.uuid,
code: functions[index].code,
value: selectedValue,
),
deviceId: device.uuid ?? '',
operation: functions[index].operationName,
icon: device.icon ?? '',
deviceName: device.name ?? '',
uniqueId: functions[index].uniqueCustomId,
));
Navigator.pop(context);
},
onDismiss: () {
final tempTaskList = context
.read<CreateSceneBloc>()
.tempTasksList;
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);
},
itemBuilder: (context, index) {
return DefaultContainer(
padding: index == 0
? const EdgeInsets.only(top: 8)
: index == functions.length - 1
? const EdgeInsets.only(bottom: 8)
: EdgeInsets.zero,
margin: EdgeInsets.zero,
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))
: index == functions.length - 1
? const BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20))
: BorderRadius.zero,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
return SceneListTile(
iconsSize: 22,
minLeadingWidth: 20,
assetPath: functions[index].icon,
titleString: functions[index].operationName,
trailingWidget: const Row(
mainAxisSize: MainAxisSize.min,
children: [
/// selected value or the default value
// BodyMedium(text: ),
Icon(
Icons.arrow_forward_ios_rounded,
color: ColorsManager.greyColor,
size: 16,
),
],
),
onPressed: () {
if (isAutomation) {
_showAutomationDialog(
context,
functions[index],
device,
);
},
);
},
),
index != functions.length - 1
? SizedBox(
width: context.width * 0.8,
child: const LightDivider())
: const SizedBox(),
],
),
);
},
),
} else {
_showTabToRunDialog(
context,
functions[index],
device,
);
}
},
);
},
),
index != functions.length - 1
? SizedBox(
width: context.width * 0.8,
child: const LightDivider())
: const SizedBox(),
],
),
);
},
));
}
void _showTabToRunDialog(
BuildContext context,
SceneStaticFunction function,
DeviceModel device,
) {
final functionValues =
context.read<CreateSceneBloc>().selectedValues[function.code];
context.customAlertDialog(
alertBody: getTheCorrectDialogBody(
function,
functionValues,
isAutomation: false,
),
title: function.operationName,
onConfirm: () {
final selectedValue =
context.read<CreateSceneBloc>().selectedValues[function.code];
if (selectedValue == null) {
return;
}
context.read<CreateSceneBloc>().add(TempHoldSceneTasksEvent(
deviceControlModel: DeviceControlModel(
deviceId: device.uuid,
code: function.code,
value: selectedValue,
),
deviceId: device.uuid ?? '',
operation: function.operationName,
icon: device.icon ?? '',
deviceName: device.name ?? '',
uniqueId: function.uniqueCustomId,
operationType: function.operationDialogType,
));
Navigator.pop(context);
},
onDismiss: () {
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
for (var element in tempTaskList) {
if (element.code == function.code) {
context
.read<CreateSceneBloc>()
.add(RemoveTempTaskByIdEvent(code: function.code));
context
.read<CreateSceneBloc>()
.add(RemoveFromSelectedValueById(code: function.code));
}
}
Navigator.pop(context);
},
);
}
void _showAutomationDialog(
BuildContext context, SceneStaticFunction function, DeviceModel device) {
final automationFunctionValues =
context.read<CreateSceneBloc>().automationSelectedValues[function.code];
context.customAlertDialog(
alertBody: getTheCorrectDialogBody(
function,
automationFunctionValues,
isAutomation: true,
),
title: function.operationName,
onConfirm: () {
final automationFunctionValues = context
.read<CreateSceneBloc>()
.automationSelectedValues[function.code];
if (automationFunctionValues == null) {
return;
}
context.read<CreateSceneBloc>().add(TempHoldSceneTasksEvent(
deviceControlModel: DeviceControlModel(
deviceId: device.uuid,
code: function.code,
value: automationFunctionValues,
),
deviceId: device.uuid ?? '',
operation: function.operationName,
icon: device.icon ?? '',
deviceName: device.name ?? '',
uniqueId: function.uniqueCustomId,
operationType: function.operationDialogType,
isAutomation: true,
));
Navigator.pop(context);
},
onDismiss: () {
final automationTempTaskList =
context.read<CreateSceneBloc>().automationTempTasksList;
for (var element in automationTempTaskList) {
if (element.code == function.code) {
context.read<CreateSceneBloc>().add(RemoveTempTaskByIdEvent(
code: function.code, isAutomation: true));
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
code: function.code, isAutomation: true));
}
}
Navigator.pop(context);
},
);
}
}
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.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/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class SceneAutoSettings extends StatelessWidget {
const SceneAutoSettings({super.key});
@override
Widget build(BuildContext context) {
final sceneSettings =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>? ??
{};
final sceneId = sceneSettings['sceneId'] as String? ?? '';
final isAutomation = sceneSettings['isAutomation'] as bool? ?? false;
final sceneName = sceneSettings['sceneName'] as String? ?? '';
return Scaffold(
backgroundColor: ColorsManager.backgroundColor,
appBar: AppBar(
centerTitle: true,
backgroundColor: ColorsManager.backgroundColor,
title: const BodyLarge(
text: "Settings",
fontColor: ColorsManager.secondaryColor,
fontWeight: FontsManager.bold,
),
),
body: DefaultContainer(
padding: EdgeInsets.zero,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Visibility(
visible: isAutomation == true,
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,
child: DeleteBottomSheetContent(
isAutomation: isAutomation,
sceneId: sceneId,
),
),
],
),
),
);
}
}
@@ -8,6 +8,8 @@ import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart
import 'package:syncrow_app/features/scene/widgets/scene_devices/scene_devices_body.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@@ -16,10 +18,12 @@ class SceneRoomsTabBarDevicesView extends StatefulWidget {
const SceneRoomsTabBarDevicesView({super.key});
@override
State<SceneRoomsTabBarDevicesView> createState() => _SceneRoomsTabBarDevicesViewState();
State<SceneRoomsTabBarDevicesView> createState() =>
_SceneRoomsTabBarDevicesViewState();
}
class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesView>
class _SceneRoomsTabBarDevicesViewState
extends State<SceneRoomsTabBarDevicesView>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
List<RoomModel>? rooms = [];
@@ -41,7 +45,8 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
}
}
_tabController = TabController(length: rooms!.length, vsync: this, initialIndex: 0);
_tabController =
TabController(length: rooms!.length, vsync: this, initialIndex: 0);
_tabController.addListener(_handleTabSwitched);
super.initState();
}
@@ -51,9 +56,8 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
final value = _tabController.index;
/// select tab
context
.read<TabBarBloc>()
.add(TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
context.read<TabBarBloc>().add(
TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
return;
}
}
@@ -72,8 +76,7 @@ class _SceneRoomsTabBarDevicesViewState extends State<SceneRoomsTabBarDevicesVie
padding: EdgeInsets.zero,
leading: IconButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
navigateToRoute(context, Routes.sceneTasksRoute);
},
icon: const Icon(
Icons.arrow_back_ios,
+68 -55
View File
@@ -5,6 +5,7 @@ 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';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/widgets/create_scene_save_button.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/if_container.dart';
@@ -13,6 +14,8 @@ import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@@ -24,28 +27,38 @@ class SceneTasksView extends StatelessWidget {
Widget build(BuildContext context) {
final sceneSettings = ModalRoute.of(context)!.settings.arguments
as SceneSettingsRouteArguments;
final isAutomation =
sceneSettings.sceneType == CreateSceneEnum.deviceStatusChanges.name;
return DefaultScaffold(
title: sceneSettings.sceneName.isNotEmpty
? sceneSettings.sceneName
: StringsManager.createScene,
padding: EdgeInsets.zero,
actions: [
SizedBox(
width: 40,
child: GestureDetector(
onTap: sceneSettings.sceneName.isEmpty
? null
: () {
context.customBottomSheet(
child: DeleteBottomSheetContent(
sceneId: sceneSettings.sceneId),
);
Visibility(
visible: sceneSettings.sceneType.isNotEmpty,
child: SizedBox(
width: 40,
child: GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
Routes.sceneAutoSettingsRoute,
arguments: {
"sceneId": sceneSettings.sceneId,
"isAutomation": isAutomation,
"sceneName": sceneSettings.sceneName,
},
child: SvgPicture.asset(
Assets.assetsIconsSettings,
colorFilter: const ColorFilter.mode(
ColorsManager.textPrimaryColor,
BlendMode.srcIn,
);
},
child: SvgPicture.asset(
Assets.assetsIconsSettings,
colorFilter: const ColorFilter.mode(
ColorsManager.textPrimaryColor,
BlendMode.srcIn,
),
),
),
),
@@ -92,52 +105,52 @@ class SceneTasksView extends StatelessWidget {
}
class DeleteBottomSheetContent extends StatelessWidget {
const DeleteBottomSheetContent({super.key, required this.sceneId});
const DeleteBottomSheetContent(
{super.key, required this.sceneId, required this.isAutomation});
final String sceneId;
final bool isAutomation;
@override
Widget build(BuildContext context) {
return DefaultContainer(
height: context.height * 0.2,
child: ListView(
shrinkWrap: true,
children: [
BlocConsumer<CreateSceneBloc, CreateSceneState>(
listener: (context, state) {
if (state is DeleteSceneSuccess) {
if (state.success) {
Navigator.pop(context);
Navigator.pop(context);
BlocProvider.of<SceneBloc>(context).add(
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
}
}
},
builder: (context, state) {
return DefaultContainer(
onTap: () {
context.read<CreateSceneBloc>().add(DeleteSceneEvent(
sceneId: sceneId,
unitUuid:
HomeCubit.getInstance().selectedSpace!.id!,
));
},
child: SceneListTile(
titleString: StringsManager.deleteScene,
leadingWidget: (state is DeleteSceneLoading)
? const SizedBox(
height: 24,
width: 24,
child: CircularProgressIndicator())
: SvgPicture.asset(
Assets.assetsDeleteIcon,
color: ColorsManager.red,
),
));
},
),
],
padding: EdgeInsets.zero,
child: BlocConsumer<CreateSceneBloc, CreateSceneState>(
listener: (context, state) {
if (state is DeleteSceneSuccess) {
if (state.success) {
navigateToRoute(context, Routes.homeRoute);
BlocProvider.of<SceneBloc>(context).add(
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
}
}
},
builder: (context, state) {
return DefaultContainer(
onTap: () {
context.read<CreateSceneBloc>().add(DeleteSceneEvent(
sceneId: sceneId,
unitUuid: HomeCubit.getInstance().selectedSpace!.id!,
));
},
child: SceneListTile(
padding: const EdgeInsets.symmetric(horizontal: 8),
titleString: isAutomation
? StringsManager.deleteAutomation
: StringsManager.deleteScene,
leadingWidget: (state is DeleteSceneLoading)
? const SizedBox(
height: 24,
width: 24,
child: CircularProgressIndicator())
: SvgPicture.asset(
Assets.assetsDeleteIcon,
color: ColorsManager.red,
),
));
},
));
}
}
+94 -23
View File
@@ -5,11 +5,13 @@ 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/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/widgets/scene_view_widget/scene_grid_view.dart';
import 'package:syncrow_app/features/scene/widgets/scene_view_widget/scene_header.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.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 SceneView extends StatelessWidget {
final bool pageType;
@@ -19,19 +21,27 @@ 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 ?? ''))
..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!));
}
}
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());
}
}
return BlocListener<SceneBloc, SceneState>(
@@ -63,29 +73,90 @@ class SceneView extends StatelessWidget {
);
}
if (state is SceneLoaded) {
if (state.scenes.isNotEmpty) {
return pageType == false
? Expanded(
child: SceneGrid(
scenes: state.scenes,
loadingSceneId: state.loadingSceneId,
),
)
: Expanded(
final scenes = state.scenes;
final automationList = state.automationList;
return pageType
? Expanded(
child: SceneListview(
scenes: state.scenes,
loadingSceneId: state.loadingSceneId,
)
);
} else {
return const Expanded(
child: Center(
child: BodyMedium(
text: 'No scenes have been added yet',
),
),
);
}
scenes: scenes,
loadingSceneId: state.loadingSceneId,
))
: Expanded(
child: ListView(
children: [
Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent),
child: ExpansionTile(
tilePadding:
const EdgeInsets.symmetric(
horizontal: 6),
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
title: const BodyMedium(
text: 'Tap to run routines'),
children: [
scenes.isNotEmpty
? SceneGrid(
scenes: scenes,
loadingSceneId:
state.loadingSceneId,
disablePlayButton: false,
loadingStates: state
.loadingStates, // Add this line
)
: const Center(
child: BodyMedium(
text:
'No scenes have been added yet',
),
),
const SizedBox(
height: 10,
),
],
),
),
Theme(
data: ThemeData().copyWith(
dividerColor: Colors.transparent),
child: ExpansionTile(
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
tilePadding:
const EdgeInsets.symmetric(
horizontal: 6),
title: const BodyMedium(
text: 'Automation'),
children: [
automationList.isNotEmpty
? SceneGrid(
scenes: automationList,
loadingSceneId:
state.loadingSceneId,
disablePlayButton: true,
loadingStates: state
.loadingStates, // Add this line
)
: const Center(
child: BodyMedium(
text:
'No automations have been added yet',
),
),
const SizedBox(
height: 10,
),
],
),
),
const SizedBox(
height: 15,
),
],
),
);
}
return const SizedBox();
},
@@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_enable_autoamtion.dart';
import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_enable_tab_run.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SmartAutomationSelectView extends StatelessWidget {
const SmartAutomationSelectView({super.key});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: "Select Smart Scene",
padding: const EdgeInsets.only(top: 24),
leading: IconButton(
onPressed: () {
navigateToRoute(context, Routes.sceneTasksRoute);
},
icon: const Icon(
Icons.arrow_back_ios,
)),
height: 260,
child: DefaultContainer(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SceneListTile(
assetPath: Assets.handClickIcon,
titleString: "Tap To Run",
subtitleString: '',
trailingWidget: const Icon(
Icons.arrow_forward_ios_rounded,
color: ColorsManager.greyColor,
),
onPressed: () {
context.customBottomSheet(
child: const SmartEnableTabRun(),
);
},
),
const Divider(
color: ColorsManager.dividerColor,
),
SceneListTile(
assetPath: Assets.refreshIcon,
titleString: "Automation",
subtitleString: '',
trailingWidget: const Icon(
Icons.arrow_forward_ios_rounded,
color: ColorsManager.greyColor,
),
onPressed: () {
context.customBottomSheet(
child: const SmartEnableAutomation(),
);
},
),
],
),
),
);
}
}
@@ -26,6 +26,7 @@ class _AlertDialogCountdownState extends State<AlertDialogCountdown> {
@override
didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
for (var element in tempTaskList) {
@@ -11,10 +11,12 @@ class AlertDialogFunctionsOperationsBody extends StatefulWidget {
super.key,
this.functionValue,
required this.taskItem,
required this.isAutomation,
});
dynamic functionValue;
final SceneStaticFunction taskItem;
final bool isAutomation;
@override
State<AlertDialogFunctionsOperationsBody> createState() =>
@@ -26,24 +28,46 @@ class _AlertDialogFunctionsOperationsBodyState
@override
didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
if (widget.isAutomation) {
final automationTempTasksList =
context.read<CreateSceneBloc>().automationTempTasksList;
if (tempTaskList.isNotEmpty) {
for (var element in tempTaskList) {
if (element.code == widget.taskItem.code) {
groupValue = element.functionValue;
} else {
context
.read<CreateSceneBloc>()
.add(RemoveFromSelectedValueById(code: widget.taskItem.code));
if (automationTempTasksList.isNotEmpty) {
for (var element in automationTempTasksList) {
if (element.code == widget.taskItem.code) {
groupValue = element.functionValue;
} else {
context.read<CreateSceneBloc>().add(RemoveFromSelectedValueById(
code: widget.taskItem.code, isAutomation: widget.isAutomation));
}
}
}
}
if (widget.functionValue != null) {
setState(() {
groupValue = widget.functionValue;
});
if (widget.functionValue != null) {
setState(() {
groupValue = widget.functionValue;
});
}
} else {
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
if (tempTaskList.isNotEmpty) {
for (var element in tempTaskList) {
if (element.code == widget.taskItem.code) {
groupValue = element.functionValue;
} else {
context
.read<CreateSceneBloc>()
.add(RemoveFromSelectedValueById(code: widget.taskItem.code));
}
}
}
if (widget.functionValue != null) {
setState(() {
groupValue = widget.functionValue;
});
}
}
}
@@ -76,7 +100,9 @@ class _AlertDialogFunctionsOperationsBodyState
groupValue = value;
});
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: value!, code: widget.taskItem.code));
value: value!,
code: widget.taskItem.code,
isAutomation: widget.isAutomation));
},
),
onPressed: () {
@@ -84,7 +110,9 @@ class _AlertDialogFunctionsOperationsBodyState
groupValue = operation.value;
});
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: groupValue, code: widget.taskItem.code));
value: groupValue,
code: widget.taskItem.code,
isAutomation: widget.isAutomation));
},
);
},
@@ -0,0 +1,242 @@
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';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class AlertDialogSliderSteps extends StatefulWidget {
const AlertDialogSliderSteps({
super.key,
this.functionValue,
required this.taskItem,
required this.isAutomation,
});
final dynamic functionValue;
final SceneStaticFunction taskItem;
final bool isAutomation;
@override
State<AlertDialogSliderSteps> createState() => _AlertDialogSliderStepsState();
}
class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
double? groupValue;
int selectedToggleIndex = 1;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final createSceneBloc = context.read<CreateSceneBloc>();
if (widget.isAutomation) {
final automationTempTaskList = createSceneBloc.automationTempTasksList;
final automationComparatorValues =
createSceneBloc.automationComparatorValues;
for (var element in automationTempTaskList) {
if (element.code == widget.taskItem.code) {
groupValue = element.functionValue;
selectedToggleIndex =
_comparatorToIndex(automationComparatorValues[element.code]);
}
}
}
if (widget.functionValue != null) {
groupValue = _normalizeValue(widget.functionValue);
} else {
groupValue =
_normalizeValue(widget.taskItem.operationalValues[0].minValue);
}
if (widget.taskItem.comparator != null) {
selectedToggleIndex = _comparatorToIndex(widget.taskItem.comparator);
}
setState(() {});
}
double _normalizeValue(dynamic value) {
if (((widget.taskItem.code == "temp_set" && value > 200) ||
widget.taskItem.code == "temp_current")) {
return (value) / 10;
}
return value.toDouble();
}
int _comparatorToIndex(String? comparator) {
switch (comparator) {
case "<":
return 0;
case "==":
return 1;
case ">":
return 2;
default:
return 1;
}
}
String _indexToComparator(int index) {
switch (index) {
case 0:
return "<";
case 1:
return "==";
case 2:
return ">";
default:
return "==";
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ToggleButtons(
isSelected: [
selectedToggleIndex == 0,
selectedToggleIndex == 1,
selectedToggleIndex == 2
],
onPressed: (index) {
setState(() {
selectedToggleIndex = index;
});
context.read<CreateSceneBloc>().add(
SelectedValueEvent(
value: _deNormalizeValue(groupValue),
code: widget.taskItem.code,
isAutomation: widget.isAutomation,
comparator: _indexToComparator(selectedToggleIndex),
),
);
},
borderRadius: BorderRadius.circular(30),
selectedColor: Colors.white,
color: ColorsManager.blackColor,
fillColor: ColorsManager.primaryColorWithOpacity,
borderColor: ColorsManager.greyColor,
constraints: BoxConstraints.tight(const Size(70, 30)),
children: [
SizedBox(
width: 70,
height: 30,
child: Container(
color: selectedToggleIndex == 0
? ColorsManager.primaryColorWithOpacity
: ColorsManager.greyColor,
alignment: Alignment.center,
child: const Text("<"),
),
),
SizedBox(
width: 70,
height: 30,
child: Container(
color: selectedToggleIndex == 1
? ColorsManager.primaryColorWithOpacity
: ColorsManager.greyColor,
alignment: Alignment.center,
child: const Text("="),
),
),
SizedBox(
width: 70,
height: 30,
child: Container(
color: selectedToggleIndex == 2
? ColorsManager.primaryColorWithOpacity
: ColorsManager.greyColor,
alignment: Alignment.center,
child: const Text(">"),
),
),
],
),
const SizedBox(height: 12),
...widget.taskItem.operationalValues.map(
(operation) => BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
return Column(
children: [
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TitleMedium(
text: groupValue != null
? (groupValue! % 1 == 0
? groupValue!.toStringAsFixed(0)
: groupValue!.toStringAsFixed(1))
: "0",
style: context.titleMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontSize: 30,
),
),
const SizedBox(width: 8),
TitleMedium(
text: operation.description.toString(),
style: context.titleMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontSize: 30,
),
),
],
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Slider(
value: groupValue ?? 0,
min: operation.minValue ?? 0,
max: operation.maxValue ?? 0,
inactiveColor: ColorsManager.primaryColorWithOpacity
.withOpacity(0.2),
divisions: operation.stepValue != null
? ((operation.maxValue!.toDouble() -
operation.minValue!.toDouble()) /
operation.stepValue!.toDouble())
.round()
: null,
onChanged: (value) {
setState(() {
groupValue = normalizeValue(value);
});
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: _deNormalizeValue(groupValue),
code: widget.taskItem.code,
isAutomation: widget.isAutomation,
comparator:
_indexToComparator(selectedToggleIndex)));
},
),
),
const SizedBox(height: 12),
],
);
},
),
),
],
);
}
double normalizeValue(double value) {
return double.parse(value.toStringAsFixed(1));
}
double _deNormalizeValue(double? value) {
if (widget.taskItem.code == "temp_set" ||
widget.taskItem.code == "temp_current") {
return (value ?? 0) * 10;
}
return value ?? 0;
}
}
@@ -14,14 +14,10 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class AlertDialogTemperatureBody extends StatefulWidget {
AlertDialogTemperatureBody({
super.key,
//required this.index,
// required this.functions,
this.functionValue,
required this.taskItem,
});
//final List<SceneStaticFunction> functions;
// final int index;
final SceneStaticFunction taskItem;
dynamic functionValue;
@@ -32,14 +28,16 @@ class AlertDialogTemperatureBody extends StatefulWidget {
class _AlertDialogTemperatureBodyState
extends State<AlertDialogTemperatureBody> {
int temperature = 24;
@override
didChangeDependencies() {
void didChangeDependencies() {
super.didChangeDependencies();
final tempTaskList = context.read<CreateSceneBloc>().tempTasksList;
for (var element in tempTaskList) {
if (element.code == widget.taskItem.code) {
temperature = element.functionValue;
temperature = _normalizeTemperature(element.functionValue);
} else {
context
.read<CreateSceneBloc>()
@@ -48,12 +46,18 @@ class _AlertDialogTemperatureBodyState
}
if (widget.functionValue != null) {
setState(() {
temperature = widget.functionValue;
temperature = _normalizeTemperature(widget.functionValue);
});
}
}
int temperature = 24;
int _normalizeTemperature(dynamic value) {
if (value is int && value >= 100) {
return value ~/ 10;
}
return value as int? ?? 24;
}
@override
Widget build(BuildContext context) {
return ListTile(
@@ -98,8 +102,7 @@ class _AlertDialogTemperatureBodyState
],
),
subtitle: BodyLarge(
text: widget.taskItem.operationalValues[0].description
.toString(),
text: widget.taskItem.operationalValues[0].description.toString(),
textAlign: TextAlign.center,
),
trailing: IconButton(
@@ -110,8 +113,7 @@ class _AlertDialogTemperatureBodyState
}
});
context.read<CreateSceneBloc>().add(SelectedValueEvent(
value: temperature * 10,
code: widget.taskItem.code));
value: temperature * 10, code: widget.taskItem.code));
},
icon: const Icon(
Icons.add,
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/features/scene/widgets/alert_dialogs/alert_dialog_countdown.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
@@ -66,7 +67,9 @@ class CustomBottomSheetWidget extends StatelessWidget {
size: 16,
color: ColorsManager.greyColor,
),
onPressed: () {},
onPressed: () {
Navigator.pushNamed(context, Routes.smartAutomationSelectRoute);
},
),
SceneListTile(
assetPath: Assets.delay,
@@ -97,6 +100,7 @@ class CustomBottomSheetWidget extends StatelessWidget {
operationName: 'Delay The Action',
code: '',
functionValue: 0,
operationDialogType: OperationDialogType.delay,
operationalValues: [
SceneOperationalValue(icon: '', value: 0),
],
@@ -123,8 +127,9 @@ class CustomBottomSheetWidget extends StatelessWidget {
icon: Assets.delay,
deviceName: 'Delay The Action',
uniqueId: functions[0].uniqueCustomId,
operationType: functions[0].operationDialogType,
));
context.read<CreateSceneBloc>().add(AddTaskEvent());
context.read<CreateSceneBloc>().add(const AddTaskEvent());
Navigator.pop(context);
Navigator.pop(context);
},
@@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/helper/scene_logic_helper.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/navigation/navigate_to_route.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@@ -43,8 +46,7 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
listener: (context, state) {
if (state is CreateSceneWithTasks) {
if (state.success == true) {
Navigator.pop(context);
Navigator.pop(context);
navigateToRoute(context, Routes.homeRoute);
context.showCustomSnackbar(
message: 'Scene created successfully',
icon: const Icon(
@@ -66,55 +68,59 @@ class _CreateSceneSaveButtonState extends State<CreateSceneSaveButton>
},
builder: (context, state) {
return DefaultButton(
onPressed: widget.sceneName.isNotEmpty
? () {
final tasks = context.read<CreateSceneBloc>().tasksList;
handleSaveButtonPress(
context,
sceneNameController,
tasks,
updateScene: true,
sceneId: widget.sceneId,
);
}
: () {
context.customAlertDialog(
alertBody: Padding(
padding:
const EdgeInsets.only(left: 8, right: 8, bottom: 8),
child: SizedBox(
height: 40,
child: SearchBar(
controller: sceneNameController,
elevation: WidgetStateProperty.all(0),
textStyle:
WidgetStateProperty.all(context.bodyMedium),
hintStyle: WidgetStateProperty.all(
context.bodyMedium.copyWith(
fontSize: 14,
color: ColorsManager.secondaryTextColor),
),
hintText: 'Enter scene name',
backgroundColor: WidgetStateProperty.all(
ColorsManager.backgroundColor),
),
onPressed: () {
final sceneBloc = context.read<CreateSceneBloc>();
final isAutomation =
sceneBloc.sceneType == CreateSceneEnum.deviceStatusChanges;
if (widget.sceneName.isNotEmpty) {
handleSaveButtonPress(
context,
sceneName: sceneNameController,
actions: sceneBloc.tasksList,
updateScene: true,
sceneId: widget.sceneId,
isAutomation: isAutomation,
conditions: sceneBloc.automationTasksList,
);
} else {
context.customAlertDialog(
alertBody: Padding(
padding: const EdgeInsets.only(left: 8, right: 8, bottom: 8),
child: SizedBox(
height: 40,
child: SearchBar(
controller: sceneNameController,
elevation: WidgetStateProperty.all(0),
textStyle: WidgetStateProperty.all(context.bodyMedium),
hintStyle: WidgetStateProperty.all(
context.bodyMedium.copyWith(
fontSize: 14,
color: ColorsManager.secondaryTextColor),
),
hintText: 'Enter scene name',
backgroundColor: WidgetStateProperty.all(
ColorsManager.backgroundColor),
),
title: 'Scene Name',
onConfirm: () {
if (sceneNameController.text.isNotEmpty) {
final tasks = context.read<CreateSceneBloc>().tasksList;
handleSaveButtonPress(
context,
sceneNameController,
tasks,
updateScene: false,
sceneId: widget.sceneId,
);
}
},
);
),
),
title: 'Scene Name',
onConfirm: () {
if (sceneNameController.text.isNotEmpty) {
handleSaveButtonPress(
context,
sceneName: sceneNameController,
actions: sceneBloc.tasksList,
updateScene: false,
sceneId: widget.sceneId,
isAutomation: isAutomation,
conditions: sceneBloc.automationTasksList,
);
}
},
);
}
},
customButtonStyle: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
ColorsManager.primaryColor,
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/period_options.dart';
import 'package:syncrow_app/features/scene/widgets/effective_period_setting/repeat_days.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import '../../helper/effect_period_helper.dart';
class EffectPeriodBottomSheetContent extends StatelessWidget {
const EffectPeriodBottomSheetContent({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextButton(
onPressed: () => Navigator.pop(context),
child: BodySmall(
text: 'Save',
style: context.bodySmall.copyWith(
color: ColorsManager.primaryColorWithOpacity),
)),
),
Expanded(
flex: 2,
child: BodyMedium(
text: 'Effective Period',
fontColor: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.bold,
textAlign: TextAlign.center,
),
),
const Spacer(),
],
),
const Divider(
color: ColorsManager.backgroundColor,
),
const PeriodOptions(
showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker,
),
const SizedBox(height: 16),
const RepeatDays(),
const SizedBox(height: 24),
],
),
);
}
}
@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/scene/enum/effective_period_options.dart';
import 'package:syncrow_app/features/scene/helper/effect_period_helper.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class PeriodOptions extends StatelessWidget {
final Future<List<String>?> Function(BuildContext) showCustomTimePicker;
const PeriodOptions({
required this.showCustomTimePicker,
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Column(
children: [
_buildRadioOption(
context, EnumEffectivePeriodOptions.allDay, '24 Hours'),
_buildRadioOption(context, EnumEffectivePeriodOptions.daytime,
'Sunrise to Sunset'),
_buildRadioOption(
context, EnumEffectivePeriodOptions.night, 'Sunset to Sunrise'),
ListTile(
contentPadding: EdgeInsets.zero,
onTap: () => showCustomTimePicker(context),
title: const BodyMedium(
text: 'Custom',
),
subtitle:
state.customStartTime != null && state.customEndTime != null
? BodySmall(
text:
'${"${state.customStartTime} AM"} - ${"${state.customEndTime} PM"}',
style: context.bodySmall.copyWith(fontSize: 10),
)
: BodySmall(
text: '00:00 AM - 11:59 PM',
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<EnumEffectivePeriodOptions>(
value: EnumEffectivePeriodOptions.custom,
groupValue: state.selectedPeriod,
onChanged: (value) async {
if (value != null) {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
}
},
),
),
],
);
},
);
}
Widget _buildRadioOption(
BuildContext context, EnumEffectivePeriodOptions value, String subtitle) {
return BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return ListTile(
contentPadding: EdgeInsets.zero,
onTap: () {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
},
title: BodyMedium(text: EffectPeriodHelper.formatEnumValue(value)),
subtitle: BodySmall(
text: subtitle,
style: context.bodySmall.copyWith(fontSize: 10),
),
trailing: Radio<EnumEffectivePeriodOptions>(
value: value,
groupValue: state.selectedPeriod,
onChanged: (value) {
if (value != null) {
context.read<EffectPeriodBloc>().add(SetPeriod(value));
}
},
),
);
},
);
}
}
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_state.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
class RepeatDays extends StatelessWidget {
const RepeatDays({super.key});
@override
Widget build(BuildContext context) {
final daysMap = {
'Mon': 'M',
'Tue': 'T',
'Wed': 'W',
'Thu': 'T',
'Fri': 'F',
'Sat': 'S',
'Sun': 'S',
};
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const BodyMedium(text: 'Repeat'),
const SizedBox(width: 8),
BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
builder: (context, state) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final dayIndex = _getDayIndex(day);
final isSelected = state.selectedDaysBinary[dayIndex] == '1';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color:
isSelected ? Colors.grey : Colors.grey.shade300,
width: 1,
),
),
child: CircleAvatar(
radius: 15,
backgroundColor: Colors.white,
child: Text(
abbreviation,
style: TextStyle(
fontSize: 16,
color:
isSelected ? Colors.grey : Colors.grey.shade300,
),
),
),
),
),
);
}).toList(),
);
},
),
],
);
}
int _getDayIndex(String day) {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return days.indexOf(day);
}
}
@@ -1,11 +1,22 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@@ -16,32 +27,173 @@ class IFDefaultContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sceneType = context.read<CreateSceneBloc>().sceneType;
return DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SceneListTile(
leadingWidget: BodyLarge(
text: 'IF',
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.primaryTextColor,
leadingWidget: InkWell(
onTap: () {
if (sceneType.name ==
CreateSceneEnum.deviceStatusChanges.name) {
context.customAlertDialog(
hideConfirmButton: true,
alertBody: Column(
children: [
ListTile(
title: const BodyMedium(
text: "When all conditions are met"),
onTap: () {
context.read<CreateSceneBloc>().add(
const SelectConditionEvent(
"When all conditions are met"));
Navigator.pop(context);
},
),
ListTile(
title: const BodyMedium(
text: "When any condition is met"),
onTap: () {
context.read<CreateSceneBloc>().add(
const SelectConditionEvent(
"When any condition is met"));
Navigator.pop(context);
},
),
],
),
title: 'Conditions Rule',
onConfirm: () {},
);
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
BodyLarge(
text: 'IF',
style: context.bodyLarge.copyWith(
fontWeight: FontWeight.bold,
color: ColorsManager.primaryTextColor,
),
),
Visibility(
visible: sceneType.name ==
CreateSceneEnum.deviceStatusChanges.name,
child: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
String conditionText = "When any condition is met";
if (state is AddSceneTask) {
if (state.condition == 'or') {
conditionText = "When any condition is met";
} else {
conditionText = "When all conditions are met";
}
}
return SizedBox(
width: context.width * 0.6,
child: Row(children: [
BodySmall(text: conditionText),
const Icon(Icons.keyboard_arrow_down)
]),
);
},
),
),
],
),
),
trailingWidget: SvgPicture.asset(Assets.addIcon),
trailingWidget: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
bool isClickable = false;
if (state is AddSceneTask) {
isClickable = state.automationTasksList?.isNotEmpty ?? false;
}
return GestureDetector(
onTap: isClickable
? () => Navigator.pushNamed(
context,
Routes.sceneControlDevicesRoute,
arguments: SceneSettingsRouteArguments(
sceneType:
CreateSceneEnum.deviceStatusChanges.name,
sceneId: '',
sceneName: '',
),
)
: null,
child: SvgPicture.asset(
Assets.addIcon,
colorFilter: ColorFilter.mode(
isClickable
? ColorsManager.primaryColor
: ColorsManager.greyColor,
BlendMode.srcIn,
),
),
);
},
),
padding: EdgeInsets.zero,
),
const LightDivider(),
const SceneListTile(
assetPath: Assets.handClickIcon,
titleString: StringsManager.tapToRun,
padding: EdgeInsets.zero,
BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
if (state is AddSceneTask) {
final automationTasksList = state.automationTasksList;
if (automationTasksList?.isNotEmpty == true) {
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: automationTasksList?.length,
reverse: true,
itemBuilder: (context, index) {
return ThenAddedTasksContainer(
taskItem: automationTasksList![index],
isAutomation: true,
);
},
);
}
}
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.tabToRun.name) {
return const SceneListTile(
padding: EdgeInsets.symmetric(horizontal: 2),
assetPath: Assets.handClickIcon,
titleString: StringsManager.tapToRun,
subtitleString: '',
);
}
return SceneListTile(
titleString: '+ Add Condition',
textAlign: TextAlign.center,
onPressed: () {
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.none.name) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => const CreateSceneView()));
} else {
Navigator.pushNamed(
context,
Routes.sceneControlDevicesRoute,
arguments: SceneSettingsRouteArguments(
sceneType: CreateSceneEnum.deviceStatusChanges.name,
sceneId: '',
sceneName: '',
),
);
}
});
},
)
],
),
);
}
}
@@ -13,6 +13,7 @@ import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class ThenAddedTasksContainer extends StatelessWidget
@@ -22,17 +23,19 @@ class ThenAddedTasksContainer extends StatelessWidget
required this.taskItem,
this.sceneId,
this.index,
this.isAutomation,
});
final SceneStaticFunction taskItem;
String? sceneId;
int? index;
bool? isAutomation;
@override
Widget build(BuildContext context) {
final createSceneBloc = context.read<CreateSceneBloc>();
String operationValue = '';
if (taskItem.code.contains('countdown') ||
if ((taskItem.code.contains('countdown') && isAutomation != true) ||
taskItem.deviceId.contains('delay')) {
final functionValue =
taskItem.functionValue ?? taskItem.operationalValues.first.value;
@@ -40,7 +43,8 @@ class ThenAddedTasksContainer extends StatelessWidget
Duration(seconds: int.tryParse(functionValue.toString()) ?? 0);
operationValue =
"${duration.inHours}h ${duration.inMinutes.remainder(60)}m ";
} else if (taskItem.code.contains('temp_set')) {
} else if (taskItem.code.contains('temp_set') ||
taskItem.code.contains('temp_current')) {
if (taskItem.functionValue != null || taskItem.functionValue != 0) {
operationValue =
'${((taskItem.functionValue / 10) as double).round().toString()}°C';
@@ -48,8 +52,13 @@ class ThenAddedTasksContainer extends StatelessWidget
operationValue = '0°C';
}
} else {
final functionValue =
var functionValue =
taskItem.functionValue ?? taskItem.operationalValues.first.value;
if (functionValue is double) {
functionValue = double.parse(functionValue.toStringAsFixed(1));
}
operationValue = functionValue.toString();
}
return DefaultContainer(
@@ -58,28 +67,49 @@ class ThenAddedTasksContainer extends StatelessWidget
/// get the task functions
functionOperation = List.from(getOperationsForOneFunction(
taskItem: taskItem, deviceId: taskItem.deviceId));
taskItem: taskItem,
deviceId: taskItem.deviceId,
isAutomation: isAutomation ?? false));
/// show alert dialog based on type
context.customAlertDialog(
alertBody: getTheCorrectDialogBody(functionOperation.first),
alertBody: getTheCorrectDialogBody(functionOperation.first, null,
isAutomation: isAutomation ?? false),
title: functionOperation.first.operationName,
onConfirm: () {
final savedCode = functionOperation.first.deviceId.contains('delay')
? 'delay'
: functionOperation.first.code;
final selectedValue = createSceneBloc.selectedValues[savedCode];
if (isAutomation == true) {
final automationSelectedValue =
createSceneBloc.automationSelectedValues[savedCode];
try {
createSceneBloc.add(
UpdateTaskEvent(
newValue: selectedValue,
taskId: taskItem.uniqueCustomId,
),
);
} catch (e) {
debugPrint('Error adding UpdateTaskEvent: $e');
try {
createSceneBloc.add(
UpdateTaskEvent(
newValue: automationSelectedValue,
taskId: taskItem.uniqueCustomId,
isAutomation: true,
),
);
} catch (e) {
debugPrint('Error adding UpdateTaskEvent: $e');
}
} else {
final selectedValue = createSceneBloc.selectedValues[savedCode];
try {
createSceneBloc.add(
UpdateTaskEvent(
newValue: selectedValue,
taskId: taskItem.uniqueCustomId,
),
);
} catch (e) {
debugPrint('Error adding UpdateTaskEvent: $e');
}
}
Navigator.pop(context);
},
);
@@ -109,16 +139,21 @@ class ThenAddedTasksContainer extends StatelessWidget
onDismissed: (direction) {
String removeFunctionById = taskItem.uniqueCustomId;
context
.read<CreateSceneBloc>()
.add(RemoveTaskByIdEvent(taskId: removeFunctionById));
if (isAutomation == true) {
context.read<CreateSceneBloc>().add(RemoveTaskByIdEvent(
taskId: removeFunctionById,
isAutomation: true,
));
} else {
context.read<CreateSceneBloc>().add(RemoveTaskByIdEvent(
taskId: removeFunctionById,
));
}
String removeFunction =
"${taskItem.operationName} with value ${taskItem.operationalValues.first.value}";
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('$removeFunction removed')),
);
CustomSnackBar.displaySnackBar('$removeFunction removed');
},
child: SceneListTile(
padding: EdgeInsets.zero,
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/widgets/if_then_containers/then_added_tasks.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/scene/widgets/bottom_sheet_widget.dart';
@@ -10,6 +12,7 @@ import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class ThenDefaultContainer extends StatelessWidget {
@@ -35,17 +38,29 @@ class ThenDefaultContainer extends StatelessWidget {
color: ColorsManager.primaryTextColor,
),
),
trailingWidget: GestureDetector(
onTap: () => context.customBottomSheet(
child: const CustomBottomSheetWidget(),
),
child: SvgPicture.asset(
Assets.addIcon,
colorFilter: const ColorFilter.mode(
ColorsManager.primaryColor,
BlendMode.srcIn,
),
),
trailingWidget: BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
bool isClickable = false;
if (state is AddSceneTask) {
isClickable = state.tasksList.isNotEmpty;
}
return GestureDetector(
onTap: isClickable
? () => context.customBottomSheet(
child: const CustomBottomSheetWidget(),
)
: null,
child: SvgPicture.asset(
Assets.addIcon,
colorFilter: ColorFilter.mode(
isClickable
? ColorsManager.primaryColor
: ColorsManager.greyColor,
BlendMode.srcIn,
),
),
);
},
),
padding: EdgeInsets.zero,
),
@@ -71,20 +86,23 @@ class ThenDefaultContainer extends StatelessWidget {
},
);
}
return SceneListTile(
titleString: '+ Add Task',
textAlign: TextAlign.center,
onPressed: () => context.customBottomSheet(
child: const CustomBottomSheetWidget(),
),
);
}
return SceneListTile(
titleString: '+ Add Task',
textAlign: TextAlign.center,
onPressed: () => context.customBottomSheet(
child: const CustomBottomSheetWidget(),
),
onPressed: () {
final sceneType = context.read<CreateSceneBloc>().sceneType;
if (sceneType.name == CreateSceneEnum.none.name) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => const CreateSceneView()));
} else {
context.customBottomSheet(
child: const CustomBottomSheetWidget(),
);
}
},
);
},
)
@@ -6,6 +6,8 @@ import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_man
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@@ -26,6 +28,11 @@ class SceneDevicesBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isAutomationDeviceStatus = ((ModalRoute.of(context)
?.settings
.arguments as SceneSettingsRouteArguments?)
?.sceneType ==
CreateSceneEnum.deviceStatusChanges.name);
return BlocBuilder<TabBarBloc, TabBarState>(
builder: (context, tabState) {
return Column(
@@ -56,7 +63,10 @@ class SceneDevicesBody extends StatelessWidget {
child: TabBarView(
controller: _tabController,
physics: const NeverScrollableScrollPhysics(),
children: rooms!.map((e) => _buildRoomTab(e, context)).toList(),
children: rooms!
.map((e) =>
_buildRoomTab(e, context, isAutomationDeviceStatus))
.toList(),
),
),
],
@@ -65,7 +75,8 @@ class SceneDevicesBody extends StatelessWidget {
);
}
Widget _buildRoomTab(RoomModel room, BuildContext context) {
Widget _buildRoomTab(
RoomModel room, BuildContext context, bool isAutomationDeviceStatus) {
return BlocBuilder<DeviceManagerBloc, DeviceManagerState>(
builder: (context, state) {
if (state.loading && state.devices == null) {
@@ -96,7 +107,10 @@ class SceneDevicesBody extends StatelessWidget {
Navigator.pushNamed(
context,
Routes.deviceFunctionsRoute,
arguments: device,
arguments: {
"device": device,
"isAutomationDeviceStatus": isAutomationDeviceStatus
},
);
},
),
@@ -1,21 +1,25 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/widgets/scene_view_widget/scene_item.dart';
class SceneGrid extends StatelessWidget {
final List<ScenesModel> scenes;
final List<dynamic> scenes;
final String? loadingSceneId;
final bool disablePlayButton;
final Map<String, bool> loadingStates;
const SceneGrid({
required this.scenes,
required this.loadingSceneId,
required this.disablePlayButton,
required this.loadingStates,
super.key,
});
@override
Widget build(BuildContext context) {
return
GridView.builder(
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 12,
@@ -26,7 +30,14 @@ class SceneGrid extends StatelessWidget {
itemBuilder: (context, index) {
final scene = scenes[index];
final isLoading = loadingSceneId == scene.id;
return SceneItem(scene: scene, isLoading: isLoading);
final isSwitchLoading = loadingStates[scene.id] ?? false;
return SceneItem(
scene: scene,
isLoading: isLoading,
disablePlayButton: disablePlayButton,
isSwitchLoading: isSwitchLoading,
);
},
);
}
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
@@ -20,10 +19,10 @@ class SceneHeader extends StatelessWidget {
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
BodySmall(
text: StringsManager.tapToRunRoutine,
),
// SizedBox(height: 20),
// BodySmall(
// text: StringsManager.tapToRunRoutine,
// ),
],
);
}
@@ -1,11 +1,14 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/model/update_automation.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
@@ -16,11 +19,15 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SceneItem extends StatelessWidget {
final ScenesModel scene;
final bool isLoading;
final bool isSwitchLoading;
final bool disablePlayButton;
const SceneItem({
required this.scene,
required this.isLoading,
super.key,
required this.disablePlayButton,
required this.isSwitchLoading,
});
@override
@@ -31,16 +38,28 @@ class SceneItem extends StatelessWidget {
context,
Routes.sceneTasksRoute,
arguments: SceneSettingsRouteArguments(
sceneType: CreateSceneEnum.tabToRun.name,
sceneType: disablePlayButton == false
? CreateSceneEnum.tabToRun.name
: CreateSceneEnum.deviceStatusChanges.name,
sceneId: scene.id,
sceneName: scene.name,
),
);
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id));
if (disablePlayButton == false) {
BlocProvider.of<CreateSceneBloc>(context)
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
BlocProvider.of<CreateSceneBloc>(context).add(
FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false));
} else {
BlocProvider.of<CreateSceneBloc>(context)
.add(const SceneTypeEvent(CreateSceneEnum.deviceStatusChanges));
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: true));
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
@@ -52,23 +71,45 @@ class SceneItem extends StatelessWidget {
Assets.assetsIconsLogo,
fit: BoxFit.fill,
),
IconButton(
padding: EdgeInsets.zero,
onPressed: () {
context
.read<SceneBloc>()
.add(SceneTrigger(scene.id, scene.name));
},
icon: isLoading
? const Center(
child: CircularProgressIndicator(),
)
: const Icon(
Icons.play_circle,
size: 40,
color: ColorsManager.greyColor,
),
),
disablePlayButton == false
? IconButton(
padding: EdgeInsets.zero,
onPressed: () {
context
.read<SceneBloc>()
.add(SceneTrigger(scene.id, scene.name));
},
icon: isLoading
? const Center(
child: CircularProgressIndicator(),
)
: const Icon(
Icons.play_circle,
size: 40,
color: ColorsManager.greyColor,
),
)
: isSwitchLoading
? Center(
child: CircularProgressIndicator(
color: ColorsManager.primaryColorWithOpacity,
),
)
: CupertinoSwitch(
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));
},
),
],
),
const SizedBox(height: 10),
@@ -0,0 +1,280 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/model/scene_static_function.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/smart_scene_enable.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SmartSceneSelectAutomationList extends StatefulWidget {
const SmartSceneSelectAutomationList({
super.key,
required this.automationList,
});
final List<ScenesModel> automationList;
@override
State<SmartSceneSelectAutomationList> createState() =>
_SmartSceneSelectAutomationListState();
}
class _SmartSceneSelectAutomationListState
extends State<SmartSceneSelectAutomationList> {
final List<Color> colorList = _generateDarkColors(100);
static List<Color> _generateDarkColors(int count) {
final random = Random();
final colors = <Color>[];
while (colors.length < count) {
final color =
Color((random.nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
if (_isDark(color)) {
colors.add(color);
}
}
return colors;
}
static bool _isDark(Color color) {
final brightness =
((color.red * 299) + (color.green * 587) + (color.blue * 114)) / 1000;
return brightness < 128;
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextButton(
onPressed: () => Navigator.pop(context),
child: BodySmall(
text: 'Save',
style: context.bodySmall
.copyWith(color: ColorsManager.primaryColorWithOpacity),
)),
),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: BodyMedium(
text: 'Automation',
textAlign: TextAlign.center,
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
const Spacer(),
],
),
const Divider(
color: ColorsManager.dividerColor,
),
Expanded(
child: BlocBuilder<SmartSceneSelectBloc, SmartSceneSelectState>(
builder: (context, state) {
final smartSceneEnable = ((state is SmartSceneSelected))
? state.smartSceneEnable
: context.read<SmartSceneSelectBloc>().smartSceneEnable;
return ListView.builder(
shrinkWrap: true,
itemCount: widget.automationList.length,
itemBuilder: (context, index) {
final automation = widget.automationList[index];
final isSelected =
smartSceneEnable?.entityId == automation.id;
final descriptionSelected = isSelected
? (smartSceneEnable?.actionExecutor == 'rule_enable'
? 'Enable'
: 'Disable')
: automation.status == 'enable'
? 'Enable'
: 'Disable';
return SceneListTile(
padding: const EdgeInsets.symmetric(horizontal: 10),
leadingWidget: CircleAvatar(
backgroundColor: colorList[index % colorList.length],
radius: 15,
child: Text(
index.toString(),
style: context.bodyMedium.copyWith(color: Colors.white),
),
),
titleString: automation.name,
trailingWidget: TextButton.icon(
iconAlignment: IconAlignment.end,
onPressed: () {
context.customAlertDialog(
alertBody: EnableDisableAutomationDialog(
automationId: automation.id,
descriptionSelected: descriptionSelected,
),
title: automation.name,
onConfirm: () {
Navigator.pop(context);
},
onDismiss: () {
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
Navigator.pop(context);
},
);
},
label: BodyMedium(
text: _capitalizeFirst(descriptionSelected),
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
),
icon: const Icon(
Icons.arrow_forward_ios_rounded,
color: ColorsManager.greyColor,
size: 14,
),
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
),
onPressed: () {
context.customAlertDialog(
alertBody: EnableDisableAutomationDialog(
automationId: automation.id,
descriptionSelected: descriptionSelected,
),
title: automation.name,
onConfirm: () {
Navigator.pop(context);
},
onDismiss: () {
context
.read<SmartSceneSelectBloc>()
.add(const SmartSceneClearEvent());
Navigator.pop(context);
},
);
},
);
},
);
},
),
),
],
);
}
String _capitalizeFirst(String description) {
if (description.isEmpty) return description;
return '${description[0].toUpperCase()}${description.substring(1)}';
}
}
class EnableDisableAutomationDialog extends StatefulWidget {
const EnableDisableAutomationDialog({
super.key,
required this.automationId,
required this.descriptionSelected,
});
final String automationId;
final String descriptionSelected;
@override
State<EnableDisableAutomationDialog> createState() =>
_EnableDisableAutomationDialogState();
}
class _EnableDisableAutomationDialogState
extends State<EnableDisableAutomationDialog> {
String? groupValue;
final List<SceneOperationalValue> values = [
SceneOperationalValue(
icon: Assets.assetsAcPower,
description: 'Enable',
value: 'rule_enable',
),
SceneOperationalValue(
icon: Assets.assetsAcPowerOFF,
description: 'Disable',
value: 'rule_disable',
),
];
@override
void initState() {
super.initState();
groupValue =
widget.descriptionSelected == 'Enable' ? 'rule_enable' : 'rule_disable';
}
@override
Widget build(BuildContext context) {
return BlocBuilder<SmartSceneSelectBloc, SmartSceneSelectState>(
builder: (context, state) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
...values.map(
(operation) => SceneListTile(
iconsSize: 25,
minLeadingWidth: 15,
padding: const EdgeInsets.symmetric(horizontal: 16),
assetPath: operation.icon,
assetHeaderValue: operation.iconValue,
titleString: operation.description.toString(),
textAlign: TextAlign.start,
trailingWidget: Radio(
value: operation.value,
groupValue: groupValue,
onChanged: (value) {
setState(() {
groupValue = value;
});
context
.read<SmartSceneSelectBloc>()
.add(SmartSceneEnableEvent(
SmartSceneEnable(
entityId: widget.automationId,
actionExecutor: value!,
),
));
},
),
onPressed: () {
setState(() {
groupValue = operation.value;
});
context
.read<SmartSceneSelectBloc>()
.add(SmartSceneEnableEvent(
SmartSceneEnable(
entityId: widget.automationId,
actionExecutor: operation.value,
),
));
},
),
),
],
);
},
);
}
}
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_automation_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart';
class SmartEnableAutomation extends StatelessWidget {
const SmartEnableAutomation({super.key});
@override
Widget build(BuildContext context) {
return DefaultContainer(
height: context.height * 0.5,
width: double.infinity,
child: BlocBuilder<SceneBloc, SceneState>(
bloc: context.read<SceneBloc>()
..add(
LoadAutomation(HomeCubit.getInstance().selectedSpace?.id ?? '')),
builder: (context, state) {
if (state is SceneLoading) {
return const Align(
alignment: Alignment.topCenter,
child: LinearProgressIndicator());
}
if (state is SceneLoaded) {
return SmartSceneSelectAutomationList(
automationList: state.automationList);
}
return const SizedBox.shrink();
},
),
);
}
}
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/widgets/select_smart_scene/smart_tab_run_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart';
class SmartEnableTabRun extends StatelessWidget {
const SmartEnableTabRun({super.key});
@override
Widget build(BuildContext context) {
return DefaultContainer(
height: context.height * 0.5,
width: double.infinity,
child: BlocBuilder<SceneBloc, SceneState>(
bloc: context.read<SceneBloc>()
..add(LoadScenes(HomeCubit.getInstance().selectedSpace?.id ?? '')),
builder: (context, state) {
if (state is SceneLoading) {
return const Align(
alignment: Alignment.topCenter,
child: LinearProgressIndicator());
}
if (state is SceneLoaded) {
return SmartSceneSelectTabToRunList(scenes: state.scenes);
}
return const SizedBox.shrink();
},
),
);
}
}
@@ -0,0 +1,112 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/smart_scene_enable.dart';
import 'package:syncrow_app/features/scene/widgets/scene_list_tile.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SmartSceneSelectTabToRunList extends StatefulWidget {
const SmartSceneSelectTabToRunList({
super.key,
required this.scenes,
});
final List<ScenesModel> scenes;
@override
State<SmartSceneSelectTabToRunList> createState() =>
_SmartSceneSelectTabToRunListState();
}
class _SmartSceneSelectTabToRunListState
extends State<SmartSceneSelectTabToRunList> {
String groupValue = '';
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextButton(
onPressed: () => Navigator.pop(context),
child: BodySmall(
text: 'Save',
style: context.bodySmall
.copyWith(color: ColorsManager.primaryColorWithOpacity),
)),
),
Expanded(
flex: 2,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: BodyMedium(
text: 'Tab To Run',
textAlign: TextAlign.center,
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
const Spacer(),
],
),
const Divider(
color: ColorsManager.dividerColor,
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.scenes.length,
itemBuilder: (context, index) {
final scene = widget.scenes[index];
return SceneListTile(
padding: const EdgeInsets.symmetric(horizontal: 10),
leadingWidget: Image.asset(
height: 32,
width: 32,
Assets.assetsIconsLogo,
fit: BoxFit.fill,
),
titleString: scene.name,
trailingWidget: Radio(
value: scene.id,
groupValue: groupValue,
onChanged: (String? value) {
if (value != null) {
setState(() {
groupValue = value;
});
context
.read<SmartSceneSelectBloc>()
.add(SmartSceneEnableEvent(SmartSceneEnable(
entityId: scene.id,
actionExecutor: 'rule_enable',
)));
}
}),
onPressed: () {
setState(() {
groupValue = scene.id;
});
context
.read<SmartSceneSelectBloc>()
.add(SmartSceneEnableEvent(SmartSceneEnable(
entityId: scene.id,
actionExecutor: 'rule_enable',
)));
},
);
}),
),
],
);
}
}
@@ -17,6 +17,7 @@ class DefaultScaffold extends StatelessWidget {
this.padding,
this.leading,
this.leadingWidth,
this.height,
});
final Widget child;
@@ -27,6 +28,7 @@ class DefaultScaffold extends StatelessWidget {
final EdgeInsetsGeometry? padding;
final Widget? leading;
final double? leadingWidth;
final double? height;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
@@ -54,8 +56,9 @@ class DefaultScaffold extends StatelessWidget {
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
padding: padding ?? const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
height: height ?? MediaQuery.sizeOf(context).height,
padding: padding ??
const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
+227 -71
View File
@@ -3,7 +3,8 @@ class Assets {
/// Assets for assetsFontsAftikaRegular
/// assets/fonts/AftikaRegular.ttf
static const String assetsFontsAftikaRegular = "assets/fonts/AftikaRegular.ttf";
static const String assetsFontsAftikaRegular =
"assets/fonts/AftikaRegular.ttf";
/// Assets for assetsIcons3GangSwitch
/// assets/icons/3GangSwitch.svg
@@ -19,82 +20,98 @@ class Assets {
/// Assets for assetsIconsAutomatedClock
/// assets/icons/automated_clock.svg
static const String assetsIconsAutomatedClock = "assets/icons/automated_clock.svg";
static const String assetsIconsAutomatedClock =
"assets/icons/automated_clock.svg";
static const String acSwitchIcon = "assets/icons/ac_switch_ic.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstChargeddmOff
/// assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstChargeddmOff =
"assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstDefaultdmOff
/// assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOfflowOffpmOffstDefaultdmOff =
"assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOfflowOffpmOnstChargeddmOff
/// assets/icons/battery/dmOff/perOffchargOfflowOffpmOnstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOfflowOffpmOnstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOfflowOffpmOnstChargeddmOff =
"assets/icons/battery/dmOff/perOffchargOfflowOffpmOnstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOfflowOnpmOffstDefaultdmOff
/// assets/icons/battery/dmOff/perOffchargOfflowOnpmOffstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOfflowOnpmOffstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOfflowOnpmOffstDefaultdmOff =
"assets/icons/battery/dmOff/perOffchargOfflowOnpmOffstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOfflowOnpmOnstDefaultdmOff
/// assets/icons/battery/dmOff/perOffchargOfflowOnpmOnstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOfflowOnpmOnstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOfflowOnpmOnstDefaultdmOff =
"assets/icons/battery/dmOff/perOffchargOfflowOnpmOnstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOnlowOffpmOffstChargeddmOff
/// assets/icons/battery/dmOff/perOffchargOnlowOffpmOffstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOnlowOffpmOffstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOnlowOffpmOffstChargeddmOff =
"assets/icons/battery/dmOff/perOffchargOnlowOffpmOffstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOnlowOnpmOffstlowBatterydmOff
/// assets/icons/battery/dmOff/perOffchargOnlowOnpmOffstlowBatterydmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOnlowOnpmOffstlowBatterydmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOnlowOnpmOffstlowBatterydmOff =
"assets/icons/battery/dmOff/perOffchargOnlowOnpmOffstlowBatterydmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOffchargOnlowOnpmOnstlowpmdmOff
/// assets/icons/battery/dmOff/perOffchargOnlowOnpmOnstlowpmdmOff.svg
static const String assetsIconsBatteryDmOffPerOffchargOnlowOnpmOnstlowpmdmOff =
static const String
assetsIconsBatteryDmOffPerOffchargOnlowOnpmOnstlowpmdmOff =
"assets/icons/battery/dmOff/perOffchargOnlowOnpmOnstlowpmdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstChargeddmOff
/// assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstChargeddmOff =
"assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstDefaultdmOff
/// assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOfflowOffpmOffstDefaultdmOff =
"assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOfflowOffpmOnstChargeddmOff
/// assets/icons/battery/dmOff/perOnchargOfflowOffpmOnstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOfflowOffpmOnstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOfflowOffpmOnstChargeddmOff =
"assets/icons/battery/dmOff/perOnchargOfflowOffpmOnstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOfflowOnpmOffstDefaultdmOff
/// assets/icons/battery/dmOff/perOnchargOfflowOnpmOffstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOfflowOnpmOffstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOfflowOnpmOffstDefaultdmOff =
"assets/icons/battery/dmOff/perOnchargOfflowOnpmOffstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOfflowOnpmOnstDefaultdmOff
/// assets/icons/battery/dmOff/perOnchargOfflowOnpmOnstDefaultdmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOfflowOnpmOnstDefaultdmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOfflowOnpmOnstDefaultdmOff =
"assets/icons/battery/dmOff/perOnchargOfflowOnpmOnstDefaultdmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOnlowOffpmOffstChargeddmOff
/// assets/icons/battery/dmOff/perOnchargOnlowOffpmOffstChargeddmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOnlowOffpmOffstChargeddmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOnlowOffpmOffstChargeddmOff =
"assets/icons/battery/dmOff/perOnchargOnlowOffpmOffstChargeddmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOnlowOnpmOffstlowBatterydmOff
/// assets/icons/battery/dmOff/perOnchargOnlowOnpmOffstlowBatterydmOff.svg
static const String assetsIconsBatteryDmOffPerOnchargOnlowOnpmOffstlowBatterydmOff =
static const String
assetsIconsBatteryDmOffPerOnchargOnlowOnpmOffstlowBatterydmOff =
"assets/icons/battery/dmOff/perOnchargOnlowOnpmOffstlowBatterydmOff.svg";
/// Assets for assetsIconsBatteryDmOffPerOnchargOnlowOnpmOnstlowpmdmOff
@@ -104,37 +121,44 @@ class Assets {
/// Assets for assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstChargeddmOn
/// assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstChargeddmOn =
"assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstDefaultdmOn
/// assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOfflowOffpmOffstDefaultdmOn =
"assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOfflowOffpmOnstChargeddmOn
/// assets/icons/battery/dmOn/perOffchargOfflowOffpmOnstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOfflowOffpmOnstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOfflowOffpmOnstChargeddmOn =
"assets/icons/battery/dmOn/perOffchargOfflowOffpmOnstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOfflowOnpmOffstDefaultdmOn
/// assets/icons/battery/dmOn/perOffchargOfflowOnpmOffstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOfflowOnpmOffstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOfflowOnpmOffstDefaultdmOn =
"assets/icons/battery/dmOn/perOffchargOfflowOnpmOffstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOfflowOnpmOnstDefaultdmOn
/// assets/icons/battery/dmOn/perOffchargOfflowOnpmOnstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOfflowOnpmOnstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOfflowOnpmOnstDefaultdmOn =
"assets/icons/battery/dmOn/perOffchargOfflowOnpmOnstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOnlowOffpmOffstChargeddmOn
/// assets/icons/battery/dmOn/perOffchargOnlowOffpmOffstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOnlowOffpmOffstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOnlowOffpmOffstChargeddmOn =
"assets/icons/battery/dmOn/perOffchargOnlowOffpmOffstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOnlowOnpmOffstlowBatterydmOn
/// assets/icons/battery/dmOn/perOffchargOnlowOnpmOffstlowBatterydmOn.svg
static const String assetsIconsBatteryDmOnPerOffchargOnlowOnpmOffstlowBatterydmOn =
static const String
assetsIconsBatteryDmOnPerOffchargOnlowOnpmOffstlowBatterydmOn =
"assets/icons/battery/dmOn/perOffchargOnlowOnpmOffstlowBatterydmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOffchargOnlowOnpmOnstlowpmdmOn
@@ -144,37 +168,44 @@ class Assets {
/// Assets for assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstChargeddmOn
/// assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstChargeddmOn =
"assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstDefaultdmOn
/// assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOfflowOffpmOffstDefaultdmOn =
"assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOfflowOffpmOnstChargeddmOn
/// assets/icons/battery/dmOn/perOnchargOfflowOffpmOnstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOfflowOffpmOnstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOfflowOffpmOnstChargeddmOn =
"assets/icons/battery/dmOn/perOnchargOfflowOffpmOnstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOfflowOnpmOffstDefaultdmOn
/// assets/icons/battery/dmOn/perOnchargOfflowOnpmOffstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOfflowOnpmOffstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOfflowOnpmOffstDefaultdmOn =
"assets/icons/battery/dmOn/perOnchargOfflowOnpmOffstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOfflowOnpmOnstDefaultdmOn
/// assets/icons/battery/dmOn/perOnchargOfflowOnpmOnstDefaultdmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOfflowOnpmOnstDefaultdmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOfflowOnpmOnstDefaultdmOn =
"assets/icons/battery/dmOn/perOnchargOfflowOnpmOnstDefaultdmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOnlowOffpmOffstChargeddmOn
/// assets/icons/battery/dmOn/perOnchargOnlowOffpmOffstChargeddmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOnlowOffpmOffstChargeddmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOnlowOffpmOffstChargeddmOn =
"assets/icons/battery/dmOn/perOnchargOnlowOffpmOffstChargeddmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOnlowOnpmOffstlowBatterydmOn
/// assets/icons/battery/dmOn/perOnchargOnlowOnpmOffstlowBatterydmOn.svg
static const String assetsIconsBatteryDmOnPerOnchargOnlowOnpmOffstlowBatterydmOn =
static const String
assetsIconsBatteryDmOnPerOnchargOnlowOnpmOffstlowBatterydmOn =
"assets/icons/battery/dmOn/perOnchargOnlowOnpmOffstlowBatterydmOn.svg";
/// Assets for assetsIconsBatteryDmOnPerOnchargOnlowOnpmOnstlowpmdmOn
@@ -226,7 +257,8 @@ class Assets {
/// Assets for assetsIconsDashboardFill
/// assets/icons/dashboard-fill.svg
static const String assetsIconsDashboardFill = "assets/icons/dashboard-fill.svg";
static const String assetsIconsDashboardFill =
"assets/icons/dashboard-fill.svg";
/// Assets for assetsIconsDevices
/// assets/icons/Devices.svg
@@ -242,7 +274,8 @@ class Assets {
/// Assets for assetsIconsDoorLockLinkage
/// assets/icons/DoorLockLinkage.svg
static const String assetsIconsDoorLockLinkage = "assets/icons/DoorLockLinkage.svg";
static const String assetsIconsDoorLockLinkage =
"assets/icons/DoorLockLinkage.svg";
/// Assets for assetsIconsDoorLockLock
/// assets/icons/DoorLockLock.svg
@@ -250,15 +283,18 @@ class Assets {
/// Assets for assetsIconsDoorLockMembers
/// assets/icons/DoorLockMembers.svg
static const String assetsIconsDoorLockMembers = "assets/icons/DoorLockMembers.svg";
static const String assetsIconsDoorLockMembers =
"assets/icons/DoorLockMembers.svg";
/// Assets for assetsIconsDoorLockPassword
/// assets/icons/DoorLockPassword.svg
static const String assetsIconsDoorLockPassword = "assets/icons/DoorLockPassword.svg";
static const String assetsIconsDoorLockPassword =
"assets/icons/DoorLockPassword.svg";
/// Assets for assetsIconsDoorLockRecords
/// assets/icons/DoorLockRecords.svg
static const String assetsIconsDoorLockRecords = "assets/icons/DoorLockRecords.svg";
static const String assetsIconsDoorLockRecords =
"assets/icons/DoorLockRecords.svg";
/// Assets for assetsIconsDoorlockAssetsBatteryIndicator
/// assets/icons/doorlock-assets/BatteryIndicator.svg
@@ -279,7 +315,8 @@ class Assets {
/// assets/icons/doorlock-assets/lockIcon.svg
static const String assetsIconsDoorlockAssetsLockIcon =
"assets/icons/doorlock-assets/lockIcon.svg";
static const String doorUnlockIcon = "assets/icons/doorlock-assets/door_un_look_ic.svg";
static const String doorUnlockIcon =
"assets/icons/doorlock-assets/door_un_look_ic.svg";
/// Assets for assetsIconsDoorlockAssetsMembersManagement
/// assets/icons/doorlock-assets/members-management.svg
@@ -367,11 +404,13 @@ class Assets {
/// Assets for assetsIconsLightSwitchOff
/// assets/icons/lightSwitchOff.svg
static const String assetsIconsLightSwitchOff = "assets/icons/lightSwitchOff.svg";
static const String assetsIconsLightSwitchOff =
"assets/icons/lightSwitchOff.svg";
/// Assets for assetsIconsLightSwitchOn
/// assets/icons/lightSwitchOn.svg
static const String assetsIconsLightSwitchOn = "assets/icons/lightSwitchOn.svg";
static const String assetsIconsLightSwitchOn =
"assets/icons/lightSwitchOn.svg";
/// Assets for assetsIconsLinkageIconsDoorLockAlarm
/// assets/icons/linkageIcons/doorLockAlarm.svg
@@ -380,7 +419,8 @@ class Assets {
/// Assets for assetsIconsLinkTimeLimitedPasswordIcon
/// assets/icons/timeLimitedPasswordIcon.svg
static const String timeLimitedPasswordIcon = "assets/icons/timeLimitedPasswordIcon.svg";
static const String timeLimitedPasswordIcon =
"assets/icons/timeLimitedPasswordIcon.svg";
/// Assets for assetsIconsoneTimePassword
/// assets/icons/oneTimePassword.svg
@@ -388,7 +428,8 @@ class Assets {
/// Assets for assetsIconsTimeLimitedPassword
/// assets/icons/timeLimitedPassword.svg
static const String timeLimitedPassword = "assets/icons/timeLimitedPassword.svg";
static const String timeLimitedPassword =
"assets/icons/timeLimitedPassword.svg";
/// Assets for assetsIconsNoValidPasswords
/// assets/icons/noValidPasswords.svg
@@ -557,11 +598,13 @@ class Assets {
/// Assets for assetsIconsPresenceSensorAssetsParameterSettings
/// assets/icons/presence-sensor-assets/space_type_icon.svg
static const String spaceTypeIcon = "assets/icons/presence-sensor-assets/space_type_icon.svg";
static const String spaceTypeIcon =
"assets/icons/presence-sensor-assets/space_type_icon.svg";
/// Assets for assetsIconsPresenceSensorAssetsParameterSettings
/// assets/icons/presence-sensor-assets/space_type_icon.svg
static const String sensitivityIcon = "assets/icons/presence-sensor-assets/Sensitivity.svg";
static const String sensitivityIcon =
"assets/icons/presence-sensor-assets/Sensitivity.svg";
/// Assets for assetsIconsPresenceSensorAssetsParameterSettings
/// assets/icons/presence-sensor-assets/maximum_distance.svg
@@ -594,7 +637,8 @@ class Assets {
/// Assets for assetsIconsRoutinesFill
/// assets/icons/Routines-fill.svg
static const String assetsIconsRoutinesFill = "assets/icons/Routines-fill.svg";
static const String assetsIconsRoutinesFill =
"assets/icons/Routines-fill.svg";
/// Assets for assetsIconsScan
/// assets/icons/Scan.svg
@@ -626,7 +670,8 @@ class Assets {
/// Assets for assetsIconsSustainability
/// assets/icons/sustainability.svg
static const String assetsIconsSustainability = "assets/icons/sustainability.svg";
static const String assetsIconsSustainability =
"assets/icons/sustainability.svg";
/// Assets for assetsIconsUnlockingMethodsIconsFace
/// assets/icons/unlockingMethodsIcons/face.svg
@@ -718,7 +763,8 @@ class Assets {
/// Assets for assetsImagesHorizintalBlade
/// assets/images/HorizintalBlade.png
static const String assetsImagesHorizintalBlade = "assets/images/HorizintalBlade.png";
static const String assetsImagesHorizintalBlade =
"assets/images/HorizintalBlade.png";
/// Assets for assetsImagesLogo
/// assets/images/Logo.svg
@@ -726,7 +772,8 @@ class Assets {
/// Assets for assetsImagesLogoHorizontal
/// assets/images/logo_horizontal.png
static const String assetsImagesLogoHorizontal = "assets/images/logo_horizontal.png";
static const String assetsImagesLogoHorizontal =
"assets/images/logo_horizontal.png";
/// Assets for assetsImagesPause
/// assets/images/Pause.png
@@ -756,7 +803,8 @@ class Assets {
/// assets/images/Window.png
static const String assetsImagesWindow = "assets/images/Window.png";
static const String assetsSensitivityFunction = "assets/icons/functions_icons/sensitivity.svg";
static const String assetsSensitivityFunction =
"assets/icons/functions_icons/sensitivity.svg";
//assets/icons/functions_icons/sesitivity_operation_icon.svg
static const String assetsSensitivityOperationIcon =
@@ -764,59 +812,73 @@ class Assets {
//assets/icons/functions_icons/ac_power.svg
static const String assetsAcPower = "assets/icons/functions_icons/ac_power.svg";
static const String assetsAcPower =
"assets/icons/functions_icons/ac_power.svg";
//assets/icons/functions_icons/ac_power_off.svg
static const String assetsAcPowerOFF = "assets/icons/functions_icons/ac_power_off.svg";
static const String assetsAcPowerOFF =
"assets/icons/functions_icons/ac_power_off.svg";
//assets/icons/functions_icons/child_lock.svg
static const String assetsChildLock = "assets/icons/functions_icons/child_lock.svg";
static const String assetsChildLock =
"assets/icons/functions_icons/child_lock.svg";
//assets/icons/functions_icons/cooling.svg
static const String assetsFreezing = "assets/icons/functions_icons/freezing.svg";
static const String assetsFreezing =
"assets/icons/functions_icons/freezing.svg";
//assets/icons/functions_icons/fan_speed.svg
static const String assetsFanSpeed = "assets/icons/functions_icons/fan_speed.svg";
static const String assetsFanSpeed =
"assets/icons/functions_icons/fan_speed.svg";
//assets/icons/functions_icons/ac_cooling.svg
static const String assetsAcCooling = "assets/icons/functions_icons/ac_cooling.svg";
static const String assetsAcCooling =
"assets/icons/functions_icons/ac_cooling.svg";
//assets/icons/functions_icons/ac_heating.svg
static const String assetsAcHeating = "assets/icons/functions_icons/ac_heating.svg";
static const String assetsAcHeating =
"assets/icons/functions_icons/ac_heating.svg";
//assets/icons/functions_icons/celsius_degrees.svg
static const String assetsCelsiusDegrees = "assets/icons/functions_icons/celsius_degrees.svg";
static const String assetsCelsiusDegrees =
"assets/icons/functions_icons/celsius_degrees.svg";
//assets/icons/functions_icons/tempreture.svg
static const String assetsTempreture = "assets/icons/functions_icons/tempreture.svg";
static const String assetsTempreture =
"assets/icons/functions_icons/tempreture.svg";
//assets/icons/functions_icons/ac_fan_low.svg
static const String assetsAcFanLow = "assets/icons/functions_icons/ac_fan_low.svg";
static const String assetsAcFanLow =
"assets/icons/functions_icons/ac_fan_low.svg";
//assets/icons/functions_icons/ac_fan_middle.svg
static const String assetsAcFanMiddle = "assets/icons/functions_icons/ac_fan_middle.svg";
static const String assetsAcFanMiddle =
"assets/icons/functions_icons/ac_fan_middle.svg";
//assets/icons/functions_icons/ac_fan_high.svg
static const String assetsAcFanHigh = "assets/icons/functions_icons/ac_fan_high.svg";
static const String assetsAcFanHigh =
"assets/icons/functions_icons/ac_fan_high.svg";
//assets/icons/functions_icons/ac_fan_auto.svg
static const String assetsAcFanAuto = "assets/icons/functions_icons/ac_fan_auto.svg";
static const String assetsAcFanAuto =
"assets/icons/functions_icons/ac_fan_auto.svg";
//assets/icons/functions_icons/scene_child_lock.svg
static const String assetsSceneChildLock = "assets/icons/functions_icons/scene_child_lock.svg";
static const String assetsSceneChildLock =
"assets/icons/functions_icons/scene_child_lock.svg";
//assets/icons/functions_icons/scene_child_unlock.svg
@@ -825,15 +887,18 @@ class Assets {
//assets/icons/functions_icons/scene_refresh.svg
static const String assetsSceneRefresh = "assets/icons/functions_icons/scene_refresh.svg";
static const String assetsSceneRefresh =
"assets/icons/functions_icons/scene_refresh.svg";
//assets/icons/functions_icons/light_countdown.svg
static const String assetsLightCountdown = "assets/icons/functions_icons/light_countdown.svg";
static const String assetsLightCountdown =
"assets/icons/functions_icons/light_countdown.svg";
//assets/icons/functions_icons/far_detection.svg
static const String assetsFarDetection = "assets/icons/functions_icons/far_detection.svg";
static const String assetsFarDetection =
"assets/icons/functions_icons/far_detection.svg";
//assets/icons/functions_icons/far_detection_function.svg
@@ -842,11 +907,13 @@ class Assets {
//assets/icons/functions_icons/indicator.svg
static const String assetsIndicator = "assets/icons/functions_icons/indicator.svg";
static const String assetsIndicator =
"assets/icons/functions_icons/indicator.svg";
//assets/icons/functions_icons/motion_detection.svg
static const String assetsMotionDetection = "assets/icons/functions_icons/motion_detection.svg";
static const String assetsMotionDetection =
"assets/icons/functions_icons/motion_detection.svg";
//assets/icons/functions_icons/motionless_detection.svg
@@ -855,15 +922,18 @@ class Assets {
//assets/icons/functions_icons/nobody_time.svg
static const String assetsNobodyTime = "assets/icons/functions_icons/nobody_time.svg";
static const String assetsNobodyTime =
"assets/icons/functions_icons/nobody_time.svg";
//assets/icons/functions_icons/factory_reset.svg
static const String assetsFactoryReset = "assets/icons/functions_icons/factory_reset.svg";
static const String assetsFactoryReset =
"assets/icons/functions_icons/factory_reset.svg";
//assets/icons/functions_icons/master_state.svg
static const String assetsMasterState = "assets/icons/functions_icons/master_state.svg";
static const String assetsMasterState =
"assets/icons/functions_icons/master_state.svg";
//assets/icons/functions_icons/switch_alarm_sound.svg
@@ -872,5 +942,91 @@ class Assets {
//assets/icons/functions_icons/reset_off.svg
static const String assetsResetOff = "assets/icons/functions_icons/reset_off.svg";
static const String assetsResetOff =
"assets/icons/functions_icons/reset_off.svg";
//assets/icons/functions_icons/automation_functions/card_unlock.svg
static const String assetsCardUnlock =
"assets/icons/functions_icons/automation_functions/card_unlock.svg";
//assets/icons/functions_icons/automation_functions/doorbell.svg
static const String assetsDoorbell =
"assets/icons/functions_icons/automation_functions/doorbell.svg";
//assets/icons/functions_icons/automation_functions/doorlock_normal_open.svg
static const String assetsDoorlockNormalOpen =
"assets/icons/functions_icons/automation_functions/doorlock_normal_open.svg";
//assets/icons/functions_icons/automation_functions/double_lock.svg
static const String assetsDoubleLock =
"assets/icons/functions_icons/automation_functions/double_lock.svg";
//assets/icons/functions_icons/automation_functions/fingerprint_unlock.svg
static const String assetsFingerprintUnlock =
"assets/icons/functions_icons/automation_functions/fingerprint_unlock.svg";
//assets/icons/functions_icons/automation_functions/hijack_alarm.svg
static const String assetsHijackAlarm =
"assets/icons/functions_icons/automation_functions/hijack_alarm.svg";
//assets/icons/functions_icons/automation_functions/lock_alarm.svg
static const String assetsLockAlarm =
"assets/icons/functions_icons/automation_functions/lock_alarm.svg";
//assets/icons/functions_icons/automation_functions/password_unlock.svg
static const String assetsPasswordUnlock =
"assets/icons/functions_icons/automation_functions/password_unlock.svg";
//assets/icons/functions_icons/automation_functions/remote_unlock_req.svg
static const String assetsRemoteUnlockReq =
"assets/icons/functions_icons/automation_functions/remote_unlock_req.svg";
//assets/icons/functions_icons/automation_functions/remote_unlock_via_app.svg
static const String assetsRemoteUnlockViaApp =
"assets/icons/functions_icons/automation_functions/remote_unlock_via_app.svg";
//assets/icons/functions_icons/automation_functions/residual_electricity.svg
static const String assetsResidualElectricity =
"assets/icons/functions_icons/automation_functions/residual_electricity.svg";
//assets/icons/functions_icons/automation_functions/temp_password_unlock.svg
static const String assetsTempPasswordUnlock =
"assets/icons/functions_icons/automation_functions/temp_password_unlock.svg";
//assets/icons/functions_icons/automation_functions/self_test_result.svg
static const String assetsSelfTestResult =
"assets/icons/functions_icons/automation_functions/self_test_result.svg";
///assets/icons/functions_icons/automation_functions/presence.svg
static const String assetsPresence =
"assets/icons/functions_icons/automation_functions/presence.svg";
//assets/icons/functions_icons/automation_functions/motion.svg
static const String assetsMotion =
"assets/icons/functions_icons/automation_functions/motion.svg";
//assets/icons/functions_icons/automation_functions/current_temp.svg
static const String assetsCurrentTemp =
"assets/icons/functions_icons/automation_functions/current_temp.svg";
//assets/icons/functions_icons/automation_functions/presence_state.svg
static const String assetsPresenceState =
"assets/icons/functions_icons/automation_functions/presence_state.svg";
}
+6 -1
View File
@@ -3,6 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/profile_bloc/profile_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
@@ -28,7 +30,10 @@ class MyApp extends StatelessWidget {
BlocProvider(create: (context) => CreateSceneBloc()),
BlocProvider(create: (context) => SceneBloc()),
BlocProvider(create: (context) => ProfileBloc()),
BlocProvider(create: (context) => SmartSceneSelectBloc()),
BlocProvider(
create: (context) => EffectPeriodBloc(),
),
],
child: MaterialApp(
navigatorKey: NavigationService.navigatorKey,
+17
View File
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
void navigateToRoute(BuildContext context, String targetRoute) {
bool routeFound = false;
Navigator.popUntil(context, (route) {
if (route.settings.name == targetRoute) {
routeFound = true;
return true;
}
return route.isFirst;
});
if (!routeFound) {
Navigator.pushNamed(context, targetRoute);
}
}
+43 -17
View File
@@ -14,9 +14,11 @@ import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
import 'package:syncrow_app/features/scene/view/device_functions_view.dart';
import 'package:syncrow_app/features/scene/view/scene_auto_settings.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/view/scene_rooms_tabbar.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/features/scene/view/smart_automation_select_route.dart';
import 'package:syncrow_app/features/splash/view/splash_view.dart';
import 'routing_constants.dart';
@@ -24,54 +26,67 @@ class Router {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case Routes.splash:
return MaterialPageRoute(builder: (_) => const SplashView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const SplashView(), settings: settings);
// case Routes.devicesRoute:
// return MaterialPageRoute(
// builder: (_) => const DevicesView(), settings: settings);
case Routes.profileRoute:
return MaterialPageRoute(builder: (_) => const ProfileView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const ProfileView(), settings: settings);
case Routes.sceneRoute:
return MaterialPageRoute(builder: (_) => const SceneView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const SceneView(), settings: settings);
case Routes.layoutRoute:
return MaterialPageRoute(builder: (_) => const LayoutPage(), settings: settings);
return MaterialPageRoute(
builder: (_) => const LayoutPage(), settings: settings);
case Routes.authLogin:
return MaterialPageRoute(builder: (_) => const LoginView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const LoginView(), settings: settings);
case Routes.otpRoute:
return MaterialPageRoute(builder: (_) => const OtpView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const OtpView(), settings: settings);
case Routes.authSignUp:
return MaterialPageRoute(builder: (_) => const SignUpView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const SignUpView(), settings: settings);
case Routes.dashboardRoute:
return MaterialPageRoute(builder: (_) => const DashboardView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const DashboardView(), settings: settings);
case Routes.homeRoute:
return MaterialPageRoute(builder: (_) => const AppLayout(), settings: settings);
return MaterialPageRoute(
builder: (_) => const AppLayout(), settings: settings);
case Routes.menuRoute:
return MaterialPageRoute(builder: (_) => const MenuView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const MenuView(), settings: settings);
case Routes.createUnit:
return MaterialPageRoute(builder: (_) => const CreateUnitView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const CreateUnitView(), settings: settings);
case Routes.sceneTasksRoute:
return MaterialPageRoute(builder: (_) => const SceneTasksView(), settings: settings);
return MaterialPageRoute(
builder: (_) => const SceneTasksView(), settings: settings);
case Routes.sceneControlDevicesRoute:
return MaterialPageRoute(
builder: (_) => MultiBlocProvider(
providers: [
BlocProvider(
create: (BuildContext context) => DeviceManagerBloc()..add(FetchAllDevices()),
create: (BuildContext context) =>
DeviceManagerBloc()..add(FetchAllDevices()),
),
BlocProvider(
create: (BuildContext context) =>
TabBarBloc(context.read<DeviceManagerBloc>())
..add(const TabChanged(selectedIndex: 0, roomId: '-1')),
create: (BuildContext context) => TabBarBloc(
context.read<DeviceManagerBloc>())
..add(const TabChanged(selectedIndex: 0, roomId: '-1')),
),
],
child: const SceneRoomsTabBarDevicesView(),
@@ -79,7 +94,18 @@ class Router {
settings: settings);
case Routes.deviceFunctionsRoute:
return MaterialPageRoute(
builder: (_) => const DeviceFunctionsView(),
builder: (_) => DeviceFunctionsView(),
settings: settings,
);
case Routes.sceneAutoSettingsRoute:
return MaterialPageRoute(
builder: (_) => const SceneAutoSettings(),
settings: settings,
);
case Routes.smartAutomationSelectRoute:
return MaterialPageRoute(
builder: (_) => const SmartAutomationSelectView(),
settings: settings,
);
default:
+3 -2
View File
@@ -19,6 +19,7 @@ class Routes {
static const String createUnit = '/create-unit';
static const String sceneTasksRoute = '/scene-tasks';
static const String sceneControlDevicesRoute = '/scene-control-devices';
static const String deviceFunctionsRoute = '/device-functions';
static const String deviceFunctionsRoute = '/device-functions';
static const String sceneAutoSettingsRoute = '/scene-automation-settings';
static const String smartAutomationSelectRoute = '/smart-automation-select';
}
+25 -6
View File
@@ -81,7 +81,8 @@ abstract class ApiEndpoints {
static const String controlGroup = '/group/control';
//GET
static const String groupBySpace = '/group/{unitUuid}';
static const String devicesByGroupName = '/group/{unitUuid}/devices/{groupName}';
static const String devicesByGroupName =
'/group/{unitUuid}/devices/{groupName}';
static const String groupByUuid = '/group/{groupUuid}';
//DELETE
@@ -93,7 +94,8 @@ abstract class ApiEndpoints {
static const String addDeviceToRoom = '/device/room';
static const String addDeviceToGroup = '/device/group';
static const String controlDevice = '/device/{deviceUuid}/control';
static const String firmwareDevice = '/device/{deviceUuid}/firmware/{firmwareVersion}';
static const String firmwareDevice =
'/device/{deviceUuid}/firmware/{firmwareVersion}';
static const String getDevicesByUserId = '/device/user/{userId}';
static const String getDevicesByUnitId = '/device/unit/{unitUuid}';
@@ -102,7 +104,8 @@ abstract class ApiEndpoints {
static const String deviceByUuid = '/device/{deviceUuid}';
static const String deviceFunctions = '/device/{deviceUuid}/functions';
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
static const String deviceFunctionsStatus = '/device/{deviceUuid}/functions/status';
static const String deviceFunctionsStatus =
'/device/{deviceUuid}/functions/status';
///Device Permission Module
//POST
@@ -114,26 +117,42 @@ abstract class ApiEndpoints {
static const String assignDeviceToRoom = '/device/room';
/// Scene API ////////////////////
/// Scene & Automation API ////////////////////
/// POST
static const String createScene = '/scene/tap-to-run';
static const String triggerScene = '/scene/tap-to-run/trigger/{sceneId}';
static const String createAutomation = '/automation';
/// GET
static const String getUnitScenes = '/scene/tap-to-run/{unitUuid}';
static const String getScene = '/scene/tap-to-run/details/{sceneId}';
static const String getUnitAutomation = '/automation/{unitUuid}';
static const String getAutomationDetails =
'/automation/details/{automationId}';
/// PUT
static const String updateScene = '/scene/tap-to-run/{sceneId}';
static const String updateAutomation = '/automation/{automationId}';
static const String updateAutomationStatus =
'/automation/status/{automationId}';
/// DELETE
static const String deleteScene = '/scene/tap-to-run/{unitUuid}/{sceneId}';
static const String deleteAutomation =
'/automation/{unitUuid}/{automationId}';
//////////////////////Door Lock //////////////////////
//online
static const String addTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
static const String getTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
static const String addTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}';
static const String getTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}';
//one-time offline
static const String addOneTimeTemporaryPassword =
+115 -3
View File
@@ -1,18 +1,21 @@
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/create_scene_model.dart';
import 'package:syncrow_app/features/scene/model/scene_details_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/scene/model/update_automation.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
class SceneApi {
static final HTTPService _httpService = HTTPService();
//create scene
static Future<Map<String, dynamic>> createScene(
CreateSceneModel createSceneModel) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.createScene,
body: createSceneModel.toJson(),
body: createSceneModel.toMap(),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
@@ -24,6 +27,26 @@ class SceneApi {
}
}
// create automation
static Future<Map<String, dynamic>> createAutomation(
CreateAutomationModel createAutomationModel) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.createAutomation,
body: createAutomationModel.toMap(),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
//get scene by unit id
static Future<List<ScenesModel>> getScenesByUnitId(String unitId) async {
try {
final response = await _httpService.get(
@@ -43,6 +66,27 @@ class SceneApi {
}
}
//getAutomation
static Future<List<ScenesModel>> getAutomationByUnitId(String unitId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getUnitAutomation.replaceAll('{unitUuid}', unitId),
showServerMessage: false,
expectedResponseModel: (json) {
List<ScenesModel> scenes = [];
for (var scene in json) {
scenes.add(ScenesModel.fromJson(scene));
}
return scenes;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<bool> triggerScene(String sceneId) async {
try {
final response = await _httpService.post(
@@ -56,6 +100,38 @@ class SceneApi {
}
}
//automation details
static Future<SceneDetailsModel> getAutomationDetails(
String automationId) async {
try {
final response = await _httpService.get(
path: ApiEndpoints.getAutomationDetails
.replaceAll('{automationId}', automationId),
showServerMessage: false,
expectedResponseModel: (json) => SceneDetailsModel.fromJson(json),
);
return response;
} catch (e) {
rethrow;
}
}
//updateAutomationStatus
static Future<bool> updateAutomationStatus(String automationId,
AutomationStatusUpdate createAutomationEnable) async {
try {
final response = await _httpService.put(
path: ApiEndpoints.updateAutomationStatus
.replaceAll('{automationId}', automationId),
body: createAutomationEnable.toMap(),
expectedResponseModel: (json) => json['success'],
);
return response;
} catch (e) {
rethrow;
}
}
//getScene
static Future<SceneDetailsModel> getSceneDetails(String sceneId) async {
@@ -71,7 +147,7 @@ class SceneApi {
}
}
//updateScene
//update Scene
static updateScene(CreateSceneModel createSceneModel, String sceneId) async {
try {
final response = await _httpService.put(
@@ -88,7 +164,26 @@ class SceneApi {
}
}
//deleteScene
//update automation
static updateAutomation(
CreateAutomationModel createAutomationModel, String automationId) async {
try {
final response = await _httpService.put(
path: ApiEndpoints.updateAutomation
.replaceAll('{automationId}', automationId),
body: createAutomationModel
.toJson(automationId.isNotEmpty == true ? automationId : null),
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
//delete Scene
static Future<bool> deleteScene(
{required String unitUuid, required String sceneId}) async {
@@ -105,4 +200,21 @@ class SceneApi {
rethrow;
}
}
// delete automation
static Future<bool> deleteAutomation(
{required String unitUuid, required String automationId}) async {
try {
final response = await _httpService.delete(
path: ApiEndpoints.deleteAutomation
.replaceAll('{automationId}', automationId)
.replaceAll('{unitUuid}', unitUuid),
showServerMessage: false,
expectedResponseModel: (json) => json['statusCode'] == 200,
);
return response;
} catch (e) {
rethrow;
}
}
}
+50 -31
View File
@@ -65,6 +65,7 @@ extension ContextExtension on BuildContext {
required String title,
required VoidCallback onConfirm,
VoidCallback? onDismiss,
bool? hideConfirmButton,
}) {
showDialog(
context: this,
@@ -110,39 +111,57 @@ extension ContextExtension on BuildContext {
width: double.infinity,
color: ColorsManager.greyColor,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: onDismiss ??
() {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
hideConfirmButton != true
? Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: onDismiss ??
() {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
),
),
),
Container(
height: 50,
width: 1,
color: ColorsManager.greyColor,
),
GestureDetector(
onTap: onConfirm,
child: Center(
child: BodyMedium(
text: 'Confirm',
style: context.bodyMedium.copyWith(
color:
ColorsManager.primaryColorWithOpacity),
),
),
),
],
)
: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: GestureDetector(
onTap: onDismiss ??
() {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium
.copyWith(color: ColorsManager.greyColor),
),
),
),
),
),
Container(
height: 50,
width: 1,
color: ColorsManager.greyColor,
),
GestureDetector(
onTap: onConfirm,
child: Center(
child: BodyMedium(
text: 'Confirm',
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity),
),
),
),
],
)
],
),
),
@@ -40,4 +40,5 @@ class StringsManager {
static const String functions = "Functions";
static const String firstLaunch = "firstLaunch";
static const String deleteScene = 'Delete Scene';
static const String deleteAutomation = 'Delete Automation';
}