mirror of
https://github.com/AlexMacocian/Net.Maui.Extensions.git
synced 2026-07-15 14:59:31 +00:00
Implement context
Implement navigation Implement options
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace Net.Maui.Extensions.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class OptionSectionAttribute : Attribute
|
||||
{
|
||||
public string? SectionName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Net.Maui.Extensions.Context;
|
||||
|
||||
public interface IMauiAppContextAccessor
|
||||
{
|
||||
public MauiAppContext Context { get; }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Net.Maui.Extensions.Context;
|
||||
|
||||
public sealed class MauiAppContext
|
||||
{
|
||||
private readonly Dictionary<string, object?> resources = [];
|
||||
|
||||
internal MauiAppContext()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetContext<T>(string key, T value)
|
||||
{
|
||||
this.resources.Add(key, value);
|
||||
}
|
||||
|
||||
public bool TryGetContext<T>(string key, out T? value)
|
||||
{
|
||||
if (this.resources.TryGetValue(key, out var valueObj) &&
|
||||
valueObj is T typedValue)
|
||||
{
|
||||
value = typedValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Net.Maui.Extensions.Context;
|
||||
|
||||
internal sealed class MauiAppContextManager : IMauiAppContextAccessor
|
||||
{
|
||||
public MauiAppContext Context { get; } = new();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Net.Maui.Extensions.ControlFlow;
|
||||
|
||||
public interface INavigationService
|
||||
{
|
||||
Task GoTo<T>(bool animated = false)
|
||||
where T : ContentPage;
|
||||
|
||||
Task GoToModal<T>(bool animated = false)
|
||||
where T : ContentPage;
|
||||
|
||||
Task GoBack(bool animated = false);
|
||||
|
||||
Task GoBackModal(bool animated = false);
|
||||
|
||||
Task GoBackToRoot(bool animated = false);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions.Core;
|
||||
|
||||
namespace Net.Maui.Extensions.ControlFlow;
|
||||
|
||||
internal sealed class NavigationService : INavigationService
|
||||
{
|
||||
private readonly ScopedApplicationShell scopedApplicationShell;
|
||||
private readonly ILogger<NavigationService> logger;
|
||||
|
||||
public NavigationService(
|
||||
ScopedApplicationShell scopedApplicationShell,
|
||||
ILogger<NavigationService> logger)
|
||||
{
|
||||
this.scopedApplicationShell = scopedApplicationShell.ThrowIfNull();
|
||||
this.logger = logger.ThrowIfNull();
|
||||
}
|
||||
|
||||
public async Task GoBack(bool animated = false)
|
||||
{
|
||||
var scopedLogger = this.logger.CreateScopedLogger();
|
||||
scopedLogger.LogInformation("Going back");
|
||||
await this.scopedApplicationShell.Navigation.PopAsync(animated);
|
||||
}
|
||||
|
||||
public async Task GoBackModal(bool animated = false)
|
||||
{
|
||||
var scopedLogger = this.logger.CreateScopedLogger();
|
||||
scopedLogger.LogInformation("Going back");
|
||||
await this.scopedApplicationShell.Navigation.PopModalAsync(animated);
|
||||
}
|
||||
|
||||
public async Task GoBackToRoot(bool animated = false)
|
||||
{
|
||||
var scopedLogger = this.logger.CreateScopedLogger();
|
||||
scopedLogger.LogInformation("Going back to root");
|
||||
await this.scopedApplicationShell.Navigation.PopToRootAsync(animated);
|
||||
}
|
||||
|
||||
public async Task GoTo<T>(bool animated = false) where T : ContentPage
|
||||
{
|
||||
var scopedLogger = this.logger.CreateScopedLogger();
|
||||
scopedLogger.LogInformation($"Going to {typeof(T).Name}");
|
||||
await this.scopedApplicationShell.PushScoped<T>();
|
||||
}
|
||||
|
||||
public async Task GoToModal<T>(bool animated = false) where T : ContentPage
|
||||
{
|
||||
var scopedLogger = this.logger.CreateScopedLogger();
|
||||
scopedLogger.LogInformation($"Going to {typeof(T).Name}");
|
||||
await this.scopedApplicationShell.PushModalScoped<T>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Core.Extensions;
|
||||
|
||||
namespace Net.Maui.Extensions.ControlFlow;
|
||||
|
||||
internal class ScopedApplicationShell : Shell
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public ScopedApplicationShell(
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
this.serviceProvider = serviceProvider.ThrowIfNull();
|
||||
}
|
||||
|
||||
public async Task PushScoped<T>()
|
||||
where T : ContentPage
|
||||
{
|
||||
var page = this.GetScopedPage<T>();
|
||||
await this.Navigation.PushAsync(page);
|
||||
}
|
||||
|
||||
public async Task PushModalScoped<T>()
|
||||
where T : ContentPage
|
||||
{
|
||||
var page = this.GetScopedPage<T>();
|
||||
await this.Navigation.PushModalAsync(page);
|
||||
}
|
||||
|
||||
private T GetScopedPage<T>()
|
||||
where T : ContentPage
|
||||
{
|
||||
using var scope = this.serviceProvider.CreateScope();
|
||||
return scope.ServiceProvider.GetRequiredService<T>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Core.Extensions;
|
||||
|
||||
namespace Net.Maui.Extensions;
|
||||
|
||||
public abstract class ExtendedApplication : Application
|
||||
{
|
||||
public ExtendedApplication(Shell shell)
|
||||
{
|
||||
this.MainPage = shell.ThrowIfNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Net.Maui.Extensions.Attributes;
|
||||
using Net.Maui.Extensions.Context;
|
||||
using Net.Maui.Extensions.ControlFlow;
|
||||
using System.Core.Extensions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Net.Maui.Extensions;
|
||||
|
||||
public static class MauiAppBuilderExtensions
|
||||
{
|
||||
private static readonly Lazy<MethodInfo> ConfigureMethod = new(() =>
|
||||
{
|
||||
return typeof(OptionsConfigurationServiceCollectionExtensions)?
|
||||
.GetMethods(BindingFlags.Static | BindingFlags.Public)
|
||||
.FirstOrDefault(m => m.Name == nameof(OptionsConfigurationServiceCollectionExtensions.Configure)
|
||||
&& m.GetGenericArguments().Length == 1
|
||||
&& m.GetParameters().Length == 2
|
||||
&& m.GetParameters()[0].ParameterType == typeof(IServiceCollection)
|
||||
&& m.GetParameters()[1].ParameterType == typeof(IConfiguration)) ?? throw new InvalidOperationException($"Unable to resolve {nameof(OptionsConfigurationServiceCollectionExtensions.Configure)} method");
|
||||
}, true);
|
||||
|
||||
public static MauiAppBuilder WithExtendedOptions(this MauiAppBuilder appBuilder)
|
||||
{
|
||||
appBuilder.ThrowIfNull();
|
||||
foreach ((var optionType, var optionAttribute) in Assembly.GetCallingAssembly()?.GetTypes()?
|
||||
.Select(t => (t, t.GetCustomAttributes(true).OfType<OptionSectionAttribute>().FirstOrDefault()))
|
||||
.Where(t => t.Item2 is not null) ?? [])
|
||||
{
|
||||
var section = appBuilder.Configuration.GetRequiredSection(optionAttribute?.SectionName ?? optionType.Name);
|
||||
// Use reflection to call the generic Configure<T> method
|
||||
var method = ConfigureMethod.Value
|
||||
.MakeGenericMethod(optionType);
|
||||
|
||||
method?.Invoke(null, [appBuilder.Services, section]);
|
||||
}
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
public static MauiAppBuilder WithMauiAppContext(this MauiAppBuilder appBuilder)
|
||||
{
|
||||
appBuilder.ThrowIfNull()
|
||||
.Services.AddScoped<IMauiAppContextAccessor, MauiAppContextManager>();
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
public static MauiAppBuilder WithExtendedApp<T>(this MauiAppBuilder appBuilder)
|
||||
where T : ExtendedApplication
|
||||
{
|
||||
appBuilder.ThrowIfNull().UseMauiApp<T>();
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
public static MauiAppBuilder WithNavigation(this MauiAppBuilder appBuilder)
|
||||
{
|
||||
appBuilder.ThrowIfNull();
|
||||
appBuilder.Services.AddScoped<Shell, ScopedApplicationShell>();
|
||||
appBuilder.Services.AddScoped<INavigationService, NavigationService>();
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
public static MauiAppBuilder WithPages(this MauiAppBuilder appBuilder)
|
||||
{
|
||||
appBuilder.ThrowIfNull();
|
||||
foreach (var pageType in Assembly.GetCallingAssembly()?.GetTypes()?.Where(t => t.IsAssignableTo(typeof(ContentPage))) ?? [])
|
||||
{
|
||||
appBuilder.Services.AddScoped(pageType);
|
||||
appBuilder.Services.AddScoped(typeof(ContentPage), sp => sp.GetRequiredService(pageType));
|
||||
}
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
}
|
||||
@@ -45,9 +45,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.80" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.80" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="SystemExtensions.NetCore" Version="1.6.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user