Load map places from backend
All checks were successful
Build and deploy Flutter Web / build (push) Successful in 3m26s
All checks were successful
Build and deploy Flutter Web / build (push) Successful in 3m26s
This commit is contained in:
141
lib/api/mapflow_api.dart
Normal file
141
lib/api/mapflow_api.dart
Normal file
@@ -0,0 +1,141 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import '../models/place_models.dart';
|
||||
|
||||
class MapflowApi {
|
||||
MapflowApi({
|
||||
http.Client? client,
|
||||
String endpoint = const String.fromEnvironment(
|
||||
'API_BASE_URL',
|
||||
defaultValue: '/graphql',
|
||||
),
|
||||
}) : _client = client ?? http.Client(),
|
||||
_endpoint = Uri.base.resolve(endpoint);
|
||||
|
||||
final http.Client _client;
|
||||
final Uri _endpoint;
|
||||
|
||||
Future<List<PlaceRecommendation>> fetchPlaces() async {
|
||||
final data = await _graphql('''
|
||||
query Places {
|
||||
places {
|
||||
id
|
||||
googlePlaceId
|
||||
name
|
||||
latitude
|
||||
longitude
|
||||
experiences {
|
||||
id
|
||||
status
|
||||
analysis
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
final places = data['places'] as List<dynamic>;
|
||||
return places.map((item) {
|
||||
final place = item as Map<String, dynamic>;
|
||||
return PlaceRecommendation(
|
||||
id: place['id'] as String,
|
||||
name: place['name'] as String,
|
||||
area: '',
|
||||
photoUrls: const [],
|
||||
coordinate: LatLng(
|
||||
(place['latitude'] as num).toDouble(),
|
||||
(place['longitude'] as num).toDouble(),
|
||||
),
|
||||
traits: _traitsFromExperiences(place['experiences'] as List<dynamic>),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Future<void> createVoiceExperience({
|
||||
required String googlePlaceId,
|
||||
required String googleName,
|
||||
required LatLng coordinate,
|
||||
required int durationSeconds,
|
||||
required String audioObjectKey,
|
||||
}) async {
|
||||
await _graphql(
|
||||
'''
|
||||
mutation CreateVoiceExperience(\$input: CreateVoiceExperienceInput!) {
|
||||
createVoiceExperience(input: \$input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
''',
|
||||
variables: {
|
||||
'input': {
|
||||
'googlePlaceId': googlePlaceId,
|
||||
'googleName': googleName,
|
||||
'latitude': coordinate.latitude,
|
||||
'longitude': coordinate.longitude,
|
||||
'durationSeconds': durationSeconds,
|
||||
'audioObjectKey': audioObjectKey,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _graphql(
|
||||
String query, {
|
||||
Map<String, dynamic>? variables,
|
||||
}) async {
|
||||
final response = await _client.post(
|
||||
_endpoint,
|
||||
headers: const {'content-type': 'application/json'},
|
||||
body: jsonEncode({'query': query, 'variables': variables ?? {}}),
|
||||
);
|
||||
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
throw StateError('GraphQL request failed with ${response.statusCode}.');
|
||||
}
|
||||
|
||||
final payload = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
final errors = payload['errors'];
|
||||
if (errors is List && errors.isNotEmpty) {
|
||||
throw StateError(jsonEncode(errors));
|
||||
}
|
||||
|
||||
return payload['data'] as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
Set<PlaceTrait> _traitsFromExperiences(List<dynamic> experiences) {
|
||||
final traits = <PlaceTrait>{};
|
||||
for (final item in experiences) {
|
||||
final experience = item as Map<String, dynamic>;
|
||||
final analysis = experience['analysis'];
|
||||
if (analysis is! Map<String, dynamic>) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final tags = analysis['tags'];
|
||||
if (tags is! List) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final tag in tags) {
|
||||
final trait = _traitByName(tag.toString());
|
||||
if (trait != null) {
|
||||
traits.add(trait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return traits;
|
||||
}
|
||||
|
||||
PlaceTrait? _traitByName(String name) {
|
||||
for (final trait in PlaceTrait.values) {
|
||||
if (trait.name == name) {
|
||||
return trait;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user