master
Baptiste BAVEREL 2 years ago
parent 28afaa6d81
commit 999f676d98

Binary file not shown.

Binary file not shown.

@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.2.0" />
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="Blazorise.Bootstrap" Version="1.1.2" />
<PackageReference Include="Blazorise.DataGrid" Version="1.1.2" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.1.2" />

@ -0,0 +1,48 @@
using BlazorApp1.Models;
namespace BlazorApp1.Factories
{
public static class ItemFactory
{
public static ItemModel ToModel(Item item, byte[] imageContent)
{
return new ItemModel
{
Id = item.Id,
DisplayName = item.DisplayName,
Name = item.Name,
RepairWith = item.RepairWith,
EnchantCategories = item.EnchantCategories,
MaxDurability = item.MaxDurability,
StackSize = item.StackSize,
ImageContent = imageContent
};
}
public static Item Create(ItemModel model)
{
return new Item
{
Id = model.Id,
DisplayName = model.DisplayName,
Name = model.Name,
RepairWith = model.RepairWith,
EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability,
StackSize = model.StackSize,
CreatedDate = DateTime.Now
};
}
public static void Update(Item item, ItemModel model)
{
item.DisplayName = model.DisplayName;
item.Name = model.Name;
item.RepairWith = model.RepairWith;
item.EnchantCategories = model.EnchantCategories;
item.MaxDurability = model.MaxDurability;
item.StackSize = model.StackSize;
item.UpdatedDate = DateTime.Now;
}
}
}

@ -2,4 +2,81 @@
<h3>Edit</h3>
<div>My paremeter: @Id</div>
<EditForm Model="@itemModel" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label for="display-name">
Display name:
<InputText id="display-name" @bind-Value="itemModel.DisplayName" />
</label>
</p>
<p>
<label for="name">
Name:
<InputText id="name" @bind-Value="itemModel.Name" />
</label>
</p>
<p>
<label for="stack-size">
Stack size:
<InputNumber id="stack-size" @bind-Value="itemModel.StackSize" />
</label>
</p>
<p>
<label for="max-durability">
Max durability:
<InputNumber id="max-durability" @bind-Value="itemModel.MaxDurability" />
</label>
</p>
<p>
Enchant categories:
<div>
@foreach (var item in enchantCategories)
{
<label>
<input type="checkbox" @onchange="@(e => OnEnchantCategoriesChange(item, e.Value))" checked="@(itemModel.EnchantCategories.Contains(item) ? "checked" : null)" />@item
</label>
}
</div>
</p>
<p>
Repair with:
<div>
@foreach (var item in repairWith)
{
<label>
<input type="checkbox" @onchange="@(e => OnRepairWithChange(item, e.Value))" checked="@(itemModel.RepairWith.Contains(item) ? "checked" : null)" />@item
</label>
}
</div>
</p>
<p>
<label>
Current Item image:
@if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png"))
{
<img src="images/@(itemModel.Name).png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px"/>
}
else
{
<img src="images/default.png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px"/>
}
</label>
</p>
<p>
<label>
Item image:
<InputFile OnChange="@LoadImage" accept=".png" />
</label>
</p>
<p>
<label>
Accept Condition:
<InputCheckbox @bind-Value="itemModel.AcceptCondition" />
</label>
</p>
<button type="submit">Submit</button>
</EditForm>

@ -1,4 +1,8 @@
using Microsoft.AspNetCore.Components;
using BlazorApp1.Factories;
using BlazorApp1.Models;
using BlazorApp1.Sevices;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace BlazorApp1.Pages
{
@ -6,5 +10,101 @@ namespace BlazorApp1.Pages
{
[Parameter]
public int Id { get; set; }
/// <summary>
/// The default enchant categories.
/// </summary>
private List<string> enchantCategories = new List<string>() { "armor", "armor_head", "armor_chest", "weapon", "digger", "breakable", "vanishable" };
/// <summary>
/// The current item model
/// </summary>
private ItemModel itemModel = new()
{
EnchantCategories = new List<string>(),
RepairWith = new List<string>()
};
/// <summary>
/// The default repair with.
/// </summary>
private List<string> repairWith = new List<string>() { "oak_planks", "spruce_planks", "birch_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "crimson_planks", "warped_planks" };
[Inject]
public IDataService DataService { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
protected override async Task OnInitializedAsync()
{
var item = await DataService.GetById(Id);
var fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/default.png");
if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png"))
{
fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/{item.Name}.png");
}
// Set the model with the item
itemModel = ItemFactory.ToModel(item, fileContent);
}
private async void HandleValidSubmit()
{
await DataService.Update(Id, itemModel);
NavigationManager.NavigateTo("list");
}
private async Task LoadImage(InputFileChangeEventArgs e)
{
// Set the content of the image to the model
using (var memoryStream = new MemoryStream())
{
await e.File.OpenReadStream().CopyToAsync(memoryStream);
itemModel.ImageContent = memoryStream.ToArray();
}
}
private void OnEnchantCategoriesChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!itemModel.EnchantCategories.Contains(item))
{
itemModel.EnchantCategories.Add(item);
}
return;
}
if (itemModel.EnchantCategories.Contains(item))
{
itemModel.EnchantCategories.Remove(item);
}
}
private void OnRepairWithChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!itemModel.RepairWith.Contains(item))
{
itemModel.RepairWith.Add(item);
}
return;
}
if (itemModel.RepairWith.Contains(item))
{
itemModel.RepairWith.Remove(item);
}
}
}
}

