Skip to content

Commit

Permalink
#289 - Preparations for customizable mobile menu.
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf committed May 26, 2021
1 parent 5fd49d3 commit c93155c
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 68 deletions.
2 changes: 1 addition & 1 deletion src/Money.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
"RequireUppercase": false
}
},
"UserProperties": [ "PriceDecimalDigits", "DateFormat" ]
"UserProperties": [ "PriceDecimalDigits", "DateFormat", "MobileMenu" ]
}
14 changes: 8 additions & 6 deletions src/Money.Blazor.Host/Bootstrap/BootstrapTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void Initialize()
.AddTransient<CreateExpenseStorage>()
.AddTransient<OfflineCommandDispatcher>()
.AddSingleton<LocalCommandDispatcher>()
.AddSingleton<MenuItemService>()
.AddSingleton<ICommandHandlerCollection, LocalCommandHandlerCollection>()
.AddTransient<ICommandDispatcher, LocalCommandDispatcher>()
.AddTransient<IQueryDispatcher, HttpQueryDispatcher>()
Expand All @@ -96,12 +97,13 @@ public void Initialize()
.AddSingleton(exceptionHandler.Handler)
.AddSingleton(exceptionHandler.HandlerBuilder);

void AddMiddleware<T>(IServiceCollection services)
void AddMiddleware<T>(IServiceCollection services, bool register = true)
where T : class, HttpQueryDispatcher.IMiddleware
{
services
.AddScoped<T>()
.AddTransient<HttpQueryDispatcher.IMiddleware>(sp => sp.GetService<T>());
if (register)
services.AddScoped<T>();

services.AddTransient<HttpQueryDispatcher.IMiddleware>(sp => sp.GetService<T>());
}

AddMiddleware<CategoryMiddleware>(services);
Expand All @@ -110,8 +112,8 @@ void AddMiddleware<T>(IServiceCollection services)
AddMiddleware<UserPropertyMiddleware>(services);
AddMiddleware<ApiVersionChecker>(services);
AddMiddleware<UserPropertyQueryHandler>(services);

services.AddTransient<HttpQueryDispatcher.IMiddleware>(sp => sp.GetService<PwaInstallInterop>());
AddMiddleware<PwaInstallInterop>(services, register: false);
AddMiddleware<MenuItemService>(services, register: false);

//CurrencyCache currencyCache = new CurrencyCache(eventDispatcher.Handlers, queryDispatcher);

Expand Down
49 changes: 26 additions & 23 deletions src/Money.Blazor.Host/Layouts/BottomMenu.razor
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
<div class="row my-2 [email protected]">
@foreach (var item in Items)
{
<div class="col">
@if (item.Url != null)
{
<Match Url="@item.Url" PageType="@item.PageType" Context="IsActive">
<a href="@item.Url" class="btn btn-block @(IsActive ? "btn-primary" : "btn-light")">
@if (Items != null)
{
<div class="row my-2 [email protected]">
@foreach (var item in Items)
{
<div class="col">
@if (item.Url != null)
{
<Match Url="@item.Url" PageType="@item.PageType" Context="IsActive">
<a href="@item.Url" class="btn btn-block @(IsActive ? "btn-primary" : "btn-light")">
<Icon Identifier="@item.Icon" />
<span class="text">
@item.Text
</span>
</a>
</Match>
}
else
{
<button @onclick="@item.OnClick" class="btn btn-block btn-light">
<Icon Identifier="@item.Icon" />
<span class="text">
@item.Text
</span>
</a>
</Match>
}
else
{
<button @onclick="@item.OnClick" class="btn btn-block btn-light">
<Icon Identifier="@item.Icon" />
<span class="text">
@item.Text
</span>
</button>
}
</div>
}
</div>
</button>
}
</div>
}
</div>
}
46 changes: 8 additions & 38 deletions src/Money.Blazor.Host/Layouts/BottomMenu.razor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Components;
using Money.Models;
using Money.Models.Queries;
using Money.Pages;
using Money.Services;
using Neptuo.Queries;
using System;
using System.Collections.Generic;
using System.IO;
Expand All @@ -15,49 +18,16 @@ public partial class BottomMenu
[Inject]
protected Navigator Navigator { get; set; }

protected List<MenuItemModel> Items { get; set; }
[Inject]
protected IQueryDispatcher Queries { get; set; }

protected List<IActionMenuItemModel> Items { get; set; }

protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();

Items = new List<MenuItemModel>()
{
new MenuItemModel()
{
Icon = "chart-pie",
Text = "Monthly",
Url = Navigator.UrlSummary(),
PageType = typeof(SummaryMonth)
},
new MenuItemModel()
{
Icon = "search",
Text = "Search",
Url = Navigator.UrlSearch()
},
new MenuItemModel()
{
Icon = "tag",
Text = "Categories",
Url = Navigator.UrlCategories()
},
new MenuItemModel()
{
Icon = "minus-circle",
Text = "New Expense",
OnClick = Navigator.OpenExpenseCreate
}
};
Items = await Queries.QueryAsync(new ListBottomMenuItem());
}
}

public class MenuItemModel
{
public string Icon { get; set; }
public string Text { get; set; }
public string Url { get; set; }
public Type PageType { get; set; }
public Action OnClick { get; set; }
}
}
92 changes: 92 additions & 0 deletions src/Money.Blazor.Host/MenuItems/MenuItemService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Money.Models;
using Money.Models.Queries;
using Money.Pages;
using Money.Services;
using Neptuo;
using Neptuo.Queries;
using Neptuo.Queries.Handlers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money
{
internal class MenuItemService : HttpQueryDispatcher.IMiddleware
{
private const string DefaultValue = "summary-month,expense-create";

private readonly Navigator navigator;
private readonly List<MenuItemModel> storage;

public MenuItemService(Navigator navigator)
{
Ensure.NotNull(navigator, "navigator");
this.navigator = navigator;

storage = new List<MenuItemModel>()
{
new MenuItemModel()
{
Identifier = "summary-month",
Icon = "chart-pie",
Text = "Monthly",
Url = navigator.UrlSummary(),
PageType = typeof(SummaryMonth)
},
new MenuItemModel()
{
Identifier = "search",
Icon = "search",
Text = "Search",
Url = navigator.UrlSearch()
},
new MenuItemModel()
{
Identifier = "categories",
Icon = "tag",
Text = "Categories",
Url = navigator.UrlCategories()
},
new MenuItemModel()
{
Identifier = "expense-create",
Icon = "minus-circle",
Text = "New Expense",
OnClick = navigator.OpenExpenseCreate
}
};
}

async Task<object> HttpQueryDispatcher.IMiddleware.ExecuteAsync(object query, HttpQueryDispatcher dispatcher, HttpQueryDispatcher.Next next)
{
if (query is ListBottomMenuItem)
{
return storage.ToList<IActionMenuItemModel>();
}
else if (query is ListAvailableMenuItem)
{
return storage.ToList<IAvailableMenuItemModel>();
}
else if (query is FindUserProperty findProperty && findProperty.Key == "MobileMenu")
{
var value = (string)await next(findProperty);
if (String.IsNullOrEmpty(value))
return DefaultValue;
}
else if (query is ListUserProperty listProperty)
{
var value = (List<UserPropertyModel>)await next(listProperty);
var property = value.FirstOrDefault(p => p.Key == "MobileMenu");
if (property != null && String.IsNullOrEmpty(property.Value))
property.Value = DefaultValue;

return value;
}

return await next(query);
}
}
}
18 changes: 18 additions & 0 deletions src/Money.Blazor.Host/MenuItems/Models/IActionMenuItemModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Models
{
public interface IActionMenuItemModel
{
string Icon { get; }
string Text { get; }
string Url { get; }
Type PageType { get; }
Action OnClick { get; }
}
}
16 changes: 16 additions & 0 deletions src/Money.Blazor.Host/MenuItems/Models/IAvailableMenuItemModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Models
{
public interface IAvailableMenuItemModel
{
string Identifier { get; }
string Icon { get; }
string Text { get; }
}
}
19 changes: 19 additions & 0 deletions src/Money.Blazor.Host/MenuItems/Models/MenuItemModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Models
{
public class MenuItemModel : IActionMenuItemModel, IAvailableMenuItemModel
{
public string Identifier { get; set; }
public string Icon { get; set; }
public string Text { get; set; }
public string Url { get; set; }
public Type PageType { get; set; }
public Action OnClick { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Money.Models.Queries;
using Neptuo.Queries;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Models.Queries
{
public class ListAvailableMenuItem : UserQuery, IQuery<List<IAvailableMenuItemModel>>
{

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Money.Models;
using Neptuo.Queries;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Models.Queries
{
/// <summary>
/// A query providing selected bottom menu items.
/// </summary>
public class ListBottomMenuItem : UserQuery, IQuery<List<IActionMenuItemModel>>
{ }
}
21 changes: 21 additions & 0 deletions src/Money.Blazor.Host/Pages/Users/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,25 @@
<Buttons>
<button class="btn btn-primary" @onclick="(async () => { await DateFormat.SetAsync(); DateFormatEditor.Hide(); })">Set</button>
</Buttons>
</Modal>

<Modal @ref="MobileMenuEditor" Title="Modify mobile menu">
<ChildContent>
@if (MobileMenuAvailableModels != null)
{
foreach (var model in MobileMenuAvailableModels)
{
<div class="btn-group-toggle" data-toggle="buttons">
<label class="btn btn-outline-primary btn-block">
<input type="checkbox" checked autocomplete="off">
<Icon Identifier="@model.Icon" />
@model.Text
</label>
</div>
}
}
</ChildContent>
<Buttons>
<button class="btn btn-primary" @onclick="(async () => { await MobileMenu.SetAsync(); MobileMenuEditor.Hide(); })">Set</button>
</Buttons>
</Modal>
7 changes: 7 additions & 0 deletions src/Money.Blazor.Host/Pages/Users/Settings.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public partial class Settings : System.IDisposable,
protected PropertyViewModel DateFormat { get; set; }
protected Modal DateFormatEditor { get; set; }

protected PropertyViewModel MobileMenu { get; set; }
protected Modal MobileMenuEditor { get; set; }
protected List<IAvailableMenuItemModel> MobileMenuAvailableModels { get; set; }

protected List<UserPropertyModel> Models { get; set; }
protected List<PropertyViewModel> ViewModels { get; } = new List<PropertyViewModel>();

Expand All @@ -48,6 +52,9 @@ protected async override Task OnInitializedAsync()

PriceDecimals = AddProperty("PriceDecimalDigits", "Price decimal digits", () => PriceDecimalsEditor.Show(), icon: "pound-sign", defaultValue: "2");
DateFormat = AddProperty("DateFormat", "Date format", () => DateFormatEditor.Show(), icon: "calendar-day", defaultValue: CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern);
MobileMenu = AddProperty("MobileMenu", "Mobile menu", () => MobileMenuEditor.Show(), icon: "mobile");

MobileMenuAvailableModels = await Queries.QueryAsync(new ListAvailableMenuItem());

await LoadAsync();
}
Expand Down

0 comments on commit c93155c

Please sign in to comment.