| @@ -7,12 +7,12 @@ | |||
| <ItemGroup> | |||
| <PackageReference Include="BlazorAnimate" Version="3.0.0" /> | |||
| <PackageReference Include="MatBlazor" Version="2.8.0" /> | |||
| <PackageReference Include="MatBlazor" Version="2.9.0-develop-042" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.7" PrivateAssets="all" /> | |||
| <PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.7" /> | |||
| <PackageReference Include="System.Net.Http.Json" Version="5.0.0" /> | |||
| <PackageReference Include="Tewr.Blazor.FileReader" Version="3.1.0.21158" /> | |||
| <!--<PackageReference Include="Tewr.Blazor.FileReader" Version="3.1.0.21158" />--> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| @@ -10,6 +10,7 @@ | |||
| @inject PageHistoryManager PageHistoryManager | |||
| @inject MasterDataService MasterDataService | |||
| @inject IMatToaster Toaster | |||
| @inject IJSRuntime JS | |||
| <div class="row px-3 h-100"> | |||
| @@ -38,7 +39,6 @@ | |||
| </MatRipple> | |||
| </div> | |||
| <div style="margin-top:1rem"> | |||
| @* <input @ref="inputTypeFileElement" class="inputFile" id="file" type="file" name="file" accept="image/x-png,image/jpeg,image/gif" @onchange="ReadFile" />*@ | |||
| <InputFile class="inputFile" id="file" type="file" name="file" accept="image/x-png,image/jpeg,image/gif" OnChange="@OnGatheringPicture" /> | |||
| <MatRipple class="inputfile-mat-ripple" Color="@MatRippleColor.Default"> | |||
| <label for="file"> | |||
| @@ -111,13 +111,31 @@ | |||
| </MatSelectValue> | |||
| </div> | |||
| <div class="mat-layout-grid-cell mat-layout-grid-cell-span-4-phone mat-layout-grid-cell-span-4-tablet mat-layout-grid-cell-span-4-desktop"> | |||
| <MatStringField Class="w-100 form-check-label" Label="@i18n["Brand"]" Outlined="true" type="text"></MatStringField> | |||
| <div class="outlined"> | |||
| <MatAutocompleteList TItem="Brand" FullWidth="true" Label="@i18n["Brand"]" Items="@Brands" @bind-Value="selectedBrand" CustomStringSelector="@(i => i?.Name)"> | |||
| <ItemTemplate> | |||
| <div> | |||
| <span>@context?.Name</span> | |||
| </div> | |||
| </ItemTemplate> | |||
| </MatAutocompleteList> | |||
| </div> | |||
| @*<div style="display: inline-flex; width: 100%"> | |||
| <MatStringField Class="w-100 form-check-label" Label="@i18n["Brand"]" Outlined="true" type="text"></MatStringField> | |||
| <MatSelectValue Class="icon-only" Outlined="true" @bind-Value="selectedBrand" Items="@Brands" ValueSelector="@(i=>i)" > | |||
| <ItemTemplate> | |||
| <div> | |||
| <span>@context?.Name</span> | |||
| </div> | |||
| </ItemTemplate> | |||
| </MatSelectValue> | |||
| </div>*@ | |||
| </div> | |||
| <div class="mat-layout-grid-cell mat-layout-grid-cell-span-4-phone mat-layout-grid-cell-span-4-tablet mat-layout-grid-cell-span-4-desktop"> | |||
| <MatSelectValue FullWidth="true" Outlined="true" Label="@i18n["Type"]" @bind-Value="selectedBcType" Items="@BicycleTypes" ValueSelector="@(i=>i)"> | |||
| <ItemTemplate> | |||
| <div> | |||
| <span>@i18n["Bike." + @context?.Type]</span> | |||
| <span>@context?.Type</span> | |||
| </div> | |||
| </ItemTemplate> | |||
| </MatSelectValue> | |||
| @@ -144,14 +162,12 @@ | |||
| [Parameter] | |||
| public string FromRoute { get; set; } | |||
| [Parameter(CaptureUnmatchedValues = true)] | |||
| public IDictionary<string, object> Attributes { get; set; } | |||
| private static long MAX_FILE_SIZE = 3145728; //3MB | |||
| private ColorItem selectedColor; | |||
| private BicycleType selectedBcType; | |||
| private ElementReference inputTypeFileElement; | |||
| private Brand selectedBrand; | |||
| // private ElementReference inputTypeFileElement; | |||
| private string imgUrl = string.Empty; | |||
| private Boolean loading = false; | |||
| @@ -161,6 +177,7 @@ | |||
| await GetColors(); | |||
| await GetBicycleTypes(); | |||
| await GetBrands(); | |||
| PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | |||
| base.OnInitialized(); | |||
| } | |||
| @@ -179,6 +196,13 @@ | |||
| }); | |||
| } | |||
| private async Task GetBrands() { | |||
| await InvokeAsync(async () => { | |||
| await MasterDataService.GetBrands(); | |||
| StateHasChanged(); | |||
| }); | |||
| } | |||
| private ColorItem[] Colors { | |||
| get => MasterDataService.Colors; | |||
| } | |||
| @@ -187,6 +211,10 @@ | |||
| get => MasterDataService.BicycleTypes; | |||
| } | |||
| private Brand[] Brands { | |||
| get => MasterDataService.Brands; | |||
| } | |||
| private void Next() { | |||
| NavigationManager.NavigateTo("fundvelo/account/" + @FromRoute); | |||
| } | |||
| @@ -206,57 +234,76 @@ | |||
| private async Task OnGatheringPicture(InputFileChangeEventArgs e) { | |||
| IBrowserFile imgFile = e.File; | |||
| var buffers = new byte[imgFile.Size]; | |||
| var buffer = new byte[imgFile.Size]; | |||
| imgUrl = string.Empty; | |||
| loading = true; | |||
| StateHasChanged(); | |||
| try { | |||
| imgUrl = string.Empty; | |||
| loading = true; | |||
| StateHasChanged(); | |||
| await imgFile.OpenReadStream(MAX_FILE_SIZE).ReadAsync(buffers); | |||
| string imageType = imgFile.ContentType; | |||
| imgUrl = $"data:{imageType};base64,{Convert.ToBase64String(buffers)}"; | |||
| //string text = new(await JS.InvokeAsync<string>("LoadFile", e)); | |||
| //imgUrl = text; | |||
| using (var stream = imgFile.OpenReadStream(MAX_FILE_SIZE)) { | |||
| await stream.ReadAsync(buffer); | |||
| imgUrl = $"data:{imgFile.ContentType};base64,{Convert.ToBase64String(buffer)}"; | |||
| await stream.DisposeAsync(); | |||
| } | |||
| } catch (IOException ex) { | |||
| Console.WriteLine("Ex.Meesage is: {0}.", ex.Message); | |||
| Show(MatToastType.Danger, i18n.GetString("Error.PhotoOrPictureToBig.Title"), i18n.GetString("Error.PhotoOrPictureToBig.Msg", MAX_FILE_SIZE / (1024 * 1024))); | |||
| Console.WriteLine("Ex.Message is: {0}.", ex.Message); | |||
| if (ex.Message.Contains("exceeds the maximum of")) { | |||
| Show(MatToastType.Danger, i18n.GetString("Error.PhotoOrPictureToBig.Title"), i18n.GetString("Error.PhotoOrPictureToBig.Msg", MAX_FILE_SIZE / (1024 * 1024))); | |||
| } else { | |||
| Show(MatToastType.Danger, i18n.GetString("Error.IOException.Title"), i18n.GetString("Error.IOException.Msg")); | |||
| } | |||
| } catch (JSException ex) { | |||
| Console.WriteLine("Ex.Message is: {0}.", ex.Message); | |||
| } finally { | |||
| Array.Clear(buffer, 0, buffer.Length); | |||
| buffer = null; | |||
| loading = false; | |||
| StateHasChanged(); | |||
| } | |||
| } | |||
| //public async Task ReadFile() { | |||
| // foreach (var file in await fileReaderService.CreateReference(inputTypeFileElement).EnumerateFilesAsync()) { | |||
| // IFileInfo fileInfo = await file.ReadFileInfoAsync(); | |||
| public void Show(MatToastType type, string title, string message, string icon = "") { | |||
| Toaster.Add(message, type, title, icon); | |||
| } | |||
| // if (fileInfo.Size > MAX_FILE_SIZE) { | |||
| //private async Task OnGatheringPicture(InputFileChangeEventArgs e) { | |||
| // //public async Task ReadFile() { | |||
| // //foreach (var file in await fileReaderService.CreateReference(inputTypeFileElement).EnumerateFilesAsync()) { | |||
| // //IFileInfo fileInfo = await file.ReadFileInfoAsync(); | |||
| // Show(MatToastType.Danger, i18n.GetString("Error.PhotoOrPictureToBig.Title"), i18n.GetString("Error.PhotoOrPictureToBig.Msg", MAX_FILE_SIZE / (1024*1024))); | |||
| // IBrowserFile imgFile = e.File; | |||
| // //IFileInfo fileInfo = await imgFile.ReadFileInfoAsync(); | |||
| // } else { | |||
| // imgUrl = string.Empty; | |||
| // loading = true; | |||
| // StateHasChanged(); | |||
| // if (fileInfo.Size > MAX_FILE_SIZE) { | |||
| // Show(MatToastType.Danger, i18n.GetString("Error.PhotoOrPictureToBig.Title"), i18n.GetString("Error.PhotoOrPictureToBig.Msg", MAX_FILE_SIZE / (1024 * 1024))); | |||
| // byte[] buffer = new byte[fileInfo.Size]; | |||
| // } else { | |||
| // imgUrl = string.Empty; | |||
| // loading = true; | |||
| // StateHasChanged(); | |||
| // await using (Stream stream = await file.OpenReadAsync()) { | |||
| // buffer = new Byte[stream.Length]; | |||
| // await stream.ReadAsync(buffer); | |||
| // } | |||
| // byte[] buffer = new byte[fileInfo.Size]; | |||
| // using (MemoryStream memoryStream = await file.CreateMemoryStreamAsync(4096)) { | |||
| // memoryStream.Read(buffer); | |||
| // string imageType = fileInfo.Type; | |||
| // loading = false; | |||
| // imgUrl = $"data:{imageType};base64,{Convert.ToBase64String(buffer)}"; | |||
| // StateHasChanged(); | |||
| // } | |||
| // await using (Stream stream = await imgFile.OpenReadAsync()) { | |||
| // buffer = new Byte[stream.Length]; | |||
| // await stream.ReadAsync(buffer); | |||
| // } | |||
| // using (MemoryStream memoryStream = await imgFile.CreateMemoryStreamAsync(4096)) { | |||
| // memoryStream.Read(buffer); | |||
| // string imageType = fileInfo.Type; | |||
| // loading = false; | |||
| // imgUrl = $"data:{imageType};base64,{Convert.ToBase64String(buffer)}"; | |||
| // StateHasChanged(); | |||
| // } | |||
| // //} | |||
| // } | |||
| //} | |||
| public void Show(MatToastType type, string title, string message, string icon = "") { | |||
| Toaster.Add(message, type, title, icon); | |||
| } | |||
| } | |||
| } | |||
| @@ -64,6 +64,6 @@ | |||
| } | |||
| private async void ShowCaritasWebpage() { | |||
| await JSRuntime.InvokeAsync<string>("open", $"https://www.caritas.ch", "_blank"); | |||
| await JSRuntime.InvokeAsync<string>("open", $"https://www.caritas.ch", "_blank", "noopener"); | |||
| } | |||
| } | |||
| @@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection; | |||
| using System; | |||
| using System.Net.Http; | |||
| using System.Threading.Tasks; | |||
| using Tewr.Blazor.FileReader; | |||
| namespace CaritasPWA { | |||
| @@ -16,7 +15,6 @@ namespace CaritasPWA { | |||
| builder.RootComponents.Add<App>("app"); | |||
| builder.Services.AddMatBlazor(); | |||
| builder.Services.AddFileReaderService(options => options.UseWasmSharedBuffer = true); | |||
| builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); | |||
| builder.Services.AddSingleton<ILFBicycleRest, LFBicycleRest>(); | |||
| builder.Services.AddSingleton<AppState>(); | |||
| @@ -1,13 +1,13 @@ | |||
| namespace CaritasPWA.Shared.Models { | |||
| public class BicycleType { | |||
| public int Index { get; set; } | |||
| public int Id { get; set; } | |||
| public string Type { get; set; } | |||
| public BicycleType() { } | |||
| public BicycleType(int index, string type) { | |||
| Index = index; | |||
| public BicycleType(int id, string type) { | |||
| Id = id; | |||
| Type = type; | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| namespace CaritasPWA.Shared.Models { | |||
| public class Brand { | |||
| public int Id { get; set; } | |||
| public string Name { get; set; } | |||
| public Brand() { } | |||
| public Brand(int id, string name) { | |||
| Id = id; | |||
| Name = name; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| namespace CaritasPWA.Shared.Models { | |||
| public class Defaults { | |||
| public static ColorItem[] ColorItems = { | |||
| public static readonly ColorItem[] ColorItems = { | |||
| new ColorItem(3, "Blue","0,0,255"), | |||
| new ColorItem(14, "Brown", "165,42,42"), | |||
| new ColorItem(4, "Yellow", "255, 255, 0"), | |||
| @@ -18,7 +18,7 @@ | |||
| new ColorItem(7, "White", "255, 255, 255"), | |||
| }; | |||
| public static BicycleType[] BycicleTypes = { | |||
| public static readonly BicycleType[] BycicleTypes = { | |||
| new BicycleType(1, "Men_Bycicle"), | |||
| new BicycleType(2, "Women_Bycicle"), | |||
| new BicycleType(3, "Child_Bycicle"), | |||
| @@ -28,6 +28,14 @@ | |||
| new BicycleType(7, "Tandem"), | |||
| new BicycleType(8, "Trailer") | |||
| }; | |||
| public static readonly Brand[] Brands = { | |||
| new Brand(1, "Mondia"), | |||
| new Brand(2, "Leopard"), | |||
| new Brand(3, "Cilo"), | |||
| new Brand(4, "Kettler") | |||
| }; | |||
| } | |||
| } | |||
| @@ -20,7 +20,7 @@ | |||
| <MatAppBarTitle Class="navBar-title">@LocationUrl</MatAppBarTitle> | |||
| </MatAppBarSection> | |||
| <MatAppBarSection align="@MatAppBarSectionAlign.End" Style="max-width:min-content"> | |||
| <NavLink target="_blank" class="text-white small" href="https://www.caritas.ch" align="@MatAppBarSectionAlign.End" style="padding-right:1em">@i18n["Learnmore"]</NavLink> | |||
| <NavLink rel="noopener" target="_blank" class="text-white small" href="https://www.caritas.ch" align="@MatAppBarSectionAlign.End" style="padding-right:1em">@i18n["Learnmore"]</NavLink> | |||
| </MatAppBarSection> | |||
| </MatAppBarRow> | |||
| </MatAppBar> | |||
| @@ -225,6 +225,12 @@ | |||
| <data name="DevelopedBy" xml:space="preserve"> | |||
| <value>Entwickelt durch</value> | |||
| </data> | |||
| <data name="Error.IOException.Msg" xml:space="preserve"> | |||
| <value>Die Datei konnte nicht gelesen werden.</value> | |||
| </data> | |||
| <data name="Error.IOException.Title" xml:space="preserve"> | |||
| <value>Fehler beim Lesen der Datei!</value> | |||
| </data> | |||
| <data name="Error.PhotoOrPictureToBig.Msg" xml:space="preserve"> | |||
| <value>Die Grösse des gewählten Bildes oder Fotos darf {0:d} MB nicht überschreiten!</value> | |||
| </data> | |||
| @@ -225,6 +225,12 @@ | |||
| <data name="DevelopedBy" xml:space="preserve"> | |||
| <value>Développé par</value> | |||
| </data> | |||
| <data name="Error.IOException.Msg" xml:space="preserve"> | |||
| <value>The file could not be read.</value> | |||
| </data> | |||
| <data name="Error.IOException.Title" xml:space="preserve"> | |||
| <value>Error while reading file!</value> | |||
| </data> | |||
| <data name="Error.PhotoOrPictureToBig.Msg" xml:space="preserve"> | |||
| <value>La taille de l'image sélectionnée ou de la photo prise dépasse la taille maximale autorisée de {0:d} MB.</value> | |||
| </data> | |||
| @@ -225,6 +225,12 @@ | |||
| <data name="DevelopedBy" xml:space="preserve"> | |||
| <value>Sviluppata da</value> | |||
| </data> | |||
| <data name="Error.IOException.Msg" xml:space="preserve"> | |||
| <value>Il file non ha potuto essere caricato.</value> | |||
| </data> | |||
| <data name="Error.IOException.Title" xml:space="preserve"> | |||
| <value>Errore!</value> | |||
| </data> | |||
| <data name="Error.PhotoOrPictureToBig.Msg" xml:space="preserve"> | |||
| <value>La dimensione dell'immagine selezionata o della foto scattata supera la dimensione massima consentita di {0:d} MB.</value> | |||
| </data> | |||
| @@ -225,6 +225,12 @@ | |||
| <data name="DevelopedBy" xml:space="preserve"> | |||
| <value>Developed by</value> | |||
| </data> | |||
| <data name="Error.IOException.Msg" xml:space="preserve"> | |||
| <value>The file could not be read.</value> | |||
| </data> | |||
| <data name="Error.IOException.Title" xml:space="preserve"> | |||
| <value>Error while reading file!</value> | |||
| </data> | |||
| <data name="Error.PhotoOrPictureToBig.Msg" xml:space="preserve"> | |||
| <value>The size of the selected picture or taken photo exceeds the max. allowed size of {0:d} MB.</value> | |||
| </data> | |||
| @@ -7,5 +7,7 @@ namespace CaritasPWA.Shared.Services { | |||
| List<ColorItem> GetColors(); | |||
| List<BicycleType> GetBicycleTypes(); | |||
| List<Brand> GetBrands(); | |||
| } | |||
| } | |||
| @@ -1,4 +1,6 @@ | |||
| using CaritasPWA.Shared.Models; | |||
| using CaritasPWA.Shared.ResourceFiles; | |||
| using Microsoft.Extensions.Localization; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| @@ -7,16 +9,31 @@ namespace CaritasPWA.Shared.Services { | |||
| // REST interface responsible to submit lost or found reports and get the available masterdata. | |||
| public class LFBicycleRest : ILFBicycleRest { | |||
| private readonly IStringLocalizer<Resources> _i18n; | |||
| public LFBicycleRest(IStringLocalizer<Resources> i18n) { | |||
| _i18n = i18n; | |||
| } | |||
| public List<ColorItem> GetColors() { | |||
| //return Defaults.ColorItems.ToList(); | |||
| return new List<ColorItem>(); | |||
| } | |||
| public List<BicycleType> GetBicycleTypes() { | |||
| return Defaults.BycicleTypes.ToList(); | |||
| List<BicycleType> bicycleTypes = new (); | |||
| foreach (BicycleType bct in Defaults.BycicleTypes) { | |||
| bicycleTypes.Add(new BicycleType(bct.Id, _i18n.GetString("Bike." + bct.Type))); | |||
| } | |||
| return bicycleTypes; | |||
| //return new List<BicycleType>(); | |||
| } | |||
| public List<Brand> GetBrands() { | |||
| return Defaults.Brands.ToList(); | |||
| //return new List<BicycleType>(); | |||
| } | |||
| } | |||
| } | |||
| @@ -6,15 +6,18 @@ using System.Threading.Tasks; | |||
| namespace CaritasPWA.Shared.Services { | |||
| public class MasterDataService { | |||
| private ILFBicycleRest _lFBicycleRest; | |||
| private readonly ILFBicycleRest _lFBicycleRest; | |||
| private const string KeyNameColors = "colors"; | |||
| private const string KeyNameBcTypes = "bicycleTypes"; | |||
| private const string KeyNameBrands = "brands"; | |||
| private readonly IJSRuntime _jsRuntime; | |||
| private bool _initializedColors; | |||
| private bool _initializedBcTypes; | |||
| private ColorItem[] _colors = new ColorItem[] { }; | |||
| private BicycleType[] _bicycleTypes = new BicycleType[] { }; | |||
| private bool _initializedBrands; | |||
| private ColorItem[] _colors; | |||
| private BicycleType[] _bicycleTypes; | |||
| private Brand[] _brands; | |||
| public ColorItem[] Colors { | |||
| get => _colors; | |||
| @@ -26,6 +29,11 @@ namespace CaritasPWA.Shared.Services { | |||
| set => _bicycleTypes = value; | |||
| } | |||
| public Brand[] Brands { | |||
| get => _brands; | |||
| set => _brands = value; | |||
| } | |||
| public event EventHandler Changed; | |||
| public MasterDataService(IJSRuntime jsRuntime, ILFBicycleRest lFBicycleRest) { | |||
| @@ -36,6 +44,7 @@ namespace CaritasPWA.Shared.Services { | |||
| public async Task SynchronizeMasterdata() { | |||
| await SynchronizeColors(); | |||
| await SynchronizeBcTypes(); | |||
| await SynchronizeBrands(); | |||
| } | |||
| public async Task SynchronizeColors() { | |||
| @@ -52,6 +61,13 @@ namespace CaritasPWA.Shared.Services { | |||
| } | |||
| } | |||
| public async Task SynchronizeBrands() { | |||
| Brands = _lFBicycleRest.GetBrands().ToArray(); | |||
| if (Brands != null && Brands.Length > 0) { | |||
| await SaveBrandsToStorage(); | |||
| } | |||
| } | |||
| public async Task<ColorItem[]> GetColors() { | |||
| ColorItem[] colors = await GetColorsFromStorage(); | |||
| Colors = (colors != null && colors.Length > 0) ? colors : Defaults.ColorItems; | |||
| @@ -64,6 +80,12 @@ namespace CaritasPWA.Shared.Services { | |||
| return BicycleTypes; | |||
| } | |||
| public async Task<BicycleType[]> GetBrands() { | |||
| Brand[] brands = await GetBrandsFromStorage(); | |||
| Brands = (brands != null && brands.Length > 0) ? brands : Defaults.Brands; | |||
| return BicycleTypes; | |||
| } | |||
| private async ValueTask<ColorItem[]> GetColorsFromStorage() { | |||
| // Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed. | |||
| @@ -79,9 +101,9 @@ namespace CaritasPWA.Shared.Services { | |||
| ColorItem[] result; | |||
| var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameColors); | |||
| if (str != null) { | |||
| result = System.Text.Json.JsonSerializer.Deserialize<ColorItem[]>(str) ?? new ColorItem[] { }; | |||
| result = System.Text.Json.JsonSerializer.Deserialize<ColorItem[]>(str) ?? Array.Empty<ColorItem>(); | |||
| } else { | |||
| result = new ColorItem[] { }; | |||
| result = Array.Empty<ColorItem>(); | |||
| } | |||
| _colors = result; | |||
| return result; | |||
| @@ -102,14 +124,38 @@ namespace CaritasPWA.Shared.Services { | |||
| BicycleType[] result; | |||
| var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameBcTypes); | |||
| if (str != null) { | |||
| result = System.Text.Json.JsonSerializer.Deserialize<BicycleType[]>(str) ?? new BicycleType[] { }; | |||
| result = System.Text.Json.JsonSerializer.Deserialize<BicycleType[]>(str) ?? Array.Empty<BicycleType>(); | |||
| } else { | |||
| result = new BicycleType[] { }; | |||
| result = Array.Empty<BicycleType>(); | |||
| } | |||
| _bicycleTypes = result; | |||
| return result; | |||
| } | |||
| private async ValueTask<Brand[]> GetBrandsFromStorage() { | |||
| // Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed. | |||
| // This way, you can reload the settings when another instance of the application (tab / window) save the settings | |||
| if (!_initializedBrands) { | |||
| // Create a reference to the current object, so the JS function can call the public method "OnStorageUpdated" | |||
| var reference = DotNetObjectReference.Create(this); | |||
| await _jsRuntime.InvokeVoidAsync("BlazorRegisterStorageEvent", reference); | |||
| _initializedBrands = true; | |||
| } | |||
| // Read the JSON string that contains the data from the local storage | |||
| Brand[] result; | |||
| var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameBrands); | |||
| if (str != null) { | |||
| result = System.Text.Json.JsonSerializer.Deserialize<Brand[]>(str) ?? Array.Empty<Brand>(); | |||
| } else { | |||
| result = Array.Empty<Brand>(); | |||
| } | |||
| _brands = result; | |||
| return result; | |||
| } | |||
| private async Task SaveColorsToStorage() { | |||
| var json = System.Text.Json.JsonSerializer.Serialize(_colors); | |||
| await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameColors, json); | |||
| @@ -120,6 +166,11 @@ namespace CaritasPWA.Shared.Services { | |||
| await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameBcTypes, json); | |||
| } | |||
| private async Task SaveBrandsToStorage() { | |||
| var json = System.Text.Json.JsonSerializer.Serialize(_brands); | |||
| await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameBrands, json); | |||
| } | |||
| // This method is called from BlazorRegisterStorageEvent when the storage changed | |||
| [JSInvokable] | |||
| public void OnStorageUpdated(string key) { | |||
| @@ -4,7 +4,7 @@ using System.Linq; | |||
| namespace CaritasPWA.Shared.Services { | |||
| public class PageHistoryManager { | |||
| private List<string> previousPages; | |||
| private readonly List<string> previousPages; | |||
| public PageHistoryManager() { | |||
| previousPages = new List<string>(); | |||
| @@ -9,7 +9,7 @@ namespace CaritasPWA.Shared.Services { | |||
| private readonly IJSRuntime _jsRuntime; | |||
| private bool _initialized; | |||
| private UserData _data = new UserData(); | |||
| private UserData _data = new (); | |||
| public UserData Data { | |||
| get => _data; | |||
| @@ -13,9 +13,9 @@ a { | |||
| color: var(--primary); | |||
| } | |||
| a:hover { | |||
| color: var(--caritas-red-accent); | |||
| } | |||
| a:hover { | |||
| color: var(--caritas-red-accent); | |||
| } | |||
| .inputFile { | |||
| width: 0.1px; | |||
| @@ -26,11 +26,11 @@ a:hover { | |||
| z-index: -1; | |||
| } | |||
| .inputFile + label { | |||
| cursor: pointer; | |||
| width: 100%; | |||
| text-align: center; | |||
| } | |||
| .inputFile + label { | |||
| cursor: pointer; | |||
| width: 100%; | |||
| text-align: center; | |||
| } | |||
| .inputfile-mat-ripple { | |||
| width: 48px; | |||
| @@ -56,26 +56,26 @@ a:hover { | |||
| border-color: var(--caritas-red-accent); | |||
| } | |||
| .btn-primary:hover { | |||
| color: #fff; | |||
| background-color: var(--primary); | |||
| border-color: var(--caritas-red-accent); | |||
| } | |||
| .btn-primary:hover { | |||
| color: #fff; | |||
| background-color: var(--primary); | |||
| border-color: var(--caritas-red-accent); | |||
| } | |||
| .btn-primary.focus, .btn-primary:focus { | |||
| color: #fff; | |||
| background-color: var(--caritas-red-dark); | |||
| border-color: var(--primary); | |||
| box-shadow: 0 0 0 .2rem rgb(255 64 88 / 0.5); | |||
| } | |||
| .btn-primary.focus, .btn-primary:focus { | |||
| color: #fff; | |||
| background-color: var(--caritas-red-dark); | |||
| border-color: var(--primary); | |||
| box-shadow: 0 0 0 .2rem rgb(255 64 88 / 0.5); | |||
| } | |||
| .btn-primary:not(:disabled):not(.disabled).active, | |||
| .btn-primary:not(:disabled):not(.disabled):active, | |||
| .show > .btn-primary.dropdown-toggle { | |||
| color: #fff; | |||
| background-color: var(--caritas-red-deep); | |||
| border-color: var(--caritas-red-dark); | |||
| } | |||
| .btn-primary:not(:disabled):not(.disabled).active, | |||
| .btn-primary:not(:disabled):not(.disabled):active, | |||
| .show > .btn-primary.dropdown-toggle { | |||
| color: #fff; | |||
| background-color: var(--caritas-red-deep); | |||
| border-color: var(--caritas-red-dark); | |||
| } | |||
| .text-black { | |||
| color: rgba(0,0,0) !important; | |||
| @@ -86,7 +86,7 @@ a:hover { | |||
| } | |||
| .fv-mat-card { | |||
| border-radius:20px; | |||
| border-radius: 20px; | |||
| } | |||
| .mat-icon-large { | |||
| @@ -102,6 +102,7 @@ button.mat-icon-large > i { | |||
| margin-left: -5px; | |||
| display: block; | |||
| } | |||
| .fullscreen { | |||
| width: 100vw; | |||
| height: 100vh; | |||
| @@ -123,12 +124,12 @@ button.mat-icon-large > i { | |||
| z-index: 1000; | |||
| } | |||
| #blazor-error-ui .dismiss { | |||
| cursor: pointer; | |||
| position: absolute; | |||
| right: 0.75rem; | |||
| top: 0.5rem; | |||
| } | |||
| #blazor-error-ui .dismiss { | |||
| cursor: pointer; | |||
| position: absolute; | |||
| right: 0.75rem; | |||
| top: 0.5rem; | |||
| } | |||
| .navBar-title { | |||
| padding-left: 0px; | |||
| @@ -146,3 +147,53 @@ div.mat-card-media div.mdc-circular-progress { | |||
| -ms-transform: translate(-50%, -50%); | |||
| transform: translate(-50%, -50%); | |||
| } | |||
| div.icon-only.mat-select { | |||
| min-width: 48px; | |||
| max-width: 48px; | |||
| } | |||
| div.icon-only.mat-select div.mdc-select__anchor { | |||
| padding-left: 0; | |||
| } | |||
| div.icon-only.mat-select span.mdc-select_dropdown-icon { | |||
| margin-left: 0; | |||
| } | |||
| .mat-autocomplete-list-popup { | |||
| opacity: 1; | |||
| } | |||
| div.outlined label.mat-text-field { | |||
| border-bottom-right-radius: 4px; | |||
| border-bottom-left-radius: 4px; | |||
| margin-bottom: auto; | |||
| } | |||
| div.outlined input.mat-text-field-input { | |||
| border-width: 1px; | |||
| border-style: solid; | |||
| border-color: rgb(0 0 0 / 38%); | |||
| border-radius: 4px; | |||
| } | |||
| div.outlined input.mat-text-field-input:focus { | |||
| border-width: 2px; | |||
| border-style: solid; | |||
| border-color: var(--primary); | |||
| border-radius: 4px; | |||
| } | |||
| div.outlined .mdc-text-field.mdc-text-field--fullwidth .mdc-floating-label.mdc-floating-label--float-above { | |||
| transform: translateY(-172%) translateX(-8%) scale(0.75); | |||
| background-color: white; | |||
| z-index: 2; | |||
| min-width: 60px; | |||
| text-align: center; | |||
| } | |||
| .mat-autocomplete-list-popup { | |||
| background-color: white; | |||
| z-index: 5; | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| const fileInput = document.getElementById('file-999'); | |||
| fileInput.addEventListener('change', (e) => LoadFiles(e.target.files)); | |||
| function LoadFiles(fileList) { | |||
| let file = null; | |||
| for (let i = 0; i < fileList.length;) { | |||
| if (fileList[i].type.match(/^image\//)) { | |||
| file = fileList[i]; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @@ -2,11 +2,13 @@ | |||
| <html lang="de-ch"> | |||
| <head> | |||
| <title>Caritas PWA</title> | |||
| <base href="/" /> | |||
| <meta charset="utf-8" /> | |||
| <meta name="description" content="Caritas PWA, developed by INTEGRATE AG, Switzerland"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes" /> | |||
| <title>Caritas PWA</title> | |||
| <base href="/" /> | |||
| <meta name="apple-mobile-web-app-status-bar" content="#db001b"> | |||
| <meta name="theme-color" content="#db001b"> | |||
| <script src="_content/BlazorAnimate/blazorAnimateInterop.js"></script> | |||
| <script src="_content/MatBlazor/dist/matBlazor.js"></script> | |||
| <link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" /> | |||
| @@ -16,8 +18,6 @@ | |||
| <link href="css/app.css" rel="stylesheet" /> | |||
| <link href="manifest.json" rel="manifest" /> | |||
| <link rel="apple-touch-icon" href="/icons/icon-60@3x.png" /> | |||
| <meta name="apple-mobile-web-app-status-bar" content="#db001b"> | |||
| <meta name="theme-color" content="#db001b"> | |||
| </head> | |||
| <body> | |||
| @@ -52,7 +52,36 @@ | |||
| }); | |||
| } | |||
| </script> | |||
| <script> | |||
| window.LoadFile = (evt) => { | |||
| var tgt = evt.target || window.event.srcElement, | |||
| files = tgt.files; | |||
| let file = files[0]; | |||
| file64 = URL.createObjectURL(file); | |||
| //const reader = new FileReader(); | |||
| //reader.onloadend = function () { | |||
| // file64 = reader.result; | |||
| //} | |||
| //reader.addEventListener("load", function () { | |||
| // file64 = reader.result; | |||
| //}, false); | |||
| //if (file) { | |||
| // // reader.readAsDataURL(file); | |||
| // read(reader); | |||
| //} | |||
| return file64; | |||
| } | |||
| async function read(reader) { | |||
| await reader.readAsDataURL(file); | |||
| } | |||
| </script> | |||
| </body> | |||
| @@ -4,7 +4,7 @@ | |||
| const staticCacheName = 'site-static-v1'; | |||
| const assets = [ | |||
| '/', | |||
| './', | |||
| '/index.html', | |||
| '/account', | |||
| '/account/Found', | |||
| @@ -65,8 +65,8 @@ self.addEventListener('install', evt => { | |||
| // activate event | |||
| self.addEventListener('activate', event => { | |||
| // delete any caches that aren't in expectedCaches | |||
| // which will get rid of site-static-v1 | |||
| //delete any caches that aren't in expectedCaches | |||
| //which will get rid of site-static-v1 | |||
| event.waitUntil( | |||
| caches.keys().then(keys => Promise.all( | |||
| keys.map(key => { | |||