diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 73bbe88..7ea5011 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -125,14 +125,17 @@ class HomeCubit extends Cubit { emitSafe(GetSpacesLoading()); try { spaces = await SpacesAPI.getSpaces(); - selectedSpace = spaces!.isNotEmpty - ? - // selectSpace(spaces!.first) - selectedSpace = spaces!.first - : null; - emitSafe(GetSpacesLoaded(spaces!)); - } on ServerFailure catch (failure) { - emitSafe(GetSpacesError(failure.errMessage)); + } catch (failure) { + emitSafe(GetSpacesError(failure.toString())); + return; + } + + if (spaces != null && spaces!.isNotEmpty) { + selectedSpace = spaces!.first; + emitSafe(GetSpacesSuccess(spaces!)); + fetchRooms(selectedSpace!); + } else { + emitSafe(GetSpacesError("No spaces found")); } } @@ -140,13 +143,14 @@ class HomeCubit extends Cubit { emitSafe(GetSpaceRoomsLoading()); try { space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!); - if (space.rooms != null) { - emitSafe(GetSpaceRoomsLoaded(space.rooms!)); - } else { - emitSafe(GetSpaceRoomsError("No rooms found")); - } - } on ServerFailure catch (failure) { - emitSafe(GetSpacesError(failure.errMessage)); + } catch (failure) { + emitSafe(GetSpaceRoomsError(failure.toString())); + return; + } + if (space.rooms != null) { + emitSafe(GetSpaceRoomsSuccess(space.rooms!)); + } else { + emitSafe(GetSpaceRoomsError("No rooms found")); } } @@ -169,14 +173,6 @@ class HomeCubit extends Cubit { ), ], 'Devices': [ - // IconButton( - // icon: Image.asset( - // Assets.iconsFilter, - // height: 20, - // width: 20, - // ), - // onPressed: () {}, - // ), IconButton( icon: const Icon( Icons.add, diff --git a/lib/features/app_layout/bloc/home_state.dart b/lib/features/app_layout/bloc/home_state.dart index d1f5b7d..9c20d4e 100644 --- a/lib/features/app_layout/bloc/home_state.dart +++ b/lib/features/app_layout/bloc/home_state.dart @@ -4,33 +4,45 @@ abstract class HomeState {} class HomeInitial extends HomeState {} -class GetSpacesLoading extends HomeState {} +//base states +class HomeLoading extends HomeState {} -class GetSpacesLoaded extends HomeState { +class HomeError extends HomeState { + final String errMessage; + + HomeError(this.errMessage); +} + +class HomeSuccess extends HomeState {} + +///specific states +//get spaces +class GetSpacesLoading extends HomeLoading {} + +class GetSpacesSuccess extends HomeSuccess { final List spaces; - GetSpacesLoaded(this.spaces); + GetSpacesSuccess(this.spaces); } -class GetSpacesError extends HomeState { - final String errMessage; - - GetSpacesError(this.errMessage); +class GetSpacesError extends HomeError { + GetSpacesError(super.errMessage); } -class GetSpaceRoomsLoading extends HomeState {} +//get rooms +class GetSpaceRoomsLoading extends HomeLoading {} -class GetSpaceRoomsLoaded extends HomeState { +class GetSpaceRoomsSuccess extends HomeSuccess { final List rooms; - GetSpaceRoomsLoaded(this.rooms); + GetSpaceRoomsSuccess(this.rooms); } -class GetSpaceRoomsError extends HomeState { - final String errMessage; - GetSpaceRoomsError(this.errMessage); +class GetSpaceRoomsError extends HomeError { + GetSpaceRoomsError(super.errMessage); } +//UI states class SpaceSelected extends HomeState { final SpaceModel space; diff --git a/lib/features/auth/bloc/auth_cubit.dart b/lib/features/auth/bloc/auth_cubit.dart index 2ef1173..9e46276 100644 --- a/lib/features/auth/bloc/auth_cubit.dart +++ b/lib/features/auth/bloc/auth_cubit.dart @@ -41,7 +41,7 @@ class AuthCubit extends Cubit { static UserModel? user; static Token token = Token.emptyConstructor(); - +/////////////////////////////////////API CALLS///////////////////////////////////// login() async { emit(AuthLoginLoading()); try { @@ -51,23 +51,23 @@ class AuthCubit extends Cubit { password: passwordController.text, ), ); - - if (token.accessTokenIsNotEmpty) { - FlutterSecureStorage storage = const FlutterSecureStorage(); - await storage.write( - key: Token.loginAccessTokenKey, value: token.accessToken); - const FlutterSecureStorage().write( - key: UserModel.userUuidKey, - value: Token.decodeToken(token.accessToken)['uuid'].toString()); - user = UserModel.fromToken(token); - emailController.clear(); - passwordController.clear(); - emit(AuthLoginSuccess()); - } else { - emit(AuthLoginError(message: 'Something went wrong')); - } - } on ServerFailure catch (failure) { - emit(AuthError(message: failure.errMessage)); + } catch (failure) { + emit(AuthLoginError(message: failure.toString())); + return; + } + if (token.accessTokenIsNotEmpty) { + FlutterSecureStorage storage = const FlutterSecureStorage(); + await storage.write( + key: Token.loginAccessTokenKey, value: token.accessToken); + const FlutterSecureStorage().write( + key: UserModel.userUuidKey, + value: Token.decodeToken(token.accessToken)['uuid'].toString()); + user = UserModel.fromToken(token); + emailController.clear(); + passwordController.clear(); + emit(AuthLoginSuccess()); + } else { + emit(AuthLoginError(message: 'Something went wrong')); } } @@ -79,8 +79,9 @@ class AuthCubit extends Cubit { NavigationService.navigatorKey.currentState! .popAndPushNamed(Routes.authLogin); emit(AuthLogoutSuccess()); - } on ServerFailure catch (failure) { - emit(AuthError(message: failure.errMessage)); + } catch (failure) { + emit(AuthLogoutError(message: failure.toString())); + return; } } @@ -109,11 +110,4 @@ class AuthCubit extends Cubit { emit(AuthTokenError(message: "Something went wrong")); } } - - static void logUserOut() async { - user = null; - token = Token.emptyConstructor(); - FlutterSecureStorage storage = const FlutterSecureStorage(); - await storage.delete(key: Token.loginAccessTokenKey); - } } diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index d976f59..5784091 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -251,32 +251,42 @@ class DevicesCubit extends Cubit { code: control.code, )); try { - await DevicesAPI.controlDevice(control).then((response) { - emitSafe(DeviceControlSuccess( - code: control.code, - )); - if (response['success'] ?? false) { - Future.delayed(const Duration(milliseconds: 400), () { - getDevicesStatues( - deviceId, - HomeCubit.getInstance().selectedSpace!.rooms!.indexOf( - HomeCubit.getInstance().selectedRoom!, - ), - code: control.code); - }); - } else { - emitSafe(DeviceControlError('Failed to control the device')); - } - }); - } on ServerFailure catch (failure) { - emitSafe(DeviceControlError(failure.errMessage)); + var response = await DevicesAPI.controlDevice(control); + + if (response['success'] ?? false) { + emitSafe(DeviceControlSuccess(code: control.code)); + //this delay is to give tuya server time to update the status + Future.delayed(const Duration(milliseconds: 400), () { + getDevicesStatues( + deviceId, + HomeCubit.getInstance() + .selectedSpace! + .rooms! + .indexOf(HomeCubit.getInstance().selectedRoom!), + code: control.code); + }); + } else { + emitSafe(DeviceControlError('Failed to control the device')); + } + } catch (failure) { + emitSafe(DeviceControlError(failure.toString())); + return; } } fetchGroups(int spaceId) async { emitSafe(DevicesCategoriesLoading()); - allCategories = await DevicesAPI.fetchGroups(spaceId); - emitSafe(DevicesCategoriesSuccess()); + try { + allCategories = await DevicesAPI.fetchGroups(spaceId); + } catch (e) { + emitSafe(DevicesCategoriesError(e.toString())); + return; + } + if (allCategories!.isNotEmpty && allCategories != null) { + emitSafe(DevicesCategoriesSuccess()); + } else { + emitSafe(DevicesCategoriesError('No Groups found')); + } } fetchDevicesByRoomId(int? roomId) async { @@ -287,46 +297,46 @@ class DevicesCubit extends Cubit { .selectedSpace! .rooms! .indexWhere((element) => element.id == roomId); - HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices = - await SpacesAPI.getDevicesByRoomId(roomId); + try { + HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices = + await DevicesAPI.getDevicesByRoomId(roomId); + } catch (e) { + emitSafe(GetDevicesError(e.toString())); + return; + } + emitSafe(GetDevicesSuccess()); + //get status for each device + //TODO get devices status per page via page controller instead of getting all devices status at once for (var device in HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices!) { getDevicesStatues(device.id!, roomIndex); } - - emitSafe(GetDevicesSuccess()); } getDevicesStatues(String deviceId, int roomIndex, {String? code}) async { + emitSafe(GetDeviceStatusLoading(code: code)); + int deviceIndex = HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices! + .indexWhere((element) => element.id == deviceId); + List statuses = []; try { - emitSafe(GetDeviceStatusLoading(code: code)); - int deviceIndex = HomeCubit.getInstance() - .selectedSpace! - .rooms![roomIndex] - .devices! - .indexWhere((element) => element.id == deviceId); - - List statuses = []; var response = await DevicesAPI.getDeviceStatus(deviceId); - // if (response['result']['status'].length > 4) - // print('response : ${response['result']['status'][4]}'); - for (var status in response['result']['status']) { statuses.add(StatusModel.fromJson(status)); } - - HomeCubit.getInstance() - .selectedSpace! - .rooms![roomIndex] - .devices![deviceIndex] - .status = statuses; - emitSafe(GetDeviceStatusSuccess(code: code)); - } on ServerFailure catch (failure) { - emitSafe( - GetDeviceStatusError(failure.errMessage), - ); + } catch (e) { + emitSafe(GetDeviceStatusError(e.toString())); + return; } + HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices![deviceIndex] + .status = statuses; + emitSafe(GetDeviceStatusSuccess(code: code)); } ///Lights diff --git a/lib/features/scene/bloc/scene_cubit.dart b/lib/features/scene/bloc/scene_cubit.dart index 350173a..f22d3e4 100644 --- a/lib/features/scene/bloc/scene_cubit.dart +++ b/lib/features/scene/bloc/scene_cubit.dart @@ -12,10 +12,8 @@ class SceneCubit extends Cubit { void getScenes() { emit(SceneLoading()); - //TODO: remove this it's causing the Bad State because its being after the cubit is closed - Future.delayed(const Duration(milliseconds: 50), () { - emit(SceneSuccess()); - }); + + emit(SceneSuccess()); } List scenes = []; diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index 8968bad..31bd309 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -1,5 +1,6 @@ import 'package:syncrow_app/features/devices/model/device_category_model.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/services/api/api_links_endpoints.dart'; import 'package:syncrow_app/services/api/http_service.dart'; @@ -8,18 +9,19 @@ class DevicesAPI { static Future> controlDevice( DeviceControlModel controlModel) async { - // print( - // 'contoling [${controlModel.deviceId}] with code [${controlModel.code}] and value [${controlModel.value}'); - - final response = await _httpService.post( - path: ApiEndpoints.control, - body: controlModel.toJson(), - showServerMessage: false, - expectedResponseModel: (json) { - return json; - }, - ); - return response; + try { + final response = await _httpService.post( + path: ApiEndpoints.control, + body: controlModel.toJson(), + showServerMessage: false, + expectedResponseModel: (json) { + return json; + }, + ); + return response; + } catch (e) { + rethrow; + } } static Future> fetchGroups(int spaceId) async { @@ -28,24 +30,52 @@ class DevicesAPI { "pageSize": 100, "pageNo": 1 }; - final response = await _httpService.get( - path: ApiEndpoints.groups, - queryParameters: params, - showServerMessage: false, - expectedResponseModel: (json) => - DevicesCategoryModel.fromJsonList(json['groups']), - ); - return response; + try { + final response = await _httpService.get( + path: ApiEndpoints.groups, + queryParameters: params, + showServerMessage: false, + expectedResponseModel: (json) => + DevicesCategoryModel.fromJsonList(json['groups']), + ); + return response; + } catch (e) { + rethrow; + } } static Future> getDeviceStatus(String deviceId) async { - final response = await _httpService.get( - path: '${ApiEndpoints.deviceStatus}/$deviceId/functions/status', - showServerMessage: false, - expectedResponseModel: (json) { - return json; - }, - ); - return response; + try { + final response = await _httpService.get( + path: '${ApiEndpoints.deviceStatus}/$deviceId/functions/status', + showServerMessage: false, + expectedResponseModel: (json) { + return json; + }, + ); + return response; + } catch (e) { + rethrow; + } + } + + static Future> getDevicesByRoomId(int roomId) async { + try { + final response = await _httpService.get( + path: ApiEndpoints.devicesByRoom, + queryParameters: {"roomId": roomId, "pageSize": 10}, + showServerMessage: false, + expectedResponseModel: (json) { + List devices = []; + for (var device in json['devices']) { + devices.add(DeviceModel.fromJson(device)); + } + return devices; + }, + ); + return response; + } catch (e) { + rethrow; + } } } diff --git a/lib/services/api/http_interceptor.dart b/lib/services/api/http_interceptor.dart index 38b43cb..baae847 100644 --- a/lib/services/api/http_interceptor.dart +++ b/lib/services/api/http_interceptor.dart @@ -1,18 +1,30 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/navigation/navigation_service.dart'; +import 'package:syncrow_app/services/api/api_links_endpoints.dart'; import 'dart:async'; import 'dart:developer' as developer; import 'package:syncrow_app/services/api/network_exception.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart'; class HTTPInterceptor extends InterceptorsWrapper { - @override + List headerExclusionList = []; + + List headerExclusionListOfAddedParameters = [ + ApiEndpoints.login, + ]; @override void onResponse(Response response, ResponseInterceptorHandler handler) async { - return handler.next(response); + if (await validateResponse(response)) { + super.onResponse(response, handler); + } else { + handler.reject(DioException( + requestOptions: response.requestOptions, response: response)); + } } @override @@ -20,17 +32,20 @@ class HTTPInterceptor extends InterceptorsWrapper { RequestOptions options, RequestInterceptorHandler handler) async { var storage = const FlutterSecureStorage(); var token = await storage.read(key: Token.loginAccessTokenKey); - // options.headers['Authorization'] = 'Bearer $token'; - options.headers['Authorization'] = 'Bearer ${'${token!}123'}'; + if (checkHeaderExclusionListOfAddedParameters(options.path)) { + options.headers + .putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $token"); + } + // options.headers['Authorization'] = 'Bearer ${'${token!}123'}'; super.onRequest(options, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) async { - developer.log('Error Message: ${err.message}'); - developer.log('Error res Code: ${err.response?.statusCode}'); - developer.log('Error res Data: ${err.response?.data}'); - developer.log('Error res status message: ${err.response?.statusMessage}'); + // developer.log('Error Message: ${err.message}'); + // developer.log('Error res Code: ${err.response?.statusCode}'); + // developer.log('Error res Data: ${err.response?.data}'); + // developer.log('Error res status message: ${err.response?.statusMessage}'); ServerFailure failure = ServerFailure.fromDioError(err); CustomSnackBar.displaySnackBar(failure.toString()); @@ -39,8 +54,8 @@ class HTTPInterceptor extends InterceptorsWrapper { if (err.response?.statusCode == 401 && token != null) { await AuthCubit.get(NavigationService.navigatorKey.currentContext!) .logout(); - super.onError(err, handler); } + super.onError(err, handler); } /// Validates the response and returns true if it is successful (status code 2xx). @@ -60,4 +75,15 @@ class HTTPInterceptor extends InterceptorsWrapper { return false; } } + + checkHeaderExclusionListOfAddedParameters(String path) { + bool shouldAddHeader = true; + + for (var urlConstant in headerExclusionListOfAddedParameters) { + if (path.contains(urlConstant)) { + shouldAddHeader = false; + } + } + return shouldAddHeader; + } } diff --git a/lib/services/api/http_service.dart b/lib/services/api/http_service.dart index 690c11c..414741d 100644 --- a/lib/services/api/http_service.dart +++ b/lib/services/api/http_service.dart @@ -57,8 +57,6 @@ class HTTPService { queryParameters: queryParameters, options: options, ); - // developer.log("status code is ${response.statusCode}"); - // developer.log("response data is ${response.data}"); return expectedResponseModel(response.data); } catch (error) { rethrow; diff --git a/lib/services/api/spaces_api.dart b/lib/services/api/spaces_api.dart index ebf2597..f05df9f 100644 --- a/lib/services/api/spaces_api.dart +++ b/lib/services/api/spaces_api.dart @@ -12,47 +12,39 @@ class SpacesAPI { static Future> getSpaces() async { var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); - final response = await _httpService.get( - path: ApiEndpoints.spaces, - queryParameters: { - "userUuid": uuid, - }, - showServerMessage: false, - expectedResponseModel: (json) => SpaceModel.fromJsonList(json), - ); - return response; + try { + final response = await _httpService.get( + path: ApiEndpoints.spaces, + queryParameters: { + "userUuid": uuid, + }, + showServerMessage: false, + expectedResponseModel: (json) => SpaceModel.fromJsonList(json), + ); + return response; + } catch (e) { + rethrow; + } } //get rooms by space id static Future> getRoomsBySpaceId(int spaceId) async { - final response = await _httpService.get( - path: ApiEndpoints.rooms, - queryParameters: {"homeId": spaceId}, - showServerMessage: false, - expectedResponseModel: (json) { - List rooms = []; - for (var room in json) { - rooms.add(RoomModel.fromJson(room)); - } - return rooms; - }, - ); - return response; - } - - static Future> getDevicesByRoomId(int roomId) async { - final response = await _httpService.get( - path: ApiEndpoints.devicesByRoom, - queryParameters: {"roomId": roomId, "pageSize": 10}, - showServerMessage: false, - expectedResponseModel: (json) { - List devices = []; - for (var device in json['devices']) { - devices.add(DeviceModel.fromJson(device)); - } - return devices; - }, - ); - return response; + try { + final response = await _httpService.get( + path: ApiEndpoints.rooms, + queryParameters: {"homeId": spaceId}, + showServerMessage: false, + expectedResponseModel: (json) { + List rooms = []; + for (var room in json) { + rooms.add(RoomModel.fromJson(room)); + } + return rooms; + }, + ); + return response; + } catch (e) { + rethrow; + } } }