This commit is contained in:
@@ -28,7 +28,7 @@ jobs:
|
||||
--tag "$IMAGE_SHA" \
|
||||
--tag "$IMAGE_LATEST" \
|
||||
--build-arg MAPBOX_ACCESS_TOKEN="${{ secrets.MAPBOX_ACCESS_TOKEN }}" \
|
||||
--build-arg MAPBOX_STYLE="mapbox/streets-v12" \
|
||||
--build-arg MAPBOX_STYLE="mapbox/standard" \
|
||||
--build-arg TELEGRAM_BOT_USERNAME="carfteebot" \
|
||||
--build-arg BUILD_VERSION="${GITHUB_SHA}" \
|
||||
. &&
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
FROM ghcr.io/cirruslabs/flutter:stable AS build
|
||||
WORKDIR /app
|
||||
ARG MAPBOX_ACCESS_TOKEN=""
|
||||
ARG MAPBOX_STYLE="mapbox/streets-v12"
|
||||
ARG MAPBOX_STYLE="mapbox/standard"
|
||||
ARG TELEGRAM_BOT_USERNAME="carfteebot"
|
||||
ARG BUILD_VERSION="local"
|
||||
COPY pubspec.* ./
|
||||
|
||||
@@ -65,7 +65,7 @@ class PlaceState {
|
||||
return place;
|
||||
}
|
||||
}
|
||||
return visiblePlaces.isEmpty ? null : visiblePlaces.first;
|
||||
return null;
|
||||
}
|
||||
|
||||
PlaceState copyWith({
|
||||
@@ -165,7 +165,7 @@ class PlaceCubit extends Cubit<PlaceViewState> {
|
||||
PlaceState(
|
||||
selectedTrait: null,
|
||||
places: places,
|
||||
selectedPlaceId: places.isEmpty ? null : places.first.id,
|
||||
selectedPlaceId: null,
|
||||
currentUser: currentUser,
|
||||
hasTelegramAuth: _authRepository.hasTelegramAuth,
|
||||
userCoordinate: null,
|
||||
@@ -201,10 +201,9 @@ class PlaceCubit extends Cubit<PlaceViewState> {
|
||||
|
||||
void clearTrait() {
|
||||
final value = _requireReady();
|
||||
final selectedPlaceId = value.places.isEmpty ? null : value.places.first.id;
|
||||
emit(
|
||||
PlaceViewState.ready(
|
||||
value.copyWith(selectedTrait: null, selectedPlaceId: selectedPlaceId),
|
||||
value.copyWith(selectedTrait: null, selectedPlaceId: null),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -337,12 +336,11 @@ class PlaceCubit extends Cubit<PlaceViewState> {
|
||||
);
|
||||
|
||||
final places = await _placesRepository.fetchPlaces();
|
||||
final selectedPlace = places.isEmpty ? null : places.first.id;
|
||||
emit(
|
||||
PlaceViewState.ready(
|
||||
value.copyWith(
|
||||
places: places,
|
||||
selectedPlaceId: selectedPlace,
|
||||
selectedPlaceId: null,
|
||||
reviewDraft: _emptyDraft,
|
||||
voiceFilterTranscript: '',
|
||||
voiceFilterTags: const [],
|
||||
|
||||
@@ -4,10 +4,10 @@ import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:latlong2/latlong.dart' hide Path;
|
||||
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mbx;
|
||||
import 'package:waveform_flutter/waveform_flutter.dart' show Amplitude;
|
||||
import 'package:waveform_recorder/waveform_recorder.dart';
|
||||
|
||||
@@ -21,10 +21,9 @@ import '../data/places_repository.dart';
|
||||
import '../domain/place_models.dart';
|
||||
import 'widgets/place_photo_card.dart';
|
||||
|
||||
const _mapboxAccessToken = String.fromEnvironment('MAPBOX_ACCESS_TOKEN');
|
||||
const _mapboxStyle = String.fromEnvironment(
|
||||
'MAPBOX_STYLE',
|
||||
defaultValue: 'mapbox/streets-v12',
|
||||
defaultValue: 'mapbox/standard',
|
||||
);
|
||||
|
||||
class MapflowShell extends StatelessWidget {
|
||||
@@ -51,18 +50,24 @@ class MapflowShell extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _MapContent extends StatelessWidget {
|
||||
class _MapContent extends StatefulWidget {
|
||||
const _MapContent({required this.state});
|
||||
|
||||
static const _fallbackCenter = LatLng(10.7718, 106.6982);
|
||||
|
||||
final PlaceState state;
|
||||
|
||||
@override
|
||||
State<_MapContent> createState() => _MapContentState();
|
||||
}
|
||||
|
||||
class _MapContentState extends State<_MapContent> {
|
||||
static const _fallbackCenter = LatLng(16.0544, 108.2022);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = widget.state;
|
||||
final selected = state.selectedPlace;
|
||||
final userCoordinate = state.userCoordinate;
|
||||
final mapCenter = userCoordinate ?? selected?.coordinate ?? _fallbackCenter;
|
||||
final mapCenter = _focusCenter(state) ?? _fallbackCenter;
|
||||
final placeCubit = context.read<PlaceCubit>();
|
||||
final traitCounts = _countPlaceTraits(state.places);
|
||||
final availableTraits = [
|
||||
@@ -81,38 +86,13 @@ class _MapContent extends StatelessWidget {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
FlutterMap(
|
||||
options: MapOptions(
|
||||
initialCenter: mapCenter,
|
||||
initialZoom: 14.2,
|
||||
minZoom: 3,
|
||||
maxZoom: 18,
|
||||
),
|
||||
children: [
|
||||
const _BaseMapTileLayer(),
|
||||
MarkerLayer(
|
||||
markers: [
|
||||
for (final place in state.recommendations)
|
||||
Marker(
|
||||
width: 52,
|
||||
height: 52,
|
||||
point: place.coordinate,
|
||||
child: _PlaceMarker(
|
||||
selected: selected?.id == place.id,
|
||||
onTap: () => _selectAndShowPlace(context, place),
|
||||
),
|
||||
),
|
||||
if (userCoordinate != null)
|
||||
Marker(
|
||||
width: 30,
|
||||
height: 30,
|
||||
point: userCoordinate,
|
||||
child: const _UserLocationMarker(),
|
||||
),
|
||||
],
|
||||
),
|
||||
const _MapAttribution(),
|
||||
],
|
||||
_MapboxMapLayer(
|
||||
initialCenter: mapCenter,
|
||||
focusCenter: _focusCenter(state),
|
||||
places: state.recommendations,
|
||||
selectedPlaceId: selected?.id,
|
||||
userCoordinate: userCoordinate,
|
||||
onPlaceTap: (place) => _selectAndShowPlace(context, place),
|
||||
),
|
||||
SafeArea(
|
||||
child: Align(
|
||||
@@ -183,6 +163,10 @@ class _MapContent extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
LatLng? _focusCenter(PlaceState state) {
|
||||
return state.userCoordinate ?? state.selectedPlace?.coordinate;
|
||||
}
|
||||
|
||||
Future<void> _openSearchSheet(
|
||||
BuildContext context, {
|
||||
required List<PlaceTrait> traits,
|
||||
@@ -314,6 +298,169 @@ class _UserLocationMarker extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _ProjectedMarker {
|
||||
const _ProjectedMarker({required this.place, required this.offset});
|
||||
|
||||
final PlaceRecommendation place;
|
||||
final Offset offset;
|
||||
}
|
||||
|
||||
class _MapboxMapLayer extends StatefulWidget {
|
||||
const _MapboxMapLayer({
|
||||
required this.initialCenter,
|
||||
required this.focusCenter,
|
||||
required this.places,
|
||||
required this.selectedPlaceId,
|
||||
required this.userCoordinate,
|
||||
required this.onPlaceTap,
|
||||
});
|
||||
|
||||
final LatLng initialCenter;
|
||||
final LatLng? focusCenter;
|
||||
final List<PlaceRecommendation> places;
|
||||
final String? selectedPlaceId;
|
||||
final LatLng? userCoordinate;
|
||||
final ValueChanged<PlaceRecommendation> onPlaceTap;
|
||||
|
||||
@override
|
||||
State<_MapboxMapLayer> createState() => _MapboxMapLayerState();
|
||||
}
|
||||
|
||||
class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
||||
mbx.MapboxMap? _mapboxMap;
|
||||
var _mapLoaded = false;
|
||||
var _didInitialFlyIn = false;
|
||||
var _projectionVersion = 0;
|
||||
LatLng? _lastFocusCenter;
|
||||
List<_ProjectedMarker> _projectedPlaces = const [];
|
||||
Offset? _projectedUserCoordinate;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant _MapboxMapLayer oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_updateCameraForFocus();
|
||||
unawaited(_projectMarkers());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
mbx.MapWidget(
|
||||
styleUri: _mapboxStyleUri,
|
||||
viewport: mbx.CameraViewportState(
|
||||
center: _mapboxPoint(widget.initialCenter),
|
||||
zoom: _didInitialFlyIn ? 14.8 : 1.25,
|
||||
bearing: _didInitialFlyIn ? -16 : 0,
|
||||
pitch: _didInitialFlyIn ? 62 : 0,
|
||||
),
|
||||
onMapCreated: _onMapCreated,
|
||||
onMapLoadedListener: (_) {
|
||||
_mapLoaded = true;
|
||||
_updateCameraForFocus();
|
||||
unawaited(_projectMarkers());
|
||||
},
|
||||
onCameraChangeListener: (_) => unawaited(_projectMarkers()),
|
||||
onMapIdleListener: (_) => unawaited(_projectMarkers()),
|
||||
),
|
||||
for (final projected in _projectedPlaces)
|
||||
Positioned(
|
||||
left: projected.offset.dx - 26,
|
||||
top: projected.offset.dy - 26,
|
||||
width: 52,
|
||||
height: 52,
|
||||
child: _PlaceMarker(
|
||||
selected: projected.place.id == widget.selectedPlaceId,
|
||||
onTap: () => widget.onPlaceTap(projected.place),
|
||||
),
|
||||
),
|
||||
if (_projectedUserCoordinate != null)
|
||||
Positioned(
|
||||
left: _projectedUserCoordinate!.dx - 15,
|
||||
top: _projectedUserCoordinate!.dy - 15,
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: const _UserLocationMarker(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onMapCreated(mbx.MapboxMap mapboxMap) {
|
||||
_mapboxMap = mapboxMap;
|
||||
}
|
||||
|
||||
void _updateCameraForFocus() {
|
||||
final mapboxMap = _mapboxMap;
|
||||
final focusCenter = widget.focusCenter;
|
||||
if (!_mapLoaded || mapboxMap == null || focusCenter == null) {
|
||||
return;
|
||||
}
|
||||
if (focusCenter == _lastFocusCenter) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastFocusCenter = focusCenter;
|
||||
final camera = mbx.CameraOptions(
|
||||
center: _mapboxPoint(focusCenter),
|
||||
zoom: 14.8,
|
||||
bearing: -16,
|
||||
pitch: 62,
|
||||
);
|
||||
if (_didInitialFlyIn) {
|
||||
unawaited(
|
||||
mapboxMap.easeTo(camera, mbx.MapAnimationOptions(duration: 900)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_didInitialFlyIn = true;
|
||||
unawaited(mapboxMap.flyTo(camera, mbx.MapAnimationOptions(duration: 2600)));
|
||||
}
|
||||
|
||||
Future<void> _projectMarkers() async {
|
||||
final mapboxMap = _mapboxMap;
|
||||
if (!_mapLoaded || mapboxMap == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final version = ++_projectionVersion;
|
||||
final coordinates = [
|
||||
for (final place in widget.places) _mapboxPoint(place.coordinate),
|
||||
if (widget.userCoordinate != null) _mapboxPoint(widget.userCoordinate!),
|
||||
];
|
||||
if (coordinates.isEmpty) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_projectedPlaces = const [];
|
||||
_projectedUserCoordinate = null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
final pixels = await mapboxMap.pixelsForCoordinates(coordinates);
|
||||
if (!mounted || version != _projectionVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_projectedPlaces = [
|
||||
for (var index = 0; index < widget.places.length; index++)
|
||||
_ProjectedMarker(
|
||||
place: widget.places[index],
|
||||
offset: Offset(pixels[index].x, pixels[index].y),
|
||||
),
|
||||
];
|
||||
_projectedUserCoordinate = widget.userCoordinate == null
|
||||
? null
|
||||
: Offset(pixels.last.x, pixels.last.y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _UserAvatar extends StatelessWidget {
|
||||
const _UserAvatar({
|
||||
required this.user,
|
||||
@@ -916,12 +1063,13 @@ class _MapError extends StatelessWidget {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
FlutterMap(
|
||||
options: const MapOptions(
|
||||
initialCenter: LatLng(10.7718, 106.6982),
|
||||
initialZoom: 14.2,
|
||||
),
|
||||
children: [const _BaseMapTileLayer(), const _MapAttribution()],
|
||||
const _MapboxMapLayer(
|
||||
initialCenter: LatLng(16.0544, 108.2022),
|
||||
focusCenter: LatLng(16.0544, 108.2022),
|
||||
places: [],
|
||||
selectedPlaceId: null,
|
||||
userCoordinate: null,
|
||||
onPlaceTap: _ignorePlaceTap,
|
||||
),
|
||||
SafeArea(
|
||||
child: Align(
|
||||
@@ -944,50 +1092,22 @@ class _MapError extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _BaseMapTileLayer extends StatelessWidget {
|
||||
const _BaseMapTileLayer();
|
||||
void _ignorePlaceTap(PlaceRecommendation _) {}
|
||||
|
||||
static const _osmUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_mapboxAccessToken.isEmpty) {
|
||||
return TileLayer(
|
||||
urlTemplate: _osmUrl,
|
||||
userAgentPackageName: 'com.mapflow.app',
|
||||
);
|
||||
}
|
||||
|
||||
return TileLayer(
|
||||
urlTemplate:
|
||||
'https://api.mapbox.com/styles/v1/$_mapboxStyle/tiles/512/{z}/{x}/{y}@2x'
|
||||
'?access_token=$_mapboxAccessToken',
|
||||
tileDimension: 512,
|
||||
zoomOffset: -1,
|
||||
maxNativeZoom: 22,
|
||||
userAgentPackageName: 'com.mapflow.app',
|
||||
);
|
||||
}
|
||||
mbx.Point _mapboxPoint(LatLng coordinate) {
|
||||
return mbx.Point(
|
||||
coordinates: mbx.Position(coordinate.longitude, coordinate.latitude),
|
||||
);
|
||||
}
|
||||
|
||||
class _MapAttribution extends StatelessWidget {
|
||||
const _MapAttribution();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_mapboxAccessToken.isEmpty) {
|
||||
return const RichAttributionWidget(
|
||||
attributions: [TextSourceAttribution('OpenStreetMap contributors')],
|
||||
);
|
||||
}
|
||||
|
||||
return const RichAttributionWidget(
|
||||
attributions: [
|
||||
TextSourceAttribution('Mapbox', prependCopyright: false),
|
||||
TextSourceAttribution('OpenStreetMap contributors'),
|
||||
],
|
||||
);
|
||||
String get _mapboxStyleUri {
|
||||
if (_mapboxStyle.startsWith('mapbox://')) {
|
||||
return _mapboxStyle;
|
||||
}
|
||||
if (_mapboxStyle.startsWith('mapbox/')) {
|
||||
return 'mapbox://styles/$_mapboxStyle';
|
||||
}
|
||||
return _mapboxStyle;
|
||||
}
|
||||
|
||||
class _TraitPickerSheet extends StatelessWidget {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mbx;
|
||||
|
||||
import 'app/app.dart';
|
||||
import 'shared/auth/telegram_session.dart' as telegram_session;
|
||||
|
||||
const _mapboxAccessToken = String.fromEnvironment('MAPBOX_ACCESS_TOKEN');
|
||||
|
||||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
if (_mapboxAccessToken.isNotEmpty) {
|
||||
mbx.MapboxOptions.setAccessToken(_mapboxAccessToken);
|
||||
}
|
||||
usePathUrlStrategy();
|
||||
telegram_session.configureTelegramWebApp();
|
||||
runApp(const MapflowApp());
|
||||
|
||||
+104
@@ -41,6 +41,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.1"
|
||||
benchmark:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: benchmark
|
||||
sha256: cb3eeea01e3f054df76ee9775ca680f3afa5f19f39b2bb426ba78ba27654493b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -209,6 +217,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
dart_sort_queue:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_sort_queue
|
||||
sha256: f3353ba8b4850e072d3368757f62edb79af34a9703c3e3df9c59342721f5f5b1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2+3"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -342,6 +358,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.3.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.35"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -424,6 +448,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.5"
|
||||
geotypes:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geotypes
|
||||
sha256: "5bedf57de92283133dd221e363812ef50eaaba414f0823b1974ef7d84b86991f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -640,6 +672,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
mapbox_maps_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mapbox_maps_flutter
|
||||
sha256: f98e3808113088c6e0bc60f592d23eb5a23215b10a9389754642c8e5f9bdc117
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0-alpha.1"
|
||||
mapbox_maps_flutter_mobile:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mapbox_maps_flutter_mobile
|
||||
sha256: "4ef1a6cb23dfe4a6f5bb896ea7b1195dd474aaffd056bab77434fda03bc9446b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0-alpha.1"
|
||||
mapbox_maps_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mapbox_maps_flutter_platform_interface
|
||||
sha256: e64dc1df85cb2fe5c7d704771a01e53b6d6ccdafb8be70c2879c0d7e8bf6cbd8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0-alpha.1"
|
||||
mapbox_maps_flutter_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mapbox_maps_flutter_web
|
||||
sha256: "01ef5f2b4578e33cbdae27d05b7b9aa37246b205746a552f507d66b0deaf20cc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0-alpha.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -880,6 +944,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
rbush:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rbush
|
||||
sha256: "48b683421b4afb43a642f82c6aa31911e54f3069143d31c7d33cbe329df13403"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
record:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1045,6 +1117,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
sweepline_intersections:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sweepline_intersections
|
||||
sha256: a665c707200a4f07140a4029b41a7c4883beb3f04322cd8e08ebf650f69e1176
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1061,6 +1141,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.10"
|
||||
turf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: turf
|
||||
sha256: "7684654c561e751332bc2fa6e9bb7bcf0c71bad5315acf126206e7ecfef67256"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.12"
|
||||
turf_equality:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: turf_equality
|
||||
sha256: f0f44ffe389547941358e0d3d4a747db2bd56115b32ff1cede5e5bdf3126a3e2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
turf_pip:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: turf_pip
|
||||
sha256: ba4fd414baffd5d7b30880658ad6db82461c49ec023f8ffd0c23d398ad8b14be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -51,6 +51,7 @@ dependencies:
|
||||
gql_code_builder_serializers: ^0.1.0+1
|
||||
built_collection: ^5.1.1
|
||||
built_value: ^8.12.6
|
||||
mapbox_maps_flutter: ^3.0.0-alpha.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user