diff --git a/assets/images/curtain.svg b/assets/images/curtain.svg new file mode 100644 index 00000000..34fb387a --- /dev/null +++ b/assets/images/curtain.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index 9e4fb1d1..aee4224b 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -31,7 +31,8 @@ class AuthBloc extends Bloc { ////////////////////////////// forget password ////////////////////////////////// final TextEditingController forgetEmailController = TextEditingController(); - final TextEditingController forgetPasswordController = TextEditingController(); + final TextEditingController forgetPasswordController = + TextEditingController(); final TextEditingController forgetOtp = TextEditingController(); final forgetFormKey = GlobalKey(); late bool checkValidate = false; @@ -40,22 +41,55 @@ class AuthBloc extends Bloc { int _remainingTime = 0; List? regionList = [RegionModel(name: 'name', id: 'id')]; - Future _onStartTimer(StartTimerEvent event, Emitter emit) async { + + Future _onStartTimer( + StartTimerEvent event, Emitter emit) async { if (_validateInputs(emit)) return; if (_timer != null && _timer!.isActive) { return; } _remainingTime = 1; - add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); - _remainingTime = (await AuthenticationAPI.sendOtp( - email: forgetEmailController.text, regionUuid: regionUuid))!; + add(UpdateTimerEvent( + remainingTime: _remainingTime, isButtonEnabled: false)); + try { + forgetEmailValidate = ''; + _remainingTime = (await AuthenticationAPI.sendOtp( + email: forgetEmailController.text, regionUuid: regionUuid))!; + } on DioException catch (e) { + if (e.response!.statusCode == 400) { + final errorData = e.response!.data; + String errorMessage = errorData['message']; + print('sendOtp=$errorMessage'); + if (errorMessage == 'User not found') { + validate='Invalid Credential'; + emit(AuthInitialState()); + return 1; + } else { + validate=''; + _remainingTime = errorData['data']['cooldown'] ?? 1; + emit(AuthInitialState()); + } + } else { + emit(AuthInitialState()); + + return 1; + } + emit(AuthInitialState()); + + } catch (e) { + emit(AuthInitialState()); + + return 1; + } + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { _remainingTime--; if (_remainingTime <= 0) { _timer?.cancel(); add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true)); } else { - add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); + add(UpdateTimerEvent( + remainingTime: _remainingTime, isButtonEnabled: false)); } }); } @@ -65,14 +99,16 @@ class AuthBloc extends Bloc { emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); } - Future changePassword(ChangePasswordEvent event, Emitter emit) async { + Future changePassword( + ChangePasswordEvent event, Emitter emit) async { try { emit(LoadingForgetState()); var response = await AuthenticationAPI.verifyOtp( email: forgetEmailController.text, otpCode: forgetOtp.text); if (response == true) { await AuthenticationAPI.forgetPassword( - password: forgetPasswordController.text, email: forgetEmailController.text); + password: forgetPasswordController.text, + email: forgetEmailController.text); _timer?.cancel(); emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); emit(SuccessForgetState()); @@ -89,7 +125,12 @@ class AuthBloc extends Bloc { } else if (errorMessage == "OTP expired") { forgetValidate = 'One time password has been expired.'; emit(AuthInitialState()); + }else{ + validate=''; + emit(AuthInitialState()); + } + } } @@ -101,7 +142,9 @@ class AuthBloc extends Bloc { } void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) { - emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime)); + emit(TimerState( + isButtonEnabled: event.isButtonEnabled, + remainingTime: event.remainingTime)); } ///////////////////////////////////// login ///////////////////////////////////// @@ -115,6 +158,7 @@ class AuthBloc extends Bloc { String otpCode = ''; String validate = ''; String forgetValidate = ''; + String forgetEmailValidate = ''; String regionUuid = ''; static Token token = Token.emptyConstructor(); static UserModel? user; @@ -132,7 +176,9 @@ class AuthBloc extends Bloc { token = await AuthenticationAPI.loginWithEmail( model: LoginWithEmailModel( - email: event.username, password: event.password, regionUuid: event.regionUuid), + email: event.username, + password: event.password, + regionUuid: event.regionUuid), ); } catch (failure) { validate = 'Invalid Credentials!'; @@ -142,7 +188,8 @@ class AuthBloc extends Bloc { if (token.accessTokenIsNotEmpty) { FlutterSecureStorage storage = const FlutterSecureStorage(); - await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken); + await storage.write( + key: Token.loginAccessTokenKey, value: token.accessToken); const FlutterSecureStorage().write( key: UserModel.userUuidKey, value: Token.decodeToken(token.accessToken)['uuid'].toString()); @@ -160,9 +207,9 @@ class AuthBloc extends Bloc { } checkBoxToggle( - CheckBoxEvent event, - Emitter emit, - ) { + CheckBoxEvent event, + Emitter emit, + ) { emit(AuthLoading()); isChecked = event.newValue!; add(CheckEnableEvent()); @@ -218,7 +265,9 @@ class AuthBloc extends Bloc { emit(LoadingForgetState()); final nameError = validateEmail(forgetEmailController.text); if (nameError != null) { - emit(FailureForgetState(error: nameError)); + forgetEmailValidate = nameError; + emit(AuthInitialState()); + // emit(FailureForgetState(error: nameError)); return true; } return false; @@ -297,12 +346,14 @@ class AuthBloc extends Bloc { static Future getTokenAndValidate() async { try { const storage = FlutterSecureStorage(); - final firstLaunch = - await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true; + final firstLaunch = await SharedPreferencesHelper.readBoolFromSP( + StringsManager.firstLaunch) ?? + true; if (firstLaunch) { storage.deleteAll(); } - await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false); + await SharedPreferencesHelper.saveBoolToSP( + StringsManager.firstLaunch, false); final value = await storage.read(key: Token.loginAccessTokenKey) ?? ''; if (value.isEmpty) { return 'Token not found'; @@ -354,7 +405,9 @@ class AuthBloc extends Bloc { final String formattedTime = [ if (days > 0) '${days}d', // Append 'd' for days if (days > 0 || hours > 0) - hours.toString().padLeft(2, '0'), // Show hours if there are days or hours + hours + .toString() + .padLeft(2, '0'), // Show hours if there are days or hours minutes.toString().padLeft(2, '0'), seconds.toString().padLeft(2, '0'), ].join(':'); @@ -363,9 +416,9 @@ class AuthBloc extends Bloc { } bool checkEnable( - CheckEnableEvent event, - Emitter emit, - ) { + CheckEnableEvent event, + Emitter emit, + ) { emit(AuthLoading()); checkValidate = isChecked == true && loginPasswordController.text.isNotEmpty && @@ -376,18 +429,18 @@ class AuthBloc extends Bloc { } changeValidate( - ChangeValidateEvent event, - Emitter emit, - ) { + ChangeValidateEvent event, + Emitter emit, + ) { emit(AuthLoading()); validate = ''; emit(LoginInitial()); } changeForgetValidate( - ChangeValidateEvent event, - Emitter emit, - ) { + ChangeValidateEvent event, + Emitter emit, + ) { emit(AuthLoading()); forgetValidate = ''; emit(LoginInitial()); diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index a342a9a3..60270908 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -64,307 +64,310 @@ class ForgetPasswordWebPage extends StatelessWidget { Size size = MediaQuery.of(context).size; return FirstLayer( second: Center( - child: Stack( - children: [ - if (state is AuthLoading) - const Center(child: CircularProgressIndicator()), - ListView( - shrinkWrap: true, - controller: _scrollController, + child: Stack( children: [ - Container( - padding: EdgeInsets.all(size.width * 0.02), - margin: EdgeInsets.all(size.width * 0.09), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.3), - borderRadius: const BorderRadius.all(Radius.circular(20)), - ), - child: Center( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Spacer(), - Expanded( - flex: 3, - child: SvgPicture.asset( - Assets.loginLogo, - ), - ), - const Spacer(), - Expanded( - flex: 3, - child: Container( - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: - const BorderRadius.all(Radius.circular(30)), - border: Border.all( - color: - ColorsManager.graysColor.withOpacity(0.2)), + if (state is AuthLoading) + const Center(child: CircularProgressIndicator()), + ListView( + shrinkWrap: true, + controller: _scrollController, + children: [ + Container( + padding: EdgeInsets.all(size.width * 0.02), + margin: EdgeInsets.all(size.width * 0.09), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.3), + borderRadius: const BorderRadius.all(Radius.circular(20)), + ), + child: Center( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(), + Expanded( + flex: 3, + child: SvgPicture.asset( + Assets.loginLogo, + ), ), - child: Form( - key: forgetBloc.forgetFormKey, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: size.width * 0.02, - vertical: size.width * 0.003), - child: Column( - mainAxisAlignment: + const Spacer(), + Expanded( + flex: 3, + child: Container( + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + borderRadius: + const BorderRadius.all(Radius.circular(30)), + border: Border.all( + color: + ColorsManager.graysColor.withOpacity(0.2)), + ), + child: Form( + key: forgetBloc.forgetFormKey, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: size.width * 0.02, + vertical: size.width * 0.003), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 10), - const Text( - 'Forget Password', - style: TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold), - ), - const SizedBox(height: 10), - Text( - 'Please fill in your account information to\nretrieve your password', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + const Text( + 'Forget Password', + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold), + ), + const SizedBox(height: 10), + Text( + 'Please fill in your account information to\nretrieve your password', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( fontSize: 14, fontWeight: FontWeight.w400), - ), - const SizedBox(height: 10), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ + ), const SizedBox(height: 10), - SizedBox( - child: _buildDropdownField(context, forgetBloc, size) - ) - ], - ), - const SizedBox(height: 20), - Column( - crossAxisAlignment: + Column( + crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Account", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const SizedBox(height: 10), + SizedBox( + child: _buildDropdownField(context, forgetBloc, size) + ) + ], + ), + const SizedBox(height: 20), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Account", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( fontSize: 14, fontWeight: FontWeight.w400), + ), + const SizedBox(height: 10), + SizedBox( + child: TextFormField( + controller:forgetBloc.forgetEmailController , + validator: forgetBloc.validateEmail, + decoration: textBoxDecoration()!.copyWith( + hintText: 'Enter your email', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400), + ), + style: const TextStyle( + color: Colors.black), + ), + ), + if(forgetBloc.forgetEmailValidate!='') + SizedBox( + child: Text( + forgetBloc.forgetEmailValidate, + style: const TextStyle( + fontWeight: FontWeight.w700, + color: ColorsManager.red), + ), + ), + const SizedBox(height: 10.0), + + ], ), - const SizedBox(height: 10), - SizedBox( - child: TextFormField( - controller:forgetBloc.forgetEmailController , - validator: forgetBloc.validateEmail, - decoration: textBoxDecoration()! - .copyWith( - hintText: 'Enter your email', - hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400)), - style: const TextStyle( - color: Colors.black), - ), - ), - ], - ), - const SizedBox(height: 20.0), - Column( - crossAxisAlignment: + const SizedBox(height: 20.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "One Time Password", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "One Time Password", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( fontSize: 14, fontWeight: FontWeight.w400), - ), - const SizedBox(height: 10), - SizedBox( - child: TextFormField( - validator: forgetBloc.validateCode, - keyboardType: + ), + const SizedBox(height: 10), + SizedBox( + child: TextFormField( + validator: forgetBloc.validateCode, + keyboardType: TextInputType.visiblePassword, - controller: forgetBloc.forgetOtp, - decoration: + controller: forgetBloc.forgetOtp, + decoration: textBoxDecoration()!.copyWith( - hintText: 'Enter Code', - hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400), - suffixIcon: SizedBox( - width: 100, - child: Center( - child: InkWell( - onTap: state is TimerState && + hintText: 'Enter Code', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400), + suffixIcon: SizedBox( + width: 100, + child: Center( + child: InkWell( + onTap: state is TimerState && !state.isButtonEnabled && - state.remainingTime != - 1 - ? null - : () { - forgetBloc.add( - StartTimerEvent()); - }, - child: Text( - 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', - style: TextStyle( - color: state is TimerState && + state.remainingTime != 1 + ? null : () { + forgetBloc.add(StartTimerEvent()); + + }, + child: Text( + 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', + style: TextStyle( + color: state is TimerState && !state.isButtonEnabled - ? Colors.grey - : ColorsManager - .btnColor, + ? Colors.grey + : ColorsManager.btnColor, + ), + ), ), ), ), ), + style: const TextStyle( + color: Colors.black), ), ), - style: const TextStyle( - color: Colors.black), - ), - ), - if (forgetBloc.forgetValidate != '') // Check if there is a validation message - Padding( - padding: + if (forgetBloc.forgetValidate != '') // Check if there is a validation message + Padding( + padding: const EdgeInsets.only(top: 8.0), - child: Text( - forgetBloc.forgetValidate, - style: const TextStyle( - color: ColorsManager.red, - fontSize: 10, - fontWeight: FontWeight.w700), - ), - ), - ], - ), - const SizedBox(height: 20.0), - Column( - crossAxisAlignment: + child: Text( + forgetBloc.forgetValidate, + style: const TextStyle( + color: ColorsManager.red, + fontSize: 10, + fontWeight: FontWeight.w700), + ), + ), + ], + ), + const SizedBox(height: 20.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Password", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Password", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( fontSize: 14, fontWeight: FontWeight.w400), - ), - const SizedBox(height: 10), - SizedBox( - child: TextFormField( - validator: forgetBloc.passwordValidator, - keyboardType: TextInputType.visiblePassword, - controller: forgetBloc.forgetPasswordController, - decoration: textBoxDecoration()!.copyWith( - hintText: 'At least 8 characters', + ), + const SizedBox(height: 10), + SizedBox( + child: TextFormField( + validator: forgetBloc.passwordValidator, + keyboardType: TextInputType.visiblePassword, + controller: forgetBloc.forgetPasswordController, + decoration: textBoxDecoration()!.copyWith( + hintText: 'At least 8 characters', hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor, fontWeight: FontWeight.w400), + ), + style: const TextStyle(color: Colors.black), + ), ), - style: const TextStyle(color: Colors.black), - ), + ], ), - ], - ), - const SizedBox( - height: 10, - ), - const SizedBox(height: 20.0), - Row( - crossAxisAlignment: + const SizedBox( + height: 10, + ), + const SizedBox(height: 20.0), + Row( + crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: size.width * 0.2, - child: DefaultButton( - backgroundColor: + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: size.width * 0.2, + child: DefaultButton( + backgroundColor: ColorsManager.btnColor, - child: const Text('Submit'), - onPressed: () { - if (forgetBloc - .forgetFormKey.currentState! - .validate()) { - forgetBloc.add(ChangePasswordEvent()); - } - }, + child: const Text('Submit'), + onPressed: () { + if (forgetBloc.forgetFormKey.currentState!.validate()) { + forgetBloc.add(ChangePasswordEvent()); + } + }, + ), + ), + ], + ), + const SizedBox(height: 10.0), + Center( + child: SizedBox( + child: Text( + forgetBloc.validate, + style: const TextStyle( + fontWeight: FontWeight.w700, + color: ColorsManager.red), + ), ), ), + const SizedBox( + height: 10, + ), + SizedBox( + child: Center( + child: Wrap( + children: [ + const Text( + "Do you have an account? ", + style: TextStyle(color: Colors.white), + ), + InkWell( + onTap: () { + forgetBloc.add(StopTimerEvent()); + Navigator.pop(context); + }, + child: const Text( + "Sign in", + ), + ), + ], + ), + ), + ), + const SizedBox(height: 15.0), ], ), - const SizedBox(height: 10.0), - Center( - child: SizedBox( - child: Text( - forgetBloc.validate, - style: const TextStyle( - fontWeight: FontWeight.w700, - color: ColorsManager.red), - ), - ), - ), - SizedBox( - height: 10, - ), - SizedBox( - width: size.width * 0.2, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - const Flexible( - child: Text( - "Do you have an account? ", - style: TextStyle(color: Colors.white), - )), - InkWell( - onTap: () { - forgetBloc.add(StopTimerEvent()); - Navigator.pop(context); - }, - child: const Flexible( - child: Text( - "Sign in", - )), - ), - ], - ), - ), - const SizedBox(height: 15.0), - ], + ), ), ), ), - ), + const Spacer(), + ], ), - const Spacer(), - ], + ), ), - ), + ], ), ], ), - ], - ), - )); + )); } + + Widget _buildDropdownField( BuildContext context, AuthBloc loginBloc, Size size) { final TextEditingController textEditingController = TextEditingController(); @@ -467,6 +470,7 @@ class ForgetPasswordWebPage extends StatelessWidget { ), ), ), + ], ); } diff --git a/lib/pages/common/curtain_toggle.dart b/lib/pages/common/curtain_toggle.dart new file mode 100644 index 00000000..3c8bf5b1 --- /dev/null +++ b/lib/pages/common/curtain_toggle.dart @@ -0,0 +1,83 @@ + + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; + +class CurtainToggle extends StatelessWidget { + final bool value; + final String code; + final String deviceId; + final String label; + + const CurtainToggle({ + super.key, + required this.value, + required this.code, + required this.deviceId, + required this.label, + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: ColorsManager.greyColor.withOpacity(0.2), + border: Border.all(color: ColorsManager.boxDivider), + ), + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipOval( + child: Container( + color: ColorsManager.whiteColors, + child: SvgPicture.asset( + Assets.curtainIcon, + width: 60, + height: 60, + fit: BoxFit.cover, + ), + )), + SizedBox( + height: 20, + width: 35, + child: CupertinoSwitch( + value: value, + activeColor: ColorsManager.dialogBlueTitle, + onChanged: (newValue) { + context.read().add( + LivingRoomControl( + deviceId: deviceId, + code: code, + value: newValue, + ), + ); + }, + ), + ), + ], + ), + const Spacer(), + Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/common/hour_picker_dialog.dart b/lib/pages/common/hour_picker_dialog.dart index 2c89b710..091fca26 100644 --- a/lib/pages/common/hour_picker_dialog.dart +++ b/lib/pages/common/hour_picker_dialog.dart @@ -48,11 +48,11 @@ class _HourPickerDialogState extends State { value: _isPm, items: const [ DropdownMenuItem( - value: false, + value: true, child: Text('AM'), ), DropdownMenuItem( - value: true, + value:false , child: Text('PM'), ), ], diff --git a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart index 14ac7c5a..8c3941db 100644 --- a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart +++ b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/device_managment/ac/view/ac_device_control.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/view/curtain_control.dart'; import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_status_view.dart'; import 'package:syncrow_web/pages/device_managment/gateway/view/gateway_view.dart'; import 'package:syncrow_web/pages/device_managment/three_gang_switch/view/living_room_device_control.dart'; @@ -27,6 +28,10 @@ mixin RouteControlsBasedCode { return CeilingSensorControls( device: device, ); + case 'CUR': + return CurtainControl( + deviceId: device.uuid!, + ); case 'AC': return AcDeviceControl(device: device); default: diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index ab2f07fc..28a1d356 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -116,7 +116,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { ? const EdgeInsets.all(30) : const EdgeInsets.all(15), child: DynamicTable( - withSelectAll: false, + withSelectAll: true, cellDecoration: containerDecoration, onRowSelected: (index, isSelected, row) { final selectedDevice = devicesToShow[index]; diff --git a/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart b/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart new file mode 100644 index 00000000..a969b2c2 --- /dev/null +++ b/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart @@ -0,0 +1,40 @@ + + +import 'dart:async'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart'; +import 'package:syncrow_web/services/devices_mang_api.dart'; + +class CurtainBloc extends Bloc { + late bool deviceStatus; + final String deviceId; + + CurtainBloc({required this.deviceId}) : super(CurtainInitial()) { + on(_onFetchDeviceStatus); + } + + FutureOr _onFetchDeviceStatus( + CurtainFetchDeviceStatus event, Emitter emit) async { + emit(CurtainStatusLoading()); + try { + final status = await DevicesManagementApi().getDeviceStatus(event.deviceId); + deviceStatus =checkStatus(status.status[0].value) ; // Assuming this is a Map + emit(CurtainStatusLoaded(deviceStatus)); + } catch (e) { + emit(CurtainError(e.toString())); + } + } + + bool checkStatus(String command) { + if (command.toLowerCase() == 'open') { + return true; + } else { + return false; + } + } + + + + +} diff --git a/lib/pages/device_managment/curtain/bloc/curtain_event.dart b/lib/pages/device_managment/curtain/bloc/curtain_event.dart new file mode 100644 index 00000000..386addf8 --- /dev/null +++ b/lib/pages/device_managment/curtain/bloc/curtain_event.dart @@ -0,0 +1,32 @@ + +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + + +sealed class CurtainEvent extends Equatable { + const CurtainEvent(); + + @override + List get props => []; +} + +class CurtainFetchDeviceStatus extends CurtainEvent { + final String deviceId; + + const CurtainFetchDeviceStatus(this.deviceId); + + @override + List get props => [deviceId]; +} + +class CurtainControl extends CurtainEvent { + final String deviceId; + final String code; + final bool value; + + const CurtainControl( + {required this.deviceId, required this.code, required this.value}); + + @override + List get props => [deviceId, code, value]; +} diff --git a/lib/pages/device_managment/curtain/bloc/curtain_state.dart b/lib/pages/device_managment/curtain/bloc/curtain_state.dart new file mode 100644 index 00000000..70fa154b --- /dev/null +++ b/lib/pages/device_managment/curtain/bloc/curtain_state.dart @@ -0,0 +1,41 @@ + +import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/model/curtain_model.dart'; + +sealed class CurtainState extends Equatable { + const CurtainState(); + + @override + List get props => []; +} + +final class CurtainInitial extends CurtainState {} + +class CurtainStatusLoading extends CurtainState {} + +class CurtainStatusLoaded extends CurtainState { + final bool status; + + const CurtainStatusLoaded(this.status); + + @override + List get props => [status]; +} + +class CurtainError extends CurtainState { + final String message; + + const CurtainError(this.message); + + @override + List get props => [message]; +} + +class CurtainControlError extends CurtainState { + final String message; + + const CurtainControlError(this.message); + + @override + List get props => [message]; +} diff --git a/lib/pages/device_managment/curtain/model/curtain_model.dart b/lib/pages/device_managment/curtain/model/curtain_model.dart new file mode 100644 index 00000000..426f4fe5 --- /dev/null +++ b/lib/pages/device_managment/curtain/model/curtain_model.dart @@ -0,0 +1,32 @@ +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; + +class CurtainModel { + final String productUuid; + final String productType; + final List status; + + CurtainModel({ + required this.productUuid, + required this.productType, + required this.status, + }); + + factory CurtainModel.fromJson(dynamic json) { + var statusList = json['status'] as List; + List status = statusList.map((i) => Status.fromJson(i)).toList(); + + return CurtainModel( + productUuid: json['productUuid'], + productType: json['productType'], + status: status, + ); + } + + Map toJson() { + return { + 'productUuid': productUuid, + 'productType': productType, + 'status': status.map((s) => s!.toJson()).toList(), + }; + } +} diff --git a/lib/pages/device_managment/curtain/view/curtain_control.dart b/lib/pages/device_managment/curtain/view/curtain_control.dart new file mode 100644 index 00000000..c7c06681 --- /dev/null +++ b/lib/pages/device_managment/curtain/view/curtain_control.dart @@ -0,0 +1,72 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/common/curtain_toggle.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_state.dart'; +import 'package:syncrow_web/pages/device_managment/curtain/model/curtain_model.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; + +class CurtainControl extends StatelessWidget with HelperResponsiveLayout { + final String deviceId; + + const CurtainControl({super.key, required this.deviceId}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => + CurtainBloc(deviceId: deviceId)..add(CurtainFetchDeviceStatus(deviceId)), + child: BlocBuilder( + builder: (context, state) { + if (state is CurtainStatusLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (state is CurtainStatusLoaded) { + return _buildStatusControls(context, state.status); + } else if (state is CurtainError || state is CurtainControlError) { + return const Center(child: Text('Error fetching status')); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ), + ); + } + + Widget _buildStatusControls(BuildContext context, bool status) { + final isExtraLarge = isExtraLargeScreenSize(context); + final isLarge = isLargeScreenSize(context); + final isMedium = isMediumScreenSize(context); + return Container( + child: GridView( + padding: const EdgeInsets.symmetric(horizontal: 50), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isLarge || isExtraLarge + ? 3 + : isMedium + ? 2 + : 1, + mainAxisExtent: 140, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + children: [ + CurtainToggle( + value: status, + code: 'Curtains', + deviceId: deviceId, + label: 'Curtains', + ), + + ], + ), + ); + } +} diff --git a/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart b/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart index e3a42a7a..0cf7ffa9 100644 --- a/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart +++ b/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart @@ -35,40 +35,42 @@ class LivingRoomDeviceControl extends StatelessWidget with HelperResponsiveLayou final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); - return GridView( - padding: const EdgeInsets.symmetric(horizontal: 50), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge || isExtraLarge - ? 3 - : isMedium - ? 2 - : 1, - mainAxisExtent: 140, - crossAxisSpacing: 12, - mainAxisSpacing: 12, + return Container( + child: GridView( + padding: const EdgeInsets.symmetric(horizontal: 50), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isLarge || isExtraLarge + ? 3 + : isMedium + ? 2 + : 1, + mainAxisExtent: 140, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + children: [ + ToggleWidget( + value: status.switch1, + code: 'switch_1', + deviceId: deviceId, + label: 'Wall Light', + ), + ToggleWidget( + value: status.switch2, + code: 'switch_2', + deviceId: deviceId, + label: 'Ceiling Light', + ), + ToggleWidget( + value: status.switch3, + code: 'switch_3', + deviceId: deviceId, + label: 'Spotlight', + ), + ], ), - children: [ - ToggleWidget( - value: status.switch1, - code: 'switch_1', - deviceId: deviceId, - label: 'Wall Light', - ), - ToggleWidget( - value: status.switch2, - code: 'switch_2', - deviceId: deviceId, - label: 'Ceiling Light', - ), - ToggleWidget( - value: status.switch3, - code: 'switch_3', - deviceId: deviceId, - label: 'Spotlight', - ), - ], ); } } diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 6fd34050..5d5dcd57 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -29,40 +29,13 @@ class AuthenticationAPI { } static Future sendOtp({required String email, required String regionUuid}) async { - try { - final response = await HTTPService().post( - path: ApiEndpoints.sendOtp, - body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid}, - showServerMessage: true, - expectedResponseModel: (json) { - return json['data']['cooldown']; - }); - return response; - } on DioException catch (e) { - final errorData = e.response!.data; - String errorMessage = errorData['message']; - print('sendOtp=$errorMessage'); - if (e.response != null) { - if (e.response!.statusCode == 400) { - final errorData = e.response!.data; - String errorMessage = errorData['message']; - print('sendOtp=$errorMessage'); - - if (errorMessage == 'User not found') { - return 1; - } else { - int cooldown = errorData['data']['cooldown'] ?? 1; - return cooldown; - } - } else { - return 1; - } - } else { - return 1; - } - } catch (e) { - return 1; - } + final response = await HTTPService().post( + path: ApiEndpoints.sendOtp, + body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid}, + showServerMessage: true, + expectedResponseModel: (json) { + return json['data']['cooldown']; + }); } static Future verifyOtp({required String email, required String otpCode}) async { diff --git a/lib/services/devices_mang_api.dart b/lib/services/devices_mang_api.dart index 7e2dc4f8..93ace830 100644 --- a/lib/services/devices_mang_api.dart +++ b/lib/services/devices_mang_api.dart @@ -33,6 +33,7 @@ class DevicesManagementApi { path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', uuid), showServerMessage: true, expectedResponseModel: (json) { + print('getDeviceStatus$json'); return DeviceStatus.fromJson(json); }, ); diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 85a06ea3..e775fd84 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -124,4 +124,5 @@ class Assets { static const String office = 'assets/icons/office.svg'; static const String parlour = 'assets/icons/parlour.svg'; static const String grid = "assets/images/grid.svg"; + static const String curtainIcon = "assets/images/curtain.svg"; }