@ -45,6 +45,7 @@
<DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="Action">
<DisplayTemplate>
<a href="Edit/@(context.Id)" class="btn btn-primary"><i class="fa fa-edit"></i> Editer</a>
<button type="button" class="btn btn-primary" @onclick="() => OnDelete(context.Id)"><i class="fa fa-trash"></i> Supprimer</button>
</DisplayTemplate>
</DataGridColumn>
</DataGrid>

@ -2,6 +2,7 @@
using Blazored.LocalStorage;
using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components;
//
namespace BlazorApp1.Pages
{
@ -30,6 +31,11 @@ namespace BlazorApp1.Pages
totalItem = await DataService.Count();
}
}
private void OnDelete(int id)
{
}
}
/*public partial class List

@ -0,0 +1,9 @@
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent" Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

@ -0,0 +1,24 @@
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}

@ -0,0 +1,14 @@
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}

@ -1,8 +1,13 @@
@page "/RouteParameter/{text}"
@page "/RouteParameter/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
}

@ -0,0 +1,17 @@
@page "/user/{Id:int}/{Option:bool?}"
<p>
Id: @Id
</p>
<p>
Option: @Option
</p>
@code {
[Parameter]
public int Id { get; set; }
[Parameter]
public bool Option { get; set; }
}

@ -0,0 +1,8 @@
namespace BlazorApp1
{
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
}

@ -7,6 +7,7 @@ using Blazorise.DataGrid;
using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Blazored.Modal;
var builder = WebApplication.CreateBuilder(args);
@ -26,6 +27,7 @@ builder.Services
.AddFontAwesomeIcons();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddBlazoredModal();
var app = builder.Build();

@ -1,4 +1,5 @@
using BlazorApp1.Models;
using BlazorApp1.Factories;
using BlazorApp1.Models;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
@ -32,17 +33,7 @@ namespace BlazorApp1.Sevices
model.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new Item
{
Id = model.Id,
DisplayName = model.DisplayName,
Name = model.Name,
RepairWith = model.RepairWith,
EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability,
StackSize = model.StackSize,
CreatedDate = DateTime.Now
});
currentData.Add(ItemFactory.Create(model));
// Save the image
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
@ -142,13 +133,31 @@ namespace BlazorApp1.Sevices
await File.WriteAllBytesAsync(fileName.FullName, model.ImageContent);
// Modify the content of the item
item.DisplayName = model.DisplayName;
item.Name = model.Name;
item.RepairWith = model.RepairWith;
item.EnchantCategories = model.EnchantCategories;
item.MaxDurability = model.MaxDurability;
item.StackSize = model.StackSize;
item.UpdatedDate = DateTime.Now;
ItemFactory.Update(item, model);
// Save the datas
await _localStorage.SetItemAsync("data", currentData);
}
public async Task Delete(int id)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<Item>>("data");
// Get the item int the list
var item = currentData.FirstOrDefault(w => w.Id == id);
// Delete item in
currentData.Remove(item);
// Delete the image
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
var fileName = new FileInfo($"{imagePathInfo}/{item.Name}.png");
if (fileName.Exists)
{
File.Delete(fileName.FullName);
}
// Save the data
await _localStorage.SetItemAsync("data", currentData);

@ -13,5 +13,7 @@ namespace BlazorApp1.Sevices
Task<Item> GetById(int id);
Task Update(int id, ItemModel model);
Task Delete(int id);
}
}

@ -14,6 +14,16 @@
<span class="oi oi-list-rich" aria-hidden="true"></span> List
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="edit/1">
<span class="oi oi-list-rich" aria-hidden="true"></span> edit
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="routeparameter/">
<span class="oi oi-list-rich" aria-hidden="true"></span> RouteParameter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="admin">
<span class="oi oi-list-rich" aria-hidden="true"></span> Admin

@ -0,0 +1,19 @@
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
@Body.Text
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
}

@ -48,6 +48,10 @@
"target": "Package",
"version": "[4.2.0, )"
},
"Blazored.Modal": {
"target": "Package",
"version": "[7.1.0, )"
},
"Blazorise.Bootstrap": {
"target": "Package",
"version": "[1.1.2, )"

@ -17,5 +17,6 @@
<Import Project="$(NuGetPackageRoot)blazorise\1.1.2\buildTransitive\Blazorise.props" Condition="Exists('$(NuGetPackageRoot)blazorise\1.1.2\buildTransitive\Blazorise.props')" />
<Import Project="$(NuGetPackageRoot)blazorise.datagrid\1.1.2\buildTransitive\Blazorise.DataGrid.props" Condition="Exists('$(NuGetPackageRoot)blazorise.datagrid\1.1.2\buildTransitive\Blazorise.DataGrid.props')" />
<Import Project="$(NuGetPackageRoot)blazorise.bootstrap\1.1.2\buildTransitive\Blazorise.Bootstrap.props" Condition="Exists('$(NuGetPackageRoot)blazorise.bootstrap\1.1.2\buildTransitive\Blazorise.Bootstrap.props')" />
<Import Project="$(NuGetPackageRoot)blazored.modal\7.1.0\buildTransitive\Blazored.Modal.props" Condition="Exists('$(NuGetPackageRoot)blazored.modal\7.1.0\buildTransitive\Blazored.Modal.props')" />
</ImportGroup>
</Project>

@ -51,14 +51,34 @@ build_metadata.AdditionalFiles.CssScope =
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcTGlzdC5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Pages/ParameterParent.razor]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUGFyYW1ldGVyUGFyZW50LnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Pages/ParameterParent2.razor]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUGFyYW1ldGVyUGFyZW50Mi5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Pages/ParameterParent3.razor]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUGFyYW1ldGVyUGFyZW50My5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Pages/RouteParameter.razor]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcUm91dGVQYXJhbWV0ZXIucmF6b3I=
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Pages/User.razor]
build_metadata.AdditionalFiles.TargetPath = UGFnZXNcVXNlci5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Shared/AdminLayout.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXEFkbWluTGF5b3V0LnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Shared/ParameterChild.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFBhcmFtZXRlckNoaWxkLnJhem9y
build_metadata.AdditionalFiles.CssScope =
[C:/Users/babaverel/Source/Repos/Blazor/BlazorApp1/Shared/SurveyPrompt.razor]
build_metadata.AdditionalFiles.TargetPath = U2hhcmVkXFN1cnZleVByb21wdC5yYXpvcg==
build_metadata.AdditionalFiles.CssScope =

@ -1 +1 @@
c0feac9b06aeb07d0970069a084861810e18935f
dfc017db507c3ed1e12a2d1aa2afd2f86d901ced

File diff suppressed because one or more lines are too long

@ -14,6 +14,27 @@
"lib/net6.0/Blazored.LocalStorage.dll": {}
}
},
"Blazored.Modal/7.1.0": {
"type": "package",
"dependencies": {
"Microsoft.AspNetCore.Components": "6.0.3",
"Microsoft.AspNetCore.Components.Web": "6.0.3",
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
"Microsoft.JSInterop.WebAssembly": "6.0.3"
},
"compile": {
"lib/net6.0/Blazored.Modal.dll": {}
},
"runtime": {
"lib/net6.0/Blazored.Modal.dll": {}
},
"build": {
"buildTransitive/Blazored.Modal.props": {}
},
"buildMultiTargeting": {
"buildMultiTargeting/Blazored.Modal.props": {}
}
},
"Blazorise/1.1.2": {
"type": "package",
"dependencies": {
@ -238,6 +259,18 @@
"lib/net6.0/Microsoft.JSInterop.dll": {}
}
},
"Microsoft.JSInterop.WebAssembly/6.0.3": {
"type": "package",
"dependencies": {
"Microsoft.JSInterop": "6.0.3"
},
"compile": {
"lib/net6.0/Microsoft.JSInterop.WebAssembly.dll": {}
},
"runtime": {
"lib/net6.0/Microsoft.JSInterop.WebAssembly.dll": {}
}
},
"System.IO.Pipelines/6.0.3": {
"type": "package",
"compile": {
@ -280,6 +313,25 @@
"lib/netstandard2.1/Blazored.LocalStorage.dll"
]
},
"Blazored.Modal/7.1.0": {
"sha512": "ft5bX5barhyzpQc9jjU029ByrAQXgqSMItwhmEbr0pb7r+of8XH0E/OyS8K6O6Disq5R+p4wpt+W+NGg3/OTMA==",
"type": "package",
"path": "blazored.modal/7.1.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"blazored.modal.7.1.0.nupkg.sha512",
"blazored.modal.nuspec",
"build/Blazored.Modal.props",
"build/Microsoft.AspNetCore.StaticWebAssets.props",
"buildMultiTargeting/Blazored.Modal.props",
"buildTransitive/Blazored.Modal.props",
"icon.png",
"lib/net6.0/Blazored.Modal.dll",
"staticwebassets/Blazored.Modal.bundle.scp.css",
"staticwebassets/BlazoredModal.razor.js"
]
},
"Blazorise/1.1.2": {
"sha512": "UGlSOaSiyg3kIN2KbwioNrAoR6Z653NCazo8Tkc5xXoWQKJvkcumhLCZmTbY9pePkOOCU7ey/BSY+cnKYMfhCQ==",
"type": "package",
@ -655,6 +707,21 @@
"microsoft.jsinterop.nuspec"
]
},
"Microsoft.JSInterop.WebAssembly/6.0.3": {
"sha512": "4B7RdZ01eKShey9MllKrVjEJZN/Y1Hvku/qTwVKSwt/n+KgFmyYEkEMbSdKDWB7MbvCPZykCQbkKnKfLzML9sg==",
"type": "package",
"path": "microsoft.jsinterop.webassembly/6.0.3",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"THIRD-PARTY-NOTICES.txt",
"lib/net6.0/Microsoft.JSInterop.WebAssembly.dll",
"lib/net6.0/Microsoft.JSInterop.WebAssembly.xml",
"microsoft.jsinterop.webassembly.6.0.3.nupkg.sha512",
"microsoft.jsinterop.webassembly.nuspec"
]
},
"System.IO.Pipelines/6.0.3": {
"sha512": "ryTgF+iFkpGZY1vRQhfCzX0xTdlV3pyaTTqRu2ETbEv+HlV7O6y7hyQURnghNIXvctl5DuZ//Dpks6HdL/Txgw==",
"type": "package",
@ -709,6 +776,7 @@
"projectFileDependencyGroups": {
"net6.0": [
"Blazored.LocalStorage >= 4.2.0",
"Blazored.Modal >= 7.1.0",
"Blazorise.Bootstrap >= 1.1.2",
"Blazorise.DataGrid >= 1.1.2",
"Blazorise.Icons.FontAwesome >= 1.1.2"
@ -762,6 +830,10 @@
"target": "Package",
"version": "[4.2.0, )"
},
"Blazored.Modal": {
"target": "Package",
"version": "[7.1.0, )"
},
"Blazorise.Bootstrap": {
"target": "Package",
"version": "[1.1.2, )"

@ -1,10 +1,11 @@
{
"version": 2,
"dgSpecHash": "W/1RkHWui7njzuhcVzHK0Af2S2YG/2t3peTwrz3Fxjcn4SImRVMhfS8pLj5D0np7Pye7WAPCgstn+wOIbp7How==",
"dgSpecHash": "Z8I5DbL+Zd0nsEOWz1CXMTDN+FV46BFlZBZXXwjEvn5pwCfQK71TUwF485Pk2mOVJnszXxBJr2IoGplzkZ0tfw==",
"success": true,
"projectFilePath": "C:\\Users\\babaverel\\Source\\Repos\\Blazor\\BlazorApp1\\BlazorApp1.csproj",
"expectedPackageFiles": [
"C:\\Users\\babaverel\\.nuget\\packages\\blazored.localstorage\\4.2.0\\blazored.localstorage.4.2.0.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\blazored.modal\\7.1.0\\blazored.modal.7.1.0.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\blazorise\\1.1.2\\blazorise.1.1.2.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\blazorise.bootstrap\\1.1.2\\blazorise.bootstrap.1.1.2.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\blazorise.datagrid\\1.1.2\\blazorise.datagrid.1.1.2.nupkg.sha512",
@ -21,6 +22,7 @@
"C:\\Users\\babaverel\\.nuget\\packages\\microsoft.extensions.options\\6.0.0\\microsoft.extensions.options.6.0.0.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\microsoft.extensions.primitives\\6.0.0\\microsoft.extensions.primitives.6.0.0.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\microsoft.jsinterop\\6.0.9\\microsoft.jsinterop.6.0.9.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\microsoft.jsinterop.webassembly\\6.0.3\\microsoft.jsinterop.webassembly.6.0.3.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\system.io.pipelines\\6.0.3\\system.io.pipelines.6.0.3.nupkg.sha512",
"C:\\Users\\babaverel\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\6.0.0\\system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
],

@ -34,3 +34,21 @@
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0

Loading…
Cancel
Save