Skip to content

Commit

Permalink
feat(map): Add map support for viewing and managing diary entry locat…
Browse files Browse the repository at this point in the history
…ions

Closes #13
  • Loading branch information
ZhuJHua committed Nov 6, 2024
1 parent f8455c7 commit bef23b8
Show file tree
Hide file tree
Showing 14 changed files with 416 additions and 49 deletions.
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -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:
43 changes: 30 additions & 13 deletions lib/api/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 = {
Expand All @@ -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 {
Expand Down
106 changes: 106 additions & 0 deletions lib/common/models/geo.dart
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions lib/common/models/map.dart
Original file line number Diff line number Diff line change
@@ -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 changes: 72 additions & 0 deletions lib/components/bubble/bubble_view.dart
Original file line number Diff line number Diff line change
@@ -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;
}
}
16 changes: 8 additions & 8 deletions lib/components/side_bar/side_bar_logic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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();
}

Expand Down
50 changes: 37 additions & 13 deletions lib/pages/edit/edit_logic.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 {
//如果是编辑,将日记对象赋值
Expand Down Expand Up @@ -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']);
}

//获取音频名称
Expand Down
Loading

0 comments on commit bef23b8

Please sign in to comment.