mirror of
https://github.com/ZhuJHua/moodiary.git
synced 2026-04-05 16:31:45 +08:00
feat(map): Add map support for viewing and managing diary entry locations
Closes #13
This commit is contained in:
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
@@ -5,6 +5,8 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:mood_diary/common/models/geo.dart';
|
||||
import 'package:mood_diary/common/models/github.dart';
|
||||
import 'package:mood_diary/common/models/hitokoto.dart';
|
||||
import 'package:mood_diary/common/models/hunyuan.dart';
|
||||
@@ -49,14 +51,12 @@ class Api {
|
||||
return (await Utils().httpUtil.get(url, type: ResponseType.bytes)).data;
|
||||
}
|
||||
|
||||
Future<List<String>?> updateWeather() async {
|
||||
Future<List<String>?> updatePosition() async {
|
||||
Position? position;
|
||||
|
||||
if (await Utils().permissionUtil.checkPermission(Permission.location)) {
|
||||
position = await Geolocator.getLastKnownPosition(forceAndroidLocationManager: true);
|
||||
position ??= await Geolocator.getCurrentPosition(locationSettings: AndroidSettings(forceLocationManager: true));
|
||||
}
|
||||
|
||||
if (position != null) {
|
||||
var local = Localizations.localeOf(Get.context!);
|
||||
var parameters = {
|
||||
@@ -65,21 +65,38 @@ class Api {
|
||||
'key': Utils().prefUtil.getValue<String>('qweatherKey'),
|
||||
'lang': local
|
||||
};
|
||||
var res = await Utils().httpUtil.get('https://devapi.qweather.com/v7/weather/now', parameters: parameters);
|
||||
var weather = await compute(WeatherResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
if (weather.now != null) {
|
||||
return [
|
||||
weather.now!.icon!,
|
||||
weather.now!.temp!,
|
||||
weather.now!.text!,
|
||||
];
|
||||
var res = await Utils().httpUtil.get('https://geoapi.qweather.com/v2/city/lookup', parameters: parameters);
|
||||
var geo = await compute(GeoResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
if (geo.location != null && geo.location!.isNotEmpty) {
|
||||
var city = geo.location!.first;
|
||||
return [position.latitude.toString(), position.longitude.toString(), '${city.adm2} ${city.name}'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
Utils().noticeUtil.showToast('定位失败');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<String>?> updateWeather({required LatLng position}) async {
|
||||
var local = Localizations.localeOf(Get.context!);
|
||||
var parameters = {
|
||||
'location':
|
||||
'${double.parse(position.longitude.toStringAsFixed(2))},${double.parse(position.latitude.toStringAsFixed(2))}',
|
||||
'key': Utils().prefUtil.getValue<String>('qweatherKey'),
|
||||
'lang': local
|
||||
};
|
||||
var res = await Utils().httpUtil.get('https://devapi.qweather.com/v7/weather/now', parameters: parameters);
|
||||
var weather = await compute(WeatherResponse.fromJson, res.data as Map<String, dynamic>);
|
||||
if (weather.now != null) {
|
||||
return [
|
||||
weather.now!.icon!,
|
||||
weather.now!.temp!,
|
||||
weather.now!.text!,
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<GithubRelease?> getGithubRelease() async {
|
||||
|
||||
106
lib/common/models/geo.dart
Normal file
106
lib/common/models/geo.dart
Normal file
@@ -0,0 +1,106 @@
|
||||
class GeoResponse {
|
||||
String? code;
|
||||
List<Location>? location;
|
||||
Refer? refer;
|
||||
|
||||
GeoResponse({this.code, this.location, this.refer});
|
||||
|
||||
GeoResponse.fromJson(Map<String, dynamic> json) {
|
||||
code = json["code"];
|
||||
location = json["location"] == null ? null : (json["location"] as List).map((e) => Location.fromJson(e)).toList();
|
||||
refer = json["refer"] == null ? null : Refer.fromJson(json["refer"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["code"] = code;
|
||||
data["location"] = location?.map((e) => e.toJson()).toList();
|
||||
data["refer"] = refer?.toJson();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Refer {
|
||||
List<String>? sources;
|
||||
List<String>? license;
|
||||
|
||||
Refer({this.sources, this.license});
|
||||
|
||||
Refer.fromJson(Map<String, dynamic> json) {
|
||||
sources = json["sources"] == null ? null : List<String>.from(json["sources"]);
|
||||
license = json["license"] == null ? null : List<String>.from(json["license"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["sources"] = sources;
|
||||
data["license"] = license;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Location {
|
||||
String? name;
|
||||
String? id;
|
||||
String? lat;
|
||||
String? lon;
|
||||
String? adm2;
|
||||
String? adm1;
|
||||
String? country;
|
||||
String? tz;
|
||||
String? utcOffset;
|
||||
String? isDst;
|
||||
String? type;
|
||||
String? rank;
|
||||
String? fxLink;
|
||||
|
||||
Location({
|
||||
this.name,
|
||||
this.id,
|
||||
this.lat,
|
||||
this.lon,
|
||||
this.adm2,
|
||||
this.adm1,
|
||||
this.country,
|
||||
this.tz,
|
||||
this.utcOffset,
|
||||
this.isDst,
|
||||
this.type,
|
||||
this.rank,
|
||||
this.fxLink,
|
||||
});
|
||||
|
||||
Location.fromJson(Map<String, dynamic> json) {
|
||||
name = json["name"];
|
||||
id = json["id"];
|
||||
lat = json["lat"];
|
||||
lon = json["lon"];
|
||||
adm2 = json["adm2"];
|
||||
adm1 = json["adm1"];
|
||||
country = json["country"];
|
||||
tz = json["tz"];
|
||||
utcOffset = json["utcOffset"];
|
||||
isDst = json["isDst"];
|
||||
type = json["type"];
|
||||
rank = json["rank"];
|
||||
fxLink = json["fxLink"];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data["name"] = name;
|
||||
data["id"] = id;
|
||||
data["lat"] = lat;
|
||||
data["lon"] = lon;
|
||||
data["adm2"] = adm2;
|
||||
data["adm1"] = adm1;
|
||||
data["country"] = country;
|
||||
data["tz"] = tz;
|
||||
data["utcOffset"] = utcOffset;
|
||||
data["isDst"] = isDst;
|
||||
data["type"] = type;
|
||||
data["rank"] = rank;
|
||||
data["fxLink"] = fxLink;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
14
lib/common/models/map.dart
Normal file
14
lib/common/models/map.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
class DiaryMapItem {
|
||||
// 坐标
|
||||
late LatLng latLng;
|
||||
|
||||
// 文章id
|
||||
late int id;
|
||||
|
||||
// 封面图片名称
|
||||
late String coverImageName;
|
||||
|
||||
DiaryMapItem(this.latLng, this.id, this.coverImageName);
|
||||
}
|
||||
72
lib/components/bubble/bubble_view.dart
Normal file
72
lib/components/bubble/bubble_view.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Bubble extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Color backgroundColor;
|
||||
final double borderRadius;
|
||||
|
||||
const Bubble({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.backgroundColor = Colors.white,
|
||||
this.borderRadius = 8.0,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomPaint(
|
||||
painter: BubblePainter(
|
||||
color: backgroundColor,
|
||||
borderRadius: borderRadius,
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BubblePainter extends CustomPainter {
|
||||
final Color color;
|
||||
final double borderRadius;
|
||||
|
||||
BubblePainter({required this.color, required this.borderRadius});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.fill;
|
||||
const arrowWidth = 16.0;
|
||||
const arrowHeight = 8.0;
|
||||
final rectWidth = size.width;
|
||||
final rectHeight = size.height - arrowHeight; // 减去箭头的高度
|
||||
|
||||
// 创建带圆角的矩形区域
|
||||
final rrect = RRect.fromLTRBR(
|
||||
0,
|
||||
0,
|
||||
rectWidth,
|
||||
rectHeight,
|
||||
Radius.circular(borderRadius),
|
||||
);
|
||||
|
||||
// 创建路径
|
||||
final path = Path()
|
||||
..addRRect(rrect) // 添加圆角矩形
|
||||
..moveTo((rectWidth - arrowWidth) / 2, rectHeight) // 箭头左侧
|
||||
..lineTo(rectWidth / 2, rectHeight + arrowHeight) // 箭头尖端
|
||||
..lineTo((rectWidth + arrowWidth) / 2, rectHeight); // 箭头右侧
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -19,17 +19,17 @@ class SideBarLogic extends GetxController {
|
||||
getHitokoto();
|
||||
getImage();
|
||||
getInfo();
|
||||
getWeather();
|
||||
// getWeather();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
Future<void> getWeather() async {
|
||||
var key = Utils().prefUtil.getValue<String>('qweatherKey');
|
||||
if (state.getWeather && key != null) {
|
||||
state.weatherResponse.value =
|
||||
await Utils().cacheUtil.getCacheList('weather', Api().updateWeather, maxAgeMillis: 15 * 60000) ?? [];
|
||||
}
|
||||
}
|
||||
// Future<void> getWeather() async {
|
||||
// var key = Utils().prefUtil.getValue<String>('qweatherKey');
|
||||
// if (state.getWeather && key != null) {
|
||||
// state.weatherResponse.value =
|
||||
// await Utils().cacheUtil.getCacheList('weather', Api().updateWeather, maxAgeMillis: 15 * 60000) ?? [];
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> getHitokoto() async {
|
||||
var res = await Utils().cacheUtil.getCacheList('hitokoto', Api().updateHitokoto, maxAgeMillis: 15 * 60000);
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/find_locale.dart';
|
||||
@@ -25,8 +26,8 @@ Future<void> initSystem() async {
|
||||
//初始化视频播放
|
||||
MediaKit.ensureInitialized();
|
||||
//地图缓存
|
||||
//await FMTCObjectBoxBackend().initialise();
|
||||
//await const FMTCStore('mapStore').manage.create();
|
||||
await FMTCObjectBoxBackend().initialise();
|
||||
await const FMTCStore('mapStore').manage.create();
|
||||
platFormOption();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_quill/flutter_quill.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
import 'package:mood_diary/api/api.dart';
|
||||
import 'package:mood_diary/common/models/isar/diary.dart';
|
||||
@@ -71,7 +72,7 @@ class EditLogic extends GetxController with WidgetsBindingObserver {
|
||||
if (Get.arguments == 'new') {
|
||||
state.currentDiary = Diary();
|
||||
if (Utils().prefUtil.getValue<bool>('autoWeather') == true) {
|
||||
unawaited(getWeather());
|
||||
unawaited(getPositionAndWeather());
|
||||
}
|
||||
} else {
|
||||
//如果是编辑,将日记对象赋值
|
||||
@@ -372,20 +373,43 @@ class EditLogic extends GetxController with WidgetsBindingObserver {
|
||||
update(['Mood']);
|
||||
}
|
||||
|
||||
//获取天气
|
||||
Future<void> getWeather() async {
|
||||
//获取天气,同时获取定位
|
||||
Future<void> getPositionAndWeather() async {
|
||||
var key = Utils().prefUtil.getValue<String>('qweatherKey');
|
||||
if (key != null) {
|
||||
state.isProcessing = true;
|
||||
update();
|
||||
var res = await Api().updateWeather();
|
||||
if (res != null) {
|
||||
state.currentDiary.weather = res;
|
||||
state.isProcessing = false;
|
||||
Utils().noticeUtil.showToast('获取成功');
|
||||
update(['Weather']);
|
||||
}
|
||||
if (key == null) return;
|
||||
|
||||
state.isProcessing = true;
|
||||
update(['Weather']);
|
||||
|
||||
// 获取定位
|
||||
var position = await Api().updatePosition();
|
||||
if (position == null) {
|
||||
_handleError('定位失败');
|
||||
return;
|
||||
}
|
||||
|
||||
state.currentDiary.position = position;
|
||||
|
||||
// 获取天气
|
||||
var weather = await Api().updateWeather(
|
||||
position: LatLng(double.parse(position[0]), double.parse(position[1])),
|
||||
);
|
||||
|
||||
if (weather == null) {
|
||||
_handleError('天气获取失败');
|
||||
return;
|
||||
}
|
||||
|
||||
state.currentDiary.weather = weather;
|
||||
state.isProcessing = false;
|
||||
Utils().noticeUtil.showToast('获取成功');
|
||||
update(['Weather']);
|
||||
}
|
||||
|
||||
void _handleError(String message) {
|
||||
state.isProcessing = false;
|
||||
Utils().noticeUtil.showToast(message);
|
||||
update(['Weather']);
|
||||
}
|
||||
|
||||
//获取音频名称
|
||||
|
||||
@@ -428,8 +428,8 @@ class EditPage extends StatelessWidget {
|
||||
trailing: state.isProcessing
|
||||
? const CircularProgressIndicator()
|
||||
: IconButton.filledTonal(
|
||||
onPressed: () {
|
||||
logic.getWeather();
|
||||
onPressed: () async {
|
||||
await logic.getPositionAndWeather();
|
||||
},
|
||||
icon: const Icon(Icons.location_on),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:mood_diary/pages/diary_details/diary_details_logic.dart';
|
||||
import 'package:mood_diary/router/app_routes.dart';
|
||||
import 'package:mood_diary/utils/utils.dart';
|
||||
|
||||
import 'map_state.dart';
|
||||
|
||||
@@ -13,6 +17,7 @@ class MapLogic extends GetxController {
|
||||
@override
|
||||
void onReady() async {
|
||||
state.currentLatLng = await getLocation();
|
||||
await getAllItem();
|
||||
update();
|
||||
super.onReady();
|
||||
}
|
||||
@@ -29,4 +34,26 @@ class MapLogic extends GetxController {
|
||||
position ??= await Geolocator.getCurrentPosition(locationSettings: AndroidSettings(forceLocationManager: true));
|
||||
return LatLng(position.latitude, position.longitude);
|
||||
}
|
||||
|
||||
Future<void> getAllItem() async {
|
||||
state.diaryMapItemList = await Utils().isarUtil.getAllMapItem();
|
||||
}
|
||||
|
||||
Future<void> toCurrentPosition() async {
|
||||
Utils().noticeUtil.showToast('定位中');
|
||||
var currentPosition = await getLocation();
|
||||
Utils().logUtil.printInfo(currentPosition.toString());
|
||||
Utils().noticeUtil.showToast('定位成功');
|
||||
mapController.move(currentPosition, mapController.camera.maxZoom!);
|
||||
}
|
||||
|
||||
Future<void> toDiaryPage({required int isarId}) async {
|
||||
await HapticFeedback.mediumImpact();
|
||||
var diary = await Utils().isarUtil.getDiaryByID(isarId);
|
||||
Bind.lazyPut(() => DiaryDetailsLogic(), tag: diary!.id);
|
||||
await Get.toNamed(
|
||||
AppRoutes.diaryPage,
|
||||
arguments: [diary, false],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:mood_diary/common/models/map.dart';
|
||||
import 'package:mood_diary/utils/utils.dart';
|
||||
|
||||
class MapState {
|
||||
late LatLng? currentLatLng;
|
||||
LatLng? currentLatLng;
|
||||
|
||||
List<DiaryMapItem> diaryMapItemList = [];
|
||||
|
||||
String? tiandituKey = Utils().prefUtil.getValue<String>('tiandituKey');
|
||||
|
||||
MapState() {
|
||||
currentLatLng = null;
|
||||
}
|
||||
MapState();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart';
|
||||
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:mood_diary/components/bubble/bubble_view.dart';
|
||||
import 'package:mood_diary/utils/utils.dart';
|
||||
|
||||
import 'map_logic.dart';
|
||||
|
||||
@@ -12,32 +19,86 @@ class MapPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final logic = Bind.find<MapLogic>();
|
||||
final state = Bind.find<MapLogic>().state;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('足迹'),
|
||||
),
|
||||
body: GetBuilder<MapLogic>(
|
||||
builder: (_) {
|
||||
return state.currentLatLng != null && state.tiandituKey != null
|
||||
? FlutterMap(
|
||||
mapController: logic.mapController,
|
||||
options: MapOptions(initialCenter: state.currentLatLng!),
|
||||
options:
|
||||
MapOptions(initialCenter: state.currentLatLng!, minZoom: 4.0, initialZoom: 16.0, maxZoom: 18.0),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
'http://t6.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${state.tiandituKey}',
|
||||
tileProvider:
|
||||
const FMTCStore('mapStore').getTileProvider(),
|
||||
'http://t${Random().nextInt(8)}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${state.tiandituKey}',
|
||||
tileProvider: const FMTCStore('mapStore').getTileProvider(),
|
||||
),
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
'http://t6.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${state.tiandituKey}',
|
||||
tileProvider:
|
||||
const FMTCStore('mapStore').getTileProvider(),
|
||||
'http://t${Random().nextInt(8)}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${state.tiandituKey}',
|
||||
tileProvider: const FMTCStore('mapStore').getTileProvider(),
|
||||
),
|
||||
MarkerClusterLayerWidget(
|
||||
options: MarkerClusterLayerOptions(
|
||||
markers: List.generate(state.diaryMapItemList.length, (index) {
|
||||
return Marker(
|
||||
point: state.diaryMapItemList[index].latLng,
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
await logic.toDiaryPage(isarId: state.diaryMapItemList[index].id);
|
||||
},
|
||||
child: Bubble(
|
||||
backgroundColor: colorScheme.tertiary,
|
||||
borderRadius: 8,
|
||||
child: Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
image: DecorationImage(
|
||||
image: FileImage(File(Utils().fileUtil.getRealPath(
|
||||
'image', state.diaryMapItemList[index].coverImageName))),
|
||||
fit: BoxFit.cover),
|
||||
),
|
||||
)),
|
||||
),
|
||||
width: 56,
|
||||
height: 64);
|
||||
}),
|
||||
rotate: true,
|
||||
maxZoom: 18.0,
|
||||
forceIntegerZoomLevel: true,
|
||||
showPolygon: false,
|
||||
builder: (context, markers) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: colorScheme.tertiaryContainer,
|
||||
border: Border.all(color: colorScheme.tertiary, width: 2)),
|
||||
child: Center(
|
||||
child: Text(
|
||||
markers.length.toString(),
|
||||
style: TextStyle(color: colorScheme.onTertiaryContainer),
|
||||
),
|
||||
),
|
||||
);
|
||||
})),
|
||||
],
|
||||
)
|
||||
: const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
logic.toCurrentPosition();
|
||||
},
|
||||
child: const FaIcon(FontAwesomeIcons.locationCrosshairs),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
40
pubspec.lock
40
pubspec.lock
@@ -22,6 +22,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.11.0"
|
||||
animated_stack_widget:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: animated_stack_widget
|
||||
sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
app_links:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -749,6 +757,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.2"
|
||||
flutter_map_marker_cluster:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_map_marker_cluster
|
||||
sha256: "2c1fb4d7a2105c4bbeb89be215320507f4b71b2036df4341fab9d2aa677d3ae9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
flutter_map_marker_popup:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_map_marker_popup
|
||||
sha256: a7540538114b5d1627ab67b498273d66bc36090385412ae49ef215af4a2861c5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
flutter_map_tile_caching:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1353,6 +1377,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.8"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
objectbox:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1577,6 +1609,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -83,6 +83,7 @@ dependencies:
|
||||
fc_native_video_thumbnail: 0.16.1
|
||||
flutter_map: 7.0.2
|
||||
flutter_map_tile_caching: 9.1.3
|
||||
flutter_map_marker_cluster: 1.4.0
|
||||
latlong2: 0.9.1
|
||||
shelf: 1.4.2
|
||||
shelf_multipart: 2.0.0
|
||||
|
||||
Reference in New Issue
Block a user