push automation details and update automation

This commit is contained in:
ashrafzarkanisala
2024-07-25 00:25:48 +03:00
parent 56024ba3a3
commit 8a4c5af2e7
23 changed files with 1271 additions and 709 deletions

View File

@ -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,
@ -45,7 +40,8 @@ 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,
@ -73,8 +69,7 @@ class SceneListview extends StatelessWidget {
],
),
),
)
);
));
},
);
}

View File

@ -276,8 +276,10 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
? await SceneApi.updateScene(event.createSceneModel!, event.sceneId)
: await SceneApi.createScene(event.createSceneModel!);
} else if (event.createAutomationModel != null) {
response =
await SceneApi.createAutomation(event.createAutomationModel!);
response = event.updateScene
? await SceneApi.updateAutomation(
event.createAutomationModel!, event.sceneId)
: await SceneApi.createAutomation(event.createAutomationModel!);
}
if (response['success'] == true) {
@ -315,13 +317,31 @@ 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(
if (event.isAutomation) {
automationTasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: [],
isAutomation: true,
conditions: response.conditions));
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
emit(AddSceneTask(
automationTasksList: automationTasksList,
tasksList: tasksList,
));
} else {
tasksList = List<SceneStaticFunction>.from(
getTaskListFunctionsFromApi(
actions: response.actions, isAutomation: false));
emit(AddSceneTask(
tasksList: tasksList,
));
}
} else {
emit(const CreateSceneError(message: 'Something went wrong'));
}
@ -420,7 +440,11 @@ class CreateSceneBloc extends Bloc<CreateSceneEvent, CreateSceneState>
conditionRule = 'and';
}
emit(ConditionSelectedState(event.condition));
emit(AddSceneTask(
tasksList: tasksList,
automationTasksList: automationTasksList,
condition: conditionRule,
));
}
FutureOr<void> _sceneTypeEvent(

View File

@ -147,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 {

View File

@ -22,7 +22,9 @@ class CreateSceneError extends CreateSceneState {
class AddSceneTask extends CreateSceneState {
final List<SceneStaticFunction> tasksList;
final List<SceneStaticFunction>? automationTasksList;
const AddSceneTask({required this.tasksList, this.automationTasksList});
final String? condition;
const AddSceneTask(
{required this.tasksList, this.automationTasksList, this.condition});
@override
List<Object> get props => [tasksList];

View File

@ -11,16 +11,20 @@ part 'scene_state.dart';
class SceneBloc extends Bloc<SceneEvent, SceneState> {
SceneBloc() : super(SceneInitial()) {
on<LoadScenes>(_onLoadScenes);
on<LoadAutomation>(_onLoadAutomation);
on<SceneTrigger>(_onSceneTrigger);
}
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: '');
}
@ -29,16 +33,34 @@ class SceneBloc extends Bloc<SceneEvent, SceneState> {
}
}
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'));
}

View File

@ -16,6 +16,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;

View File

@ -13,12 +13,13 @@ class SceneLoading extends SceneState {}
class SceneLoaded extends SceneState {
final List<ScenesModel> scenes;
final List<ScenesModel> automationList;
final String? loadingSceneId;
const SceneLoaded(this.scenes, {this.loadingSceneId});
const SceneLoaded(this.scenes, this.automationList, {this.loadingSceneId});
@override
List<Object?> get props => [scenes, loadingSceneId];
List<Object?> get props => [scenes, loadingSceneId, automationList];
}
class SceneError extends SceneState {

View File

@ -99,6 +99,16 @@ mixin SceneLogicHelper {
));
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(
@ -141,6 +151,7 @@ mixin SceneLogicHelper {
Navigator.pop(context);
}
}
}
Widget getTheCorrectDialogBody(
SceneStaticFunction taskItem, dynamic functionValue,

File diff suppressed because it is too large Load Diff

View File

@ -37,9 +37,9 @@ class CreateAutomationModel {
);
}
Map<String, dynamic> toMap() {
Map<String, dynamic> toMap([String? automationId]) {
return {
'unitUuid': unitUuid,
if (automationId == null) 'unitUuid': unitUuid,
'automationName': automationName,
'decisionExpr': decisionExpr,
'effectiveTime': effectiveTime.toMap(),
@ -61,7 +61,7 @@ class CreateAutomationModel {
);
}
String toJson() => json.encode(toMap());
String toJson([String? automationId]) => json.encode(toMap(automationId));
factory CreateAutomationModel.fromJson(String source) =>
CreateAutomationModel.fromMap(json.decode(source));

View File

@ -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) =>
@ -28,6 +34,14 @@ class SceneDetailsModel {
type: json["type"],
actions:
List<Action>.from(json["actions"].map((x) => Action.fromJson(x))),
conditions: json["conditions"] != null
? List<Condition>.from(
json["conditions"].map((x) => Condition.fromJson(x)))
: null,
decisionExpr: json["decisionExpr"],
effectiveTime: json["effectiveTime"] != null
? EffectiveTime.fromJson(json["effectiveTime"])
: null,
);
Map<String, dynamic> toJson() => {
@ -36,6 +50,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(),
};
}
@ -91,3 +110,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,
};
}

