mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-31 22:00:12 +01:00
Version 2.4.9: Implemented UseLayoutRounding during calculation of viewport positions in MapPanel. Added LogoImage property in BingMapsTileLayer.
This commit is contained in:
parent
ba45aa5901
commit
9553799a8a
|
|
@ -62,14 +62,14 @@ namespace MapControl.Caching
|
|||
|
||||
public FileDbCache(string name, string folder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentException("The parameter name must not be null or empty or consist only of white-space characters.");
|
||||
throw new ArgumentException("The parameter name must not be null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(folder))
|
||||
if (string.IsNullOrEmpty(folder))
|
||||
{
|
||||
throw new ArgumentException("The parameter folder must not be null or empty or consist only of white-space characters.");
|
||||
throw new ArgumentException("The parameter folder must not be null or empty.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace MapControl.Caching
|
|||
|
||||
public FileDbCache(string name = null, StorageFolder folder = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = TileImageLoader.DefaultCacheName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@ namespace MapControl.Caching
|
|||
|
||||
public ImageFileCache(string name, string folder)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new ArgumentException("The parameter name must not be null or empty or consist only of white-space characters.");
|
||||
throw new ArgumentException("The parameter name must not be null or empty.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(folder))
|
||||
if (string.IsNullOrEmpty(folder))
|
||||
{
|
||||
throw new ArgumentException("The parameter folder must not be null or empty or consist only of white-space characters.");
|
||||
throw new ArgumentException("The parameter folder must not be null or empty.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace MapControl.Caching
|
|||
|
||||
public ImageFileCache(string name = null, StorageFolder folder = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = TileImageLoader.DefaultCacheName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ using System.Net;
|
|||
using System.Xml;
|
||||
#if WINDOWS_RUNTIME
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
#else
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
|
|
@ -39,7 +41,7 @@ namespace MapControl
|
|||
{
|
||||
Loaded -= OnLoaded;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ApiKey))
|
||||
if (string.IsNullOrEmpty(ApiKey))
|
||||
{
|
||||
throw new InvalidOperationException("A Bing Maps API Key must be assigned to the ApiKey property.");
|
||||
}
|
||||
|
|
@ -70,6 +72,7 @@ namespace MapControl
|
|||
|
||||
private void ReadImageryMetadataResponse(XmlReader xmlReader)
|
||||
{
|
||||
string logoUri = null;
|
||||
string imageUrl = null;
|
||||
string[] imageUrlSubdomains = null;
|
||||
int? zoomMin = null;
|
||||
|
|
@ -81,6 +84,9 @@ namespace MapControl
|
|||
{
|
||||
switch (xmlReader.Name)
|
||||
{
|
||||
case "BrandLogoUri":
|
||||
logoUri = xmlReader.ReadElementContentAsString();
|
||||
break;
|
||||
case "ImageUrl":
|
||||
imageUrl = xmlReader.ReadElementContentAsString();
|
||||
break;
|
||||
|
|
@ -105,11 +111,11 @@ namespace MapControl
|
|||
}
|
||||
while (xmlReader.NodeType != XmlNodeType.None);
|
||||
|
||||
if (imageUrl != null && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
|
||||
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Culture))
|
||||
if (string.IsNullOrEmpty(Culture))
|
||||
{
|
||||
Culture = CultureInfo.CurrentUICulture.Name;
|
||||
}
|
||||
|
|
@ -125,6 +131,11 @@ namespace MapControl
|
|||
{
|
||||
MaxZoomLevel = zoomMax.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(logoUri))
|
||||
{
|
||||
LogoImage = new BitmapImage(new Uri(logoUri));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace MapControl
|
|||
TileLayers = new ObservableCollection<TileLayer>();
|
||||
|
||||
tileUpdateTimer.Tick += UpdateTiles;
|
||||
Loaded += OnLoaded;
|
||||
Loaded += MapLoaded;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
|
@ -403,9 +403,21 @@ namespace MapControl
|
|||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
Loaded -= OnLoaded;
|
||||
base.OnViewportChanged();
|
||||
|
||||
var viewportChanged = ViewportChanged;
|
||||
|
||||
if (viewportChanged != null)
|
||||
{
|
||||
viewportChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void MapLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Loaded -= MapLoaded;
|
||||
|
||||
if (tileLayerPanel.Children.Count == 0 && !Children.OfType<TileLayer>().Any())
|
||||
{
|
||||
|
|
@ -839,18 +851,6 @@ namespace MapControl
|
|||
OnViewportChanged();
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged()
|
||||
{
|
||||
base.OnViewportChanged();
|
||||
|
||||
var viewportChanged = ViewportChanged;
|
||||
|
||||
if (viewportChanged != null)
|
||||
{
|
||||
viewportChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetViewportTransform(Location origin)
|
||||
{
|
||||
var oldMapOriginX = (viewportOrigin.X - tileLayerOffset.X) / ViewportScale - 180d;
|
||||
|
|
|
|||
|
|
@ -131,16 +131,21 @@ namespace MapControl
|
|||
|
||||
private static void SetViewportPosition(UIElement element, MapBase parentMap, Location location)
|
||||
{
|
||||
Point viewportPosition;
|
||||
var viewportPosition = new Point();
|
||||
|
||||
if (parentMap != null && location != null)
|
||||
{
|
||||
var mapPosition = parentMap.MapTransform.Transform(location, parentMap.Center.Longitude); // nearest to center longitude
|
||||
|
||||
viewportPosition = parentMap.ViewportTransform.Transform(mapPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewportPosition = new Point();
|
||||
|
||||
var useLayoutRounding = element.GetValue(FrameworkElement.UseLayoutRoundingProperty);
|
||||
|
||||
if (useLayoutRounding != null && (bool)useLayoutRounding)
|
||||
{
|
||||
viewportPosition.X = Math.Round(viewportPosition.X);
|
||||
viewportPosition.Y = Math.Round(viewportPosition.Y);
|
||||
}
|
||||
}
|
||||
|
||||
var translateTransform = element.RenderTransform as TranslateTransform;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ using System.Windows;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ namespace MapControl
|
|||
private void GetTiles(IEnumerable<Tile> tiles, Dispatcher dispatcher, TileSource tileSource, string sourceName, int maxDownloads)
|
||||
{
|
||||
var useCache = Cache != null
|
||||
&& !string.IsNullOrWhiteSpace(sourceName)
|
||||
&& !string.IsNullOrEmpty(sourceName)
|
||||
&& !(tileSource is ImageTileSource)
|
||||
&& !tileSource.UriFormat.StartsWith("file:");
|
||||
|
||||
|
|
@ -307,7 +307,6 @@ namespace MapControl
|
|||
int.TryParse(cacheControl.Substring(8), out maxAge))
|
||||
{
|
||||
maxAge = Math.Min(maxAge, (int)DefaultCacheExpiration.TotalSeconds);
|
||||
|
||||
expiration = DateTime.UtcNow.AddSeconds(maxAge);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ namespace MapControl
|
|||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||
"Description", typeof(string), typeof(TileLayer), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty LogoImageProperty = DependencyProperty.Register(
|
||||
"LogoImage", typeof(ImageSource), typeof(TileLayer), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty MinZoomLevelProperty = DependencyProperty.Register(
|
||||
"MinZoomLevel", typeof(int), typeof(TileLayer), new PropertyMetadata(0));
|
||||
|
||||
|
|
@ -84,7 +87,7 @@ namespace MapControl
|
|||
partial void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Controls how map tiles are loaded.
|
||||
/// Provides map tile URIs or images.
|
||||
/// </summary>
|
||||
public TileSource TileSource
|
||||
{
|
||||
|
|
@ -93,7 +96,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the TileSource. Used as key in a TileLayerCollection and to name an optional tile cache.
|
||||
/// Name of the TileSource. Used as key in a TileLayerCollection and as component of a tile cache key.
|
||||
/// </summary>
|
||||
public string SourceName
|
||||
{
|
||||
|
|
@ -102,7 +105,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description of the TileLayer.
|
||||
/// Description of the TileLayer. Used to display copyright information on top of the map.
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
|
|
@ -110,6 +113,15 @@ namespace MapControl
|
|||
set { SetValue(DescriptionProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logo image. Used to display a provider brand logo on top of the map.
|
||||
/// </summary>
|
||||
public ImageSource LogoImage
|
||||
{
|
||||
get { return (ImageSource)GetValue(LogoImageProperty); }
|
||||
set { SetValue(LogoImageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum zoom level supported by the TileLayer.
|
||||
/// </summary>
|
||||
|
|
@ -138,7 +150,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets MapBase.Foreground, if not null.
|
||||
/// Optional foreground brush. Sets MapBase.Foreground, if not null.
|
||||
/// </summary>
|
||||
public Brush Foreground
|
||||
{
|
||||
|
|
@ -147,7 +159,7 @@ namespace MapControl
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets MapBase.Background, if not null.
|
||||
/// Optional background brush. Sets MapBase.Background, if not null.
|
||||
/// New property prevents filling of RenderTransformed TileLayer with Panel.Background.
|
||||
/// </summary>
|
||||
public new Brush Background
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ namespace MapControl
|
|||
get { return uriFormat; }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
throw new ArgumentException("The value of the UriFormat property must not be null or empty or white-space only.", "value");
|
||||
throw new ArgumentException("The value of the UriFormat property must not be null or empty.");
|
||||
}
|
||||
|
||||
uriFormat = value;
|
||||
|
|
@ -154,11 +154,11 @@ namespace MapControl
|
|||
|
||||
private Uri GetBoundingBoxUri(int x, int y, int zoomLevel)
|
||||
{
|
||||
var numTiles = (double)(1 << zoomLevel);
|
||||
var west = MetersPerDegree * ((double)x * 360d / numTiles - 180d);
|
||||
var east = MetersPerDegree * ((double)(x + 1) * 360d / numTiles - 180d);
|
||||
var south = MetersPerDegree * (180d - (double)(y + 1) * 360d / numTiles);
|
||||
var north = MetersPerDegree * (180d - (double)y * 360d / numTiles);
|
||||
var tileSize = 360d / (double)(1 << zoomLevel); // tile width in degrees
|
||||
var west = MetersPerDegree * ((double)x * tileSize - 180d);
|
||||
var east = MetersPerDegree * ((double)(x + 1) * tileSize - 180d);
|
||||
var south = MetersPerDegree * (180d - (double)(y + 1) * tileSize);
|
||||
var north = MetersPerDegree * (180d - (double)y * tileSize);
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{W}", west.ToString(CultureInfo.InvariantCulture)).
|
||||
|
|
@ -169,11 +169,11 @@ namespace MapControl
|
|||
|
||||
private Uri GetLatLonBoundingBoxUri(int x, int y, int zoomLevel)
|
||||
{
|
||||
var numTiles = (double)(1 << zoomLevel);
|
||||
var west = (double)x * 360d / numTiles - 180d;
|
||||
var east = (double)(x + 1) * 360d / numTiles - 180d;
|
||||
var south = MercatorTransform.YToLatitude(180d - (double)(y + 1) * 360d / numTiles);
|
||||
var north = MercatorTransform.YToLatitude(180d - (double)y * 360d / numTiles);
|
||||
var tileSize = 360d / (double)(1 << zoomLevel); // tile width in degrees
|
||||
var west = (double)x * tileSize - 180d;
|
||||
var east = (double)(x + 1) * tileSize - 180d;
|
||||
var south = MercatorTransform.YToLatitude(180d - (double)(y + 1) * tileSize);
|
||||
var north = MercatorTransform.YToLatitude(180d - (double)y * tileSize);
|
||||
|
||||
return new Uri(uriFormat.
|
||||
Replace("{w}", west.ToString(CultureInfo.InvariantCulture)).
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ namespace WpfApplication
|
|||
{
|
||||
if (glyphRun == null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Text))
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("2.4.8")]
|
||||
[assembly: AssemblyFileVersion("2.4.8")]
|
||||
[assembly: AssemblyVersion("2.4.9")]
|
||||
[assembly: AssemblyFileVersion("2.4.9")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue