Skip to content

Commit

Permalink
Merge branch 'main' into v3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
aritchie committed Jan 29, 2025
2 parents 26bed45 + 7abfdce commit 448c18e
Show file tree
Hide file tree
Showing 37 changed files with 177 additions and 106 deletions.
2 changes: 1 addition & 1 deletion samples/Sample/Handlers/SingletonEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Sample.Handlers;


[SingletonHandler]
public class SingletonEventHandler(IMediator mediator, AppSqliteConnection data) : IEventHandler<MyMessageEvent>
public class SingletonEventHandler(AppSqliteConnection data) : IEventHandler<MyMessageEvent>
{
public async Task Handle(MyMessageEvent @event, EventContext<MyMessageEvent> context, CancellationToken cancellationToken)
{
Expand Down
21 changes: 13 additions & 8 deletions samples/Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,21 @@ public static MauiApp CreateMauiApp()
builder.Services.AddShinyMediator(x => x
.UseMaui()
.UseBlazor()
.AddPersistentCache()

// Validation - you can only have both, but don't
.AddDataAnnotations()
// .AddFluentValidation()

.AddMauiHttpDecorator()
.AddPrismSupport()

// .AddFluentValidation() // don't add both
.AddResiliencyMiddleware(builder.Configuration)
.AddMemoryCaching(y =>
{
y.ExpirationScanFrequency = TimeSpan.FromSeconds(5);
})
// Cache - you can only have one
.AddMauiPersistentCache()
// .AddMemoryCaching(y =>
// {
// y.ExpirationScanFrequency = TimeSpan.FromSeconds(5);
// })
);
builder.Services.AddSingletonAsImplementedInterfaces<MyRequestMiddleware>();
builder.Services.AddDiscoveredMediatorHandlersFromSample();
Expand All @@ -71,7 +75,8 @@ public static MauiApp CreateMauiApp()
builder.Services.RegisterForNavigation<EventPage, EventViewModel>();
builder.Services.RegisterForNavigation<BlazorPage, BlazorViewModel>();
builder.Services.RegisterForNavigation<AnotherPage, AnotherViewModel>();

return builder.Build();

var app = builder.Build();
return app;
}
}
3 changes: 1 addition & 2 deletions samples/Sample/TriggerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Sample;

public partial class TriggerViewModel(
IMediator mediator,
IMemoryCache cache,
AppSqliteConnection data,
IPageDialogService dialogs
) : ObservableObject, IEventHandler<MyMessageEvent>
Expand Down Expand Up @@ -111,7 +110,7 @@ async Task CacheRequest()
[RelayCommand]
async Task CacheClear()
{
cache.Clear();
await mediator.Publish(new FlushAllStoresEvent());
await dialogs.DisplayAlertAsync("Cache Cleared", "DONE", "Ok");
}
[ObservableProperty] string cacheValue;
Expand Down
2 changes: 1 addition & 1 deletion samples/Sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"UserErrorNotifications": {
// this works
"Sample.Handlers.ErrorRequestHandler": {
"Sample.Handlers.ErrorCommandHandler": {
"*": {
"Title": "ERROR",
"Message" : "Failed to do something"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static class AppSupportExecutionContextExtensions
internal static void UserErrorNotification(this IMediatorContext context, UserErrorNotificationContext info)
=> context.Add(nameof(UserErrorNotification), info);

public static OfflineAvailableContext? Offline(this IMediatorContext context)
public static OfflineAvailableContext? Offline(this RequestContext context)
=> context.TryGetValue<OfflineAvailableContext>("Offline");

internal static void Offline(this RequestContext context, OfflineAvailableContext offlineContext)
Expand Down
9 changes: 0 additions & 9 deletions src/Shiny.Mediator.AppSupport/AppSupportExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ namespace Shiny.Mediator;

public static class AppSupportExtensions
{
/// <summary>
/// Adds a file based caching service - ideal for cache surviving across app sessions
/// </summary>
/// <param name="configurator"></param>
/// <returns></returns>
public static ShinyConfigurator AddPersistentCache(this ShinyConfigurator configurator)
=> configurator.AddCaching<StorageCacheService>();


/// <summary>
/// Adds standard app support middleware - offline, replay stream, & user notification
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public async Task<TResult> Process(
CancellationToken cancellationToken
)
{
if (!this.IsEnabled(context.RequestHandler, context.Request))
if (!this.IsEnabled(context.Handler, context.Request))
return await next().ConfigureAwait(false);

var result = default(TResult);
Expand All @@ -43,7 +43,7 @@ CancellationToken cancellationToken
}


async Task<TResult> GetOffline(RequestContext<TRequest> context)
async Task<TResult?> GetOffline(RequestContext<TRequest> context)
{
TResult result = default;
var offlineResult = await offline.Get<TResult>(context.Request!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public IAsyncEnumerable<TResult> Process(
CancellationToken cancellationToken
)
{
if (!this.IsEnabled(context.Request, context.RequestHandler))
if (!this.IsEnabled(context.Request, context.Handler))
return next();

logger.LogDebug("Enabled - {Request}", context.Request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public async Task<TResult> Process(
CancellationToken cancellationToken
)
{
var section = configuration.GetHandlerSection("UserErrorNotifications", context.Request!, context.RequestHandler);
var section = configuration.GetHandlerSection("UserErrorNotifications", context.Request!, context.Handler);
if (section == null)
return await next().ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Shiny.Mediator</RootNamespace>
<!--<PublishAot>true</PublishAot>-->
</PropertyGroup>

<ItemGroup>
Expand Down
28 changes: 24 additions & 4 deletions src/Shiny.Mediator.Blazor/BlazorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,33 @@ public static ShinyConfigurator UseBlazor(this ShinyConfigurator cfg, bool inclu
cfg.Services.AddSingletonAsImplementedInterfaces<BlazorEventCollector>();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Browser")))
{
cfg.Services.TryAddSingleton<IStorageService, StorageService>();
cfg.Services.TryAddSingleton<IInternetService, InternetService>();
cfg.Services.TryAddSingleton<IAlertDialogService, AlertDialogService>();

cfg.AddBlazorInfrastructure();
if (includeStandardMiddleware)
cfg.AddStandardAppSupportMiddleware();
}
return cfg;
}


public static ShinyConfigurator AddBlazorInfrastructure(this ShinyConfigurator cfg)
{
cfg.Services.TryAddSingleton<IStorageService, StorageService>();
cfg.Services.TryAddSingleton<IInternetService, InternetService>();
cfg.Services.TryAddSingleton<IAlertDialogService, AlertDialogService>();

return cfg;
}


/// <summary>
/// Adds a file based caching service - ideal for cache surviving across app sessions
/// </summary>
/// <param name="configurator"></param>
/// <returns></returns>
public static ShinyConfigurator AddBlazorPersistentCache(this ShinyConfigurator configurator)
{
configurator.AddBlazorInfrastructure();
configurator.AddCaching<StorageCacheService>();
return configurator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public IReadOnlyList<IEventHandler<TEvent>> GetHandlers<TEvent>() where TEvent :

public IComponent CreateInstance(Type componentType)
{
var component = (IComponent)Activator.CreateInstance(componentType);
var component = (IComponent)Activator.CreateInstance(componentType)!;
var isHandler = componentType
.GetInterfaces()
.Any(x =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Shiny.Mediator.Blazor.Infrastructure;

public class InternetService(IJSRuntime jsruntime) : IInternetService, IDisposable
{
public event EventHandler<bool> StateChanged;
public event EventHandler<bool>? StateChanged;
public bool IsAvailable => ((IJSInProcessRuntime)jsruntime).Invoke<bool>("MediatorServices.isOnline");


Expand Down
2 changes: 2 additions & 0 deletions src/Shiny.Mediator.Contracts/Shiny.Mediator.Contracts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Shiny.Mediator</RootNamespace>

<!--<PublishAot>true</PublishAot>-->
</PropertyGroup>
</Project>
19 changes: 14 additions & 5 deletions src/Shiny.Mediator.Maui/Http/MauiHttpRequestDecorator.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System.Globalization;
using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Shiny.Mediator.Http;


public class MauiHttpRequestDecorator<TRequest, TResult>(
IConfiguration configuration,
ILogger<MauiHttpRequestDecorator<TRequest, TResult>> logger,
IAppInfo appInfo,
IDeviceInfo deviceInfo,
IGeolocation geolocation
Expand All @@ -22,11 +23,19 @@ public async Task Decorate(HttpRequestMessage httpMessage, TRequest request)
httpMessage.Headers.Add("DeviceVersion", deviceInfo.Version.ToString());
httpMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name));

if (configuration["Mediator:Http:GpsHeader"] == "true")
try
{
var gps = await geolocation.GetLastKnownLocationAsync();
if (gps != null)
httpMessage.Headers.Add("GpsCoords", $"{gps.Latitude},{gps.Longitude}");
var result = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (result == PermissionStatus.Granted)
{
var gps = await geolocation.GetLastKnownLocationAsync();
if (gps != null)
httpMessage.Headers.Add("GpsCoords", $"{gps.Latitude},{gps.Longitude}");
}
}
catch (Exception ex)
{
logger.LogInformation(ex, "Failed to get GPS");
}
}
}
18 changes: 16 additions & 2 deletions src/Shiny.Mediator.Maui/Infrastructure/AlertDialogService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
using Microsoft.Extensions.Logging;

namespace Shiny.Mediator.Infrastructure;


public class AlertDialogService : IAlertDialogService
public class AlertDialogService(ILogger<AlertDialogService> logger) : IAlertDialogService
{
public void Display(string title, string message)
=> Application.Current.MainPage.DisplayAlert(title, message, "OK");
{
var app = Application.Current;
if (app == null)
return;

var window = app.Windows.FirstOrDefault();
if (window?.Page == null)
return;

window.Page
.DisplayAlert(title, message, "OK")
.RunInBackground(logger);
}
}
32 changes: 22 additions & 10 deletions src/Shiny.Mediator.Maui/Infrastructure/MauiEventCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,42 @@ public class MauiEventCollector : IEventCollector
public IReadOnlyList<IEventHandler<TEvent>> GetHandlers<TEvent>() where TEvent : IEvent
{
// I need to make this crawl the tree, but really I don't need a ton of use-cases here
var list = new List<IEventHandler<TEvent>>();
var mainPage = Application.Current?.MainPage;
// Application.Current.Windows
if (mainPage == null)
return list;
if (Application.Current == null)
return Array.Empty<IEventHandler<TEvent>>();

if (Application.Current.Windows.Count == 0)
return Array.Empty<IEventHandler<TEvent>>();

if (mainPage is TabbedPage tabs)
var list = new List<IEventHandler<TEvent>>();
foreach (var window in Application.Current.Windows)
{
if (window.Page != null)
VisitPage(window.Page, list);
}
return list;
}


static void VisitPage<TEvent>(Page page, List<IEventHandler<TEvent>> list) where TEvent : IEvent
{
if (page is TabbedPage tabs)
{
foreach (var tab in tabs.Children)
{
TryNavPage(tab, list);
}
}
else if (mainPage is FlyoutPage flyout)
else if (page is FlyoutPage flyout)
{
TryNavPage(flyout.Flyout, list);
TryNavPage(flyout.Detail, list); // could be a tabs page
}
else
{
TryNavPage(mainPage, list);
TryNavPage(page, list);
}
return list;
}


static void TryNavPage<TEvent>(Page page, List<IEventHandler<TEvent>> list) where TEvent : IEvent
{
Expand Down Expand Up @@ -69,6 +80,7 @@ static void TryAppendEvents<TEvent>(NavigationPage navPage, List<IEventHandler<T
}
}
}


static void TryAppendEvents<TEvent>(Shell shell, List<IEventHandler<TEvent>> list) where TEvent : IEvent
{
Expand Down
2 changes: 1 addition & 1 deletion src/Shiny.Mediator.Maui/Infrastructure/StorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public Task Set<T>(string key, T value)
}


public Task<T> Get<T>(string key)
public Task<T?> Get<T>(string key)
{
T? returnValue = default;
var path = this.GetFilePath(key);
Expand Down
Loading

0 comments on commit 448c18e

Please sign in to comment.