diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..efdcc4a 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index a0fa520..43394ed 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -18,8 +18,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.9.25" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false } include(":app") diff --git a/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 3fe440f..9c49563 100644 --- a/lib/infrastructure/service/app_navigation_observer.dart +++ b/lib/infrastructure/service/app_navigation_observer.dart @@ -27,11 +27,10 @@ class CustomNavigationObserver extends NavigatorObserver { await setupInspectionDI(); } else if (!_isWorkDone && (routeName == LiveStockRoutes.init || routeName == LiveStockRoutes.auth)) { - _isWorkDone = true; - await setupLiveStockDI(); + } super.didPush(route, previousRoute); - tLog('CustomNavigationObserver: didPush - $routeName'); + // tLog('CustomNavigationObserver: didPush - $routeName'); } @override @@ -43,12 +42,12 @@ class CustomNavigationObserver extends NavigatorObserver { @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); - tLog('CustomNavigationObserver: didPop - ${route.settings.name}'); + // tLog('CustomNavigationObserver: didPop - ${route.settings.name}'); } @override void didRemove(Route route, Route? previousRoute) { super.didRemove(route, previousRoute); - tLog('CustomNavigationObserver: didRemove - ${route.settings.name}'); + // tLog('CustomNavigationObserver: didRemove - ${route.settings.name}'); } } diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 8985caf..a82f9b1 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -1,8 +1,5 @@ -import 'package:rasadyar_chicken/presentation/routes/routes.dart'; +import 'package:rasadyar_app/presentation/routes/app_pages.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_inspection/inspection.dart'; -import 'package:rasadyar_livestock/injection/live_stock_di.dart'; -import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class ModulesLogic extends GetxController { TokenStorageService tokenService = Get.find(); @@ -32,21 +29,20 @@ class ModulesLogic extends GetxController { } Future navigateToModule(Module module) async { - if (module == Module.inspection) { - Get.offAllNamed(InspectionRoutes.init); - } else if (module == Module.liveStocks) { - await setupLiveStockDI(); - Get.offAllNamed(LiveStockRoutes.init); - } else if (module == Module.chicken) { - Get.offAllNamed(ChickenRoutes.init); + var target = getTargetPage(module).entries.first; + + if (target.value != null) { + await target.value; } + + Get.offAllNamed(target.key); } void onTapCard(Module module, int index) async { isLoading.value = true; selectedIndex.value = index; saveModule(module); - await Future.delayed(Duration(milliseconds: 800)); // Simulate loading delay + await Future.delayed(Duration(milliseconds: 500)); // Simulate loading delay navigateToModule(module); } } diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart index a9f1a8d..2250dbe 100644 --- a/lib/presentation/pages/splash/logic.dart +++ b/lib/presentation/pages/splash/logic.dart @@ -155,7 +155,10 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { tokenService.getModule(); final module = tokenService.appModule.value; final target = getTargetPage(module); - Get.offAndToNamed(target); + if (target.values.first != null) { + await target.values.first; + } + Get.offAndToNamed(target.keys.first); } catch (e, st) { debugPrint("onReady error: $e\n$st"); } diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index 44675f4..dbb99f0 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -4,8 +4,10 @@ import 'package:rasadyar_app/presentation/pages/splash/logic.dart'; import 'package:rasadyar_app/presentation/pages/splash/view.dart'; import 'package:rasadyar_app/presentation/pages/system_design/system_design.dart'; import 'package:rasadyar_chicken/chicken.dart'; +import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_inspection/inspection.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; part 'app_paths.dart'; @@ -38,15 +40,15 @@ sealed class AppPages { ]; } -String getTargetPage(Module? value) { +Map?> getTargetPage(Module? value) { switch (value) { case Module.inspection: - return InspectionRoutes.init; + return {InspectionRoutes.init:null}; case Module.liveStocks: - return LiveStockRoutes.init; + return {LiveStockRoutes.init: setupLiveStockDI()}; case Module.chicken: - return ChickenRoutes.init; + return {ChickenRoutes.init : null}; default: - return AppPaths.moduleList; + return {AppPaths.moduleList : null}; } } diff --git a/packages/chicken/pubspec.yaml b/packages/chicken/pubspec.yaml index 55b6790..683ba53 100644 --- a/packages/chicken/pubspec.yaml +++ b/packages/chicken/pubspec.yaml @@ -3,7 +3,7 @@ description: A starting point for Dart libraries or applications. version: 1.2.1+2 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: diff --git a/packages/core/.gitignore b/packages/core/.gitignore new file mode 100644 index 0000000..02b7cc0 --- /dev/null +++ b/packages/core/.gitignore @@ -0,0 +1,33 @@ +# Ignore build output and other generated files +build/ + +# Dart/Pub related +.dart_tool/ +.packages +.pub/ + +# IDE files +.idea/ +*.iml +*.ipr +*.iws + +# VS Code +.vscode/ + +# macOS +.DS_Store + +# Other +*.log +*.swp +*.pyc + +# Flutter specific +.flutter-plugins +.flutter-plugins-dependencies +pubspec.lock + +# Test outputs +test_cache/ + diff --git a/packages/core/build/unit_test_assets/AssetManifest.json b/packages/core/build/unit_test_assets/AssetManifest.json deleted file mode 100644 index 52a2006..0000000 --- a/packages/core/build/unit_test_assets/AssetManifest.json +++ /dev/null @@ -1 +0,0 @@ -{"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"],"packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf":["packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf"],"packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf":["packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf"],"packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf":["packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf"]} \ No newline at end of file diff --git a/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png b/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png deleted file mode 100644 index 8603d0a..0000000 Binary files a/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png and /dev/null differ diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 624f706..7f243b3 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -2,6 +2,7 @@ library; export 'package:android_intent_plus/android_intent.dart'; export 'package:android_intent_plus/flag.dart'; +export 'package:connectivity_plus/connectivity_plus.dart'; export 'package:device_info_plus/device_info_plus.dart'; export 'package:dio/dio.dart'; //other packages diff --git a/packages/core/lib/data/services/network_status.dart b/packages/core/lib/data/services/network_status.dart new file mode 100644 index 0000000..6eb646c --- /dev/null +++ b/packages/core/lib/data/services/network_status.dart @@ -0,0 +1,24 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:get/get.dart'; + +class NetworkStatus { + NetworkStatus._(); + + static final NetworkStatus _instance = NetworkStatus._(); + + factory NetworkStatus() => _instance; + + final Connectivity _connectivity = Connectivity(); + + RxBool isConnected = false.obs; + + void startListening() { + _connectivity.onConnectivityChanged.listen((result) { + isConnected.value = !result.contains(ConnectivityResult.none); + }); + + _connectivity.checkConnectivity().then((result) { + isConnected.value = !result.contains(ConnectivityResult.none); + }); + } +} diff --git a/packages/core/lib/infrastructure/remote/app_interceptor_n.dart b/packages/core/lib/infrastructure/remote/app_interceptor_n.dart new file mode 100644 index 0000000..bbfb0e0 --- /dev/null +++ b/packages/core/lib/infrastructure/remote/app_interceptor_n.dart @@ -0,0 +1,168 @@ +import 'dart:async'; + +import '../../core.dart'; + +/// Callback to refresh the authentication token. +/// Typically used to request a new token from the server. +typedef RefreshTokenCallback = Future Function(); + +/// Callback to save a new authentication token. +typedef SaveTokenCallback = Future Function(String token); + +/// Callback to clear the authentication token, e.g., on logout or failure. +typedef ClearTokenCallback = Future Function(); + +/// Callback invoked when token refresh fails. +/// Typically used to redirect the user to login or show a logout message. +typedef OnRefreshFailedCallback = Future Function(); + +/// Represents a queued request waiting for token refresh. +class QueuedRequest { + /// The original request options. + final RequestOptions options; + + /// Completer used to complete the response once the request is retried. + final Completer completer; + + /// Constructs a queued request. + QueuedRequest(this.options, this.completer); +} + +/// An interceptor for automatic token management and refresh handling. +/// +/// Features: +/// - Queues requests while a token refresh is in progress. +/// - Saves and clears tokens via provided callbacks. +/// - Calls [OnRefreshFailedCallback] if token refresh fails. +class AppInterceptorN extends Interceptor { + /// Callback to refresh the authentication token. + final RefreshTokenCallback? refreshTokenCallback; + + /// Callback to save the new token. + final SaveTokenCallback saveTokenCallback; + + /// Callback to clear the token. + final ClearTokenCallback clearTokenCallback; + + /// Callback executed when token refresh fails. + final OnRefreshFailedCallback onRefreshFailed; + + /// Optional additional arguments for authentication. + final dynamic authArguments; + + /// The Dio instance used to send requests. + final Dio dio; + + /// Maximum number of retry attempts for failed requests. + final int maxRetries; + + /// Whether a token refresh is currently in progress. + bool _isRefreshing = false; + + /// Queue of requests waiting for a new token. + final List _queue = []; + + /// Current token in use. + String? _currentToken; + + /// Constructs the interceptor. + AppInterceptorN({ + required this.dio, + required this.saveTokenCallback, + required this.clearTokenCallback, + required this.onRefreshFailed, + this.refreshTokenCallback, + this.authArguments, + this.maxRetries = 3, + }); + + /// Called before sending a request. + /// If a token refresh is in progress, the request is added to the queue. + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) async { + if (_isRefreshing) { + final completer = Completer(); + _queue.add(QueuedRequest(options, completer)); + return handler.resolve(await completer.future); + } + handler.next(options); + } + + /// Called when an error occurs during a request. + /// + /// - If the error is a 401 (unauthorized) and retry count is below `maxRetries`, + /// the token is refreshed and queued requests are retried. + /// - If the token refresh fails, all queued requests are cancelled and + /// [onRefreshFailed] is executed. + @override + Future onError(DioException err, ErrorInterceptorHandler handler) async { + int currentRetry = err.requestOptions.extra['retryCount'] ?? 0; + + if (err.response?.statusCode == 401 && + err.type != DioExceptionType.cancel && + currentRetry < maxRetries) { + final completer = Completer(); + final updatedOptions = err.requestOptions.copyWith( + extra: {...err.requestOptions.extra, 'retryCount': currentRetry + 1}, + ); + _queue.add(QueuedRequest(updatedOptions, completer)); + + if (!_isRefreshing) { + _isRefreshing = true; + try { + final newToken = await refreshTokenCallback?.call(); + if (newToken != null && newToken.isNotEmpty) { + _currentToken = newToken; + await saveTokenCallback(newToken); + + for (var req in _queue) { + final newOptions = req.options.copyWith( + headers: {...req.options.headers, 'Authorization': 'Bearer $newToken'}, + ); + dio + .fetch(newOptions) + .then(req.completer.complete) + .catchError(req.completer.completeError); + } + } else { + await clearTokenCallback(); + await _handleRefreshFailure(); + for (var req in _queue) { + req.completer.completeError( + DioException(requestOptions: req.options, type: DioExceptionType.cancel), + ); + } + } + } catch (e) { + await clearTokenCallback(); + await _handleRefreshFailure(); + for (var req in _queue) { + req.completer.completeError(e); + } + } finally { + _queue.clear(); + _isRefreshing = false; + } + } + + return handler.resolve(await completer.future); + } + + handler.next(err); + } + + /// Handles token refresh failure: + /// - Cancels all ongoing requests via [ApiHandler]. + /// - Executes external [onRefreshFailed] callback. + Future _handleRefreshFailure() async { + ApiHandler.cancelAllRequests("Token refresh failed"); + + await onRefreshFailed.call(); + } + + @visibleForTesting + set isRefreshingForTest(bool value) => _isRefreshing = value; + + @visibleForTesting + List get queue => _queue; +} diff --git a/packages/core/lib/injection/di.dart b/packages/core/lib/injection/di.dart index d5bc011..f59ff1d 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -1,15 +1,15 @@ import 'package:get_it/get_it.dart'; import 'package:logger/logger.dart'; -import 'package:rasadyar_core/data/services/auth_middelware.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; import 'package:rasadyar_core/infrastructure/local/hive_local_storage.dart'; final diCore = GetIt.instance; Future setupAllCoreProvider() async { - await _setUpLogger(); await _setupLocalStorage(); await _setupRemote(); + diCore.registerSingleton(NetworkStatus()..startListening()); await diCore.allReady(); } @@ -23,4 +23,4 @@ Future _setupLocalStorage() async { Future _setupRemote() async { // diCore.registerSingleton(HiveLocalStorage()); -} \ No newline at end of file +} diff --git a/packages/core/lib/utils/network/safe_call_utils.dart b/packages/core/lib/utils/network/safe_call_utils.dart index 18588b6..0c2b117 100644 --- a/packages/core/lib/utils/network/safe_call_utils.dart +++ b/packages/core/lib/utils/network/safe_call_utils.dart @@ -1,16 +1,21 @@ import 'package:flutter/material.dart'; import '../../core.dart'; - +/// Handles global API requests management with CancelToken. class ApiHandler { + // Global CancelToken for all requests. static CancelToken _globalCancelToken = CancelToken(); + /// Returns the current global CancelToken. static CancelToken get globalCancelToken => _globalCancelToken; + /// Resets the global CancelToken to a new one. static Future reset() async { _globalCancelToken = CancelToken(); } + /// Cancels all ongoing requests and resets the CancelToken. + /// [reason] is optional text explaining why requests are canceled. static void cancelAllRequests(String reason) { if (!_globalCancelToken.isCancelled) { _globalCancelToken.cancel(reason); diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index e70dda0..bbc6b7a 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build - sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4" + sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -101,26 +101,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2" + sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d + sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62 + sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.3.0" built_collection: dependency: transitive description: @@ -153,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.4" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" clock: dependency: transitive description: @@ -209,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" cross_file: dependency: transitive description: @@ -761,66 +777,66 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -889,26 +905,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -1021,6 +1037,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" package_config: dependency: transitive description: @@ -1161,10 +1185,10 @@ packages: dependency: "direct main" description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: @@ -1285,6 +1309,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" shelf_web_socket: dependency: transitive description: @@ -1322,6 +1362,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.6" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: @@ -1378,14 +1434,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" + url: "https://pub.dev" + source: hosted + version: "1.26.2" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" + test_core: + dependency: transitive + description: + name: test_core + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" + url: "https://pub.dev" + source: hosted + version: "0.6.11" time: dependency: transitive description: @@ -1454,10 +1526,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1498,6 +1570,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: @@ -1555,5 +1635,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 1c24c3c..0168865 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none version: 1.2.0+2 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: @@ -17,7 +17,7 @@ dependencies: package_info_plus: ^8.3.1 ##image_picker - image_picker: ^1.1.2 + image_picker: ^1.2.0 image_cropper: ^9.1.0 #UI @@ -58,7 +58,7 @@ dependencies: #other permission_handler: ^12.0.1 - persian_datetime_picker: ^3.1.0 + persian_datetime_picker: ^3.1.1 encrypt: ^5.0.3 #L10N tools @@ -89,10 +89,11 @@ dev_dependencies: sdk: flutter flutter_lints: ^6.0.0 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 json_serializable: ^6.10.0 + test: ^1.24.0 ##test diff --git a/packages/core/test/infrastructure/remote/app_interceptor_test.dart b/packages/core/test/infrastructure/remote/app_interceptor_test.dart new file mode 100644 index 0000000..b0bd2bf --- /dev/null +++ b/packages/core/test/infrastructure/remote/app_interceptor_test.dart @@ -0,0 +1,106 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:rasadyar_core/infrastructure/remote/app_interceptor_n.dart'; + +class MockDio extends Mock implements Dio {} + +class MockResponse extends Mock implements Response {} + +class MockRequestOptions extends Mock implements RequestOptions {} + + +class FakeRequestOptions extends Fake implements RequestOptions {} + + +void main() { + late MockDio dio; + late AppInterceptorN interceptor; + late MockResponse response; + late MockRequestOptions requestOptions; + + late bool saveCalled; + late bool clearCalled; + late bool refreshFailedCalled; + String? savedToken; + + setUp(() { + dio = MockDio(); + response = MockResponse(); + requestOptions = MockRequestOptions(); + + saveCalled = false; + clearCalled = false; + refreshFailedCalled = false; + savedToken = null; + interceptor = AppInterceptorN( + dio: dio, + saveTokenCallback: (token) async { + savedToken = token; + saveCalled = true; + }, + clearTokenCallback: () async { + clearCalled = true; + }, + refreshTokenCallback: () async => 'newToken', + onRefreshFailed: () async { + refreshFailedCalled = true; + }, + ); + }); + + setUpAll(() { + registerFallbackValue(FakeRequestOptions()); + }); + + + + test('should refresh token and retry queued requests on 401', () async { + final options = RequestOptions(path: "/test"); + final response = Response(requestOptions: options, statusCode: 200, data: 'ok'); + when(() => dio.fetch(any())).thenAnswer((_) async => response); + final handler = ErrorInterceptorHandler(); + final dioException = DioException( + requestOptions: options, + response: Response(requestOptions: options, statusCode: 401), + type: DioExceptionType.badResponse, + ); + await interceptor.onError(dioException, handler); + expect(saveCalled, isTrue); + expect(savedToken, 'newToken'); + expect(interceptor.queue.isEmpty, isTrue); + expect(clearCalled, isFalse); + expect(refreshFailedCalled, isFalse); + }); + + + test('should queue request if refreshing', () async { + interceptor.isRefreshingForTest = true; + final options = RequestOptions(path: "/test"); + final handler = RequestInterceptorHandler(); + final completer = Completer(); + interceptor.queue.add(QueuedRequest(options, completer)); + interceptor.onRequest(options, handler); + expect(interceptor.queue.length, 2); // One added in setUp, one here + }); + + test('should refresh token and retry queued requests on 401', () async { + final options = RequestOptions(path: "/test"); + final response = Response(requestOptions: options, statusCode: 200, data: 'ok'); + when(() => dio.fetch(any())).thenAnswer((_) async => response); + final handler = ErrorInterceptorHandler(); + final dioException = DioException( + requestOptions: options, + response: Response(requestOptions: options, statusCode: 401), + type: DioExceptionType.badResponse, + ); + await interceptor.onError(dioException, handler); + expect(saveCalled, isTrue); + expect(savedToken, 'newToken'); + expect(interceptor.queue.isEmpty, isTrue); + expect(clearCalled, isFalse); + expect(refreshFailedCalled, isFalse); + }); +} diff --git a/packages/core/test/infrastructure/remote/dio_form_data.dart b/packages/core/test/infrastructure/remote/dio_form_data.dart deleted file mode 100644 index 8e74832..0000000 --- a/packages/core/test/infrastructure/remote/dio_form_data.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; - -import 'interfaces/i_form_data.dart'; - -class DioFormData implements IFormData { - final FormData _formData = FormData(); - - @override - void addFile(String field, Uint8List bytes, String filename) { - _formData.files.add(MapEntry( - field, - MultipartFile.fromBytes(bytes, filename: filename), - )); - } - - @override - void addField(String key, String value) { - _formData.fields.add(MapEntry(key, value)); - } - - FormData get raw => _formData; -} diff --git a/packages/core/test/infrastructure/remote/dio_form_data_test.dart b/packages/core/test/infrastructure/remote/dio_form_data_test.dart new file mode 100644 index 0000000..a25d9da --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_form_data_test.dart @@ -0,0 +1,55 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/core.dart'; + +void main() { + group('DioFormData', () { + late DioFormData formData; + + setUp(() { + formData = DioFormData(); + }); + + test('addField should add a field to FormData', () { + formData.addField('userName', 'mojtaba'); + expect(formData.raw.fields.length, 1); + expect(formData.raw.fields.first.key, 'userName'); + expect(formData.raw.fields.first.value, 'mojtaba'); + }); + + test('addFile should add a file to FormData', () async { + final bytes = Uint8List.fromList([1, 2, 3, 4]); + formData.addFile('fileField', bytes, 'test.txt'); + + expect(formData.raw.files.length, 1); + + final fileEntry = formData.raw.files.first; + expect(fileEntry.key, 'fileField'); + + final multipart = fileEntry.value; + expect(multipart.filename, 'test.txt'); + + final uploadedBytes = await multipart.finalize().toBytes(); + expect(uploadedBytes, bytes); + + }); + + test('raw getter should return the internal FormData instance', () { + final tmp = formData.raw; + expect(tmp, isA()); + }); + + + }); +} + +extension on Stream> { + /// Helper to collect stream into a single Uint8List for comparison + Future toBytes() async { + final chunks = []; + await for (final chunk in this) { + chunks.addAll(chunk); + } + return Uint8List.fromList(chunks); + } +} diff --git a/packages/core/test/infrastructure/remote/dio_remote_test.dart b/packages/core/test/infrastructure/remote/dio_remote_test.dart index e69de29..e3b62e1 100644 --- a/packages/core/test/infrastructure/remote/dio_remote_test.dart +++ b/packages/core/test/infrastructure/remote/dio_remote_test.dart @@ -0,0 +1,201 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:rasadyar_core/core.dart'; + +class MockDio extends Mock implements Dio {} + +class MockInterceptor extends Mock implements AppInterceptor {} + +class FakeRequestOptions extends Fake implements RequestOptions {} + +void main() { + setUpAll(() { + registerFallbackValue(FakeRequestOptions()); + registerFallbackValue(RequestOptions(path: '')); + registerFallbackValue(Options()); + registerFallbackValue(CancelToken()); + }); + + group('Dio Remote', () { + late DioRemote dioRemote; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + dioRemote = DioRemote(); + dioRemote.dio = mockDio; + }); + + test('init sets dio and adds interceptor if provided', () async { + final interceptor = MockInterceptor(); + + final client = DioRemote(interceptors: interceptor); + await client.init(); + + expect(client.dio, isA()); + + }); + + test('get returns DioResponse with raw data', () async { + final response = Response( + requestOptions: RequestOptions(path: '/test'), + statusCode: 200, + data: {'message': 'ok'}, + ); + when( + () => mockDio.get( + any(), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.get>('/test'); + + expect(result, isA>>()); + expect(result.data, {'message': 'ok'}); + expect(result.statusCode, 200); + }); + + test('get applies fromJson mapper', () async { + final response = Response( + requestOptions: RequestOptions(path: '/user'), + statusCode: 200, + data: {'id': 1, 'name': 'Ali'}, + ); + when( + () => mockDio.get( + any(), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.get( + '/user', + fromJson: (json) => "User: ${json['name']}", + ); + + expect(result.data, 'User: Ali'); + }); + + test('post applies fromJson correctly', () async { + final response = Response( + requestOptions: RequestOptions(path: '/post'), + statusCode: 200, + data: {'id': 99}, + ); + when( + () => mockDio.post( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.post( + '/post', + fromJson: (json) => json['id'], + ); + + expect(result.data, 99); + }); + + test('put returns parsed data', () async { + final response = Response( + requestOptions: RequestOptions(path: '/put'), + statusCode: 200, + data: {'value': 'updated'}, + ); + when( + () => mockDio.put( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.put('/put', fromJson: (json) => json['value']); + + expect(result.data, 'updated'); + }); + + test('delete works with fromJson', () async { + final response = Response( + requestOptions: RequestOptions(path: '/delete'), + statusCode: 200, + data: {'removed': true}, + ); + when( + () => mockDio.delete( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.delete('/delete', fromJson: (json) => json['removed']); + + expect(result.data, true); + }); + + test('download returns DioResponse with bytes', () async { + final response = Response( + requestOptions: RequestOptions(path: '/download'), + statusCode: 200, + data: Uint8List.fromList([1, 2, 3]), + ); + when( + () => mockDio.get( + any(), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.download('/download'); + + expect(result.data, isA()); + expect(result.data!.length, 3); + }); + + test('upload sends DioFormData and returns DioResponse', () async { + final formData = DioFormData(); + formData.addField('field', 'value'); + final response = Response( + requestOptions: RequestOptions(path: '/upload'), + statusCode: 200, + data: 'uploaded', + ); + when( + () => mockDio.post( + any(), + data: any(named: 'data'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.upload('/upload', formData: formData); + + expect(result.data, 'uploaded'); + }); + }); +} diff --git a/packages/core/test/infrastructure/remote/dio_response.dart b/packages/core/test/infrastructure/remote/dio_response.dart deleted file mode 100644 index 30f54eb..0000000 --- a/packages/core/test/infrastructure/remote/dio_response.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'interfaces/i_http_response.dart'; -import 'package:dio/dio.dart'; - -class DioResponse implements IHttpResponse { - final Response _response; - - DioResponse(this._response); - - @override - T? get data => _response.data; - - @override - int get statusCode => _response.statusCode ?? 0; - - @override - Map? get headers => _response.headers.map; - - @override - bool get isSuccessful => statusCode >= 200 && statusCode < 300; -} diff --git a/packages/core/test/infrastructure/remote/dio_response_test.dart b/packages/core/test/infrastructure/remote/dio_response_test.dart new file mode 100644 index 0000000..7d68452 --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_response_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/core.dart'; + +void main() { + group('DioResponse', () { + test('data should return response data', () { + final response = Response( + requestOptions: RequestOptions(path: "/"), + data: 'hello', + ); + + final dioResponse = DioResponse(response); + + expect(dioResponse.data, 'hello'); + }); + + test('status Code should return 0 if null', () { + final response = Response(requestOptions: RequestOptions(path: "/"), statusCode: null); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 0); + }); + + test('headers should return response headers map', () { + final headers = Headers.fromMap({ + 'content-type': ['application/json'], + }); + final response = Response( + requestOptions: RequestOptions(path: "/"), + headers: headers, + ); + final dioResponse = DioResponse(response); + + expect(dioResponse.headers, isA()); + expect(dioResponse.headers, { + 'content-type': ['application/json'], + }); + }); + + test('isSuccessful should return true for 2xx codes', () { + final response = Response(requestOptions: RequestOptions(path: "/"), statusCode: 200); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 200); + + expect(dioResponse.isSuccessful, true); + }); + + test('isSuccessful should return false for non-2xx codes', () { + final response = Response(requestOptions: RequestOptions(path: "/"),statusCode: 404); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 404); + + expect(dioResponse.isSuccessful, false); + + }); + + }); +} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart b/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart deleted file mode 100644 index ddbda85..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter/foundation.dart'; - -abstract class IFormData{ - void addFile(String field, Uint8List bytes, String filename); - void addField(String key, String value); -} \ No newline at end of file diff --git a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart deleted file mode 100644 index 3e6327c..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart +++ /dev/null @@ -1,53 +0,0 @@ - -import 'package:dio/dio.dart'; -import 'i_form_data.dart'; -import 'i_http_response.dart'; - -abstract class IHttpClient { - Future init(); - - Future> get( - String path, { - Map? queryParameters, - Map? headers, - ProgressCallback? onReceiveProgress, - }); - - - Future> post( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - ProgressCallback? onSendProgress, - ProgressCallback? onReceiveProgress, - }); - - Future> put( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - ProgressCallback? onSendProgress, - ProgressCallback? onReceiveProgress, - }); - - Future> delete( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - }); - - Future> download( - String url, { - ProgressCallback? onReceiveProgress, - }); - - Future> upload( - String path, { - required IFormData formData, - Map? headers, - ProgressCallback? onSendProgress, - }); -} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart b/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart deleted file mode 100644 index 461146a..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class IHttpResponse { - T? get data; - int get statusCode; - Map? get headers; - bool get isSuccessful; -} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_remote.dart b/packages/core/test/infrastructure/remote/interfaces/i_remote.dart deleted file mode 100644 index 648883b..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_remote.dart +++ /dev/null @@ -1,4 +0,0 @@ -abstract class IRemote{ - Future init(); -} - diff --git a/packages/inspection/pubspec.lock b/packages/inspection/pubspec.lock index 126a3f1..c3a0fb6 100644 --- a/packages/inspection/pubspec.lock +++ b/packages/inspection/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: android_intent_plus - sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.1" animated_stack_widget: dependency: transitive description: @@ -193,6 +193,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -285,10 +301,10 @@ packages: dependency: transitive description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 url: "https://pub.dev" source: hosted - version: "5.8.0+1" + version: "5.9.0" dio_web_adapter: dependency: transitive description: @@ -533,14 +549,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: transitive - description: - name: font_awesome_flutter - sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a - url: "https://pub.dev" - source: hosted - version: "10.8.0" freezed: dependency: "direct dev" description: @@ -641,10 +649,10 @@ packages: dependency: transitive description: name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.2.0" get_test: dependency: "direct dev" description: @@ -769,66 +777,66 @@ packages: dependency: transitive description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -897,26 +905,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: "direct dev" description: @@ -1021,6 +1029,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" node_preamble: dependency: transitive description: @@ -1041,18 +1057,18 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.3.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" path: dependency: transitive description: @@ -1169,10 +1185,10 @@ packages: dependency: transitive description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: @@ -1429,26 +1445,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" url: "https://pub.dev" source: hosted - version: "1.25.15" + version: "1.26.2" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" test_core: dependency: transitive description: name: test_core - sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" url: "https://pub.dev" source: hosted - version: "0.6.8" + version: "0.6.11" time: dependency: transitive description: @@ -1517,10 +1533,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1626,5 +1642,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/packages/inspection/pubspec.yaml b/packages/inspection/pubspec.yaml index 0a3d2b2..52fa6f3 100644 --- a/packages/inspection/pubspec.yaml +++ b/packages/inspection/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.2.0 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: diff --git a/packages/livestock/lib/data/common/checkk_di_middleware.dart b/packages/livestock/lib/data/common/checkk_di_middleware.dart new file mode 100644 index 0000000..32c9f0f --- /dev/null +++ b/packages/livestock/lib/data/common/checkk_di_middleware.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; + +class CheckDiMiddleWare extends GetMiddleware { + @override + Future redirectDelegate(GetNavConfig route) async { + return super.redirectDelegate(route); + } + + @override + GetPage? onPageCalled(GetPage? page) { + return super.onPageCalled(page); + } +} diff --git a/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart b/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart new file mode 100644 index 0000000..ca0b98b --- /dev/null +++ b/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart @@ -0,0 +1,18 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; + +class TmpLocalDataSource { + Future addLocations(List list) async { + IsolatedBox box = await IsolatedHive.openBox('TmpBox'); + if (await box.isNotEmpty) { + box.clear(); + } + box.addAll(list); + } + + Future> getLocations() async { + IsolatedBox box = await IsolatedHive.openBox('TmpBox'); + var res = await box.values; + return res.toList(); + } +} diff --git a/packages/livestock/lib/data/model/local/live_tmp/car.dart b/packages/livestock/lib/data/model/local/live_tmp/car.dart deleted file mode 100644 index 19bb320..0000000 --- a/packages/livestock/lib/data/model/local/live_tmp/car.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:rasadyar_core/core.dart'; - - -part 'car.g.dart'; - - -@HiveType(typeId: 50) -class CarsLocal extends HiveObject { - @HiveField(0) - String? name; - - @HiveField(1) - String? price; - - CarsLocal({this.name, this.price}); - - factory CarsLocal.fromJson(Map json) { - return CarsLocal(name: json['name'] as String?, price: json['price'] as String?); - } - - Map toJson() { - return {'name': name, 'price': price}; - } -} - -class Cars { - String? name; - String? price; - - Cars({this.name, this.price}); - - factory Cars.fromJson(Map json) { - return Cars(name: json['name'] as String?, price: json['price'] as String?); - } - - Map toJson() { - return {'name': name, 'price': price}; - } -} diff --git a/packages/livestock/lib/data/model/local/location/tmp_locations.dart b/packages/livestock/lib/data/model/local/location/tmp_locations.dart new file mode 100644 index 0000000..f9413fd --- /dev/null +++ b/packages/livestock/lib/data/model/local/location/tmp_locations.dart @@ -0,0 +1,16 @@ +import 'package:rasadyar_core/core.dart'; + +part 'tmp_locations.g.dart'; + +@HiveType(typeId: 100) +class TmpLocations extends HiveObject{ + + @HiveField(0) + double? lat; + + + @HiveField(1) + double? long; + + TmpLocations({this.lat, this.long}); +} \ No newline at end of file diff --git a/packages/livestock/lib/data/model/local/live_tmp/car.g.dart b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart similarity index 63% rename from packages/livestock/lib/data/model/local/live_tmp/car.g.dart rename to packages/livestock/lib/data/model/local/location/tmp_locations.g.dart index 77d0985..2c70c49 100644 --- a/packages/livestock/lib/data/model/local/live_tmp/car.g.dart +++ b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart @@ -1,32 +1,34 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'car.dart'; +part of 'tmp_locations.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** -class CarsLocalAdapter extends TypeAdapter { +class TmpLocationsAdapter extends TypeAdapter { @override - final typeId = 50; + final typeId = 100; @override - CarsLocal read(BinaryReader reader) { + TmpLocations read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; - return CarsLocal(name: fields[0] as String?, price: fields[1] as String?); + return TmpLocations() + ..lat = (fields[0] as num?)?.toDouble() + ..long = (fields[1] as num?)?.toDouble(); } @override - void write(BinaryWriter writer, CarsLocal obj) { + void write(BinaryWriter writer, TmpLocations obj) { writer ..writeByte(2) ..writeByte(0) - ..write(obj.name) + ..write(obj.lat) ..writeByte(1) - ..write(obj.price); + ..write(obj.long); } @override @@ -35,7 +37,7 @@ class CarsLocalAdapter extends TypeAdapter { @override bool operator ==(Object other) => identical(this, other) || - other is CarsLocalAdapter && + other is TmpLocationsAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart index 7a1aaca..77b1954 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -1,6 +1,5 @@ +import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_livestock/data/model/response/address/address.dart'; -import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; -import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; abstract class LivestockRepository { @@ -11,4 +10,6 @@ abstract class LivestockRepository { Future createTaggingLiveStock({required LivestockData data}); +/* Future> getLocations(); + Future addLocations(List latList);*/ } diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart index 2911c6c..53d75d1 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -1,4 +1,9 @@ +import 'package:latlong2/latlong.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; +import 'package:rasadyar_livestock/data/data_source/local/tmp/tmp_local_data-source.dart'; import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; import 'package:rasadyar_livestock/data/model/response/address/address.dart'; import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; @@ -24,4 +29,35 @@ class LivestockRepositoryImp implements LivestockRepository { Future createTaggingLiveStock({required LivestockData data}) async { return await livestockRemote.createTaggingLiveStock(data: data); } +/* + @override + Future> getLocations() async { + if (NetworkStatus().isConnected.value) { + return [ + LatLng(35.824891, 50.948025), + LatLng(35.825000, 50.949000), + LatLng(35.823000, 50.947000), + LatLng(35.826000, 50.950000), + LatLng(35.827000, 50.951000), + LatLng(35.828000, 50.952000), + LatLng(35.829000, 50.953000), + LatLng(35.830000, 50.954000), + LatLng(35.831000, 50.955000), + LatLng(35.832000, 50.956000), + LatLng(35.832000, 50.956055), + ]; + } else { + *//*var res = await tmpLocalDataSource.getLocations(); + + return res.map((e) => LatLng(e.lat ?? 0.0, e.long ?? 0.0)).toList();*//* + } + } + + @override + Future addLocations(List latList) async { + *//* await tmpLocalDataSource.addLocations( + latList.map((e) => TmpLocations(lat: e.latitude, long: e.longitude)).toList(), + );*//* + iLog("it is done"); + }*/ } diff --git a/packages/livestock/lib/data/service/live_stock_storage_service.dart b/packages/livestock/lib/data/service/live_stock_storage_service.dart index 1d3e60a..35b5a3e 100644 --- a/packages/livestock/lib/data/service/live_stock_storage_service.dart +++ b/packages/livestock/lib/data/service/live_stock_storage_service.dart @@ -1,5 +1,4 @@ import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/data/model/local/live_tmp/car.dart'; import 'package:rasadyar_livestock/data/model/local/live_tmp/livestock_local_model.dart'; import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; import 'package:rasadyar_livestock/data/utils/mapper.dart'; @@ -7,7 +6,7 @@ import 'package:rasadyar_livestock/data/utils/mapper.dart'; class LiveStockStorageService extends GetxService { final String _liveStockBoxName = 'LiveStockBox'; late IsolatedBox _LiveStockbox; - late IsolatedBox _carbox; + @override void onInit() { diff --git a/packages/livestock/lib/hive_registrar.g.dart b/packages/livestock/lib/hive_registrar.g.dart index 715ff9e..a9f8f96 100644 --- a/packages/livestock/lib/hive_registrar.g.dart +++ b/packages/livestock/lib/hive_registrar.g.dart @@ -3,27 +3,27 @@ // Check in to version control import 'package:hive_ce/hive.dart'; -import 'package:rasadyar_livestock/data/model/local/live_tmp/car.dart'; import 'package:rasadyar_livestock/data/model/local/live_tmp/livestock_local_model.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; extension HiveRegistrar on HiveInterface { void registerAdapters() { - registerAdapter(CarsLocalAdapter()); registerAdapter(HerdLocalAdapter()); registerAdapter(LivestockLocalAdapter()); registerAdapter(LivestockLocalModelAdapter()); registerAdapter(LocationLocalAdapter()); registerAdapter(RancherLocalAdapter()); + registerAdapter(TmpLocationsAdapter()); } } extension IsolatedHiveRegistrar on IsolatedHiveInterface { void registerAdapters() { - registerAdapter(CarsLocalAdapter()); registerAdapter(HerdLocalAdapter()); registerAdapter(LivestockLocalAdapter()); registerAdapter(LivestockLocalModelAdapter()); registerAdapter(LocationLocalAdapter()); registerAdapter(RancherLocalAdapter()); + registerAdapter(TmpLocationsAdapter()); } } diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index eb099c9..fad3b19 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -20,7 +20,7 @@ Future setupLiveStockDI() async { IsolatedHive.registerAdapters(); iLog("Sssssssssssssssssssss"); final tokenService = Get.find(); - Get.put(LiveStockStorageService()); + if (tokenService.baseurl.value == null) { @@ -31,7 +31,7 @@ Future setupLiveStockDI() async { diLiveStock.registerLazySingleton( () => AppInterceptor( refreshTokenCallback: () async { - // Use lazy access to avoid circular dependency + /* // Use lazy access to avoid circular dependency final authRepository = diLiveStock.get(); final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { @@ -39,7 +39,7 @@ Future setupLiveStockDI() async { authRequest: {'refresh': tokenService.refreshToken.value}, ); return newToken?.access; - } + }*/ return null; }, saveTokenCallback: (String newToken) async { diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index 53575a7..4638752 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -2,7 +2,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; - +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository_imp.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; enum ErrorLocationType { serviceDisabled, permissionDenied, none } @@ -11,7 +14,6 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { String tileType = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; RxDouble currentZoom = 15.0.obs; - RxList allMarkers = [].obs; Rx mapController = MapController().obs; RxList errorLocationType = RxList(); @@ -19,19 +21,9 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; - RxList markerLocations = [ - LatLng(35.824891, 50.948025), - LatLng(35.825000, 50.949000), - LatLng(35.823000, 50.947000), - LatLng(35.826000, 50.950000), - LatLng(35.827000, 50.951000), - LatLng(35.828000, 50.952000), - LatLng(35.829000, 50.953000), - LatLng(35.830000, 50.954000), - LatLng(35.831000, 50.955000), - LatLng(35.832000, 50.956000), - LatLng(35.832000, 50.956055), - ].obs; + RxList markerLocations = RxList(); + RootLogic rootLogic = Get.find(); + late LivestockRepository repository ; @override void onInit() { @@ -67,6 +59,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { void onReady() { super.onReady(); determineCurrentPosition(); + // getLoc(); } @override @@ -158,5 +151,14 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { return rawMarkers.where((marker) => distance(center, marker) <= radiusInMeters).toList(); } - +/* Future getLoc() async { + await Future.delayed(Duration(seconds: 3)); + await safeCall( + call: () async => repository.getLocations(), + onSuccess: (result) { + markerLocations.addAll(result); + }, + onError: (error, stackTrace) {}, + ); + }*/ } diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart index 75eb4b7..5bbc67d 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; import 'logic.dart'; @@ -148,6 +149,16 @@ class MapWidget extends GetView { ); }, controller.currentLocation), + Positioned( + top: 15, + left: 20, + child: ObxValue((status) { + + + return Text("Connection: ${status.value}", style: TextStyle(fontSize: 20)); + }, NetworkStatus().isConnected), + ), + // Uncomment the following lines to enable the search widget /* Positioned( top: 10, diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 750671f..c39aa87 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,5 +1,11 @@ +import 'dart:async'; +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository_imp.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/page/map/view.dart'; import 'package:rasadyar_livestock/presentation/page/profile/view.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; @@ -28,10 +34,49 @@ class RootLogic extends GetxController { ]; RxInt currentIndex = 0.obs; - - TokenStorageService tokenService = Get.find(); + late StreamSubscription> connectivitySubscription; + RxList connectivityResults = [].obs; + + @override + void onInit() { + super.onInit(); + connectivitySubscription = Connectivity().onConnectivityChanged.listen((result) { + if (result.isNotEmpty) { + connectivityResults.assignAll(result); + } + }); + + /* GetIt.instance.allReady().then((value) async { + await diLiveStock.get().addLocations(generateRandomPoints()); + });*/ + } + + List generateRandomPoints() { + final Random random = Random(); + final double centerLat = 35.824891; + final double centerLon = 50.948025; + final double radiusKm = 1.0; + final double kmToDegLat = 1 / 111.0; // 1 km ≈ 0.009° latitude + final double kmToDegLon = 1 / (111.0 * cos(centerLat * pi / 180)); // Adjust for longitude + + List points = []; + for (int i = 0; i < 100; i++) { + // Generate random angle (0 to 2π) and random radius (0 to 1 km, using sqrt for uniform distribution) + double theta = random.nextDouble() * 2 * pi; + double r = + sqrt(random.nextDouble()) * radiusKm; // Square root for uniform distribution in circle + // Convert polar coordinates to Cartesian, then to LatLng + double deltaLat = r * cos(theta) * kmToDegLat; + double deltaLon = r * sin(theta) * kmToDegLon; + double newLat = centerLat + deltaLat; + double newLon = centerLon + deltaLon; + points.add(LatLng(newLat, newLon)); + } + return points; + } + @override void onReady() { // TODO: implement onReady @@ -40,7 +85,7 @@ class RootLogic extends GetxController { @override void onClose() { - // TODO: implement onClose + connectivitySubscription.cancel(); super.onClose(); } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 3544cef..4bba1e0 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -23,6 +23,7 @@ class RootPage extends GetView { final navigatorKey = Get.nestedKey(currentIndex); if (currentIndex.value == 0 && + navigatorKey != null && navigatorKey.currentState != null) { if (navigatorKey.currentState!.canPop()) { diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 411f5c0..6ff7302 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -14,6 +14,8 @@ import 'package:rasadyar_livestock/presentation/page/tagging/view.dart'; import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; import 'package:rasadyar_livestock/presentation/widgets/captcha/logic.dart'; +import '../../injection/live_stock_di.dart'; + part 'app_routes.dart'; sealed class LiveStockPages { diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml index 5b61757..ffa9508 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' # repository: https://github.com/my_org/my_repo environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: @@ -24,7 +24,7 @@ dev_dependencies: lints: ^6.0.0 test: ^1.25.15 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 json_serializable: ^6.10.0 diff --git a/pubspec.lock b/pubspec.lock index c98f20e..317ee5e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: android_intent_plus - sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.1" animated_stack_widget: dependency: transitive description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build - sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4" + sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -101,26 +101,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2" + sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d + sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62 + sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.3.0" built_collection: dependency: transitive description: @@ -201,6 +201,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -285,10 +301,10 @@ packages: dependency: transitive description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 url: "https://pub.dev" source: hosted - version: "5.8.0+1" + version: "5.9.0" dio_web_adapter: dependency: transitive description: @@ -541,14 +557,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: transitive - description: - name: font_awesome_flutter - sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a - url: "https://pub.dev" - source: hosted - version: "10.8.0" freezed: dependency: "direct dev" description: @@ -649,10 +657,10 @@ packages: dependency: transitive description: name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.2.0" get_test: dependency: "direct dev" description: @@ -777,66 +785,66 @@ packages: dependency: transitive description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -905,26 +913,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -1029,6 +1037,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" package_config: dependency: transitive description: @@ -1041,18 +1057,18 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.3.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" path: dependency: transitive description: @@ -1169,10 +1185,10 @@ packages: dependency: transitive description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: @@ -1418,10 +1434,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" time: dependency: transitive description: @@ -1490,10 +1506,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1591,5 +1607,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5472dd0..8c503e9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.3.6+4 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: @@ -36,7 +36,7 @@ dev_dependencies: sdk: flutter flutter_lints: ^6.0.0 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 json_serializable: ^6.10.0