162 lines
4.6 KiB
C#
162 lines
4.6 KiB
C#
using FieldLogger.Models;
|
|
using FieldLogger.ViewModels;
|
|
|
|
#if WINDOWS
|
|
using System.Text.Json;
|
|
#else
|
|
using Microsoft.Maui.Controls.Maps;
|
|
using Microsoft.Maui.Maps;
|
|
using Map = Microsoft.Maui.Controls.Maps.Map;
|
|
#endif
|
|
|
|
namespace FieldLogger.Views;
|
|
|
|
public partial class MapPage : ContentPage
|
|
{
|
|
private readonly MapViewModel _viewModel;
|
|
|
|
#if WINDOWS
|
|
private WebView? _webView;
|
|
private bool _webMapReady;
|
|
private List<LoggedPoint>? _pendingPoints;
|
|
#else
|
|
private Map? _map;
|
|
#endif
|
|
|
|
public MapPage(MapViewModel viewModel)
|
|
{
|
|
InitializeComponent();
|
|
BindingContext = _viewModel = viewModel;
|
|
}
|
|
|
|
protected override async void OnAppearing()
|
|
{
|
|
base.OnAppearing();
|
|
await RefreshMapAsync();
|
|
}
|
|
|
|
private async void OnRefreshClicked(object? sender, EventArgs e)
|
|
{
|
|
await RefreshMapAsync();
|
|
}
|
|
|
|
private async Task RefreshMapAsync()
|
|
{
|
|
await EnsureMapCreatedAsync();
|
|
var points = await _viewModel.LoadPointsAsync();
|
|
ShowPoints(points);
|
|
}
|
|
|
|
#if WINDOWS
|
|
|
|
private async Task EnsureMapCreatedAsync()
|
|
{
|
|
if (_webView is not null)
|
|
return;
|
|
|
|
var apiKey = _viewModel.Settings.GoogleMapsApiKey;
|
|
if (string.IsNullOrWhiteSpace(apiKey))
|
|
{
|
|
MapHost.Content = new Label
|
|
{
|
|
Text = "Google Maps API key is not set.\nEnter your Maps JavaScript API key on the Settings page.",
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
VerticalOptions = LayoutOptions.Center,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
};
|
|
return;
|
|
}
|
|
|
|
using var stream = await FileSystem.OpenAppPackageFileAsync("map.html");
|
|
using var reader = new StreamReader(stream);
|
|
var html = (await reader.ReadToEndAsync()).Replace("%%GOOGLE_MAPS_API_KEY%%", apiKey);
|
|
|
|
_webView = new WebView { Source = new HtmlWebViewSource { Html = html } };
|
|
_webView.Navigated += async (_, _) =>
|
|
{
|
|
_webMapReady = true;
|
|
if (_pendingPoints is not null)
|
|
{
|
|
var pts = _pendingPoints;
|
|
_pendingPoints = null;
|
|
await PushPointsToWebAsync(pts);
|
|
}
|
|
};
|
|
MapHost.Content = _webView;
|
|
}
|
|
|
|
private async void ShowPoints(List<LoggedPoint> points)
|
|
{
|
|
if (_webView is null)
|
|
return;
|
|
if (!_webMapReady)
|
|
{
|
|
_pendingPoints = points;
|
|
return;
|
|
}
|
|
await PushPointsToWebAsync(points);
|
|
}
|
|
|
|
private async Task PushPointsToWebAsync(List<LoggedPoint> points)
|
|
{
|
|
var payload = points.Select(p => new
|
|
{
|
|
id = p.Id,
|
|
lat = p.Latitude,
|
|
lng = p.Longitude,
|
|
utility = ((UmUtility)p.Utility).ToString(),
|
|
depth = p.DepthRaw,
|
|
current = p.CurrentRaw,
|
|
frequency = p.Frequency,
|
|
fix = ((GnssFixStatus)p.FixStatus).ToString(),
|
|
hrms = p.Hrms,
|
|
time = p.TimestampUtc.ToLocalTime().ToString("g"),
|
|
});
|
|
var json = JsonSerializer.Serialize(payload);
|
|
await _webView!.EvaluateJavaScriptAsync($"setPoints({json})");
|
|
}
|
|
|
|
#else
|
|
|
|
private Task EnsureMapCreatedAsync()
|
|
{
|
|
if (_map is null)
|
|
{
|
|
_map = new Map { MapType = MapType.Hybrid, IsShowingUser = false };
|
|
MapHost.Content = _map;
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void ShowPoints(List<LoggedPoint> points)
|
|
{
|
|
if (_map is null)
|
|
return;
|
|
|
|
_map.Pins.Clear();
|
|
foreach (var p in points)
|
|
{
|
|
_map.Pins.Add(new Pin
|
|
{
|
|
Label = $"#{p.Id} {(UmUtility)p.Utility} · depth {p.DepthRaw}",
|
|
Address = $"{(GnssFixStatus)p.FixStatus} · ±{p.Hrms:F3} m · {p.TimestampUtc.ToLocalTime():g}",
|
|
Location = new Location(p.Latitude, p.Longitude),
|
|
});
|
|
}
|
|
|
|
if (points.Count > 0)
|
|
{
|
|
var minLat = points.Min(p => p.Latitude);
|
|
var maxLat = points.Max(p => p.Latitude);
|
|
var minLon = points.Min(p => p.Longitude);
|
|
var maxLon = points.Max(p => p.Longitude);
|
|
var center = new Location((minLat + maxLat) / 2, (minLon + maxLon) / 2);
|
|
var spanKm = Math.Max(0.05,
|
|
Location.CalculateDistance(minLat, minLon, maxLat, maxLon, DistanceUnits.Kilometers) * 0.7);
|
|
_map.MoveToRegion(MapSpan.FromCenterAndRadius(center, Distance.FromKilometers(spanKm)));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|