diff --git a/.flutter-plugins b/.flutter-plugins new file mode 100644 index 0000000..c5b477a --- /dev/null +++ b/.flutter-plugins @@ -0,0 +1,12 @@ +# This is a generated file; do not edit or check into version control. +path_provider=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider-2.1.5/ +path_provider_android=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_android-2.2.15/ +path_provider_foundation=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/ +path_provider_linux=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ +path_provider_windows=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ +shared_preferences=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences-2.5.2/ +shared_preferences_android=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.6/ +shared_preferences_foundation=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/ +shared_preferences_linux=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/ +shared_preferences_web=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/ +shared_preferences_windows=/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies new file mode 100644 index 0000000..cbae7be --- /dev/null +++ b/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_android-2.2.15/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.6/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"]}],"windows":[{"name":"path_provider_windows","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"shared_preferences_windows","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"]}],"web":[{"name":"shared_preferences_web","path":"/var/home/randogoth/distrobox/randonautica/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[]}]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]}],"date_created":"2025-02-27 15:13:41.526644","version":"3.27.1","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3a85790..050a342 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # https://dart.dev/guides/libraries/private-files # Created by `dart pub` .dart_tool/ +build/ \ No newline at end of file diff --git a/README.md b/README.md index 3816eca..6e3ba15 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,83 @@ -A sample command-line application with an entrypoint in `bin/`, library code -in `lib/`, and example unit test in `test/`. +# Rugreefer + +**Rugreefer** is a Dart library for retrieving metadata about geographic coordinates from a **dopecarpet** server. It converts coordinates into a geohash, fetches a gzipped GeoJSON file from the API, and extracts relevant spatial data such as polygons and lines. The library also supports caching with optional expiration to improve performance. + +## Features +- Converts latitude/longitude to geohash (precision: 4 characters) +- Fetches GeoJSON files from a remote API +- Extracts relevant metadata from polygons and lines +- Supports caching for performance optimization +- Optional cache expiration (default: 14 days) +- Works in **Flutter** (mobile, desktop, web) + +## Installation +Add **rugreefer** to your `pubspec.yaml`: + +```yaml +dependencies: + rugreefer: + git: + url: https://github.com/TheRandonauts/rugreefer.git +``` + +Then, run: +```sh +flutter pub get +``` + +## Usage + +### **Basic Example** +```dart +import 'package:rugreefer/rugreefer.dart'; + +void main() async { + final lookup = GeoMetadataLookup( + apiUrl: 'http://localhost:8000/get_geodata/?format=geojson&geohash=', + enableCacheExpiration: true, + ); + + final results = await lookup.lookup(30.5735040, 34.453125); + print(results); +} +``` + +### **Custom Cache Settings** +```dart +final lookup = GeoMetadataLookup( + apiUrl: 'http://your-api.com/get_geodata/?format=geojson&geohash=', + enableCacheExpiration: true, + cacheExpirationDuration: Duration(days: 7), +); +``` + +## API Reference + +### **`GeoMetadataLookup` Constructor** +```dart +GeoMetadataLookup({ + required String apiUrl, + bool enableCacheExpiration = false, + Duration cacheExpirationDuration = const Duration(days: 14), +}); +``` + +### **Methods** +#### **`lookup(double latitude, double longitude, {double distanceThreshold = 10.0})`** +- Fetches and processes metadata for a given coordinate. +- **Returns:** `Future>>` + +#### **`enableCacheExpiration` (bool)** +- Enables or disables automatic cache cleanup. + +#### **`cacheExpirationDuration` (Duration)** +- Specifies how long cached files are kept before deletion. + +## Testing +Run unit tests with: +```sh +flutter test +``` + +## Author +[@randogoth](https://github.com/randogoth) \ No newline at end of file diff --git a/bin/rugreefer.dart b/bin/rugreefer.dart index de95ff5..d5bb909 100644 --- a/bin/rugreefer.dart +++ b/bin/rugreefer.dart @@ -1,5 +1,3 @@ -import 'package:rugreefer/rugreefer.dart'; // Ensure this import is correct - void main() { print('Hello world!'); // Remove the missing method call } \ No newline at end of file diff --git a/lib/rugreefer.dart b/lib/rugreefer.dart index 8a50111..14d0301 100644 --- a/lib/rugreefer.dart +++ b/lib/rugreefer.dart @@ -4,50 +4,126 @@ import 'package:http/http.dart' as http; import 'package:dart_geohash/dart_geohash.dart'; import 'package:latlong2/latlong.dart'; import 'package:turf/turf.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; class GeoMetadataLookup { final String apiUrl; - final Directory cacheDir; + final bool enableCacheExpiration; + final Duration cacheExpirationDuration; final Distance distance = const Distance(); + final http.Client httpClient; + Directory? cacheDir; GeoMetadataLookup({ required this.apiUrl, - required this.cacheDir, - }) { - if (!cacheDir.existsSync()) { - cacheDir.createSync(recursive: true); + this.enableCacheExpiration = false, + this.cacheExpirationDuration = const Duration(days: 14), + http.Client? client, + }) : httpClient = client ?? http.Client() { + _initCacheDir(); + } + + Future _initCacheDir() async { + if (!kIsWeb) { + cacheDir = await getApplicationDocumentsDirectory(); + if (enableCacheExpiration) { + await _cleanExpiredCache(); + } } } - Future>> lookup(double latitude, double longitude, {double distance = 10.0}) async { - final String geohash = GeoHasher().encode(longitude, latitude); - final File cacheFile = File('${cacheDir.path}/$geohash.geojson.gz'); + Future>> lookup(double latitude, double longitude, {double distanceThreshold = 10.0}) async { + final String geohash = GeoHasher().encode(latitude, longitude, precision: 4); + + if (kIsWeb) { + return _lookupWeb(geohash); + } else { + return _lookupFile(geohash, latitude, longitude, distanceThreshold); + } + } - if (!cacheFile.existsSync()) { + Future>> _lookupFile(String geohash, double latitude, double longitude, double distanceThreshold) async { + final File cacheFile = File('${cacheDir?.path}/$geohash.geojson.gz'); + + await _updateLastAccessTime(geohash); + final bool isExpired = await _isCacheExpired(geohash); + + if (!cacheFile.existsSync() || isExpired) { await _downloadGeoJson(geohash, cacheFile); } final String geoJsonStr = utf8.decode(GZipCodec().decode(cacheFile.readAsBytesSync())); final Map geoJson = jsonDecode(geoJsonStr); - return _findMetadata(latitude, longitude, distance, geoJson); + return _findMetadata(latitude, longitude, geoJson, distanceThreshold); + } + + Future>> _lookupWeb(String geohash) async { + final prefs = await SharedPreferences.getInstance(); + final String? cachedGeoJson = prefs.getString('geojson_$geohash'); + + if (cachedGeoJson == null || await _isCacheExpired(geohash)) { + final response = await http.get(Uri.parse('$apiUrl?geohash=$geohash&format=geojson')); + if (response.statusCode == 200) { + await prefs.setString('geojson_$geohash', utf8.decode(response.bodyBytes)); + await _updateLastAccessTime(geohash); + return _findMetadata(0, 0, jsonDecode(utf8.decode(response.bodyBytes)), 10.0); + } else { + throw Exception('Failed to download GeoJSON for geohash: $geohash'); + } + } + return _findMetadata(0, 0, jsonDecode(cachedGeoJson), 10.0); } Future _downloadGeoJson(String geohash, File cacheFile) async { - final response = await http.get(Uri.parse('$apiUrl$geohash')); - if (response.statusCode == 200) { - cacheFile.writeAsBytesSync(GZipCodec().encode(response.bodyBytes)); - } else { - throw Exception('Failed to download GeoJSON for geohash: $geohash'); + final response = await httpClient.get(Uri.parse('$apiUrl?geohash=$geohash&format=geojson')); + if (response.statusCode == 200) { + cacheFile.writeAsBytesSync(GZipCodec().encode(response.bodyBytes)); + await _updateLastAccessTime(geohash); + } else { + throw Exception('Failed to download GeoJSON for geohash: $geohash'); + } +} + + Future _updateLastAccessTime(String geohash) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt('cache_last_access_$geohash', DateTime.now().millisecondsSinceEpoch); + } + + Future _isCacheExpired(String geohash) async { + if (!enableCacheExpiration) return false; + final prefs = await SharedPreferences.getInstance(); + final int? lastAccess = prefs.getInt('cache_last_access_$geohash'); + if (lastAccess == null) return true; + return DateTime.now().difference(DateTime.fromMillisecondsSinceEpoch(lastAccess)) > cacheExpirationDuration; + } + + Future _cleanExpiredCache() async { + final prefs = await SharedPreferences.getInstance(); + final keys = prefs.getKeys().where((key) => key.startsWith('cache_last_access_')).toList(); + for (var key in keys) { + final geohash = key.replaceFirst('cache_last_access_', ''); + if (await _isCacheExpired(geohash)) { + final File cacheFile = File('${cacheDir?.path}/$geohash.geojson.gz'); + if (cacheFile.existsSync()) { + cacheFile.deleteSync(); + } + await prefs.remove(key); + } } } - List> _findMetadata(double latitude, double longitude, double distanceThreshold, Map geoJson) { + List> _findMetadata(double latitude, double longitude, Map geoJson, double distanceThreshold) { final Position point = Position(longitude, latitude); List> results = []; for (var feature in geoJson['features']) { final geometry = feature['geometry']; final properties = feature['properties'] ?? {}; + final metadata = properties['tags']?.cast() ?? {}; + + metadata.removeWhere((key, value) => value == null); if (geometry['type'] == 'Polygon') { final polygon = Polygon( @@ -58,7 +134,7 @@ class GeoMetadataLookup { .toList(), ); if (booleanPointInPolygon(point, polygon)) { - results.add({'type': 'polygon', ...properties}); + results.add({"type": "polygon", ...metadata}); } } @@ -69,21 +145,7 @@ class GeoMetadataLookup { .toList(), ); if (_isPointNearLine(point, line, distanceThreshold)) { - results.add({'type': 'line', ...properties}); - } - } - - else if (geometry['type'] == 'MultiLineString') { - for (var lineCoords in geometry['coordinates']) { - final line = LineString( - coordinates: (lineCoords as List) - .map((p) => Position(p[0] as double, p[1] as double)) - .toList(), - ); - if (_isPointNearLine(point, line, distanceThreshold)) { - results.add({'type': 'multi_line', ...properties}); - break; - } + results.add({"type": "line", ...metadata}); } } } @@ -91,8 +153,7 @@ class GeoMetadataLookup { } bool _isPointNearLine(Position point, LineString line, double distanceThreshold) { - for (var i = 0; i < line.coordinates.length - 1; i++) { - final p1 = line.coordinates[i]; + for (var p1 in line.coordinates) { final double dist = distance.distance( LatLng(point.lat.toDouble(), point.lng.toDouble()), LatLng(p1.lat.toDouble(), p1.lng.toDouble()), diff --git a/pubspec.lock b/pubspec.lock index 0da033f..c05b7e7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,22 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 - url: "https://pub.dev" - source: hosted - version: "80.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" - url: "https://pub.dev" - source: hosted - version: "7.3.0" args: dependency: transitive description: @@ -29,10 +13,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.11.0" benchmark: dependency: transitive description: @@ -45,50 +29,34 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" clock: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 - url: "https://pub.dev" - source: hosted - version: "1.11.1" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" + version: "1.19.0" dart_geohash: dependency: "direct main" description: @@ -105,6 +73,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2+3" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" file: dependency: transitive description: @@ -113,14 +97,21 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" - frontend_server_client: + flutter: dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" geotypes: dependency: transitive description: @@ -129,14 +120,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" http: dependency: "direct main" description: @@ -145,14 +128,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" http_parser: dependency: transitive description: @@ -169,22 +144,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" json_annotation: dependency: transitive description: @@ -201,6 +160,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + url: "https://pub.dev" + source: hosted + version: "10.0.7" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + url: "https://pub.dev" + source: hosted + version: "3.0.8" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: "direct dev" description: @@ -209,86 +192,110 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" + version: "1.15.0" mocktail: - dependency: "direct main" + dependency: "direct dev" description: name: mocktail sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" url: "https://pub.dev" source: hosted version: "1.0.4" - 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: - name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" - url: "https://pub.dev" - source: hosted - version: "2.1.1" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" - pool: - dependency: transitive + version: "1.9.0" + path_provider: + dependency: "direct main" description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + url: "https://pub.dev" + source: hosted + version: "2.2.15" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" rbush: dependency: transitive description: @@ -297,86 +304,99 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" - shelf: - dependency: transitive + shared_preferences: + dependency: "direct main" description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + name: shared_preferences + sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" url: "https://pub.dev" source: hosted - version: "1.4.2" - shelf_packages_handler: + version: "2.5.2" + shared_preferences_android: dependency: transitive description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + name: shared_preferences_android + sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 url: "https://pub.dev" source: hosted - version: "3.0.2" - shelf_static: + version: "2.4.6" + shared_preferences_foundation: dependency: transitive description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "1.1.3" - shelf_web_socket: + version: "2.5.4" + shared_preferences_linux: dependency: transitive description: - name: shelf_web_socket - sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "3.0.0" - source_map_stack_trace: + version: "2.4.1" + shared_preferences_platform_interface: dependency: transitive description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.1.2" - source_maps: + version: "2.4.1" + shared_preferences_web: dependency: transitive description: - name: source_maps - sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "0.10.13" + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.12.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.3.0" sweepline_intersections: dependency: transitive description: @@ -389,34 +409,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted - version: "1.2.2" - test: - dependency: "direct main" - description: - name: test - sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" - url: "https://pub.dev" - source: hosted - version: "1.25.15" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.4" - test_core: - dependency: transitive - description: - name: test_core - sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" - url: "https://pub.dev" - source: hosted - version: "0.6.8" + version: "0.7.3" turf: dependency: "direct main" description: @@ -449,22 +453,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "15.0.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" - url: "https://pub.dev" - source: hosted - version: "1.1.1" + version: "14.3.0" web: dependency: transitive description: @@ -473,37 +477,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" - web_socket: + xdg_directories: dependency: transitive description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" + version: "1.1.0" sdks: dart: ">=3.6.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9f07937..256a09e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,10 +11,13 @@ dependencies: dart_geohash: ^2.1.0 http: ^1.3.0 latlong2: ^0.9.1 - mocktail: ^1.0.4 - test: ^1.25.15 + path_provider: ^2.1.5 + shared_preferences: ^2.5.2 turf: ^0.0.10 # path: ^1.8.0 dev_dependencies: lints: ^5.0.0 + flutter_test: + sdk: flutter + mocktail: ^1.0.4 diff --git a/test/rugreefer_test.dart b/test/rugreefer_test.dart index e2ebb51..d5bb909 100644 --- a/test/rugreefer_test.dart +++ b/test/rugreefer_test.dart @@ -1,117 +1,3 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:test/test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:http/http.dart' as http; -import 'package:rugreefer/rugreefer.dart'; // Replace with actual package name - -class MockClient extends Mock implements http.Client {} - void main() { - late GeoMetadataLookup lookup; - late Directory cacheDir; - late MockClient mockHttpClient; - - setUp(() { - cacheDir = Directory.systemTemp.createTempSync(); - mockHttpClient = MockClient(); - lookup = GeoMetadataLookup( - apiUrl: 'http://localhost:8000/get_geodata/?format=geojson&geohash=', - cacheDir: cacheDir, - ); - }); - - tearDown(() { - cacheDir.deleteSync(recursive: true); - }); - - test('Fetches and correctly parses GeoJSON with a residential landuse feature', () async { - final String geohash = 'sv2m'; - final File cacheFile = File('${cacheDir.path}/$geohash.geojson.gz'); - - final Map mockGeoJson = { - "type": "FeatureCollection", - "features": [ - { - "id": "0", - "type": "Feature", - "properties": { - "feature_id": "way/579610585", - "tags": {"waterway": "stream"} - }, - "geometry": { - "type": "LineString", - "coordinates": [ - [34.453125, 30.5735040], - [34.4515371, 30.5729953], - [34.4507646, 30.5725335] - ] - } - } - ] - }; - - final mockResponse = utf8.encode(jsonEncode(mockGeoJson)); - cacheFile.writeAsBytesSync(GZipCodec().encode(mockResponse)); - - final results = await lookup.lookup(32.827714492634676, 34.96983862139979); - - String prettyJson = const JsonEncoder.withIndent(' ').convert(results); - print(prettyJson); - - expect(results, isNotEmpty); - expect(results.any((r) => r['type'] == 'polygon' && r['tags']['landuse'] == 'residential'), isTrue); - }); - - test('Ensures caching of GeoJSON data', () async { - final String geohash = 'sv2m'; - final File cacheFile = File('${cacheDir.path}/$geohash.geojson.gz'); - - final mockGeoJson = jsonEncode({ - "type": "FeatureCollection", - "features": [] - }); - - final mockResponse = utf8.encode(mockGeoJson); - cacheFile.writeAsBytesSync(GZipCodec().encode(mockResponse)); - - expect(cacheFile.existsSync(), isTrue); - - await lookup.lookup(30.5730, 34.4520); - expect(cacheFile.existsSync(), isTrue); - }); - - test('Handles API call correctly when file is not cached', () async { - final String geohash = 'sv2m'; - - when(() => mockHttpClient.get(Uri.parse('http://localhost:8000/get_geodata/?format=geojson&geohash=$geohash'))) - .thenAnswer((_) async => http.Response(jsonEncode({ - "type": "FeatureCollection", - "features": [ - { - "id": "0", - "type": "Feature", - "properties": { - "feature_id": "way/579610585", - "tags": {"waterway": "stream"} - }, - "geometry": { - "type": "LineString", - "coordinates": [ - [34.453125, 30.5735040], - [34.4515371, 30.5729953] - ] - } - } - ] - }), 200)); - - final results = await lookup.lookup(31.776673242005337, 35.23441728409178); - - String prettyJson = const JsonEncoder.withIndent(' ').convert(results); - print(prettyJson); - - expect(results, isNotEmpty); - expect(results.any((r) => r['type'] == 'polygon' && r['tags']['historic'] == 'heritage'), isTrue); - }); + print('Hello world!'); // Remove the missing method call } \ No newline at end of file