diff --git a/lib/pages/routiens/bloc/routine_bloc.dart b/lib/pages/routiens/bloc/routine_bloc.dart index 86da3211..a7fd7228 100644 --- a/lib/pages/routiens/bloc/routine_bloc.dart +++ b/lib/pages/routiens/bloc/routine_bloc.dart @@ -1,13 +1,19 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; +import 'package:syncrow_web/services/routines_api.dart'; part 'routine_event.dart'; part 'routine_state.dart'; +const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; + class RoutineBloc extends Bloc { RoutineBloc() : super(const RoutineState()) { on(_onAddToIfContainer); on(_onAddToThenContainer); + on(_onLoadScenes); + on(_onLoadAutomation); } void _onAddToIfContainer(AddToIfContainer event, Emitter emit) { @@ -19,4 +25,38 @@ class RoutineBloc extends Bloc { final updatedThenItems = List>.from(state.thenItems)..add(event.item); emit(state.copyWith(thenItems: updatedThenItems)); } + + Future _onLoadScenes(LoadScenes event, Emitter emit) async { + emit(state.copyWith(isLoading: true, errorMessage: null)); + + try { + final scenes = await SceneApi.getScenesByUnitId(event.unitId); + emit(state.copyWith( + scenes: scenes, + isLoading: false, + )); + } catch (e) { + emit(state.copyWith( + isLoading: false, + errorMessage: 'Something went wrong', + )); + } + } + + Future _onLoadAutomation(LoadAutomation event, Emitter emit) async { + emit(state.copyWith(isLoading: true, errorMessage: null)); + + try { + final automations = await SceneApi.getAutomationByUnitId(event.unitId); + emit(state.copyWith( + automations: automations, + isLoading: false, + )); + } catch (e) { + emit(state.copyWith( + isLoading: false, + errorMessage: 'Something went wrong', + )); + } + } } diff --git a/lib/pages/routiens/bloc/routine_event.dart b/lib/pages/routiens/bloc/routine_event.dart index 6570d637..6dcacf9c 100644 --- a/lib/pages/routiens/bloc/routine_event.dart +++ b/lib/pages/routiens/bloc/routine_event.dart @@ -24,3 +24,21 @@ class AddToThenContainer extends RoutineEvent { @override List get props => [item]; } + +class LoadScenes extends RoutineEvent { + final String unitId; + + const LoadScenes(this.unitId); + + @override + List get props => [unitId]; +} + +class LoadAutomation extends RoutineEvent { + final String unitId; + + const LoadAutomation(this.unitId); + + @override + List get props => [unitId]; +} diff --git a/lib/pages/routiens/bloc/routine_state.dart b/lib/pages/routiens/bloc/routine_state.dart index 3dbd5b9f..8f715428 100644 --- a/lib/pages/routiens/bloc/routine_state.dart +++ b/lib/pages/routiens/bloc/routine_state.dart @@ -3,22 +3,47 @@ part of 'routine_bloc.dart'; class RoutineState extends Equatable { final List> ifItems; final List> thenItems; + final List> availableCards; + final List scenes; + final List automations; + final bool isLoading; + final String? errorMessage; const RoutineState({ this.ifItems = const [], this.thenItems = const [], + this.availableCards = const [], + this.scenes = const [], + this.automations = const [], + this.isLoading = false, + this.errorMessage, }); RoutineState copyWith({ List>? ifItems, List>? thenItems, + List? scenes, + List? automations, + bool? isLoading, + String? errorMessage, }) { return RoutineState( ifItems: ifItems ?? this.ifItems, thenItems: thenItems ?? this.thenItems, + scenes: scenes ?? this.scenes, + automations: automations ?? this.automations, + isLoading: isLoading ?? this.isLoading, + errorMessage: errorMessage ?? this.errorMessage, ); } @override - List get props => [ifItems, thenItems]; + List get props => [ + ifItems, + thenItems, + scenes, + automations, + isLoading, + errorMessage, + ]; } diff --git a/lib/pages/routiens/models/routine_model.dart b/lib/pages/routiens/models/routine_model.dart new file mode 100644 index 00000000..2db2247f --- /dev/null +++ b/lib/pages/routiens/models/routine_model.dart @@ -0,0 +1,30 @@ +import 'dart:convert'; + +class ScenesModel { + final String id; + final String name; + final String status; + final String type; + final String? icon; + + ScenesModel({required this.id, required this.name, required this.status, required this.type, this.icon}); + + factory ScenesModel.fromRawJson(String str) => ScenesModel.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ScenesModel.fromJson(Map json) => ScenesModel( + id: json["id"], + name: json["name"] ?? '', + status: json["status"] ?? '', + type: json["type"] ?? '', + icon: json["icon"] as String?, + ); + + Map toJson() => { + "id": id, + "name": name, + "status": status, + "type": type, + }; +} diff --git a/lib/pages/routiens/widgets/conditions_routines_devices_view.dart b/lib/pages/routiens/widgets/conditions_routines_devices_view.dart index 6e6ef4a2..91100220 100644 --- a/lib/pages/routiens/widgets/conditions_routines_devices_view.dart +++ b/lib/pages/routiens/widgets/conditions_routines_devices_view.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart'; +import 'package:syncrow_web/pages/routiens/widgets/routine_devices.dart'; import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart'; +import 'package:syncrow_web/pages/routiens/widgets/scenes_and_automations.dart'; import 'package:syncrow_web/pages/routiens/widgets/search_bar_condition_title.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; @@ -50,6 +50,9 @@ class ConditionsRoutinesDevicesView extends StatelessWidget { title: 'Conditions', subtitle: '(THEN)', ), + const SizedBox( + height: 10, + ), const Wrap( spacing: 10, runSpacing: 10, @@ -71,33 +74,21 @@ class ConditionsRoutinesDevicesView extends StatelessWidget { title: 'Routines', subtitle: '(THEN)', ), + const SizedBox( + height: 10, + ), + const ScenesAndAutomations(), + const SizedBox( + height: 10, + ), const TitleRoutine( title: 'Devices', subtitle: '', ), - BlocProvider( - create: (context) => DeviceManagementBloc() - ..add( - FetchDevices(), - ), - child: BlocBuilder( - builder: (context, state) { - if (state is DeviceManagementLoaded) { - return Wrap( - spacing: 10, - runSpacing: 10, - children: state.devices - .map((device) => DraggableCard( - imagePath: device.getDefaultIcon(device.productType), - title: device.name ?? '', - )) - .toList(), - ); - } - return const Center(child: CircularProgressIndicator()); - }, - ), + const SizedBox( + height: 10, ), + const RoutineDevices(), ], ), ), diff --git a/lib/pages/routiens/widgets/dragable_card.dart b/lib/pages/routiens/widgets/dragable_card.dart index 1724e04c..7e98da28 100644 --- a/lib/pages/routiens/widgets/dragable_card.dart +++ b/lib/pages/routiens/widgets/dragable_card.dart @@ -60,13 +60,17 @@ class DraggableCard extends StatelessWidget { const SizedBox( height: 8, ), - Text( - title, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: context.textTheme.bodySmall?.copyWith( - color: titleColor ?? ColorsManager.blackColor, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: Text( + title, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: context.textTheme.bodySmall?.copyWith( + color: titleColor ?? ColorsManager.blackColor, + fontSize: 12, + ), ), ), ], diff --git a/lib/pages/routiens/widgets/routine_devices.dart b/lib/pages/routiens/widgets/routine_devices.dart new file mode 100644 index 00000000..9fba225c --- /dev/null +++ b/lib/pages/routiens/widgets/routine_devices.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart'; +import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart'; + +class RoutineDevices extends StatelessWidget { + const RoutineDevices({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => DeviceManagementBloc() + ..add( + FetchDevices(), + ), + child: BlocBuilder( + builder: (context, state) { + if (state is DeviceManagementLoaded) { + final deviceList = state.devices + .where((device) => + device.productType == 'AC' || + device.productType == '1G' || + device.productType == '2G' || + device.productType == '3G') + .toList(); + return Wrap( + spacing: 10, + runSpacing: 10, + children: deviceList + .map((device) => DraggableCard( + imagePath: device.getDefaultIcon(device.productType), + title: device.name ?? '', + )) + .toList(), + ); + } + return const Center(child: CircularProgressIndicator()); + }, + ), + ); + } +} diff --git a/lib/pages/routiens/widgets/scenes_and_automations.dart b/lib/pages/routiens/widgets/scenes_and_automations.dart new file mode 100644 index 00000000..9819f0fe --- /dev/null +++ b/lib/pages/routiens/widgets/scenes_and_automations.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/routiens/bloc/routine_bloc.dart'; +import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; + +class ScenesAndAutomations extends StatelessWidget { + const ScenesAndAutomations({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => RoutineBloc() + ..add( + LoadScenes(spaceId), + ) + ..add( + LoadAutomation(spaceId), + ), + child: BlocBuilder( + builder: (context, state) { + if (state.scenes.isNotEmpty || state.automations.isNotEmpty) { + var scenes = [...state.scenes, ...state.automations]; + return Wrap( + spacing: 10, + runSpacing: 10, + children: scenes + .map((scene) => DraggableCard( + imagePath: Assets.logo, + title: scene.name ?? '', + )) + .toList(), + ); + } + return const Center(child: CircularProgressIndicator()); + }, + ), + ); + } +} diff --git a/lib/services/routines_api.dart b/lib/services/routines_api.dart new file mode 100644 index 00000000..edf865a3 --- /dev/null +++ b/lib/services/routines_api.dart @@ -0,0 +1,216 @@ +import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; +import 'package:syncrow_web/services/api/http_service.dart'; +import 'package:syncrow_web/utils/constants/api_const.dart'; + +class SceneApi { + static final HTTPService _httpService = HTTPService(); + +// //create scene +// static Future> createScene( +// CreateSceneModel createSceneModel) async { +// try { +// final response = await _httpService.post( +// path: ApiEndpoints.createScene, +// body: createSceneModel.toMap(), +// showServerMessage: false, +// expectedResponseModel: (json) { +// return json; +// }, +// ); +// return response; +// } catch (e) { +// rethrow; +// } +// } +// +// // create automation +// static Future> 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> getScenesByUnitId(String unitId) async { + try { + final response = await _httpService.get( + path: ApiEndpoints.getSpaceScenes.replaceAll('{unitUuid}', unitId), + showServerMessage: false, + expectedResponseModel: (json) { + List scenes = []; + for (var scene in json) { + scenes.add(ScenesModel.fromJson(scene)); + } + return scenes; + }, + ); + return response; + } catch (e) { + rethrow; + } + } + + //getAutomation + + static Future> getAutomationByUnitId(String unitId) async { + try { + final response = await _httpService.get( + path: ApiEndpoints.getSpaceAutomation.replaceAll('{unitUuid}', unitId), + showServerMessage: false, + expectedResponseModel: (json) { + List scenes = []; + for (var scene in json) { + scenes.add(ScenesModel.fromJson(scene)); + } + return scenes; + }, + ); + return response; + } catch (e) { + rethrow; + } + } + + // static Future triggerScene(String sceneId) async { + // try { + // final response = await _httpService.post( + // path: ApiEndpoints.triggerScene.replaceAll('{sceneId}', sceneId), + // showServerMessage: false, + // expectedResponseModel: (json) => json['success'], + // ); + // return response; + // } catch (e) { + // rethrow; + // } + // } + +// //automation details +// static Future 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 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 getSceneDetails(String sceneId) async { + // try { + // final response = await _httpService.get( + // path: ApiEndpoints.getScene.replaceAll('{sceneId}', sceneId), + // showServerMessage: false, + // expectedResponseModel: (json) => SceneDetailsModel.fromJson(json), + // ); + // return response; + // } catch (e) { + // rethrow; + // } + // } + // + // //update Scene + // static updateScene(CreateSceneModel createSceneModel, String sceneId) async { + // try { + // final response = await _httpService.put( + // path: ApiEndpoints.updateScene.replaceAll('{sceneId}', sceneId), + // body: createSceneModel + // .toJson(sceneId.isNotEmpty == true ? sceneId : null), + // expectedResponseModel: (json) { + // return json; + // }, + // ); + // return response; + // } catch (e) { + // rethrow; + // } + // } + // + // //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 deleteScene( + // {required String unitUuid, required String sceneId}) async { + // try { + // final response = await _httpService.delete( + // path: ApiEndpoints.deleteScene + // .replaceAll('{sceneId}', sceneId) + // .replaceAll('{unitUuid}', unitUuid), + // showServerMessage: false, + // expectedResponseModel: (json) => json['statusCode'] == 200, + // ); + // return response; + // } catch (e) { + // rethrow; + // } + // } + // + // // delete automation + // static Future 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; + // } + // } +} diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index bf167ab5..759ef7d7 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -11,16 +11,12 @@ abstract class ApiEndpoints { static const String visitorPassword = '/visitor-password'; static const String getDevices = '/visitor-password/devices'; - static const String sendOnlineOneTime = - '/visitor-password/temporary-password/online/one-time'; - static const String sendOnlineMultipleTime = - '/visitor-password/temporary-password/online/multiple-time'; + static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time'; + static const String sendOnlineMultipleTime = '/visitor-password/temporary-password/online/multiple-time'; //offline Password - static const String sendOffLineOneTime = - '/visitor-password/temporary-password/offline/one-time'; - static const String sendOffLineMultipleTime = - '/visitor-password/temporary-password/offline/multiple-time'; + static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time'; + static const String sendOffLineMultipleTime = '/visitor-password/temporary-password/offline/multiple-time'; static const String getUser = '/user/{userUuid}'; @@ -40,14 +36,12 @@ abstract class ApiEndpoints { '/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}'; static const String scheduleByDeviceId = '/schedule/{deviceUuid}'; - static const String getScheduleByDeviceId = - '/schedule/{deviceUuid}?category={category}'; - static const String deleteScheduleByDeviceId = - '/schedule/{deviceUuid}/{scheduleUuid}'; - static const String updateScheduleByDeviceId = - '/schedule/enable/{deviceUuid}'; + static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}'; + static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}'; + static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}'; static const String factoryReset = '/device/factory/reset/{deviceUuid}'; - static const String powerClamp = - '/device/{powerClampUuid}/power-clamp/status'; + static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status'; + static const String getSpaceScenes = '/scene/tap-to-run/{unitUuid}'; + static const String getSpaceAutomation = '/automation/{unitUuid}'; }