瀏覽代碼

Masterdata laoding enhancement, brands added

master
Flo Smilari 4 年之前
父節點
當前提交
6fc02f44d7

+ 2
- 2
CaritasPWA.csproj 查看文件

<ItemGroup> <ItemGroup>
<PackageReference Include="BlazorAnimate" Version="3.0.0" /> <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" Version="5.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.7" PrivateAssets="all" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.7" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.7" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.7" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" /> <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>
<ItemGroup> <ItemGroup>

+ 88
- 41
Pages/CaritasServiceFundVeloKeyDataPage.razor 查看文件

@inject PageHistoryManager PageHistoryManager @inject PageHistoryManager PageHistoryManager
@inject MasterDataService MasterDataService @inject MasterDataService MasterDataService
@inject IMatToaster Toaster @inject IMatToaster Toaster
@inject IJSRuntime JS
<div class="row px-3 h-100"> <div class="row px-3 h-100">
</MatRipple> </MatRipple>
</div> </div>
<div style="margin-top:1rem"> <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" /> <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"> <MatRipple class="inputfile-mat-ripple" Color="@MatRippleColor.Default">
<label for="file"> <label for="file">
</MatSelectValue> </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"> <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>
<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"> <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)"> <MatSelectValue FullWidth="true" Outlined="true" Label="@i18n["Type"]" @bind-Value="selectedBcType" Items="@BicycleTypes" ValueSelector="@(i=>i)">
<ItemTemplate> <ItemTemplate>
<div> <div>
<span>@i18n["Bike." + @context?.Type]</span>
<span>@context?.Type</span>
</div> </div>
</ItemTemplate> </ItemTemplate>
</MatSelectValue> </MatSelectValue>
[Parameter] [Parameter]
public string FromRoute { get; set; } public string FromRoute { get; set; }
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> Attributes { get; set; }
private static long MAX_FILE_SIZE = 3145728; //3MB private static long MAX_FILE_SIZE = 3145728; //3MB
private ColorItem selectedColor; private ColorItem selectedColor;
private BicycleType selectedBcType; private BicycleType selectedBcType;
private ElementReference inputTypeFileElement;
private Brand selectedBrand;
// private ElementReference inputTypeFileElement;
private string imgUrl = string.Empty; private string imgUrl = string.Empty;
private Boolean loading = false; private Boolean loading = false;
await GetColors(); await GetColors();
await GetBicycleTypes(); await GetBicycleTypes();
await GetBrands();
PageHistoryManager.AddPageToHistory(NavigationManager.Uri); PageHistoryManager.AddPageToHistory(NavigationManager.Uri);
base.OnInitialized(); base.OnInitialized();
} }
}); });
} }
private async Task GetBrands() {
await InvokeAsync(async () => {
await MasterDataService.GetBrands();
StateHasChanged();
});
}
private ColorItem[] Colors { private ColorItem[] Colors {
get => MasterDataService.Colors; get => MasterDataService.Colors;
} }
get => MasterDataService.BicycleTypes; get => MasterDataService.BicycleTypes;
} }
private Brand[] Brands {
get => MasterDataService.Brands;
}
private void Next() { private void Next() {
NavigationManager.NavigateTo("fundvelo/account/" + @FromRoute); NavigationManager.NavigateTo("fundvelo/account/" + @FromRoute);
} }
private async Task OnGatheringPicture(InputFileChangeEventArgs e) { private async Task OnGatheringPicture(InputFileChangeEventArgs e) {
IBrowserFile imgFile = e.File; IBrowserFile imgFile = e.File;
var buffers = new byte[imgFile.Size];
var buffer = new byte[imgFile.Size];
imgUrl = string.Empty;
loading = true;
StateHasChanged();
try { 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) { } 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 { } finally {
Array.Clear(buffer, 0, buffer.Length);
buffer = null;
loading = false; loading = false;
StateHasChanged(); 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);
}
}
}

+ 1
- 1
Pages/InfoPage.razor 查看文件

} }
private async void ShowCaritasWebpage() { 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");
} }
} }

+ 0
- 2
Program.cs 查看文件

