All checks were successful
Build and deploy Flutter Web / build (push) Successful in 3m26s
142 lines
3.5 KiB
Dart
142 lines
3.5 KiB
Dart
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;
|
|
}
|
|
}
|