feat: prepare Pro licensing and Android API 36
This commit is contained in:
1 parent
b600412285
commit
11a91863a3
25 files changed
+2447
-62
No files matched your search
+254
-26
@@ -10,9 +10,11 @@
|
||||
@inject MapExportService MapExportService
|
||||
@inject CloudSyncService CloudSyncService
|
||||
@inject AppUpdateService AppUpdateService
|
||||
@inject AppLocalizationService L10n
|
||||
@inject EntitlementService Entitlements
|
||||
@implements IAsyncDisposable
|
||||
|
||||
<PageTitle>LME Mappe Catastali</PageTitle>
|
||||
<PageTitle>LME Mappe Catastali Pro</PageTitle>
|
||||
|
||||
<div class="map-app">
|
||||
<section class="map-stage @(ActiveTab == "search" ? "search-active" : null)">
|
||||
@@ -40,14 +42,14 @@
|
||||
@if (NavigationMenuOpen)
|
||||
{
|
||||
<nav class="map-navigation-menu" aria-label="Menu principale">
|
||||
<button @onclick='() => SelectTab("map")'>Mappa</button>
|
||||
<button @onclick='() => SelectTab("search")'>Cerca località</button>
|
||||
<button @onclick='() => SelectTab("cadastre")'>Ricerca catastale</button>
|
||||
<button @onclick='() => SelectTab("data")'>Dati e disegni</button>
|
||||
<button @onclick='() => SelectTab("projects")'>Progetti</button>
|
||||
<button @onclick='() => SelectTab("save")'>Esporta</button>
|
||||
<button @onclick='() => SelectTab("tools")'>Strumenti avanzati</button>
|
||||
<button @onclick='() => SelectTab("settings")'>Impostazioni</button>
|
||||
<button @onclick='() => SelectTab("map")'>@L("menu.map")</button>
|
||||
<button @onclick='() => SelectTab("search")'>@L("menu.search")</button>
|
||||
<button @onclick='() => SelectTab("cadastre")'>@L("menu.cadastre")</button>
|
||||
<button @onclick='() => SelectTab("data")'>@L("menu.data")</button>
|
||||
<button @onclick='() => SelectTab("projects")'>@L("menu.projects")</button>
|
||||
<button @onclick='() => SelectTab("save")'>@L("menu.export")</button>
|
||||
<button @onclick='() => SelectTab("tools")'>@L("menu.tools")</button>
|
||||
<button @onclick='() => SelectTab("settings")'>@L("menu.settings")</button>
|
||||
<div class="menu-credits"><strong>LME Mappe Catastali</strong><span>Autore: Livio Merola</span><a href="mailto:info@liviomerola.net">info@liviomerola.net</a><span>Mappe: Esri, OpenStreetMap, CARTO, OpenTopoMap. Catasto: Agenzia delle Entrate CC BY 4.0.</span></div>
|
||||
</nav>
|
||||
}
|
||||
@@ -307,9 +309,13 @@
|
||||
<span>Traccia GPS registrata</span>
|
||||
</label>
|
||||
</div>
|
||||
<button class="primary-command" @onclick="ExportMapFile" disabled="@(ExportBusy || string.IsNullOrWhiteSpace(ExportFileName))">
|
||||
<button class="primary-command" @onclick="ExportMapFile" disabled="@(ExportBusy || string.IsNullOrWhiteSpace(ExportFileName) || !CanUse(AppFeatures.Export))">
|
||||
@(ExportBusy ? "Preparazione file..." : "Esporta e salva file")
|
||||
</button>
|
||||
@if (!CanUse(AppFeatures.Export))
|
||||
{
|
||||
<small class="field-help">@ProUpgradeText</small>
|
||||
}
|
||||
<small class="field-help">KML e KMZ sono compatibili con Google Earth. Gli sfondi satellitari e il WMS non vengono incorporati nel file vettoriale.</small>
|
||||
</section>
|
||||
|
||||
@@ -329,7 +335,11 @@
|
||||
<input type="checkbox" @bind="IncludeCadastralParcels" @bind:after="SaveFlagPreferences" />
|
||||
<span>Includi le particelle catastali evidenziate</span>
|
||||
</label>
|
||||
<button class="primary-command" @onclick="SaveProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(NewProjectName))">Salva progetto</button>
|
||||
<button class="primary-command" @onclick="SaveProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(NewProjectName) || !CanUse(AppFeatures.ProjectArchive))">Salva progetto</button>
|
||||
@if (!CanUse(AppFeatures.ProjectArchive))
|
||||
{
|
||||
<small class="field-help">@ProUpgradeText</small>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section class="panel-section">
|
||||
@@ -353,12 +363,12 @@
|
||||
<input @bind="ProjectFolder" placeholder="Es. Cantieri 2026" maxlength="60" />
|
||||
</label>
|
||||
<div class="project-command-stack">
|
||||
<button class="secondary-command" @onclick="UpdateProjectFolder" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId))">Sposta</button>
|
||||
<button class="secondary-command" @onclick="RenameProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || SelectedProject?.IsReadOnly == true)">Rinomina</button>
|
||||
<button class="secondary-command" @onclick="DuplicateProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId))">Duplica</button>
|
||||
<button class="secondary-command" @onclick="ToggleProjectArchive" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId))">@(SelectedProject?.IsArchived == true ? "Ripristina" : "Archivia")</button>
|
||||
<button class="secondary-command" @onclick='() => ShareProject(false)' disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId))">Condividi modificabile</button>
|
||||
<button class="secondary-command" @onclick='() => ShareProject(true)' disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId))">Condividi in sola lettura</button>
|
||||
<button class="secondary-command" @onclick="UpdateProjectFolder" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || !CanUse(AppFeatures.ProjectArchive))">Sposta</button>
|
||||
<button class="secondary-command" @onclick="RenameProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || SelectedProject?.IsReadOnly == true || !CanUse(AppFeatures.ProjectArchive))">Rinomina</button>
|
||||
<button class="secondary-command" @onclick="DuplicateProject" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || !CanUse(AppFeatures.ProjectArchive))">Duplica</button>
|
||||
<button class="secondary-command" @onclick="ToggleProjectArchive" disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || !CanUse(AppFeatures.ProjectArchive))">@(SelectedProject?.IsArchived == true ? "Ripristina" : "Archivia")</button>
|
||||
<button class="secondary-command" @onclick='() => ShareProject(false)' disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || !CanUse(AppFeatures.ProjectArchive))">Condividi modificabile</button>
|
||||
<button class="secondary-command" @onclick='() => ShareProject(true)' disabled="@(ProjectBusy || string.IsNullOrWhiteSpace(SelectedProjectId) || !CanUse(AppFeatures.ProjectArchive))">Condividi in sola lettura</button>
|
||||
</div>
|
||||
@if (SelectedProject?.IsReadOnly == true)
|
||||
{
|
||||
@@ -392,10 +402,10 @@
|
||||
<section class="panel-section">
|
||||
<h2>Backup e trasferimento</h2>
|
||||
<div class="button-row">
|
||||
<button class="secondary-command" @onclick="ShareFullBackup">Crea backup</button>
|
||||
<button class="secondary-command" @onclick="RestoreBackup">Ripristina backup</button>
|
||||
<button class="secondary-command" @onclick="ShareFullBackup" disabled="@(!CanUse(AppFeatures.ProjectArchive))">Crea backup</button>
|
||||
<button class="secondary-command" @onclick="RestoreBackup" disabled="@(!CanUse(AppFeatures.ProjectArchive))">Ripristina backup</button>
|
||||
</div>
|
||||
<button class="secondary-command" @onclick="ImportProject">Importa progetto condiviso</button>
|
||||
<button class="secondary-command" @onclick="ImportProject" disabled="@(!CanUse(AppFeatures.ProjectArchive))">Importa progetto condiviso</button>
|
||||
</section>
|
||||
|
||||
<section class="panel-section">
|
||||
@@ -443,7 +453,7 @@
|
||||
Livelli di zoom aggiuntivi
|
||||
<input type="number" min="0" max="4" @bind="OfflineExtraZoomLevels" />
|
||||
</label>
|
||||
<button class="primary-command" @onclick="DownloadOfflineArea" disabled="@OfflineBusy">@(OfflineBusy ? "Download in corso..." : "Scarica area visibile")</button>
|
||||
<button class="primary-command" @onclick="DownloadOfflineArea" disabled="@(OfflineBusy || !CanUse(AppFeatures.OfflineMaps))">@(OfflineBusy ? "Download in corso..." : "Scarica area visibile")</button>
|
||||
<div class="button-row">
|
||||
<button class="secondary-command" @onclick="UseOfflineMap">Usa mappe offline</button>
|
||||
<button class="danger-command" @onclick="ClearOfflineArea">Svuota archivio</button>
|
||||
@@ -456,6 +466,66 @@
|
||||
else if (ActiveTab == "settings")
|
||||
{
|
||||
<section class="panel-content">
|
||||
<section class="panel-section">
|
||||
<h2>@L("settings.localization.title")</h2>
|
||||
<label>
|
||||
@L("settings.language")
|
||||
<select @bind="LanguagePreference" @bind:after="ApplyLanguagePreference">
|
||||
<option value="auto">@L("settings.language.auto")</option>
|
||||
<option value="it">@L("settings.language.it")</option>
|
||||
<option value="en">@L("settings.language.en")</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
@L("settings.measurements")
|
||||
<select @bind="MeasurementPreference" @bind:after="ApplyMeasurementPreference">
|
||||
<option value="auto">@L("settings.measurements.auto")</option>
|
||||
<option value="metric">@L("settings.measurements.metric")</option>
|
||||
<option value="imperial">@L("settings.measurements.imperial")</option>
|
||||
</select>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section class="panel-section">
|
||||
<h2>@L("settings.pro.title")</h2>
|
||||
<div class="service-note">
|
||||
<strong>@L("settings.pro.status"): @Entitlements.PlanLabel</strong>
|
||||
<p>@L("settings.pro.note")</p>
|
||||
<p>@L("settings.pro.offline")</p>
|
||||
<div class="button-row">
|
||||
<button class="primary-command" @onclick='() => SubscribeGooglePro(EntitlementService.MonthlyBasePlanId)' disabled="@BillingBusy">@L("settings.pro.monthly")</button>
|
||||
<button class="primary-command" @onclick='() => SubscribeGooglePro(EntitlementService.YearlyBasePlanId)' disabled="@BillingBusy">@L("settings.pro.yearly")</button>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="secondary-command" @onclick="RestorePurchases" disabled="@BillingBusy">@L("settings.pro.restore")</button>
|
||||
<button class="secondary-command" @onclick="OpenSubscriptionManagement">@L("settings.pro.manage")</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
@L("settings.pro.manual.code")
|
||||
<textarea class="license-code-input" @bind="ManualLicenseCode" rows="5" spellcheck="false" autocomplete="off" placeholder="LME1..."></textarea>
|
||||
</label>
|
||||
<small class="field-help">@L("settings.pro.manual.help")</small>
|
||||
<div class="button-row">
|
||||
<button class="primary-command" @onclick="ActivateManualLicense" disabled="@string.IsNullOrWhiteSpace(ManualLicenseCode)">@L("settings.pro.manual.activate")</button>
|
||||
<button class="secondary-command" @onclick="RemoveManualLicense" disabled="@(Entitlements.ManualLicense is null)">@L("settings.pro.manual.remove")</button>
|
||||
</div>
|
||||
@if (Entitlements.ManualLicense is { } manualLicense)
|
||||
{
|
||||
<div class="service-note">
|
||||
<strong>@manualLicense.HolderName</strong>
|
||||
<p>@manualLicense.Email</p>
|
||||
<p>@L("settings.pro.manual.expires"): @manualLicense.ExpiresAtUtc.ToLocalTime().ToString("g", L10n.Culture)</p>
|
||||
<p>@(Entitlements.HasManualProAccess ? L("settings.pro.manual.valid") : L("settings.pro.manual.expired"))</p>
|
||||
</div>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(ManualLicenseMessage))
|
||||
{
|
||||
<small class="field-help">@ManualLicenseMessage</small>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section class="panel-section">
|
||||
<h2>Mappa e sfondo</h2>
|
||||
<label>
|
||||
@@ -546,8 +616,8 @@
|
||||
</label>
|
||||
<button class="secondary-command" @onclick="SaveWebDavSettings">Salva configurazione</button>
|
||||
<div class="button-row">
|
||||
<button class="primary-command" @onclick="SyncUpload" disabled="@SyncBusy">Invia al cloud</button>
|
||||
<button class="secondary-command" @onclick="SyncDownload" disabled="@SyncBusy">Scarica dal cloud</button>
|
||||
<button class="primary-command" @onclick="SyncUpload" disabled="@(SyncBusy || !CanUse(AppFeatures.CloudSync))">Invia al cloud</button>
|
||||
<button class="secondary-command" @onclick="SyncDownload" disabled="@(SyncBusy || !CanUse(AppFeatures.CloudSync))">Scarica dal cloud</button>
|
||||
</div>
|
||||
<small class="field-help">@SyncStatus</small>
|
||||
</section>
|
||||
@@ -573,7 +643,7 @@
|
||||
<span>Mostra punto e cerchio GPS</span>
|
||||
</label>
|
||||
<label class="toggle-line project-save-option">
|
||||
<input type="checkbox" @bind="TrailEnabled" @bind:after="ApplyTrailOption" />
|
||||
<input type="checkbox" @bind="TrailEnabled" @bind:after="ApplyTrailOption" disabled="@(!CanUse(AppFeatures.GpsTrail))" />
|
||||
<span>Registra la traccia mentre cammini</span>
|
||||
</label>
|
||||
<div class="button-row">
|
||||
@@ -644,6 +714,11 @@
|
||||
private string ProjectArchiveMessage { get; set; } = "Nessun progetto salvato.";
|
||||
private string ProjectFolder { get; set; } = string.Empty;
|
||||
private string SelectedVersionId { get; set; } = string.Empty;
|
||||
private string LanguagePreference { get; set; } = "auto";
|
||||
private string MeasurementPreference { get; set; } = "auto";
|
||||
private string ManualLicenseCode { get; set; } = string.Empty;
|
||||
private string ManualLicenseMessage { get; set; } = string.Empty;
|
||||
private bool BillingBusy { get; set; }
|
||||
private string Status { get; set; } = "online";
|
||||
private string SelectedBaseLayer { get; set; } = "satellite";
|
||||
private string GoogleMapsApiKey { get; set; } = string.Empty;
|
||||
@@ -700,6 +775,7 @@
|
||||
private string UpdateStatus { get; set; } = $"Versione installata: {AppUpdateService.CurrentVersion}";
|
||||
private string UpdateDownloadUrl { get; set; } = string.Empty;
|
||||
private string UpdateReleaseNotes { get; set; } = string.Empty;
|
||||
private string ProUpgradeText => "Funzione inclusa in LME Pro. I dati esistenti restano consultabili.";
|
||||
private CancellationTokenSource? CatalogCancellation { get; set; }
|
||||
private CancellationTokenSource? GpsLookupCancellation { get; set; }
|
||||
private CancellationTokenSource? ProjectAutoSaveCancellation { get; set; }
|
||||
@@ -727,7 +803,7 @@
|
||||
"projects" => "Archivio progetti",
|
||||
"save" => "Salvataggio ed esportazione",
|
||||
"tools" => "Strumenti avanzati",
|
||||
"settings" => "Impostazioni",
|
||||
"settings" => L("panel.settings.title"),
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
@@ -738,7 +814,7 @@
|
||||
"projects" => "Salva, apri e visualizza i tuoi lavori",
|
||||
"save" => "Esporta file GIS",
|
||||
"tools" => "Oggetti, geometrie, coordinate e offline",
|
||||
"settings" => "Mappa, GPS e servizi ufficiali",
|
||||
"settings" => L("panel.settings.eyebrow"),
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
@@ -754,6 +830,11 @@
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
L10n.Load();
|
||||
L10n.ApplyCulture();
|
||||
await Entitlements.LoadAsync();
|
||||
LanguagePreference = L10n.LanguagePreference;
|
||||
MeasurementPreference = L10n.MeasurementPreference;
|
||||
LoadFlagPreferences();
|
||||
|
||||
try
|
||||
@@ -797,6 +878,8 @@
|
||||
{
|
||||
MapCallbackReference = DotNetObjectReference.Create(this);
|
||||
await JS.InvokeVoidAsync("lmeMap.init", MapCallbackReference);
|
||||
await ApplyLocalizationToMapAsync();
|
||||
await ApplyEntitlementsToMapAsync();
|
||||
await ApplyFlagPreferencesToMapAsync();
|
||||
await ApplyAdvancedOptions();
|
||||
await CenterOnInitialLocationAsync();
|
||||
@@ -1418,6 +1501,7 @@
|
||||
|
||||
private async Task DuplicateProject()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
if (SelectedProject is null) return;
|
||||
var copy = await ProjectStorageService.DuplicateAsync(SelectedProject.Id);
|
||||
await RefreshProjectsAsync();
|
||||
@@ -1429,6 +1513,7 @@
|
||||
|
||||
private async Task RenameProject()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
if (SelectedProject is not { } project) return;
|
||||
var requestedName = await JS.InvokeAsync<string?>("lmeMap.promptProjectName", project.Name);
|
||||
if (string.IsNullOrWhiteSpace(requestedName)
|
||||
@@ -1463,6 +1548,7 @@
|
||||
|
||||
private async Task UpdateProjectFolder()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
if (SelectedProject is null) return;
|
||||
await ProjectStorageService.UpdateOrganizationAsync(SelectedProject.Id, ProjectFolder);
|
||||
await RefreshProjectsAsync();
|
||||
@@ -1471,6 +1557,7 @@
|
||||
|
||||
private async Task ToggleProjectArchive()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
if (SelectedProject is not { } project) return;
|
||||
await ProjectStorageService.UpdateOrganizationAsync(project.Id, isArchived: !project.IsArchived);
|
||||
await RefreshProjectsAsync();
|
||||
@@ -1479,6 +1566,7 @@
|
||||
|
||||
private async Task ShareProject(bool readOnly)
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
if (SelectedProject is null) return;
|
||||
var path = await ProjectStorageService.CreateProjectPackageAsync(SelectedProject.Id, readOnly);
|
||||
await Share.Default.RequestAsync(new ShareFileRequest { Title = readOnly ? "Condividi progetto LME in sola lettura" : "Condividi progetto LME modificabile", File = new ShareFile(path, "application/json") });
|
||||
@@ -1486,12 +1574,14 @@
|
||||
|
||||
private async Task ShareFullBackup()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
var path = await ProjectStorageService.CreateBackupAsync();
|
||||
await Share.Default.RequestAsync(new ShareFileRequest { Title = "Backup completo LME Mappe Catastali", File = new ShareFile(path, "application/zip") });
|
||||
}
|
||||
|
||||
private async Task RestoreBackup()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
var file = await FilePicker.Default.PickAsync(new PickOptions { PickerTitle = "Scegli backup LME" });
|
||||
if (file is null) return;
|
||||
var path = await CopyPickedFileToCacheAsync(file);
|
||||
@@ -1502,6 +1592,7 @@
|
||||
|
||||
private async Task ImportProject()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive)) { await ShowProRequiredAsync(); return; }
|
||||
var file = await FilePicker.Default.PickAsync(new PickOptions { PickerTitle = "Scegli progetto LME" });
|
||||
if (file is null) return;
|
||||
var path = await CopyPickedFileToCacheAsync(file);
|
||||
@@ -1541,6 +1632,12 @@
|
||||
|
||||
private async Task ExportMapFile()
|
||||
{
|
||||
if (!CanUse(AppFeatures.Export))
|
||||
{
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ExportImported && !ExportImportedSheets && !ExportCadastral
|
||||
&& !ExportDrawings && !ExportPoi && !ExportTrail)
|
||||
{
|
||||
@@ -1583,6 +1680,12 @@
|
||||
|
||||
private async Task SaveProject()
|
||||
{
|
||||
if (!CanUse(AppFeatures.ProjectArchive))
|
||||
{
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
var name = NewProjectName.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
@@ -1731,6 +1834,12 @@
|
||||
|
||||
private async Task DownloadOfflineArea()
|
||||
{
|
||||
if (!CanUse(AppFeatures.OfflineMaps))
|
||||
{
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
OfflineBusy = true;
|
||||
try
|
||||
{
|
||||
@@ -1765,6 +1874,12 @@
|
||||
|
||||
private async Task SyncUpload()
|
||||
{
|
||||
if (!CanUse(AppFeatures.CloudSync))
|
||||
{
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
SyncBusy = true;
|
||||
try
|
||||
{
|
||||
@@ -1779,6 +1894,12 @@
|
||||
|
||||
private async Task SyncDownload()
|
||||
{
|
||||
if (!CanUse(AppFeatures.CloudSync))
|
||||
{
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await JS.InvokeAsync<bool>("lmeMap.confirmDiscardChanges", "ripristinare l'archivio cloud")) return;
|
||||
SyncBusy = true;
|
||||
try
|
||||
@@ -1829,8 +1950,115 @@
|
||||
}
|
||||
|
||||
private Task CenterOnGps() => JS.InvokeVoidAsync("lmeMap.centerOnGps").AsTask();
|
||||
|
||||
private string L(string key) => L10n.T(key);
|
||||
|
||||
private bool CanUse(string feature) => Entitlements.CanUse(feature);
|
||||
|
||||
private Task ShowProRequiredAsync() => JS.InvokeVoidAsync("lmeMap.showInfo", ProUpgradeText).AsTask();
|
||||
|
||||
private async Task ApplyLanguagePreference()
|
||||
{
|
||||
L10n.SetLanguage(LanguagePreference);
|
||||
LanguagePreference = L10n.LanguagePreference;
|
||||
await ApplyLocalizationToMapAsync();
|
||||
}
|
||||
|
||||
private async Task ApplyMeasurementPreference()
|
||||
{
|
||||
L10n.SetMeasurementSystem(MeasurementPreference);
|
||||
MeasurementPreference = L10n.MeasurementPreference;
|
||||
await ApplyLocalizationToMapAsync();
|
||||
}
|
||||
|
||||
private Task ApplyLocalizationToMapAsync() => JS.InvokeVoidAsync("lmeMap.setLocalization", new
|
||||
{
|
||||
culture = L10n.Culture.Name,
|
||||
measurementSystem = L10n.MeasurementSystem,
|
||||
labels = new
|
||||
{
|
||||
measureArea = L("measure.area"),
|
||||
measureDistance = L("measure.distance"),
|
||||
measureCircle = L("measure.circle"),
|
||||
drawRectangle = L("measure.rectangle"),
|
||||
addPoi = L("measure.poi"),
|
||||
proRequired = ProUpgradeText
|
||||
}
|
||||
}).AsTask();
|
||||
|
||||
private Task ApplyEntitlementsToMapAsync() => JS.InvokeVoidAsync("lmeMap.setEntitlements", new
|
||||
{
|
||||
advancedGeometry = CanUse(AppFeatures.AdvancedGeometry)
|
||||
}).AsTask();
|
||||
|
||||
private async Task RestorePurchases()
|
||||
{
|
||||
BillingBusy = true;
|
||||
try
|
||||
{
|
||||
var result = await Entitlements.RestorePurchasesAsync();
|
||||
await ApplyEntitlementsToMapAsync();
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", result.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BillingBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SubscribeGooglePro(string basePlanId)
|
||||
{
|
||||
BillingBusy = true;
|
||||
try
|
||||
{
|
||||
var result = await Entitlements.PurchaseGoogleProAsync(basePlanId);
|
||||
await ApplyEntitlementsToMapAsync();
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", result.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BillingBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ActivateManualLicense()
|
||||
{
|
||||
var result = await Entitlements.ActivateManualLicenseAsync(ManualLicenseCode);
|
||||
ManualLicenseMessage = result.IsValid
|
||||
? L("settings.pro.manual.activated")
|
||||
: result.Error ?? L("settings.pro.manual.invalid");
|
||||
if (result.IsValid)
|
||||
{
|
||||
ManualLicenseCode = string.Empty;
|
||||
}
|
||||
|
||||
await ApplyEntitlementsToMapAsync();
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", ManualLicenseMessage);
|
||||
}
|
||||
|
||||
private async Task RemoveManualLicense()
|
||||
{
|
||||
await Entitlements.RemoveManualLicenseAsync();
|
||||
ManualLicenseCode = string.Empty;
|
||||
ManualLicenseMessage = L("settings.pro.manual.removed");
|
||||
await ApplyEntitlementsToMapAsync();
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", ManualLicenseMessage);
|
||||
}
|
||||
|
||||
private Task OpenSubscriptionManagement() => Launcher.Default.OpenAsync(new Uri(
|
||||
"https://play.google.com/store/account/subscriptions"));
|
||||
|
||||
private async Task ApplyTrailOption()
|
||||
{
|
||||
if (!CanUse(AppFeatures.GpsTrail))
|
||||
{
|
||||
TrailEnabled = false;
|
||||
SaveFlagPreferences();
|
||||
await JS.InvokeVoidAsync("lmeMap.toggleTrail", false);
|
||||
await ShowProRequiredAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
SaveFlagPreferences();
|
||||
await JS.InvokeVoidAsync("lmeMap.toggleTrail", TrailEnabled);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user