diff --git a/example/pubspec.lock b/example/pubspec.lock index 6e96b6fa4..8d8dbaa3e 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: b1595874fbc8f7a50da90f5d8f327bb0bfd6a95dc906c390efe991540c3b54aa + sha256: "5fdcea390499dd26c808a3c662df5f4208d6bbc0643072eee94f1476249e2818" url: "https://pub.dev" source: hosted - version: "1.3.40" + version: "1.3.43" args: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: asn1lib - sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda" + sha256: "2ca377ad4d677bbadca278e0ba4da4e057b80a10b927bfc8f7d8bda8fe2ceb75" url: "https://pub.dev" source: hosted - version: "1.5.3" + version: "1.5.4" async: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" connectivity_plus: dependency: transitive description: @@ -229,66 +229,66 @@ packages: dependency: transitive description: name: firebase_core - sha256: "3187f4f8e49968573fd7403011dca67ba95aae419bc0d8131500fae160d94f92" + sha256: c7de9354eb2cd8bfe8059e1112174c9a58beda7051807207306bc48283277cfb url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.5.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: "3c3a1e92d6f4916c32deea79c4a7587aa0e9dbbe5889c7a16afcf005a485ee02" + sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.3.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: e8d1e22de72cb21cdcfc5eed7acddab3e99cd83f3b317f54f7a96c32f25fd11e + sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5 url: "https://pub.dev" source: hosted - version: "2.17.4" + version: "2.18.1" firebase_crashlytics: dependency: transitive description: name: firebase_crashlytics - sha256: "30260e1b8ad1464b41ca4531b44ce63d752daaf2f12c92ca6cdcd82b270abecc" + sha256: "7821f9d8373b91f2a5ca8214226891d5870e196a7376f66350f65204387e9c15" url: "https://pub.dev" source: hosted - version: "4.0.4" + version: "4.1.2" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: a75e1826d92ea4e86e4a753c7b5d64b844a362676fa653185f1581c859186d18 + sha256: "8ed539fd9e9b6c07905f9f44c5f6d4785ac841a5a8195bd35586c8b1d54ec26d" url: "https://pub.dev" source: hosted - version: "3.6.40" + version: "3.6.43" firebase_messaging: dependency: transitive description: name: firebase_messaging - sha256: "1b0a4f9ecbaf9007771bac152afad738ddfacc4b8431a7591c00829480d99553" + sha256: "32ce60b747e755b48d7112d728d4f736ba82acd98ec825626558d444d385fa3a" url: "https://pub.dev" source: hosted - version: "15.0.4" + version: "15.1.2" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: c5a6443e66ae064fe186901d740ee7ce648ca2a6fd0484b8c5e963849ac0fc28 + sha256: "69671a0f1a40c7b7c46ad0283e6f34ca2a59a0362ca14a240a4ea01c46e8a521" url: "https://pub.dev" source: hosted - version: "4.5.42" + version: "4.5.45" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: "232ef63b986467ae5b5577a09c2502b26e2e2aebab5b85e6c966a5ca9b038b89" + sha256: "6890111a9d01d7b13d0f6fe74850812c334e903d2c80a2d9356a3abb8c3a9e9a" url: "https://pub.dev" source: hosted - version: "3.8.12" + version: "3.9.1" fixnum: dependency: transitive description: @@ -354,10 +354,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" url: "https://pub.dev" source: hosted - version: "2.0.21" + version: "2.0.22" flutter_test: dependency: "direct dev" description: flutter @@ -436,10 +436,10 @@ packages: dependency: transitive description: name: geolocator_web - sha256: "7a22f400d831f924a89d931ba126a10e6b8b437f31e6b9311320435f3e1571bd" + sha256: "2ed69328e05cd94e7eb48bb0535f5fc0c0c44d1c4fa1e9737267484d05c29b5e" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.1" geolocator_windows: dependency: transitive description: @@ -468,10 +468,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.0" image_picker: dependency: transitive description: @@ -484,10 +484,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56" + sha256: c0a6763d50b354793d0192afd0a12560b823147d3ded7c6b77daf658fa05cc85 url: "https://pub.dev" source: hosted - version: "0.8.12+12" + version: "0.8.12+13" image_picker_for_web: dependency: transitive description: @@ -556,18 +556,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -628,18 +628,18 @@ packages: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" mime_type: dependency: transitive description: name: mime_type - sha256: "2ad6e67d3d2de9ac0f8ef5352d998fd103cb21351ae8c02fb0c78b079b37d275" + sha256: d652b613e84dac1af28030a9fba82c0999be05b98163f9e18a0849c6e63838bb url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" nm: dependency: transitive description: @@ -771,10 +771,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974 + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_foundation: dependency: transitive description: @@ -819,7 +819,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -848,10 +848,10 @@ packages: dependency: transitive description: name: sqflite_common - sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + sha256: "4058172e418eb7e7f2058dcb7657d451a8fc264afa0dea4dbd0f304a57131611" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.4+3" stack_trace: dependency: transitive description: @@ -872,18 +872,18 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" synchronized: dependency: transitive description: name: synchronized - sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + sha256: "51b08572b9f091f8c3eb4d9d4be253f196ff0075d5ec9b10a884026d5b55d7bc" url: "https://pub.dev" source: hosted - version: "3.1.0+1" + version: "3.3.0+2" term_glyph: dependency: transitive description: @@ -896,10 +896,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" timezone: dependency: transitive description: @@ -960,10 +960,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 + sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab url: "https://pub.dev" source: hosted - version: "6.3.9" + version: "6.3.10" url_launcher_ios: dependency: transitive description: @@ -1016,10 +1016,10 @@ packages: dependency: transitive description: name: uuid - sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" + sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77 url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.5.0" vector_math: dependency: transitive description: @@ -1032,34 +1032,34 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" web: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.0.0" webview_flutter: dependency: transitive description: name: webview_flutter - sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522" + sha256: ec81f57aa1611f8ebecf1d2259da4ef052281cb5ad624131c93546c79ccc7736 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.9.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: c66651fba15f9d7ddd31daec42da8d6bce46c85610a7127e3ebcb39a4395c3c9 + sha256: "6e64fcb1c19d92024da8f33503aaeeda35825d77142c01d0ea2aa32edc79fdc8" url: "https://pub.dev" source: hosted - version: "3.16.6" + version: "3.16.7" webview_flutter_platform_interface: dependency: transitive description: @@ -1072,10 +1072,10 @@ packages: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb" + sha256: "1942a12224ab31e9508cf00c0c6347b931b023b8a4f0811e5dec3b06f94f117d" url: "https://pub.dev" source: hosted - version: "3.14.0" + version: "3.15.0" xdg_directories: dependency: transitive description: @@ -1093,5 +1093,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/lib/model/places.dart b/lib/model/places.dart new file mode 100644 index 000000000..2ab20016b --- /dev/null +++ b/lib/model/places.dart @@ -0,0 +1,86 @@ +import 'package:flutter/cupertino.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'places.g.dart'; + +@JsonSerializable(explicitToJson: true, fieldRename: FieldRename.snake) +class Place { + String id; + String? name; + String? address; + List? imageUrls; + String? description; + double latitude; + double longitude; + UserPlace? userData; + List? types; + List? tags; + DateTime? dateCreated; + DateTime? dateUpdated; + + Place({ + required this.id, + this.name, + this.address, + this.imageUrls, + this.description, + required this.latitude, + required this.longitude, + this.userData, + this.types, + this.tags, + this.dateCreated, + this.dateUpdated, + }); + + factory Place.fromJson(Map json) => _$PlaceFromJson(json); + + Map toJson() => _$PlaceToJson(this); + + static List? listFromJson(List? jsonList) { + List? result; + if (jsonList != null) { + result = []; + for (dynamic jsonEntry in jsonList) { + try{ + Place place = Place.fromJson(jsonEntry); + result.add(place); + } + catch(e){ + debugPrint("Error decoding places list $e"); + } + } + } + return result; + } + + static List? listToJson(List? contentList) { + List? jsonList; + if (contentList != null) { + jsonList = []; + for (dynamic contentEntry in contentList) { + jsonList.add(contentEntry?.toJson()); + } + } + return jsonList; + } +} + +@JsonSerializable(explicitToJson: true, fieldRename: FieldRename.snake) +class UserPlace { + String id; + List? visited; + DateTime? dateCreated; + DateTime? dateUpdated; + + UserPlace({ + required this.id, + this.visited, + this.dateCreated, + this.dateUpdated, + }); + + factory UserPlace.fromJson(Map json) => _$UserPlaceFromJson(json); + + Map toJson() => _$UserPlaceToJson(this); +} diff --git a/lib/model/places.g.dart b/lib/model/places.g.dart new file mode 100644 index 000000000..666926e33 --- /dev/null +++ b/lib/model/places.g.dart @@ -0,0 +1,66 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'places.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Place _$PlaceFromJson(Map json) => Place( + id: json['id'] as String, + name: json['name'] as String?, + address: json['address'] as String?, + imageUrls: (json['image_urls'] as List?) + ?.map((e) => e as String) + .toList(), + description: json['description'] as String?, + latitude: (json['latitude'] as num).toDouble(), + longitude: (json['longitude'] as num).toDouble(), + userData: json['user_data'] == null + ? null + : UserPlace.fromJson(json['user_data'] as Map), + types: + (json['types'] as List?)?.map((e) => e as String).toList(), + tags: (json['tags'] as List?)?.map((e) => e as String).toList(), + dateCreated: json['date_created'] == null + ? null + : DateTime.parse(json['date_created'] as String), + dateUpdated: json['date_updated'] == null + ? null + : DateTime.parse(json['date_updated'] as String), + ); + +Map _$PlaceToJson(Place instance) => { + 'id': instance.id, + 'name': instance.name, + 'address': instance.address, + 'image_urls': instance.imageUrls, + 'description': instance.description, + 'latitude': instance.latitude, + 'longitude': instance.longitude, + 'user_data': instance.userData?.toJson(), + 'types': instance.types, + 'tags': instance.tags, + 'date_created': instance.dateCreated?.toIso8601String(), + 'date_updated': instance.dateUpdated?.toIso8601String(), + }; + +UserPlace _$UserPlaceFromJson(Map json) => UserPlace( + id: json['id'] as String, + visited: (json['visited'] as List?) + ?.map((e) => DateTime.parse(e as String)) + .toList(), + dateCreated: json['date_created'] == null + ? null + : DateTime.parse(json['date_created'] as String), + dateUpdated: json['date_updated'] == null + ? null + : DateTime.parse(json['date_updated'] as String), + ); + +Map _$UserPlaceToJson(UserPlace instance) => { + 'id': instance.id, + 'visited': instance.visited?.map((e) => e.toIso8601String()).toList(), + 'date_created': instance.dateCreated?.toIso8601String(), + 'date_updated': instance.dateUpdated?.toIso8601String(), + }; diff --git a/lib/service/config.dart b/lib/service/config.dart index f989a1ab1..86dffcced 100644 --- a/lib/service/config.dart +++ b/lib/service/config.dart @@ -522,6 +522,7 @@ class Config with Service, NetworkAuthProvider, NotificationsListener { String? get contentUrl => JsonUtils.stringValue(platformBuildingBlocks["content_url"]); String? get calendarUrl => JsonUtils.stringValue(platformBuildingBlocks["calendar_url"]); String? get surveysUrl => JsonUtils.stringValue(platformBuildingBlocks["surveys_url"]); + String? get placesUrl => JsonUtils.stringValue(platformBuildingBlocks["places_url"]); // Getters: otherUniversityServices String? get assetsUrl => JsonUtils.stringValue(otherUniversityServices['assets_url']); diff --git a/lib/service/places.dart b/lib/service/places.dart new file mode 100644 index 000000000..83a1971c8 --- /dev/null +++ b/lib/service/places.dart @@ -0,0 +1,135 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:rokwire_plugin/model/places.dart'; +import 'package:rokwire_plugin/utils/utils.dart'; +import 'auth2.dart'; +import 'config.dart'; +import 'network.dart'; + +class PlacesService { + static final PlacesService _instance = PlacesService._internal(); + + factory PlacesService() => _instance; + + PlacesService._internal(); + + /// Retrieves all places based on provided filters. + Future?> getAllPlaces({ + Set? ids, + Set? types, + Set? tags, + }) async { + Map queryParams = {}; + + if (ids != null && ids.isNotEmpty) queryParams['ids'] = ids.join(','); + if (types != null && types.isNotEmpty) queryParams['types'] = types.join(','); + if (tags != null && tags.isNotEmpty) queryParams['tags'] = tags.join(','); + + Uri uri; + try { + uri = Uri.parse('${Config().placesUrl}/places').replace(queryParameters: queryParams); + } catch (e) { + debugPrint('Failed to parse URI: $e'); + return null; + } + + try { + final response = await Network().get(uri.toString(), auth: Auth2()); + + if (response?.statusCode == 200) { + List? jsonList = JsonUtils.decodeList(response?.body); + if (jsonList != null) { + try { + return Place.listFromJson(jsonList); + } catch (e) { + debugPrint('Failed to parse places: $e'); + return null; + } + } else { + debugPrint('Failed to decode places list'); + return null; + } + } else { + debugPrint('Failed to load places: ${response?.statusCode} ${response?.body}'); + return null; + } + } catch (e) { + debugPrint('Network error while fetching places: $e'); + return null; + } + } + + /// Updates the 'visited' status of a place. + Future updatePlaceVisited(String id, bool visited) async { + Map queryParams = {'visited': visited.toString()}; + + Uri uri; + try { + uri = Uri.parse('${Config().placesUrl}/places/$id/visited').replace(queryParameters: queryParams); + } catch (e) { + debugPrint('Failed to parse URI: $e'); + return null; + } + + try { + final response = await Network().put( + uri.toString(), + headers: {'Content-Type': 'application/json'}, + auth: Auth2(), + ); + + if (response?.statusCode == 200) { + Map? jsonMap = JsonUtils.decodeMap(response?.body); + if (jsonMap != null) { + try { + return Place.fromJson(jsonMap); + } catch (e) { + debugPrint('Failed to parse place from JSON: $e'); + return null; + } + } else { + debugPrint('Failed to decode response body'); + return null; + } + } else { + debugPrint('Failed to update place visited status: ${response?.statusCode} ${response?.body}'); + return null; + } + } catch (e) { + debugPrint('Network error while updating place visited status: $e'); + return null; + } + } + + /// Deletes a visited place record. + Future deleteVisitedPlace(String id, DateTime visited) async { + Map queryParams = { + 'visited': visited.toIso8601String(), + }; + + Uri uri; + try { + uri = Uri.parse('${Config().placesUrl}/places/$id/visited').replace(queryParameters: queryParams); + } catch (e) { + debugPrint('Failed to parse URI: $e'); + return false; + } + + try { + final response = await Network().delete( + uri.toString(), + auth: Auth2(), + ); + + if (response?.statusCode == 200) { + return true; + } else { + debugPrint('Failed to delete visited place: ${response?.statusCode} ${response?.body}'); + return false; + } + } catch (e) { + debugPrint('Network error while deleting visited place: $e'); + return false; + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 8dfd849fe..39bd8cdb0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,11 +55,13 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^4.0.0 + json_serializable: ^6.8.0 + build_runner: ^2.4.12 # comment the override below if published plugin is used -dependency_overrides: - font_awesome_flutter: - path: plugins/font_awesome_flutter +#dependency_overrides: +# font_awesome_flutter: +# path: plugins/font_awesome_flutter # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec