Frontend WIP - just websocket support left

This commit is contained in:
2025-02-09 21:23:27 -07:00
parent f73bd53214
commit e7641f6aec
19 changed files with 484 additions and 132 deletions
+50 -2
View File
@@ -1,12 +1,60 @@
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_models/jwt.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'auth.g.dart';
final logger = Logger('provider/auth');
@riverpod
class JwtNotifier extends _$JwtNotifier {
@override
JWTBody? build() {
return null;
Future<JWTBody?> build() async {
if (!await SharedPreferencesAsync().containsKey('jwt')) {
logger.fine('No JWT saved to client');
return null;
}
final jwtString = await SharedPreferencesAsync().getString('jwt');
if (jwtString == null) {
logger.fine('Saved JWT came back null, removing key');
SharedPreferencesAsync().remove('jwt');
return null;
}
final payload = JwtDecoder.tryDecode(jwtString);
if (payload == null) {
logger.fine('Failed to decode JWT, removing key.');
SharedPreferencesAsync().remove('jwt');
return null;
}
try {
final body = JWTBody.fromJson(payload);
return body;
} catch (e) {
logger.shout('Failed to parse JWT payload to JWTBody, something is wrong:', e, StackTrace.current);
return null;
}
}
Future<void> setJwt(String jwt) async {
final payload = JwtDecoder.tryDecode(jwt);
if (payload == null) {
logger.info('Tried to set JWT token that did not decode to payload');
state = AsyncValue.error('JWT set to invalid token', StackTrace.current);
return;
}
logger.fine('Saving jwt token to shared prefs');
await SharedPreferencesAsync().setString('jwt', jwt);
try {
final jwtBody = JWTBody.fromJson(payload);
state = AsyncValue.data(jwtBody);
} catch (e) {
state = AsyncError(e, StackTrace.current);
}
}
}
+47
View File
@@ -0,0 +1,47 @@
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'dio.g.dart';
final logger = Logger('Dio');
@riverpod
Dio dio(Ref ref) {
final dio = Dio(BaseOptions(
baseUrl: 'http://localhost:8080',
connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 3),
));
dio.interceptors.add(LogInterceptor(responseBody: true));
return dio;
}
// Create a custom LogInterceptor using the logger object
class CustomLogInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
logger.info('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
// ignore: strict_raw_type
void onResponse(Response response, ResponseInterceptorHandler handler) {
logger.info(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}',
);
return super.onResponse(response, handler);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
logger.severe(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}',
);
return super.onError(err, handler);
}
}
+10
View File
@@ -0,0 +1,10 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
part 'utility.g.dart';
@riverpod
Future<SharedPreferencesAsync> sharedPreferencesAsync(Ref ref) async {
return SharedPreferencesAsync();
}