Refactor code for better readability and maintainability

- Add method to get token and validate in AuthCubit
- Update AuthState with loading, success, and error states for token
- Use BlocBuilder in SplashView for token validation and navigation

This commit refactors the code in AuthCubit to include a method to get the token and validate it. It also updates the AuthState with loading, success, and error states for token handling. In SplashView, BlocBuilder is now used to handle token validation and navigation based on the token status.
This commit is contained in:
Mohammad Salameh
2024-03-19 11:15:45 +03:00
parent 5cc2db7645
commit 79279180df
6 changed files with 58 additions and 44 deletions

View File

@ -13,7 +13,9 @@ import 'package:syncrow_app/services/api/network_exception.dart';
part 'auth_state.dart'; part 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> { class AuthCubit extends Cubit<AuthState> {
AuthCubit() : super(AuthInitial()); AuthCubit() : super(AuthInitial()) {
getTokenAndValidate();
}
static AuthCubit get(context) => BlocProvider.of(context); static AuthCubit get(context) => BlocProvider.of(context);
@ -79,4 +81,30 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthError(ServerFailure.fromDioError(e).errMessage)); emit(AuthError(ServerFailure.fromDioError(e).errMessage));
} }
} }
getTokenAndValidate() async {
emit(AuthTokenLoading());
final value =
await const FlutterSecureStorage().read(key: Token.loginAccessTokenKey);
if (value == null) {
emit(AuthTokenError("Token not found"));
return;
}
final tokenData = Token.decodeToken(value);
if (tokenData.containsKey('exp')) {
final exp = tokenData['exp'] ?? 0;
final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
if (currentTime < exp) {
emit(AuthTokenSuccess());
} else {
emit(AuthTokenError("Token expired"));
}
} else {
emit(AuthTokenError("Something went wrong"));
}
}
} }

View File

@ -21,3 +21,13 @@ class AuthLoggedOut extends AuthState {}
class AuthPasswordVisibilityChanged extends AuthState {} class AuthPasswordVisibilityChanged extends AuthState {}
class AuthAgreeToTermsChanged extends AuthState {} class AuthAgreeToTermsChanged extends AuthState {}
class AuthTokenLoading extends AuthState {}
class AuthTokenSuccess extends AuthState {}
class AuthTokenError extends AuthState {
final String message;
AuthTokenError(this.message);
}

View File

@ -1,3 +1,5 @@
// ignore_for_file: constant_identifier_names
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';

View File

@ -43,7 +43,7 @@ class _ACModeControlUnitState extends State<ACModeControlUnit> {
// widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1; // widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1;
}); });
}, },
child: DefaultContainer( child: const DefaultContainer(
height: 55, height: 55,
child: Center( child: Center(
// child: SvgPicture.asset(fanSpeeds[widget.model.fanSpeed]), // child: SvgPicture.asset(fanSpeeds[widget.model.fanSpeed]),

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
@ -10,11 +10,9 @@ class SplashView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder( return BlocBuilder<AuthCubit, AuthState>(
future: getTokenAndValidate(context), builder: (context, state) {
builder: (context, snapshot) { if (state is AuthTokenSuccess) {
if (snapshot.hasData) {
if (snapshot.data ?? false) {
Future.delayed(const Duration(seconds: 1), () { Future.delayed(const Duration(seconds: 1), () {
Navigator.pushReplacementNamed(context, Routes.homeRoute); Navigator.pushReplacementNamed(context, Routes.homeRoute);
}); });
@ -23,7 +21,7 @@ class SplashView extends StatelessWidget {
Navigator.pushReplacementNamed(context, Routes.authLogin); Navigator.pushReplacementNamed(context, Routes.authLogin);
}); });
} }
}
return Scaffold( return Scaffold(
body: Stack( body: Stack(
alignment: Alignment.center, alignment: Alignment.center,
@ -61,26 +59,4 @@ class SplashView extends StatelessWidget {
}, },
); );
} }
Future<bool> getTokenAndValidate(BuildContext context) async {
return await const FlutterSecureStorage()
.read(key: Token.loginAccessTokenKey)
.then((value) {
if (value == null) {
return false;
}
print("Decoding token Started");
var tokenData = Token.decodeToken(value ?? "");
print("checking token data");
if (tokenData.containsKey('exp')) {
var exp = tokenData['exp'] ?? 0;
var currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
print('time: $currentTime exp: $exp');
return currentTime < exp;
} else {
return false;
}
});
}
} }

View File

@ -23,13 +23,11 @@ class DevicesAPI {
Map<String, dynamic> params = { Map<String, dynamic> params = {
"homeId": spaceId, "homeId": spaceId,
"pageSize": 100, "pageSize": 100,
"page": 1 "pageNo": 1
}; };
final response = await _httpService.get( final response = await _httpService.get(
path: path: ApiEndpoints.groups,
"https://syncrow.azurewebsites.net/group?homeId=$spaceId&pageSize=100&pageNo=1", queryParameters: params,
// path: ApiEndpoints.groups,
// queryParameters: params,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => expectedResponseModel: (json) =>
DevicesCategoryModel.fromJsonList(json['groups']), DevicesCategoryModel.fromJsonList(json['groups']),