using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tewr.Blazor.FileReader;
namespace CaritasPWA { namespace CaritasPWA {
builder.RootComponents.Add<App>("app"); builder.RootComponents.Add<App>("app");
builder.Services.AddMatBlazor(); builder.Services.AddMatBlazor();
builder.Services.AddFileReaderService(options => options.UseWasmSharedBuffer = true);
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddSingleton<ILFBicycleRest, LFBicycleRest>(); builder.Services.AddSingleton<ILFBicycleRest, LFBicycleRest>();
builder.Services.AddSingleton<AppState>(); builder.Services.AddSingleton<AppState>();

+ 3
- 3
Shared/Models/BicycleType.cs 查看文件

namespace CaritasPWA.Shared.Models { namespace CaritasPWA.Shared.Models {
public class BicycleType { public class BicycleType {
public int Index { get; set; }
public int Id { get; set; }
public string Type { get; set; } public string Type { get; set; }
public BicycleType() { } public BicycleType() { }
public BicycleType(int index, string type) {
Index = index;
public BicycleType(int id, string type) {
Id = id;
Type = type; Type = type;
} }
} }

+ 14
- 0
Shared/Models/Brand.cs 查看文件

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;
}
}
}

+ 10
- 2
Shared/Models/Defaults.cs 查看文件

namespace CaritasPWA.Shared.Models { namespace CaritasPWA.Shared.Models {
public class Defaults { public class Defaults {
public static ColorItem[] ColorItems = {
public static readonly ColorItem[] ColorItems = {
new ColorItem(3, "Blue","0,0,255"), new ColorItem(3, "Blue","0,0,255"),
new ColorItem(14, "Brown", "165,42,42"), new ColorItem(14, "Brown", "165,42,42"),
new ColorItem(4, "Yellow", "255, 255, 0"), new ColorItem(4, "Yellow", "255, 255, 0"),
new ColorItem(7, "White", "255, 255, 255"), new ColorItem(7, "White", "255, 255, 255"),
}; };
public static BicycleType[] BycicleTypes = {
public static readonly BicycleType[] BycicleTypes = {
new BicycleType(1, "Men_Bycicle"), new BicycleType(1, "Men_Bycicle"),
new BicycleType(2, "Women_Bycicle"), new BicycleType(2, "Women_Bycicle"),
new BicycleType(3, "Child_Bycicle"), new BicycleType(3, "Child_Bycicle"),
new BicycleType(7, "Tandem"), new BicycleType(7, "Tandem"),
new BicycleType(8, "Trailer") 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")
};
} }
} }

+ 1
- 1
Shared/NavMenu.razor 查看文件

<MatAppBarTitle Class="navBar-title">@LocationUrl</MatAppBarTitle> <MatAppBarTitle Class="navBar-title">@LocationUrl</MatAppBarTitle>
</MatAppBarSection> </MatAppBarSection>
<MatAppBarSection align="@MatAppBarSectionAlign.End" Style="max-width:min-content"> <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> </MatAppBarSection>
</MatAppBarRow> </MatAppBarRow>
</MatAppBar> </MatAppBar>

+ 6
- 0
Shared/ResourceFiles/Resources.de.resx 查看文件

<data name="DevelopedBy" xml:space="preserve"> <data name="DevelopedBy" xml:space="preserve">
<value>Entwickelt durch</value> <value>Entwickelt durch</value>
</data> </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"> <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> <value>Die Grösse des gewählten Bildes oder Fotos darf {0:d} MB nicht überschreiten!</value>
</data> </data>

+ 6
- 0
Shared/ResourceFiles/Resources.fr.resx 查看文件

<data name="DevelopedBy" xml:space="preserve"> <data name="DevelopedBy" xml:space="preserve">
<value>Développé par</value> <value>Développé par</value>
</data> </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"> <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> <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> </data>

+ 6
- 0
Shared/ResourceFiles/Resources.it.resx 查看文件

<data name="DevelopedBy" xml:space="preserve"> <data name="DevelopedBy" xml:space="preserve">
<value>Sviluppata da</value> <value>Sviluppata da</value>
</data> </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"> <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> <value>La dimensione dell'immagine selezionata o della foto scattata supera la dimensione massima consentita di {0:d} MB.</value>
</data> </data>

+ 6
- 0
Shared/ResourceFiles/Resources.resx 查看文件

<data name="DevelopedBy" xml:space="preserve"> <data name="DevelopedBy" xml:space="preserve">
<value>Developed by</value> <value>Developed by</value>
</data> </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"> <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> <value>The size of the selected picture or taken photo exceeds the max. allowed size of {0:d} MB.</value>
</data> </data>

+ 2
- 0
Shared/Services/ILFBicycleRest.cs 查看文件

List<ColorItem> GetColors(); List<ColorItem> GetColors();
List<BicycleType> GetBicycleTypes(); List<BicycleType> GetBicycleTypes();
List<Brand> GetBrands();
} }
} }

