add m.location support
Needs cross-platform testing. Currently only tested on Android.
This commit is contained in:
parent
979068fc3a
commit
3a8d977f11
3 changed files with 810 additions and 12 deletions
|
|
@ -4,6 +4,7 @@ import "package:nexus/models/content/content.dart";
|
|||
import "package:nexus/models/info/file.dart";
|
||||
import "package:nexus/models/info/image.dart";
|
||||
import "package:nexus/models/info/video.dart";
|
||||
import "package:nexus/models/location.dart";
|
||||
part "message.freezed.dart";
|
||||
part "message.g.dart";
|
||||
|
||||
|
|
@ -90,8 +91,12 @@ sealed class MessageContent extends Content with _$MessageContent {
|
|||
}) = VideoMessageContent;
|
||||
|
||||
@FreezedUnionValue("m.location")
|
||||
factory MessageContent.location({required String body, required Uri geoUri}) =
|
||||
LocationMessageContent;
|
||||
factory MessageContent.location({
|
||||
required String body,
|
||||
required Uri geoUri,
|
||||
@JsonKey(name: "m.location", includeIfNull: false) LocationInfo? location,
|
||||
@JsonKey(name: "m.asset", includeIfNull: false) LocationAsset? asset,
|
||||
}) = LocationMessageContent;
|
||||
|
||||
factory MessageContent.fromJson(Map<String, Object?> json) =>
|
||||
_$MessageContentFromJson(json);
|
||||
|
|
|
|||
84
lib/models/location.dart
Normal file
84
lib/models/location.dart
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
import "package:latlong2/latlong.dart";
|
||||
import "package:nexus/models/content/message.dart";
|
||||
|
||||
part "location.freezed.dart";
|
||||
part "location.g.dart";
|
||||
|
||||
/// A location message's `m.location` block.
|
||||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable(includeIfNull: false)
|
||||
class const LocationInfo({required final Uri uri, final String? description})
|
||||
with _$LocationInfo {
|
||||
Map<String, Object?> toJson() => _$LocationInfoToJson(this);
|
||||
|
||||
factory LocationInfo.fromJson(Map<String, Object?> json) =>
|
||||
_$LocationInfoFromJson(json);
|
||||
}
|
||||
|
||||
/// A location message's `m.asset` block.
|
||||
@Freezed(toJson: false, fromJson: false)
|
||||
@JsonSerializable()
|
||||
class const LocationAsset({
|
||||
@JsonKey(unknownEnumValue: LocationAssetType.pin)
|
||||
final LocationAssetType type = .self,
|
||||
}) with _$LocationAsset {
|
||||
Map<String, Object?> toJson() => _$LocationAssetToJson(this);
|
||||
|
||||
factory LocationAsset.fromJson(Map<String, Object?> json) =>
|
||||
_$LocationAssetFromJson(json);
|
||||
}
|
||||
|
||||
enum LocationAssetType {
|
||||
@JsonValue("m.self")
|
||||
self,
|
||||
|
||||
@JsonValue("m.pin")
|
||||
pin,
|
||||
}
|
||||
|
||||
extension LocationMessagePoint on LocationMessageContent {
|
||||
LatLng? get point => location?.uri.latLng ?? geoUri.latLng;
|
||||
|
||||
String? get description => switch (location?.description?.trim()) {
|
||||
final description? when description.isNotEmpty => description,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
LocationAssetType get assetType => asset?.type ?? .self;
|
||||
}
|
||||
|
||||
extension FormatLatLng on LatLng {
|
||||
String get formatted =>
|
||||
"${latitude.toStringAsFixed(5)}, ${longitude.toStringAsFixed(5)}";
|
||||
}
|
||||
|
||||
extension GeoUri on Uri {
|
||||
/// The coordinates of a geo: URI, like `geo:51.5,-0.12;u=35`.
|
||||
LatLng? get latLng {
|
||||
if (scheme != "geo") return null;
|
||||
final coordinates = path.split(";").first.split(",");
|
||||
if (coordinates.length < 2) return null;
|
||||
|
||||
return switch ((
|
||||
double.tryParse(coordinates[0]),
|
||||
double.tryParse(coordinates[1]),
|
||||
)) {
|
||||
(final latitude?, final longitude?)
|
||||
when latitude.abs() <= 90 && longitude.abs() <= 180 =>
|
||||
LatLng(latitude, longitude),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
static Uri openStreetMap(LatLng point) => Uri.https(
|
||||
"www.openstreetmap.org",
|
||||
"/",
|
||||
{"mlat": "${point.latitude}", "mlon": "${point.longitude}"},
|
||||
).replace(fragment: "map=16/${point.latitude}/${point.longitude}");
|
||||
|
||||
static Uri fromLatLng(LatLng point, {double? uncertainty}) => Uri.parse(
|
||||
"geo:${point.latitude},${point.longitude}"
|
||||
"${uncertainty == null ? "" : ";u=${uncertainty.round()}"}",
|
||||
);
|
||||
}
|
||||
11
lib/models/location_exception.dart
Normal file
11
lib/models/location_exception.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
enum LocationException(final String message) implements Exception {
|
||||
servicesOff("Location services are turned off."),
|
||||
denied("Nexus doesn't have permission to see your location."),
|
||||
timedOut("Couldn't get your location in time."),
|
||||
failed(
|
||||
"Couldn't get your location. Check that location services are on, and that Nexus is allowed to use them.",
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
Loading…
Reference in a new issue