PWA Fundvelo der Caritas.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CaritasServiceFundVeloFoundKeyDataPage.razor.cs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using BlazorGeolocation;
  2. using cwebplusApp.Shared.Models;
  3. using cwebplusApp.Shared.ResourceFiles;
  4. using cwebplusApp.Shared.Services;
  5. using FisSst.BlazorMaps;
  6. using Microsoft.AspNetCore.Components;
  7. using Microsoft.Extensions.Localization;
  8. using System;
  9. using System.Threading.Tasks;
  10. namespace cwebplusApp.Pages {
  11. public class CaritasServiceFundVeloKeyDataPageBase : ComponentBase {
  12. protected readonly LatLng geoPositionCenterSwiss;
  13. protected Map mapRef;
  14. protected MapOptions mapOptions;
  15. protected BicycleGeoPosition bicycleGeoPosition;
  16. private Marker bicyclePositionMarker;
  17. private MarkerOptions bicycleMarkerOptions;
  18. private NominatimReverseAddress addressDto;
  19. private Marker devicePositionMarker;
  20. [Inject]
  21. private IMarkerFactory MarkerFactory { get; init; }
  22. [Inject]
  23. private IIconFactory IconFactory { get; init; }
  24. [Inject]
  25. private BlazorGeolocationService BlazorGeolocationService { get; init; }
  26. [Inject]
  27. private Toaster Toaster { get; init; }
  28. [Inject]
  29. private IStringLocalizer<Resources> I18n { get; init; }
  30. [Inject]
  31. private OnlineStatusProvider OnlineStatusProvider { get; init; }
  32. [Inject]
  33. private PermissionsProvider PermissionsProvider { get; init; }
  34. private NominatimService NominatimService { get; set; }
  35. public CaritasServiceFundVeloKeyDataPageBase() : base() {
  36. this.geoPositionCenterSwiss = new LatLng(46.80121, 8.22669); // Centered on Swiss
  37. this.mapOptions = new MapOptions() {
  38. DivId = "bicycleLocationMap",
  39. Center = this.geoPositionCenterSwiss,
  40. Zoom = 6,
  41. UrlTileLayer = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  42. SubOptions = new MapSubOptions() {
  43. Attribution = "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap&nbsp;</a>",
  44. MaxZoom = 18,
  45. TileSize = 256,
  46. ZoomOffset = 0,
  47. }
  48. };
  49. this.bicycleGeoPosition = new();
  50. this.NominatimService = new NominatimService();
  51. }
  52. protected async Task AddEventsToMap() {
  53. await this.mapRef.OnClick(async (MouseEvent mouseEvent) => await OnMouseMapClicked(mouseEvent));
  54. }
  55. protected async Task<LatLng> InitializeDeviceMapPosition() {
  56. CreateBicycleMarkerOptions();
  57. return await ShowDeviceGeoLocation();
  58. }
  59. protected async Task InitializeBicycleMapPosition() {
  60. CreateBicycleMarkerOptions();
  61. await ShowBicycleGeoLocation(false);
  62. }
  63. protected async Task<string> GetFormattedAddressZipAndTown(ReportDataProvider ReportDataProvider) {
  64. if (this.addressDto == null) {
  65. this.bicycleGeoPosition.Latitude = ReportDataProvider.GetFoundReport().GeographicInfo.Latitude;
  66. this.bicycleGeoPosition.Longitude = ReportDataProvider.GetFoundReport().GeographicInfo.Longitude;
  67. if (OnlineStatusProvider.Online && this.bicycleGeoPosition.Latitude != 0 && this.bicycleGeoPosition.Longitude != 0) {
  68. this.addressDto = await NominatimService.GetAddressForCoordinates(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude);
  69. }
  70. if (this.addressDto == null) {
  71. this.addressDto = new();
  72. this.addressDto.address = new();
  73. this.addressDto.address.postcode = ReportDataProvider.GetFoundReport().GeographicInfo.Postcode;
  74. this.addressDto.address.town = ReportDataProvider.GetFoundReport().GeographicInfo.Town;
  75. }
  76. }
  77. return GetFormattedAddressZipAndTown(addressDto);
  78. }
  79. protected async Task AddBicycleMarkerOnClickPosition(MouseEvent mouseEvent) {
  80. if (mouseEvent.LatLng.Lat != 0 && mouseEvent.LatLng.Lng != 0) {
  81. if (this.bicyclePositionMarker != null) {
  82. await bicyclePositionMarker.Remove();
  83. }
  84. this.bicyclePositionMarker = await this.MarkerFactory.CreateAndAddToMap(mouseEvent.LatLng, this.mapRef, this.bicycleMarkerOptions);
  85. }
  86. }
  87. protected async Task<LatLng> GetDeviceGeoLocation() {
  88. LatLng geoPosition = geoPositionCenterSwiss; // Centered on Swiss
  89. if (PermissionsProvider.IsGeoLocationAllowed) {
  90. BlazorGeolocationPosition position = await this.BlazorGeolocationService.GetPositionAsync();
  91. if (position.ErrorCode != null) {
  92. Toaster.ShowError(I18n.GetString("Error.GeoLocation.Title", position.ErrorCode), I18n.GetString("Error.GeoLocation.Msg", position.ErrorMessage));
  93. } else {
  94. geoPosition = new((double)position.Latitude, (double)position.Longitude);
  95. }
  96. } else {
  97. Toaster.ShowWarning(I18n.GetString("Warning.Permission.GeoLocation.Title"), I18n.GetString("Warning.Permission.GeoLocation.Msg"));
  98. }
  99. return geoPosition;
  100. }
  101. private async void CreateBicycleMarkerOptions() {
  102. this.bicycleMarkerOptions = new MarkerOptions() {
  103. IconRef = await this.IconFactory.Create(new IconOptions() {
  104. IconUrl = "./icons/bicycle_location.png",
  105. IconSize = new Point(48, 48),
  106. IconAnchor = new Point(24, 47),
  107. ShadowUrl = "./icons/bicycle_location_shadow.png",
  108. ShadowSize = new Point(48, 48),
  109. ShadowAnchor = new Point(16, 48),
  110. })
  111. };
  112. }
  113. protected async Task RemoveDeviceLocationMarker() {
  114. if (this.devicePositionMarker != null) {
  115. await devicePositionMarker.Remove();
  116. }
  117. }
  118. private async Task<LatLng> ShowDeviceGeoLocation() {
  119. LatLng geoPosition = await GetDeviceGeoLocation();
  120. await RemoveDeviceLocationMarker();
  121. if (PermissionsProvider.IsGeoLocationAllowed) {
  122. this.devicePositionMarker = await this.MarkerFactory.CreateAndAddToMap(geoPosition, this.mapRef);
  123. await this.mapRef.SetZoom(16);
  124. } else {
  125. await this.mapRef.SetZoom(6);
  126. }
  127. await this.mapRef.SetView(geoPosition);
  128. return geoPosition;
  129. }
  130. protected async Task ShowBicycleGeoLocation(bool forceRecalc) {
  131. if (this.bicycleGeoPosition.Latitude != 0 && this.bicycleGeoPosition.Longitude != 0 && !forceRecalc) {
  132. LatLng geoPosition = new(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude);
  133. await this.mapRef.SetZoom(16);
  134. await this.mapRef.SetView(geoPosition);
  135. } else if (!String.IsNullOrEmpty(this.bicycleGeoPosition.Address) &&
  136. !String.IsNullOrEmpty(this.bicycleGeoPosition.Zip) &&
  137. !String.IsNullOrEmpty(this.bicycleGeoPosition.City)) {
  138. LatLng geoPosition = await NominatimService.GetCoordinatesForAddress(bicycleGeoPosition.Address + ", " + bicycleGeoPosition.Zip + " " + bicycleGeoPosition.City);
  139. if (geoPosition != null) {
  140. this.bicycleGeoPosition.Latitude = geoPosition.Lat;
  141. this.bicycleGeoPosition.Longitude = geoPosition.Lng;
  142. await this.mapRef.SetZoom(16);
  143. await this.mapRef.SetView(geoPosition);
  144. MouseEvent mouseEvent = new MouseEvent();
  145. mouseEvent.LatLng = geoPosition;
  146. await AddBicycleMarkerOnClickPosition(mouseEvent);
  147. }
  148. } else {
  149. MouseEvent mouseEvent = new MouseEvent();
  150. mouseEvent.LatLng = geoPositionCenterSwiss;
  151. await AddBicycleMarkerOnClickPosition(mouseEvent);
  152. }
  153. }
  154. private static string GetFormattedAddressZipAndTown(NominatimReverseAddress addressDto) {
  155. string zip = SplitAndGetFirstPostcode(addressDto.address.postcode);
  156. string town = addressDto.address.city ?? addressDto.address.town ?? addressDto.address.village;
  157. return (zip + " " + town).TrimEnd();
  158. }
  159. private static string SplitAndGetFirstPostcode(string postcode) {
  160. return String.IsNullOrEmpty(postcode) ? "" : postcode.Split("-", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)[0];
  161. }
  162. protected async Task OnMouseMapClicked(MouseEvent mouseEvent) {
  163. await AddBicycleMarkerOnClickPosition(mouseEvent);
  164. this.bicycleGeoPosition.Latitude = mouseEvent.LatLng.Lat;
  165. this.bicycleGeoPosition.Longitude = mouseEvent.LatLng.Lng;
  166. addressDto = await NominatimService.GetAddressForCoordinates(mouseEvent.LatLng.Lat, mouseEvent.LatLng.Lng);
  167. if (addressDto != null) {
  168. this.bicycleGeoPosition.Address = GetFormattedAddressStreet(addressDto);
  169. this.bicycleGeoPosition.City = addressDto.address.city ?? addressDto.address.town ?? addressDto.address.village;
  170. this.bicycleGeoPosition.Zip = SplitAndGetFirstPostcode(addressDto.address.postcode);
  171. this.bicycleGeoPosition.DisplayCity = GetFormattedAddressZipAndTown(addressDto);
  172. } else {
  173. Toaster.ShowWarning(I18n.GetString("Warning.Nominatim.Title"), I18n.GetString("Warning.Nominatim.Msg"));
  174. }
  175. StateHasChanged();
  176. }
  177. private static string GetFormattedAddressStreet(NominatimReverseAddress addressDto) {
  178. string street = addressDto.address.road;
  179. string houseNr = addressDto.address.house_number ?? "";
  180. return street + (!houseNr.Equals("") ? " " + houseNr : "");
  181. }
  182. }
  183. }