Improve subdomain notation, fix error catching for xyz in tile URL

This commit is contained in:
stopflock
2025-11-22 22:26:04 -06:00
parent 52af77e1ed
commit 3868236816
12 changed files with 106 additions and 35 deletions
+1 -1
View File
@@ -235,7 +235,7 @@
"urlTemplate": "URL-Vorlage",
"urlTemplateHint": "https://beispiel.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "URL-Vorlage ist erforderlich",
"urlTemplatePlaceholders": "URL muss {z}, {x} und {y} Platzhalter enthalten",
"urlTemplatePlaceholders": "URL muss entweder {quadkey} oder {z}, {x} und {y} Platzhalter enthalten",
"attribution": "Zuschreibung",
"attributionHint": "© Karten-Anbieter",
"attributionRequired": "Zuschreibung ist erforderlich",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "URL Template",
"urlTemplateHint": "https://example.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "URL template is required",
"urlTemplatePlaceholders": "URL must contain {z}, {x}, and {y} placeholders",
"urlTemplatePlaceholders": "URL must contain either {quadkey} or {z}, {x}, and {y} placeholders",
"attribution": "Attribution",
"attributionHint": "© Map Provider",
"attributionRequired": "Attribution is required",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "Plantilla de URL",
"urlTemplateHint": "https://ejemplo.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "La plantilla de URL es requerida",
"urlTemplatePlaceholders": "La URL debe contener marcadores {z}, {x} y {y}",
"urlTemplatePlaceholders": "La URL debe contener marcadores {quadkey} o {z}, {x} y {y}",
"attribution": "Atribución",
"attributionHint": "© Proveedor de Mapas",
"attributionRequired": "La atribución es requerida",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "Modèle d'URL",
"urlTemplateHint": "https://exemple.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "Le modèle d'URL est requis",
"urlTemplatePlaceholders": "L'URL doit contenir les marqueurs {z}, {x} et {y}",
"urlTemplatePlaceholders": "L'URL doit contenir soit {quadkey} soit les marqueurs {z}, {x} et {y}",
"attribution": "Attribution",
"attributionHint": "© Fournisseur de Cartes",
"attributionRequired": "L'attribution est requise",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "Template URL",
"urlTemplateHint": "https://esempio.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "Il template URL è obbligatorio",
"urlTemplatePlaceholders": "L'URL deve contenere i segnaposto {z}, {x} e {y}",
"urlTemplatePlaceholders": "L'URL deve contenere o {quadkey} o i segnaposto {z}, {x} e {y}",
"attribution": "Attribuzione",
"attributionHint": "© Fornitore Mappe",
"attributionRequired": "L'attribuzione è obbligatoria",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "Modelo de URL",
"urlTemplateHint": "https://exemplo.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "Modelo de URL é obrigatório",
"urlTemplatePlaceholders": "URL deve conter os marcadores {z}, {x} e {y}",
"urlTemplatePlaceholders": "URL deve conter {quadkey} ou os marcadores {z}, {x} e {y}",
"attribution": "Atribuição",
"attributionHint": "© Provedor de Mapas",
"attributionRequired": "Atribuição é obrigatória",
+1 -1
View File
@@ -267,7 +267,7 @@
"urlTemplate": "URL 模板",
"urlTemplateHint": "https://example.com/{z}/{x}/{y}.png",
"urlTemplateRequired": "URL 模板为必填项",
"urlTemplatePlaceholders": "URL 必须包含 {z}、{x} 和 {y} 占位符",
"urlTemplatePlaceholders": "URL 必须包含 {quadkey} 或 {z}、{x} 和 {y} 占位符",
"attribution": "归属",
"attributionHint": "© 地图提供商",
"attributionRequired": "归属为必填项",
+17 -5
View File
@@ -20,6 +20,13 @@ class TileType {
});
/// Create URL for a specific tile, replacing template variables
///
/// Supported placeholders:
/// - {x}, {y}, {z}: Standard tile coordinates
/// - {quadkey}: Bing Maps quadkey format (alternative to x/y/z)
/// - {0_3}: Subdomain 0-3 for load balancing
/// - {1_4}: Subdomain 1-4 for providers that use 1-based indexing
/// - {api_key}: API key placeholder (optional)
String getTileUrl(int z, int x, int y, {String? apiKey}) {
String url = urlTemplate;
@@ -29,10 +36,15 @@ class TileType {
url = url.replaceAll('{quadkey}', quadkey);
}
// Handle subdomains (for Bing Maps and other multi-subdomain providers)
if (url.contains('{subdomain}')) {
final subdomain = (x + y) % 4; // Distribute across 0-3 subdomains
url = url.replaceAll('{subdomain}', subdomain.toString());
// Handle subdomains for load balancing
if (url.contains('{0_3}')) {
final subdomain = (x + y) % 4; // 0, 1, 2, 3
url = url.replaceAll('{0_3}', subdomain.toString());
}
if (url.contains('{1_4}')) {
final subdomain = ((x + y) % 4) + 1; // 1, 2, 3, 4
url = url.replaceAll('{1_4}', subdomain.toString());
}
// Standard x/y/z replacement
@@ -196,7 +208,7 @@ class DefaultTileProviders {
TileType(
id: 'bing_satellite',
name: 'Satellite',
urlTemplate: 'https://ecn.t{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=1&n=z',
urlTemplate: 'https://ecn.t{0_3}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=1&n=z',
attribution: '© Microsoft Corporation',
maxZoom: 20,
),
+21 -6
View File
@@ -318,9 +318,15 @@ class _TileTypeDialogState extends State<_TileTypeDialog> {
),
validator: (value) {
if (value?.trim().isEmpty == true) return locService.t('tileTypeEditor.urlTemplateRequired');
if (!value!.contains('{z}') || !value.contains('{x}') || !value.contains('{y}')) {
// Check for either quadkey OR x+y+z placeholders
final hasQuadkey = value!.contains('{quadkey}');
final hasXYZ = value.contains('{x}') && value.contains('{y}') && value.contains('{z}');
if (!hasQuadkey && !hasXYZ) {
return locService.t('tileTypeEditor.urlTemplatePlaceholders');
}
return null;
},
),
@@ -403,11 +409,20 @@ class _TileTypeDialogState extends State<_TileTypeDialog> {
});
try {
// Use a sample tile from configured preview location
final url = _urlController.text
.replaceAll('{z}', kPreviewTileZoom.toString())
.replaceAll('{x}', kPreviewTileX.toString())
.replaceAll('{y}', kPreviewTileY.toString());
// Create a temporary TileType to use the getTileUrl method
final tempTileType = TileType(
id: 'preview',
name: 'Preview',
urlTemplate: _urlController.text.trim(),
attribution: 'Preview',
);
final url = tempTileType.getTileUrl(
kPreviewTileZoom,
kPreviewTileX,
kPreviewTileY,
apiKey: null, // Don't use API key for preview
);
final response = await http.get(Uri.parse(url));