View File

@ -37,9 +37,10 @@ enum Status { ENABLE }
final statusValues = EnumValues({"enable": Status.ENABLE});
enum Type { TAP_TO_RUN }
enum Type { TAP_TO_RUN, automation }
final typeValues = EnumValues({"tap_to_run": Type.TAP_TO_RUN});
final typeValues =
EnumValues({"tap_to_run": Type.TAP_TO_RUN, "automation": Type.automation});
class EnumValues<T> {
Map<String, T> map;

View File

@ -20,7 +20,7 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DeviceFunctionsView extends StatelessWidget
with SceneOperationsDataHelper, SceneLogicHelper {
const DeviceFunctionsView({super.key});
DeviceFunctionsView({super.key});
@override
Widget build(BuildContext context) {

View File

@ -13,6 +13,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,6 +26,7 @@ class SceneTasksView extends StatelessWidget {
Widget build(BuildContext context) {
final sceneSettings = ModalRoute.of(context)!.settings.arguments
as SceneSettingsRouteArguments;
return DefaultScaffold(
title: sceneSettings.sceneName.isNotEmpty
? sceneSettings.sceneName
@ -107,8 +110,7 @@ class DeleteBottomSheetContent extends StatelessWidget {
listener: (context, state) {
if (state is DeleteSceneSuccess) {
if (state.success) {
Navigator.pop(context);
Navigator.pop(context);
navigateToRoute(context, Routes.homeRoute);
BlocProvider.of<SceneBloc>(context).add(
LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
}

View File

@ -1,7 +1,6 @@
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/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';
@ -9,7 +8,9 @@ import 'package:syncrow_app/features/scene/widgets/scene_view_widget/scene_grid_
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/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';
class SceneView extends StatelessWidget {
final bool pageType;
@ -19,7 +20,8 @@ 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) {
@ -32,6 +34,8 @@ class SceneView extends StatelessWidget {
if (state.success == true) {
BlocProvider.of<SceneBloc>(context)
.add(LoadScenes(HomeCubit.getInstance().selectedSpace!.id!));
BlocProvider.of<SceneBloc>(context).add(
LoadAutomation(HomeCubit.getInstance().selectedSpace!.id!));
}
}
return BlocListener<SceneBloc, SceneState>(
@ -63,30 +67,70 @@ class SceneView extends StatelessWidget {
);
}
if (state is SceneLoaded) {
if (state.scenes.isNotEmpty) {
return pageType == false
? Expanded(
child: SceneGrid(
scenes: state.scenes,
loadingSceneId: state.loadingSceneId,
),
final scenes = state.scenes;
final automationList = state.automationList;
return Expanded(
child: ListView(
children: [
ExpansionTile(
tilePadding: const EdgeInsets.symmetric(
horizontal: 6),
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
title: const BodySmall(
text: 'Tap to run routines'),
children: [
scenes.isNotEmpty
? SceneGrid(
scenes: scenes,
loadingSceneId:
state.loadingSceneId,
disablePLayButton: false,
)
: Expanded(
child: SceneListview(
scenes: state.scenes,
loadingSceneId: state.loadingSceneId,
)
);
} else {
return const Expanded(
child: Center(
: const Center(
child: BodyMedium(
text: 'No scenes have been added yet',
text:
'No scenes have been added yet',
),
),
const SizedBox(
height: 10,
),
],
),
ExpansionTile(
initiallyExpanded: true,
iconColor: ColorsManager.grayColor,
tilePadding: const EdgeInsets.symmetric(
horizontal: 6),
title: const BodySmall(text: 'Automation'),
children: [
automationList.isNotEmpty
? SceneGrid(
scenes: automationList,
loadingSceneId:
state.loadingSceneId,
disablePLayButton: true,
)
: const Center(
child: BodyMedium(
text:
'No automations have been added yet',
),
),
const SizedBox(
height: 10,
),
],
),
const SizedBox(
height: 15,
),
],
),
);
}
}
return const SizedBox();
},
),

View File

@ -62,7 +62,7 @@ class _AlertDialogSliderStepsState extends State<AlertDialogSliderSteps> {
double _normalizeValue(dynamic value) {
if (widget.taskItem.code == "temp_set" ||
widget.taskItem.code == "temp_current") {
return (value as double) / 10;
return (value) / 10;
}
return value.toDouble();
}

View File

@ -83,8 +83,12 @@ class IFDefaultContainer extends StatelessWidget {
BlocBuilder<CreateSceneBloc, CreateSceneState>(
builder: (context, state) {
String conditionText = "When any condition is met";
if (state is ConditionSelectedState) {
conditionText = state.condition;
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,

View File

@ -1,21 +1,22 @@
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;
const SceneGrid({
required this.scenes,
required this.loadingSceneId,
super.key,
required this.disablePLayButton,
});
@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 +27,10 @@ class SceneGrid extends StatelessWidget {
itemBuilder: (context, index) {
final scene = scenes[index];
final isLoading = loadingSceneId == scene.id;
return SceneItem(scene: scene, isLoading: isLoading);
return SceneItem(
scene: scene,
isLoading: isLoading,
disablePLayButton: disablePLayButton);
},
);
}

View File

@ -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,
// ),
],
);
}

View File

@ -16,11 +16,13 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SceneItem extends StatelessWidget {
final ScenesModel scene;
final bool isLoading;
final bool disablePLayButton;
const SceneItem({
required this.scene,
required this.isLoading,
super.key,
required this.disablePLayButton,
});
@override
@ -31,16 +33,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,
),
);
if (disablePLayButton == false) {
BlocProvider.of<CreateSceneBloc>(context)
.add(FetchSceneTasksEvent(sceneId: scene.id));
.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,7 +66,9 @@ class SceneItem extends StatelessWidget {
Assets.assetsIconsLogo,
fit: BoxFit.fill,
),
IconButton(
Visibility(
visible: disablePLayButton == false,
child: IconButton(
padding: EdgeInsets.zero,
onPressed: () {
context
@ -69,6 +85,7 @@ class SceneItem extends StatelessWidget {
color: ColorsManager.greyColor,
),
),
),
],
),
const SizedBox(height: 10),

View File

@ -24,53 +24,66 @@ 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>())
create: (BuildContext context) => TabBarBloc(
context.read<DeviceManagerBloc>())
..add(const TabChanged(selectedIndex: 0, roomId: '-1')),
),
],
@ -79,7 +92,7 @@ class Router {
settings: settings);
case Routes.deviceFunctionsRoute:
return MaterialPageRoute(
builder: (_) => const DeviceFunctionsView(),
builder: (_) => DeviceFunctionsView(),
settings: settings,
);
default:

View File

@ -129,7 +129,7 @@ abstract class ApiEndpoints {
static const String assignDeviceToRoom = '$baseUrl/device/room';
/// Scene API ////////////////////
/// Scene & Automation API ////////////////////
/// POST
static const String createScene = '$baseUrl/scene/tap-to-run';
static const String triggerScene =
@ -142,9 +142,16 @@ abstract class ApiEndpoints {
static const String getScene = '$baseUrl/scene/tap-to-run/details/{sceneId}';
static const String getUnitAutomation = '$baseUrl/automation/{unitUuid}';
static const String getAutomationDetails = '$baseUrl/automation/details/{automationId}';
/// PUT
static const String updateScene = '$baseUrl/scene/tap-to-run/{sceneId}';
static const String updateAutomation =
'$baseUrl/automation/{automationId}';
/// DELETE
static const String deleteScene =
'$baseUrl/scene/tap-to-run/{unitUuid}/{sceneId}';

View File

@ -8,6 +8,7 @@ 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 {
@ -25,6 +26,7 @@ class SceneApi {
}
}
// create automation
static Future<Map<String, dynamic>> createAutomation(
CreateAutomationModel createAutomationModel) async {
try {
@ -42,6 +44,8 @@ class SceneApi {
}
}
//get scene by unit id
static Future<List<ScenesModel>> getScenesByUnitId(String unitId) async {
try {
final response = await _httpService.get(
@ -61,6 +65,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(
@ -74,6 +99,22 @@ 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;
}
}
//getScene
static Future<SceneDetailsModel> getSceneDetails(String sceneId) async {
@ -106,6 +147,25 @@ class SceneApi {
}
}
//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(