feat: prepare Pro licensing and Android API 36

This commit is contained in:
livio committed 2026-09-28 09:50:58 +02:00
1 parent b600412285
commit 11a91863a3
25 files changed
+2447 -62

No files matched your search

+23 -4
View File
@@ -31,7 +31,8 @@ body {
button,
input,
select {
select,
textarea {
font: inherit;
}
@@ -54,16 +55,34 @@ button:disabled {
}
input,
select {
select,
textarea {
width: 100%;
min-height: 44px;
border: 1px solid #bfcbd2;
border-radius: 6px;
padding: 0 11px;
background: #fff;
color: var(--ink);
}
input,
select {
min-height: 44px;
padding: 0 11px;
}
textarea {
padding: 9px 11px;
resize: vertical;
}
.license-code-input {
min-height: 108px;
font-family: Consolas, "Courier New", monospace;
font-size: 11px;
line-height: 1.35;
overflow-wrap: anywhere;
}
input[type="range"],
input[type="checkbox"] {
min-height: auto;
+92 -19
View File
@@ -92,7 +92,20 @@ const lmeState = {
changeNotifyTimer: null,
offlineDbPromise: null,
offlineTileCount: 0,
dotNetReference: null
dotNetReference: null,
culture: "it-IT",
measurementSystem: "metric",
entitlements: {
advancedGeometry: false
},
labels: {
measureArea: "Misura area",
measureDistance: "Misura distanza",
measureCircle: "Misura cerchio",
drawRectangle: "Disegna rettangolo",
addPoi: "Aggiungi POI",
proRequired: "Funzione inclusa in LME Pro."
}
};
// AdE publishes the cadastral WMS in ETRS89. WMS 1.1.1 keeps the longitude,
@@ -167,9 +180,38 @@ window.lmeMap = {
clearOfflineTiles,
getOfflineTileStats,
resize,
setLocalization,
setEntitlements,
showInfo: setInfo
};
function setLocalization(options = {}) {
lmeState.culture = options.culture || lmeState.culture || "it-IT";
lmeState.measurementSystem = options.measurementSystem === "imperial" ? "imperial" : "metric";
lmeState.labels = { ...lmeState.labels, ...(options.labels || {}) };
configureDrawLabels();
if (lmeState.drawControl) {
const wasVisible = true;
setDrawToolsVisible(false);
if (wasVisible) {
setDrawToolsVisible(true);
}
}
refreshImportedMeasurements();
refreshDrawingMeasurements();
refreshLayerManager();
}
function setEntitlements(options = {}) {
lmeState.entitlements = { ...lmeState.entitlements, ...options };
}
function requireProFeature(feature) {
if (lmeState.entitlements?.[feature]) return true;
setInfo(lmeState.labels.proRequired || "Funzione inclusa in LME Pro.");
return false;
}
function init(dotNetReference) {
if (dotNetReference) {
lmeState.dotNetReference = dotNetReference;
@@ -2634,6 +2676,7 @@ async function moveManagedRecords(records) {
}
async function bufferManagedRecords(records) {
if (!requireProFeature("advancedGeometry")) return;
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return; }
const result = await showFormDialog("Crea buffer", [{ name: "meters", label: "Distanza in metri", type: "number", value: "5", step: "0.01" }], "Crea buffer");
if (!result) return;
@@ -2651,6 +2694,7 @@ async function bufferManagedRecords(records) {
}
function unionManagedRecords(records) {
if (!requireProFeature("advancedGeometry")) return;
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return; }
const polygons = records.filter(record => record.layer instanceof L.Polygon).map(record => record.layer.toGeoJSON());
if (polygons.length < 2) { setInfo("Per unire seleziona almeno due aree o poligoni."); return; }
@@ -2667,6 +2711,7 @@ function unionManagedRecords(records) {
}
function splitManagedRecords(records) {
if (!requireProFeature("advancedGeometry")) return;
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return; }
const polygonRecord = records.find(record => record.layer instanceof L.Polygon);
const lineRecord = records.find(record => record.layer instanceof L.Polyline && !(record.layer instanceof L.Polygon));
@@ -2696,6 +2741,7 @@ function selectedManagedRecords() {
}
function createHoleFromSelected() {
if (!requireProFeature("advancedGeometry")) return false;
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return false; }
const polygons = selectedManagedRecords().filter(record => record.layer instanceof L.Polygon);
if (polygons.length !== 2) { showGeometryResult("Creazione foro", "Seleziona esattamente due poligoni: l'area esterna e l'area interna da escludere.", "warning"); return false; }
@@ -2718,6 +2764,7 @@ function createHoleFromSelected() {
}
function validateAndRepairSelected() {
if (!requireProFeature("advancedGeometry")) return "LME Pro richiesto";
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return "Progetto in sola lettura"; }
const records = selectedManagedRecords();
if (!records.length) { showGeometryResult("Controlla e ripara", "Seleziona uno o più oggetti dalla mappa, dal pannello Layer o dalla tabella oggetti.", "warning"); return "Nessuna selezione"; }
@@ -2750,6 +2797,7 @@ function validateAndRepairSelected() {
}
function compareSelectedGeometries() {
if (!requireProFeature("advancedGeometry")) return false;
if (lmeState.readOnly) { setInfo("Il progetto e' in sola lettura."); return false; }
const polygons = selectedManagedRecords().filter(record => record.layer instanceof L.Polygon);
if (polygons.length !== 2) { showGeometryResult("Confronta due confini", "Seleziona esattamente due poligoni dalla mappa, dal pannello Layer o dalla tabella oggetti.", "warning"); return false; }
@@ -3747,11 +3795,11 @@ function addProjectMarker(name) {
}
function configureDrawLabels() {
L.drawLocal.draw.toolbar.buttons.polygon = "Misura area";
L.drawLocal.draw.toolbar.buttons.polyline = "Misura distanza";
L.drawLocal.draw.toolbar.buttons.circle = "Misura cerchio";
L.drawLocal.draw.toolbar.buttons.rectangle = "Disegna rettangolo";
L.drawLocal.draw.toolbar.buttons.marker = "Aggiungi POI";
L.drawLocal.draw.toolbar.buttons.polygon = lmeState.labels.measureArea;
L.drawLocal.draw.toolbar.buttons.polyline = lmeState.labels.measureDistance;
L.drawLocal.draw.toolbar.buttons.circle = lmeState.labels.measureCircle;
L.drawLocal.draw.toolbar.buttons.rectangle = lmeState.labels.drawRectangle;
L.drawLocal.draw.toolbar.buttons.marker = lmeState.labels.addPoi;
L.drawLocal.edit.toolbar.buttons.edit = "Scegli quali disegni modificare";
L.drawLocal.edit.toolbar.buttons.remove = "Scegli quali disegni eliminare";
L.drawLocal.draw.handlers.polygon.tooltip.start = "Tocca il primo vertice dell'area.";
@@ -3842,19 +3890,19 @@ function enableDrawTools() {
}
},
draw: {
circle: { metric: true, feet: false, showRadius: true, shapeOptions: orangeArea },
circle: { metric: usesMetricMeasurements(), feet: usesImperialMeasurements(), showRadius: true, shapeOptions: orangeArea },
circlemarker: false,
marker: { zIndexOffset: 0 },
polygon: {
metric: true,
feet: false,
metric: usesMetricMeasurements(),
feet: usesImperialMeasurements(),
showArea: true,
allowIntersection: false,
shapeOptions: orangeArea
},
polyline: {
metric: true,
feet: false,
metric: usesMetricMeasurements(),
feet: usesImperialMeasurements(),
showLength: true,
shapeOptions: {
pane: "drawingsPane",
@@ -3864,7 +3912,7 @@ function enableDrawTools() {
opacity: 0.95
}
},
rectangle: { metric: true, shapeOptions: orangeArea }
rectangle: { metric: usesMetricMeasurements(), feet: usesImperialMeasurements(), shapeOptions: orangeArea }
}
});
lmeState.map.addControl(lmeState.drawControl);
@@ -4018,8 +4066,8 @@ function startMeasurementDrawing(mode) {
area: () => new L.Draw.Polygon(lmeState.map, {
allowIntersection: false,
showArea: true,
metric: true,
feet: false,
metric: usesMetricMeasurements(),
feet: usesImperialMeasurements(),
shapeOptions: {
pane: "drawingsPane",
renderer: lmeState.drawingsRenderer,
@@ -4030,8 +4078,8 @@ function startMeasurementDrawing(mode) {
}
}),
distance: () => new L.Draw.Polyline(lmeState.map, {
metric: true,
feet: false,
metric: usesMetricMeasurements(),
feet: usesImperialMeasurements(),
showLength: true,
shapeOptions: {
pane: "drawingsPane",
@@ -4042,8 +4090,8 @@ function startMeasurementDrawing(mode) {
}
}),
circle: () => new L.Draw.Circle(lmeState.map, {
metric: true,
feet: false,
metric: usesMetricMeasurements(),
feet: usesImperialMeasurements(),
showRadius: true,
shapeOptions: {
pane: "drawingsPane",
@@ -4447,6 +4495,14 @@ function addMeasurementLabel(targetGroup, latLng, html, labelType, context) {
}
function formatDistance(meters) {
if (usesImperialMeasurements()) {
const feet = meters * 3.280839895;
if (feet >= 5280) {
return `${formatNumber(feet / 5280, 3)} mi`;
}
return `${formatNumber(feet, feet < 100 ? 1 : 0)} ft`;
}
if (meters >= 1000) {
return `${formatNumber(meters / 1000, 3)} km`;
}
@@ -4454,6 +4510,15 @@ function formatDistance(meters) {
}
function formatArea(squareMeters) {
if (usesImperialMeasurements()) {
const squareFeet = squareMeters * 10.763910417;
const acres = squareMeters * 0.000247105381;
if (acres >= 1) {
return `${formatNumber(acres, 3)} ac`;
}
return `${formatNumber(squareFeet, squareFeet < 100 ? 1 : 0)} ft²`;
}
if (squareMeters >= 10000) {
return `${formatNumber(squareMeters / 10000, 4)} ha`;
}
@@ -4461,12 +4526,20 @@ function formatArea(squareMeters) {
}
function formatNumber(value, digits) {
return new Intl.NumberFormat("it-IT", {
return new Intl.NumberFormat(lmeState.culture || "it-IT", {
minimumFractionDigits: 0,
maximumFractionDigits: digits
}).format(value);
}
function usesMetricMeasurements() {
return lmeState.measurementSystem !== "imperial";
}
function usesImperialMeasurements() {
return lmeState.measurementSystem === "imperial";
}
function createMapExportGeoJson(options) {
migrateMisclassifiedImportedSheets();
const requested = options || {};