diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 7eef853..07c6cb1 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 232 (116 per locale) +/// Strings: 234 (117 per locale) /// -/// Built on 2024-02-25 at 03:19 UTC +/// Built on 2024-02-25 at 03:56 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -171,6 +171,7 @@ class _StringsGenericEn { String get close => 'Close'; String get error => 'Error'; String get optional => 'Optional'; + String get authTokenNotValid => 'Your authorization token is not valid anymore. Please, reauthenticate.'; } // Path: onboarding @@ -463,6 +464,7 @@ class _StringsGenericEs implements _StringsGenericEn { @override String get close => 'Cerrar'; @override String get error => 'Error'; @override String get optional => 'Opcional'; + @override String get authTokenNotValid => 'Su token de autorización ya no es válido. Por favor, vuelva a autenticarse.'; } // Path: onboarding @@ -721,6 +723,7 @@ extension on Translations { case 'generic.close': return 'Close'; case 'generic.error': return 'Error'; case 'generic.optional': return 'Optional'; + case 'generic.authTokenNotValid': return 'Your authorization token is not valid anymore. Please, reauthenticate.'; case 'onboarding.title': return 'Welcome to Linkdy'; case 'onboarding.subtitle': return 'An application to manage your bookmarks.'; case 'onboarding.start': return 'Start'; @@ -845,6 +848,7 @@ extension on _StringsEs { case 'generic.close': return 'Cerrar'; case 'generic.error': return 'Error'; case 'generic.optional': return 'Opcional'; + case 'generic.authTokenNotValid': return 'Su token de autorización ya no es válido. Por favor, vuelva a autenticarse.'; case 'onboarding.title': return 'Bienvenido a Linkdy'; case 'onboarding.subtitle': return 'Una aplicación para gestionar tus enlaces favoritos.'; case 'onboarding.start': return 'Comenzar'; diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json index a0c7765..a95924f 100644 --- a/lib/i18n/strings_en.i18n.json +++ b/lib/i18n/strings_en.i18n.json @@ -6,7 +6,8 @@ "save": "Save", "close": "Close", "error": "Error", - "optional": "Optional" + "optional": "Optional", + "authTokenNotValid": "Your authorization token is not valid anymore. Please, reauthenticate." }, "onboarding": { "title": "Welcome to Linkdy", diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json index 3aba981..ea861ec 100644 --- a/lib/i18n/strings_es.i18n.json +++ b/lib/i18n/strings_es.i18n.json @@ -6,7 +6,8 @@ "save": "Guardar", "close": "Cerrar", "error": "Error", - "optional": "Opcional" + "optional": "Opcional", + "authTokenNotValid": "Su token de autorización ya no es válido. Por favor, vuelva a autenticarse." }, "onboarding": { "title": "Bienvenido a Linkdy", diff --git a/lib/providers/api_client_provider.dart b/lib/providers/api_client_provider.dart index 96cd49e..13819ac 100644 --- a/lib/providers/api_client_provider.dart +++ b/lib/providers/api_client_provider.dart @@ -1,8 +1,10 @@ import 'package:dio/dio.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + import 'package:linkdy/providers/server_instances_provider.dart'; +import 'package:linkdy/providers/dio_interceptor.provider.dart'; import 'package:linkdy/services/api_client.dart'; import 'package:linkdy/utils/api_base_url.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'api_client_provider.g.dart'; @@ -13,16 +15,17 @@ class ApiClient extends _$ApiClient { final savedInstances = ref.watch(serverInstancesProvider); if (savedInstances.isNotEmpty) { final instance = savedInstances[0]; + final dio = Dio( + BaseOptions( + baseUrl: apiBaseUrl(instance), + headers: { + "Authorization": "Token ${instance.token}", + }, + ), + )..interceptors.add(ref.watch(dioInterceptorProvider)); return ApiClientService( serverInstance: instance, - dioInstance: Dio( - BaseOptions( - baseUrl: apiBaseUrl(instance), - headers: { - "Authorization": "Token ${instance.token}", - }, - ), - ), + dioInstance: dio, ); } return null; diff --git a/lib/providers/api_client_provider.g.dart b/lib/providers/api_client_provider.g.dart index 73aa1bb..2946ef2 100644 --- a/lib/providers/api_client_provider.g.dart +++ b/lib/providers/api_client_provider.g.dart @@ -6,7 +6,7 @@ part of 'api_client_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$apiClientHash() => r'd26f8058edfc47acd2e01f2a9bcbf64102b51212'; +String _$apiClientHash() => r'81e911e24bda3baf158a7d583271c4467821b11f'; /// See also [ApiClient]. @ProviderFor(ApiClient) diff --git a/lib/providers/dio_interceptor.provider.dart b/lib/providers/dio_interceptor.provider.dart new file mode 100644 index 0000000..c23315a --- /dev/null +++ b/lib/providers/dio_interceptor.provider.dart @@ -0,0 +1,31 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/providers/server_instances_provider.dart'; +import 'package:linkdy/router/routes.dart'; +import 'package:linkdy/utils/snackbar.dart'; +import 'package:linkdy/router/paths.dart'; +import 'package:linkdy/providers/api_client_provider.dart'; + +part 'dio_interceptor.provider.g.dart'; + +@Riverpod(keepAlive: true) +InterceptorsWrapper dioInterceptor(DioInterceptorRef ref) { + return InterceptorsWrapper( + onError: (error, handler) async { + if (error.response?.statusCode == 401) { + while (GoRouter.of(rootNavigatorKey.currentContext!).canPop() == true) { + GoRouter.of(rootNavigatorKey.currentContext!).pop(); + } + GoRouter.of(rootNavigatorKey.currentContext!).pushReplacement(RoutesPaths.onboarding); + ref.read(apiClientProvider.notifier).disconnectApiClient(); + ref.read(serverInstancesProvider.notifier).removeServerInstances(); + showSnacbkar(label: t.generic.authTokenNotValid, color: Colors.red); + } + handler.next(error); + }, + ); +} diff --git a/lib/providers/dio_interceptor.provider.g.dart b/lib/providers/dio_interceptor.provider.g.dart new file mode 100644 index 0000000..63ebdcf --- /dev/null +++ b/lib/providers/dio_interceptor.provider.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'dio_interceptor.provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$dioInterceptorHash() => r'449d19df5bf143a7e0f92249d99b4d223b2468f3'; + +/// See also [dioInterceptor]. +@ProviderFor(dioInterceptor) +final dioInterceptorProvider = Provider.internal( + dioInterceptor, + name: r'dioInterceptorProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$dioInterceptorHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef DioInterceptorRef = ProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/screens/onboarding/provider/connect.provider.dart b/lib/screens/onboarding/provider/connect.provider.dart index 3682ce2..940fd83 100644 --- a/lib/screens/onboarding/provider/connect.provider.dart +++ b/lib/screens/onboarding/provider/connect.provider.dart @@ -5,6 +5,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/onboarding/model/connect.model.dart'; +import 'package:linkdy/providers/dio_interceptor.provider.dart'; import 'package:linkdy/providers/server_instances_provider.dart'; import 'package:linkdy/utils/api_base_url.dart'; import 'package:linkdy/i18n/strings.g.dart'; @@ -102,7 +103,7 @@ FutureOr connectToServer(ConnectToServerRef ref) async { "Authorization": "Token ${serverInstance.token}", }, ), - ), + )..interceptors.add(ref.watch(dioInterceptorProvider)), ); final processModal = ProcessModal(); diff --git a/lib/screens/onboarding/provider/connect.provider.g.dart b/lib/screens/onboarding/provider/connect.provider.g.dart index 9a5fe92..c7b2196 100644 --- a/lib/screens/onboarding/provider/connect.provider.g.dart +++ b/lib/screens/onboarding/provider/connect.provider.g.dart @@ -6,7 +6,7 @@ part of 'connect.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$connectToServerHash() => r'78c2abcf7949674db5961ef644275d27c73bb000'; +String _$connectToServerHash() => r'19a35bf2985d18662ce0b7ece8284cb4e83f1529'; /// See also [connectToServer]. @ProviderFor(connectToServer) diff --git a/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart b/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart index 32684b8..5cf24e7 100644 --- a/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart +++ b/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart @@ -64,7 +64,6 @@ class TagBookmarksScreenState extends ConsumerState { return false; } - print(provider.maxNumber); return Scaffold( body: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) => [