+ 18
- 1
Shared/Services/LFBicycleRest.cs 查看文件

using CaritasPWA.Shared.Models; using CaritasPWA.Shared.Models;
using CaritasPWA.Shared.ResourceFiles;
using Microsoft.Extensions.Localization;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
// REST interface responsible to submit lost or found reports and get the available masterdata. // REST interface responsible to submit lost or found reports and get the available masterdata.
public class LFBicycleRest : ILFBicycleRest { public class LFBicycleRest : ILFBicycleRest {
private readonly IStringLocalizer<Resources> _i18n;
public LFBicycleRest(IStringLocalizer<Resources> i18n) {
_i18n = i18n;
}
public List<ColorItem> GetColors() { public List<ColorItem> GetColors() {
//return Defaults.ColorItems.ToList(); //return Defaults.ColorItems.ToList();
return new List<ColorItem>(); return new List<ColorItem>();
} }
public List<BicycleType> GetBicycleTypes() { 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>(); //return new List<BicycleType>();
} }
public List<Brand> GetBrands() {
return Defaults.Brands.ToList();
//return new List<BicycleType>();
}
} }
} }

+ 58
- 7
Shared/Services/MasterDataService.cs 查看文件

namespace CaritasPWA.Shared.Services { namespace CaritasPWA.Shared.Services {
public class MasterDataService { public class MasterDataService {
private ILFBicycleRest _lFBicycleRest;
private readonly ILFBicycleRest _lFBicycleRest;
private const string KeyNameColors = "colors"; private const string KeyNameColors = "colors";
private const string KeyNameBcTypes = "bicycleTypes"; private const string KeyNameBcTypes = "bicycleTypes";
private const string KeyNameBrands = "brands";
private readonly IJSRuntime _jsRuntime; private readonly IJSRuntime _jsRuntime;
private bool _initializedColors; private bool _initializedColors;
private bool _initializedBcTypes; 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 { public ColorItem[] Colors {
get => _colors; get => _colors;
set => _bicycleTypes = value; set => _bicycleTypes = value;
} }
public Brand[] Brands {
get => _brands;
set => _brands = value;
}
public event EventHandler Changed; public event EventHandler Changed;
public MasterDataService(IJSRuntime jsRuntime, ILFBicycleRest lFBicycleRest) { public MasterDataService(IJSRuntime jsRuntime, ILFBicycleRest lFBicycleRest) {
public async Task SynchronizeMasterdata() { public async Task SynchronizeMasterdata() {
await SynchronizeColors(); await SynchronizeColors();
await SynchronizeBcTypes(); await SynchronizeBcTypes();
await SynchronizeBrands();
} }
public async Task SynchronizeColors() { public async Task SynchronizeColors() {
} }
} }
public async Task SynchronizeBrands() {
Brands = _lFBicycleRest.GetBrands().ToArray();
if (Brands != null && Brands.Length > 0) {
await SaveBrandsToStorage();
}
}
public async Task<ColorItem[]> GetColors() { public async Task<ColorItem[]> GetColors() {
ColorItem[] colors = await GetColorsFromStorage(); ColorItem[] colors = await GetColorsFromStorage();
Colors = (colors != null && colors.Length > 0) ? colors : Defaults.ColorItems; Colors = (colors != null && colors.Length > 0) ? colors : Defaults.ColorItems;
return BicycleTypes; 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() { private async ValueTask<ColorItem[]> GetColorsFromStorage() {
// Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed. // Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed.
ColorItem[] result; ColorItem[] result;
var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameColors); var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameColors);
if (str != null) { 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 { } else {
result = new ColorItem[] { };
result = Array.Empty<ColorItem>();
} }
_colors = result; _colors = result;
return result; return result;
BicycleType[] result; BicycleType[] result;
var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameBcTypes); var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameBcTypes);
if (str != null) { 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 { } else {
result = new BicycleType[] { };
result = Array.Empty<BicycleType>();
} }
_bicycleTypes = result; _bicycleTypes = result;
return 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() { private async Task SaveColorsToStorage() {
var json = System.Text.Json.JsonSerializer.Serialize(_colors); var json = System.Text.Json.JsonSerializer.Serialize(_colors);
await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameColors, json); await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameColors, json);
await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameBcTypes, json); 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 // This method is called from BlazorRegisterStorageEvent when the storage changed
[JSInvokable] [JSInvokable]
public void OnStorageUpdated(string key) { public void OnStorageUpdated(string key) {

+ 1
- 1
Shared/Services/PageHistoryManager.cs 查看文件

namespace CaritasPWA.Shared.Services { namespace CaritasPWA.Shared.Services {
public class PageHistoryManager { public class PageHistoryManager {
private List<string> previousPages;
private readonly List<string> previousPages;
public PageHistoryManager() { public PageHistoryManager() {
previousPages = new List<string>(); previousPages = new List<string>();

+ 1
- 1
Shared/Services/UserDataProvider.cs 查看文件

private readonly IJSRuntime _jsRuntime; private readonly IJSRuntime _jsRuntime;
private bool _initialized; private bool _initialized;
private UserData _data = new UserData();
private UserData _data = new ();
public UserData Data { public UserData Data {
get => _data; get => _data;

+ 84
- 33
wwwroot/css/app.css 查看文件

color: var(--primary); color: var(--primary);
} }
a:hover {
color: var(--caritas-red-accent);
}
a:hover {
color: var(--caritas-red-accent);
}
.inputFile { .inputFile {
width: 0.1px; width: 0.1px;
z-index: -1; z-index: -1;
} }
.inputFile + label {
cursor: pointer;
width: 100%;
text-align: center;
}
.inputFile + label {
cursor: pointer;
width: 100%;
text-align: center;
}
.inputfile-mat-ripple { .inputfile-mat-ripple {
width: 48px; width: 48px;
border-color: var(--caritas-red-accent); 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 { .text-black {
color: rgba(0,0,0) !important; color: rgba(0,0,0) !important;
} }
.fv-mat-card { .fv-mat-card {
border-radius:20px;
border-radius: 20px;
} }
.mat-icon-large { .mat-icon-large {
margin-left: -5px; margin-left: -5px;
display: block; display: block;
} }
.fullscreen { .fullscreen {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
z-index: 1000; 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 { .navBar-title {
padding-left: 0px; padding-left: 0px;
-ms-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%);
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;
}

+ 14
- 0
wwwroot/image-loader.js 查看文件

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;
}
}
}

+ 33
- 4
wwwroot/index.html 查看文件

<html lang="de-ch"> <html lang="de-ch">
<head> <head>
<title>Caritas PWA</title>
<base href="/" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="description" content="Caritas PWA, developed by INTEGRATE AG, Switzerland"> <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" /> <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/BlazorAnimate/blazorAnimateInterop.js"></script>
<script src="_content/MatBlazor/dist/matBlazor.js"></script> <script src="_content/MatBlazor/dist/matBlazor.js"></script>
<link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" /> <link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" /> <link href="css/app.css" rel="stylesheet" />
<link href="manifest.json" rel="manifest" /> <link href="manifest.json" rel="manifest" />
<link rel="apple-touch-icon" href="/icons/icon-60@3x.png" /> <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> </head>
<body> <body>
}); });
} }
</script> </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> </body>

+ 3
- 3
wwwroot/service-worker.js 查看文件

const staticCacheName = 'site-static-v1'; const staticCacheName = 'site-static-v1';
const assets = [ const assets = [
'/',
'./',
'/index.html', '/index.html',
'/account', '/account',
'/account/Found', '/account/Found',
// activate event // activate event
self.addEventListener('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( event.waitUntil(
caches.keys().then(keys => Promise.all( caches.keys().then(keys => Promise.all(
keys.map(key => { keys.map(key => {

Loading…
取消
儲存