diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 4a7d93f..4da9276 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: 284 (142 per locale) +/// Strings: 290 (145 per locale) /// -/// Built on 2024-02-26 at 14:46 UTC +/// Built on 2024-02-26 at 21:31 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -201,6 +201,9 @@ class _StringsOnboardingEn { String get serverDetails => 'Server details'; String get authentication => 'Authentication'; String get testConnectionUrl => 'Test connection url'; + String get connectionServerEstablished => 'Connection with server established'; + String get testingConnection => 'Testing connection...'; + String get connectionServerFailed => 'Connection with server failed'; String get connect => 'Connect'; String get connecting => 'Connecting...'; String get cannotConnectToServer => 'Cannot connect to the server.'; @@ -529,6 +532,9 @@ class _StringsOnboardingEs implements _StringsOnboardingEn { @override String get serverDetails => 'Detalles del servidor'; @override String get authentication => 'Autenticación'; @override String get testConnectionUrl => 'Probar URL de conexión'; + @override String get testingConnection => 'Probando conexión...'; + @override String get connectionServerEstablished => 'Conexión con servidor establecida'; + @override String get connectionServerFailed => 'Conexión con servidor fallida'; @override String get connect => 'Conectar'; @override String get connecting => 'Conectando...'; @override String get cannotConnectToServer => 'No se puede conectar con el servidor.'; @@ -814,6 +820,9 @@ extension on Translations { case 'onboarding.serverDetails': return 'Server details'; case 'onboarding.authentication': return 'Authentication'; case 'onboarding.testConnectionUrl': return 'Test connection url'; + case 'onboarding.connectionServerEstablished': return 'Connection with server established'; + case 'onboarding.testingConnection': return 'Testing connection...'; + case 'onboarding.connectionServerFailed': return 'Connection with server failed'; case 'onboarding.connect': return 'Connect'; case 'onboarding.connecting': return 'Connecting...'; case 'onboarding.cannotConnectToServer': return 'Cannot connect to the server.'; @@ -964,6 +973,9 @@ extension on _StringsEs { case 'onboarding.serverDetails': return 'Detalles del servidor'; case 'onboarding.authentication': return 'Autenticación'; case 'onboarding.testConnectionUrl': return 'Probar URL de conexión'; + case 'onboarding.testingConnection': return 'Probando conexión...'; + case 'onboarding.connectionServerEstablished': return 'Conexión con servidor establecida'; + case 'onboarding.connectionServerFailed': return 'Conexión con servidor fallida'; case 'onboarding.connect': return 'Conectar'; case 'onboarding.connecting': return 'Conectando...'; case 'onboarding.cannotConnectToServer': return 'No se puede conectar con el servidor.'; diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json index e590a52..373dc2d 100644 --- a/lib/i18n/strings_en.i18n.json +++ b/lib/i18n/strings_en.i18n.json @@ -30,6 +30,9 @@ "serverDetails": "Server details", "authentication": "Authentication", "testConnectionUrl": "Test connection url", + "connectionServerEstablished": "Connection with server established", + "testingConnection": "Testing connection...", + "connectionServerFailed": "Connection with server failed", "connect": "Connect", "connecting": "Connecting...", "cannotConnectToServer": "Cannot connect to the server.", diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json index db15e51..94d0835 100644 --- a/lib/i18n/strings_es.i18n.json +++ b/lib/i18n/strings_es.i18n.json @@ -30,6 +30,9 @@ "serverDetails": "Detalles del servidor", "authentication": "Autenticación", "testConnectionUrl": "Probar URL de conexión", + "testingConnection": "Probando conexión...", + "connectionServerEstablished": "Conexión con servidor establecida", + "connectionServerFailed": "Conexión con servidor fallida", "connect": "Conectar", "connecting": "Conectando...", "cannotConnectToServer": "No se puede conectar con el servidor.", diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart index a78952b..c7a4f85 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart @@ -172,7 +172,7 @@ final bookmarksRequestLoadMoreProvider = ); typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef; -String _$bookmarksHash() => r'71282b9487a2e9d4a17973af7fb3da7c0171f8d0'; +String _$bookmarksHash() => r'a2bd6f3226b5a1b9c19b536b31122fb5b449ff6a'; /// See also [Bookmarks]. @ProviderFor(Bookmarks) diff --git a/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart b/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart index 43ddb3e..c3fa6eb 100644 --- a/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart +++ b/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart @@ -174,7 +174,7 @@ final fetchSearchBookmarksLoadMoreProvider = ); typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef; -String _$searchBookmarksHash() => r'6e8eea2bf9c19b33f626e64ae74210d9b374065f'; +String _$searchBookmarksHash() => r'5a5bc02d87a3eff3976a3bc6991c2208f4232fb4'; /// See also [SearchBookmarks]. @ProviderFor(SearchBookmarks) diff --git a/lib/screens/bookmarks/ui/add_bookmark_modal.dart b/lib/screens/bookmarks/ui/add_bookmark_modal.dart index e53a4cc..803fdcd 100644 --- a/lib/screens/bookmarks/ui/add_bookmark_modal.dart +++ b/lib/screens/bookmarks/ui/add_bookmark_modal.dart @@ -123,12 +123,12 @@ class _ModalContent extends ConsumerWidget { style: ButtonStyle( foregroundColor: provider.checkBookmarkLoadStatus == LoadStatus.loaded ? const MaterialStatePropertyAll(Colors.green) - : provider.checkBookmarkLoadStatus == LoadStatus.loaded + : provider.checkBookmarkLoadStatus == LoadStatus.error ? const MaterialStatePropertyAll(Colors.red) : null, backgroundColor: provider.checkBookmarkLoadStatus == LoadStatus.loaded ? MaterialStatePropertyAll(Colors.green.withOpacity(0.15)) - : provider.checkBookmarkLoadStatus == LoadStatus.loaded + : provider.checkBookmarkLoadStatus == LoadStatus.error ? MaterialStatePropertyAll(Colors.red.withOpacity(0.15)) : null, ), diff --git a/lib/screens/onboarding/model/connect.model.dart b/lib/screens/onboarding/model/connect.model.dart index ecad01e..58cac86 100644 --- a/lib/screens/onboarding/model/connect.model.dart +++ b/lib/screens/onboarding/model/connect.model.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:linkdy/constants/enums.dart'; + class ConnectModel { bool isConnecting; int method; @@ -12,6 +14,7 @@ class ConnectModel { final TextEditingController tokenController; String? tokenError; bool validValues; + LoadStatus? testConnection; ConnectModel({ this.isConnecting = false, @@ -25,5 +28,6 @@ class ConnectModel { required this.tokenController, this.tokenError, this.validValues = true, + this.testConnection, }); } diff --git a/lib/screens/onboarding/provider/connect.provider.dart b/lib/screens/onboarding/provider/connect.provider.dart index 15d755d..08b2871 100644 --- a/lib/screens/onboarding/provider/connect.provider.dart +++ b/lib/screens/onboarding/provider/connect.provider.dart @@ -19,6 +19,8 @@ import 'package:linkdy/constants/regexp.dart'; part 'connect.provider.g.dart'; +const uuid = Uuid(); + @riverpod class Connect extends _$Connect { @override @@ -39,11 +41,13 @@ class Connect extends _$Connect { } void setConnectionMethod(int method) { + state.testConnection = null; state.method = method; ref.notifyListeners(); } void validateIpDomain(String value) { + state.testConnection = null; if (Regexps.ipAddress.hasMatch(value) || Regexps.domain.hasMatch(value)) { state.ipDomainError = null; } else { @@ -54,6 +58,7 @@ class Connect extends _$Connect { } void validatePort(String value) { + state.testConnection = null; if (value != '') { if (int.tryParse(value) != null && int.parse(value) <= 65535) { state.portError = null; @@ -66,6 +71,7 @@ class Connect extends _$Connect { } void validatePath(String value) { + state.testConnection = null; if (value == "") { state.pathError = null; } else { @@ -80,6 +86,7 @@ class Connect extends _$Connect { } void validateToken(String value) { + state.testConnection = null; if (value != "") { state.tokenError = null; } else { @@ -97,17 +104,32 @@ class Connect extends _$Connect { state.pathError == null && state.portError == null; } + + void testConnection() async { + state.testConnection = LoadStatus.loading; + ref.notifyListeners(); + + final connectionString = + "${ConnectionMethod.values[state.method].name}://${state.ipDomainController.text}${state.portController.text != '' ? ':${state.portController.text}' : ""}${state.pathController.text}"; + final result = await testServerReachability(connectionString); + + if (result == true) { + state.testConnection = LoadStatus.loaded; + } else { + state.testConnection = LoadStatus.error; + } + ref.notifyListeners(); + } } @riverpod FutureOr connectToServer(ConnectToServerRef ref) async { - const uuid = Uuid(); - final serverInstance = ServerInstance( id: uuid.v4(), method: ConnectionMethod.values[ref.watch(connectProvider).method].name, ipDomain: ref.watch(connectProvider).ipDomainController.text, token: ref.watch(connectProvider).tokenController.text, + path: ref.watch(connectProvider).pathController.text, ); final apiClient = ApiClientService( diff --git a/lib/screens/onboarding/provider/connect.provider.g.dart b/lib/screens/onboarding/provider/connect.provider.g.dart index 765c9e7..6a70627 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'370f2b67b9d20818d94e4d9b6ffb57c44aa18494'; +String _$connectToServerHash() => r'a5225cddee0824ab2e6393da9d5c305e212bbfba'; /// See also [connectToServer]. @ProviderFor(connectToServer) @@ -21,7 +21,7 @@ final connectToServerProvider = AutoDisposeFutureProvider.internal( ); typedef ConnectToServerRef = AutoDisposeFutureProviderRef; -String _$connectHash() => r'576283d8c543cdb4b1ae22c99cc63a23e4ff2981'; +String _$connectHash() => r'5382c9c95131bf263662799f30d2c131a548a8c5'; /// See also [Connect]. @ProviderFor(Connect) diff --git a/lib/screens/onboarding/ui/connect.dart b/lib/screens/onboarding/ui/connect.dart index 9a5a257..9f4975e 100644 --- a/lib/screens/onboarding/ui/connect.dart +++ b/lib/screens/onboarding/ui/connect.dart @@ -7,12 +7,11 @@ import 'package:linkdy/screens/onboarding/provider/connect.provider.dart'; import 'package:linkdy/screens/onboarding/provider/onboarding.provider.dart'; import 'package:linkdy/widgets/section_label.dart'; -import 'package:linkdy/utils/open_url.dart'; import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/i18n/strings.g.dart'; class OnboardingConnect extends ConsumerWidget { - const OnboardingConnect({Key? key}) : super(key: key); + const OnboardingConnect({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -205,10 +204,47 @@ class _ConnectForm extends ConsumerWidget { obscureText: true, ), const SizedBox(height: 24), - ElevatedButton.icon( - onPressed: ref.watch(connectProvider).validValues == true ? () => openUrl(connectionString) : null, - icon: const Icon(Icons.open_in_browser_rounded), - label: Text(t.onboarding.testConnectionUrl), + ElevatedButton( + onPressed: provider.testConnection == null ? () => ref.read(connectProvider.notifier).testConnection() : null, + style: ButtonStyle( + foregroundColor: provider.testConnection == LoadStatus.loaded + ? const MaterialStatePropertyAll(Colors.green) + : provider.testConnection == LoadStatus.error + ? const MaterialStatePropertyAll(Colors.red) + : null, + backgroundColor: provider.testConnection == LoadStatus.loaded + ? MaterialStatePropertyAll(Colors.green.withOpacity(0.15)) + : provider.testConnection == LoadStatus.error + ? MaterialStatePropertyAll(Colors.red.withOpacity(0.15)) + : null, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (provider.testConnection == null) Text(t.bookmarks.addBookmark.validateUrl), + if (provider.testConnection == LoadStatus.loading) ...[ + const SizedBox( + width: 12, + height: 12, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ), + const SizedBox(width: 8), + Text(t.onboarding.testingConnection), + ], + if (provider.testConnection == LoadStatus.loaded) ...[ + const Icon(Icons.check_circle_rounded), + const SizedBox(width: 8), + Text(t.onboarding.connectionServerEstablished), + ], + if (provider.testConnection == LoadStatus.error) ...[ + const Icon(Icons.error_rounded), + const SizedBox(width: 8), + Text(t.onboarding.connectionServerFailed), + ], + ], + ), ), const SizedBox(height: 16), ], diff --git a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart index 8c99d68..841795f 100644 --- a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart +++ b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart @@ -206,7 +206,7 @@ final tagBookmarksRequestLoadMoreProvider = ); typedef TagBookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef; -String _$tagBookmarksHash() => r'ba10c98bdd9e359e885ee8edf56b99cdfcf2eb10'; +String _$tagBookmarksHash() => r'5a183019775e04aa10f28c1492993f09445867a7'; /// See also [TagBookmarks]. @ProviderFor(TagBookmarks) diff --git a/lib/services/api_client.dart b/lib/services/api_client.dart index ef13a47..dc8c474 100644 --- a/lib/services/api_client.dart +++ b/lib/services/api_client.dart @@ -9,6 +9,15 @@ import 'package:linkdy/models/data/set_bookmark_data.dart'; import 'package:linkdy/models/data/tags.dart'; import 'package:linkdy/models/server_instance.dart'; +Future testServerReachability(String url) async { + try { + await Dio().get(url); + return true; + } catch (e) { + return false; + } +} + class ApiClientService { final ServerInstance serverInstance; final Dio dioInstance;