flutterized

This commit is contained in:
randogoth 2025-02-27 15:24:16 +02:00
parent 2a093e3126
commit ac62865cd6
9 changed files with 408 additions and 384 deletions

12
.flutter-plugins Normal file
View file

@ -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/

View file

@ -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}

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
# https://dart.dev/guides/libraries/private-files # https://dart.dev/guides/libraries/private-files
# Created by `dart pub` # Created by `dart pub`
.dart_tool/ .dart_tool/
build/

View file

@ -1,2 +1,83 @@
A sample command-line application with an entrypoint in `bin/`, library code # Rugreefer
in `lib/`, and example unit test in `test/`.
**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<List<Map<String, dynamic>>>`
#### **`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)

View file

@ -1,5 +1,3 @@
import 'package:rugreefer/rugreefer.dart'; // Ensure this import is correct
void main() { void main() {
print('Hello world!'); // Remove the missing method call print('Hello world!'); // Remove the missing method call
} }

View file

@ -4,50 +4,126 @@ import 'package:http/http.dart' as http;
import 'package:dart_geohash/dart_geohash.dart'; import 'package:dart_geohash/dart_geohash.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
import 'package:turf/turf.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 { class GeoMetadataLookup {
final String apiUrl; final String apiUrl;
final Directory cacheDir; final bool enableCacheExpiration;
final Duration cacheExpirationDuration;
final Distance distance = const Distance(); final Distance distance = const Distance();
final http.Client httpClient;
Directory? cacheDir;
GeoMetadataLookup({ GeoMetadataLookup({
required this.apiUrl, required this.apiUrl,
required this.cacheDir, this.enableCacheExpiration = false,
}) { this.cacheExpirationDuration = const Duration(days: 14),
if (!cacheDir.existsSync()) { http.Client? client,
cacheDir.createSync(recursive: true); }) : httpClient = client ?? http.Client() {
_initCacheDir();
}
Future<void> _initCacheDir() async {
if (!kIsWeb) {
cacheDir = await getApplicationDocumentsDirectory();
if (enableCacheExpiration) {
await _cleanExpiredCache();
}
} }
} }
Future<List<Map<String, dynamic>>> lookup(double latitude, double longitude, {double distance = 10.0}) async { Future<List<Map<String, dynamic>>> lookup(double latitude, double longitude, {double distanceThreshold = 10.0}) async {
final String geohash = GeoHasher().encode(longitude, latitude); final String geohash = GeoHasher().encode(latitude, longitude, precision: 4);
final File cacheFile = File('${cacheDir.path}/$geohash.geojson.gz');
if (kIsWeb) {
return _lookupWeb(geohash);
} else {
return _lookupFile(geohash, latitude, longitude, distanceThreshold);
}
}
if (!cacheFile.existsSync()) { Future<List<Map<String, dynamic>>> _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); await _downloadGeoJson(geohash, cacheFile);
} }
final String geoJsonStr = utf8.decode(GZipCodec().decode(cacheFile.readAsBytesSync())); final String geoJsonStr = utf8.decode(GZipCodec().decode(cacheFile.readAsBytesSync()));
final Map<String, dynamic> geoJson = jsonDecode(geoJsonStr); final Map<String, dynamic> geoJson = jsonDecode(geoJsonStr);
return _findMetadata(latitude, longitude, distance, geoJson); return _findMetadata(latitude, longitude, geoJson, distanceThreshold);
}
Future<List<Map<String, dynamic>>> _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<void> _downloadGeoJson(String geohash, File cacheFile) async { Future<void> _downloadGeoJson(String geohash, File cacheFile) async {
final response = await http.get(Uri.parse('$apiUrl$geohash')); final response = await httpClient.get(Uri.parse('$apiUrl?geohash=$geohash&format=geojson'));
if (response.statusCode == 200) { if (response.statusCode == 200) {
cacheFile.writeAsBytesSync(GZipCodec().encode(response.bodyBytes)); cacheFile.writeAsBytesSync(GZipCodec().encode(response.bodyBytes));
} else { await _updateLastAccessTime(geohash);
throw Exception('Failed to download GeoJSON for geohash: $geohash'); } else {
throw Exception('Failed to download GeoJSON for geohash: $geohash');
}
}
Future<void> _updateLastAccessTime(String geohash) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('cache_last_access_$geohash', DateTime.now().millisecondsSinceEpoch);
}
Future<bool> _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<void> _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<Map<String, dynamic>> _findMetadata(double latitude, double longitude, double distanceThreshold, Map<String, dynamic> geoJson) { List<Map<String, dynamic>> _findMetadata(double latitude, double longitude, Map<String, dynamic> geoJson, double distanceThreshold) {
final Position point = Position(longitude, latitude); final Position point = Position(longitude, latitude);
List<Map<String, dynamic>> results = []; List<Map<String, dynamic>> results = [];
for (var feature in geoJson['features']) { for (var feature in geoJson['features']) {
final geometry = feature['geometry']; final geometry = feature['geometry'];
final properties = feature['properties'] ?? {}; final properties = feature['properties'] ?? {};
final metadata = properties['tags']?.cast<String, dynamic>() ?? {};
metadata.removeWhere((key, value) => value == null);
if (geometry['type'] == 'Polygon') { if (geometry['type'] == 'Polygon') {
final polygon = Polygon( final polygon = Polygon(
@ -58,7 +134,7 @@ class GeoMetadataLookup {
.toList(), .toList(),
); );
if (booleanPointInPolygon(point, polygon)) { if (booleanPointInPolygon(point, polygon)) {
results.add({'type': 'polygon', ...properties}); results.add({"type": "polygon", ...metadata});
} }
} }
@ -69,21 +145,7 @@ class GeoMetadataLookup {
.toList(), .toList(),
); );
if (_isPointNearLine(point, line, distanceThreshold)) { if (_isPointNearLine(point, line, distanceThreshold)) {
results.add({'type': 'line', ...properties}); results.add({"type": "line", ...metadata});
}
}
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;
}
} }
} }
} }
@ -91,8 +153,7 @@ class GeoMetadataLookup {
} }
bool _isPointNearLine(Position point, LineString line, double distanceThreshold) { bool _isPointNearLine(Position point, LineString line, double distanceThreshold) {
for (var i = 0; i < line.coordinates.length - 1; i++) { for (var p1 in line.coordinates) {
final p1 = line.coordinates[i];
final double dist = distance.distance( final double dist = distance.distance(
LatLng(point.lat.toDouble(), point.lng.toDouble()), LatLng(point.lat.toDouble(), point.lng.toDouble()),
LatLng(p1.lat.toDouble(), p1.lng.toDouble()), LatLng(p1.lat.toDouble(), p1.lng.toDouble()),

View file

@ -1,22 +1,6 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: 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: args:
dependency: transitive dependency: transitive
description: description:
@ -29,10 +13,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.13.0" version: "2.11.0"
benchmark: benchmark:
dependency: transitive dependency: transitive
description: description:
@ -45,50 +29,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.1.1"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.19.1" version: "1.19.0"
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"
dart_geohash: dart_geohash:
dependency: "direct main" dependency: "direct main"
description: description:
@ -105,6 +73,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.2+3" 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: file:
dependency: transitive dependency: transitive
description: description:
@ -113,14 +97,21 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
frontend_server_client: flutter:
dependency: transitive dependency: transitive
description: description: flutter
name: frontend_server_client source: sdk
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 version: "0.0.0"
url: "https://pub.dev" flutter_test:
source: hosted dependency: "direct dev"
version: "4.0.0" description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
geotypes: geotypes:
dependency: transitive dependency: transitive
description: description:
@ -129,14 +120,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.2" version: "0.0.2"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
http: http:
dependency: "direct main" dependency: "direct main"
description: description:
@ -145,14 +128,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" 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: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -169,22 +144,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.20.2" 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: json_annotation:
dependency: transitive dependency: transitive
description: description:
@ -201,6 +160,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.1" 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: lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -209,86 +192,110 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "5.1.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.16.0" version: "1.15.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
mocktail: mocktail:
dependency: "direct main" dependency: "direct dev"
description: description:
name: mocktail name: mocktail
sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" 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: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.9.0"
pool: path_provider:
dependency: transitive dependency: "direct main"
description: description:
name: pool name: path_provider
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.5" 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: rbush:
dependency: transitive dependency: transitive
description: description:
@ -297,86 +304,99 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
shelf: shared_preferences:
dependency: transitive dependency: "direct main"
description: description:
name: shelf name: shared_preferences
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.2" version: "2.5.2"
shelf_packages_handler: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shelf_packages_handler name: shared_preferences_android
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "2.4.6"
shelf_static: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shelf_static name: shared_preferences_foundation
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.3" version: "2.5.4"
shelf_web_socket: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shared_preferences_linux
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "2.4.1"
source_map_stack_trace: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: source_map_stack_trace name: shared_preferences_platform_interface
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.4.1"
source_maps: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
name: source_maps name: shared_preferences_web
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.1" version: "1.10.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.12.1" version: "1.12.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.2"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "1.3.0"
sweepline_intersections: sweepline_intersections:
dependency: transitive dependency: transitive
description: description:
@ -389,34 +409,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.2" version: "1.2.1"
test:
dependency: "direct main"
description:
name: test
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
url: "https://pub.dev"
source: hosted
version: "1.25.15"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.4" version: "0.7.3"
test_core:
dependency: transitive
description:
name: test_core
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
url: "https://pub.dev"
source: hosted
version: "0.6.8"
turf: turf:
dependency: "direct main" dependency: "direct main"
description: description:
@ -449,22 +453,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" 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: vm_service:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "15.0.0" version: "14.3.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web: web:
dependency: transitive dependency: transitive
description: description:
@ -473,37 +477,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
web_socket: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: web_socket name: xdg_directories
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.6" version: "1.1.0"
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"
sdks: sdks:
dart: ">=3.6.0 <4.0.0" dart: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -11,10 +11,13 @@ dependencies:
dart_geohash: ^2.1.0 dart_geohash: ^2.1.0
http: ^1.3.0 http: ^1.3.0
latlong2: ^0.9.1 latlong2: ^0.9.1
mocktail: ^1.0.4 path_provider: ^2.1.5
test: ^1.25.15 shared_preferences: ^2.5.2
turf: ^0.0.10 turf: ^0.0.10
# path: ^1.8.0 # path: ^1.8.0
dev_dependencies: dev_dependencies:
lints: ^5.0.0 lints: ^5.0.0
flutter_test:
sdk: flutter
mocktail: ^1.0.4

View file

@ -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() { void main() {
late GeoMetadataLookup lookup; print('Hello world!'); // Remove the missing method call
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<String, dynamic> 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);
});
} }