Skip to content

Commit

Permalink
Merge pull request #17 from AvantiPoint/dev/ds/updates
Browse files Browse the repository at this point in the history
General Updates
  • Loading branch information
dansiegel authored Apr 9, 2024
2 parents 954755b + 5c930e7 commit b91dea2
Show file tree
Hide file tree
Showing 24 changed files with 354 additions and 64 deletions.
3 changes: 3 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
<PackageProjectUrl>https://github.com/AvantiPoint/mauimicromvvm</PackageProjectUrl>
<NeutralLanguage>en</NeutralLanguage>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<NoWarn>$(NoWarn);NU1507</NoWarn>
<IsPackable>$(MSBuildProjectName.Contains('MauiMicroMvvm'))</IsPackable>
</PropertyGroup>

<PropertyGroup>
Expand Down
5 changes: 5 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<PackageId>AvantiPoint.$(AssemblyName)</PackageId>
</PropertyGroup>
</Project>
2 changes: 2 additions & 0 deletions MauiMicroMvvm.sln
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{58DDD03C-E4B7-431A-8BC4-B8A8199C3DCD}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Global
Expand Down
13 changes: 13 additions & 0 deletions sample/MauiMicroSample/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiMicroSample.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
9 changes: 9 additions & 0 deletions sample/MauiMicroSample/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace MauiMicroSample;

public partial class App : Application
{
public App()
{
InitializeComponent();
}
}
5 changes: 2 additions & 3 deletions sample/MauiMicroSample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiMicroMvvm<AppShell>(
"Resources/Styles/Colors.xaml",
"Resources/Styles/Styles.xaml")
.UseMauiApp<App>()
.UseMauiMicroMvvm<AppShell>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
Expand Down
3 changes: 0 additions & 3 deletions src/MauiMicroMvvm.Rx/MauiMicroMvvm.Rx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

<PropertyGroup>
<TargetFramework>$(DotNetVersion)</TargetFramework>
<UseMaui>true</UseMaui>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Description>MauiMicroMvvm.Rx is the perfect companion for people who love Reactive design &amp; want to couple it with MauiMicro. With MauiMicro Rx you get an Observables first base ViewModel that let's you design your code around an observable for the App &amp; View lifecycles.</Description>
<PackageTags>dotnet-maui;mvvm;mauimicro;reactive;rx</PackageTags>
<PackageId>AvantiPoint.$(AssemblyName)</PackageId>
<Title>$(AssemblyName)</Title>
</PropertyGroup>

Expand Down
4 changes: 2 additions & 2 deletions src/MauiMicroMvvm.Rx/RxMauiMicroViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class RxMauiMicroViewModel : ReactiveObject, IViewModelActivation, IViewL
private readonly Subject<ViewLifecycleState> _viewLifecycleState;
private readonly Subject<IDictionary<string, object>> _queryParameters;
private readonly Lazy<ILogger> _lazyLogger;
protected ObservableAsPropertyHelper<bool> IsBusyHelper;
protected ObservableAsPropertyHelper<bool>? IsBusyHelper;
private readonly ObservableAsPropertyHelper<bool> _isNotBusyHelper;
protected readonly CompositeDisposable Disposables;

Expand All @@ -21,7 +21,7 @@ public RxMauiMicroViewModel(ViewModelContext context)
_applifecycleState = new Subject<AppLifecycleState>();
_viewLifecycleState = new Subject<ViewLifecycleState>();
_queryParameters = new Subject<IDictionary<string, object>>();
Disposables = new CompositeDisposable();
Disposables = [];
Navigation = context.Navigation;
PageDialogs = context.PageDialogs;
_lazyLogger = new Lazy<ILogger>(() => context.Logger.CreateLogger(GetType().Name));
Expand Down
2 changes: 1 addition & 1 deletion src/MauiMicroMvvm.Templates/MauiMicroMvvm.Templates.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<IncludeSymbols>false</IncludeSymbols>
<IncludeSource>false</IncludeSource>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<Description>Project Template for Maui Micro by AvantiPoint</Description>
<PackageTags>dotnet-maui;mauimicro;mauimicromvvm;mauimicrotemplates;templates;mvvm;maui;</PackageTags>
<PackageId>AvantiPoint.$(AssemblyName)</PackageId>
<Title>MauiMicroMvvm Templates</Title>
<NoWarn>$(NoWarn);NU5128</NoWarn>
</PropertyGroup>
Expand Down
13 changes: 13 additions & 0 deletions src/MauiMicroMvvm.Templates/content/MauiMicroApp.1/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiMicroApp._1.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace MauiMicroApp._1;

public partial class App : Application
{
public App()
{
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiMicroMvvm<AppShell>(
"Resources/Styles/Colors.xaml",
"Resources/Styles/Styles.xaml")
.UseMauiApp<App>()
.UseMauiMicroMvvm<AppShell>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
Expand Down
27 changes: 27 additions & 0 deletions src/MauiMicroMvvm/Behaviors/BehaviorFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace MauiMicroMvvm.Behaviors;

public sealed class BehaviorFactory : IBehaviorFactory
{
private readonly IEnumerable<IRegisteredBehavior> _behaviors;
private readonly IServiceProvider _services;

public BehaviorFactory(IServiceProvider services, IEnumerable<IRegisteredBehavior> behaviors)
{
ArgumentNullException.ThrowIfNull(services);
_behaviors = behaviors ?? [];
_services = services;
}

public void ApplyBehaviors(VisualElement element)
{
foreach (var registration in _behaviors)
{
if (!registration.ViewType.IsAssignableFrom(registration.ViewType))
continue;

var behavior = registration.GetBehavior();
if (behavior is not null)
element.Behaviors.Add(behavior);
}
}
}
24 changes: 24 additions & 0 deletions src/MauiMicroMvvm/Behaviors/DelegateViewBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace MauiMicroMvvm.Behaviors;

internal sealed class DelegateViewBehavior<TView>(Action<IServiceProvider, TView> onAttached, Action<IServiceProvider, TView> onDetached) : Behavior<TView>
where TView : VisualElement
{
private readonly Action<IServiceProvider, TView> _onAttached = onAttached;
private readonly Action<IServiceProvider, TView> _onDetached = onDetached;

protected override void OnAttachedTo(TView bindable)
{
base.OnAttachedTo(bindable);
var serviceProvider = bindable.Handler?.MauiContext?.Services;
ArgumentNullException.ThrowIfNull(serviceProvider);
_onAttached(serviceProvider, bindable);
}

protected override void OnDetachingFrom(TView bindable)
{
base.OnDetachingFrom(bindable);
var serviceProvider = bindable.Handler?.MauiContext?.Services;
ArgumentNullException.ThrowIfNull(serviceProvider);
_onDetached(serviceProvider, bindable);
}
}
6 changes: 6 additions & 0 deletions src/MauiMicroMvvm/Behaviors/IBehaviorFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace MauiMicroMvvm.Behaviors;

public interface IBehaviorFactory
{
void ApplyBehaviors(VisualElement element);
}
7 changes: 7 additions & 0 deletions src/MauiMicroMvvm/Behaviors/IRegisteredBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace MauiMicroMvvm.Behaviors;

public interface IRegisteredBehavior
{
Type ViewType { get; }
Behavior GetBehavior();
}
10 changes: 10 additions & 0 deletions src/MauiMicroMvvm/Behaviors/RegisteredBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace MauiMicroMvvm.Behaviors;

internal class RegisteredBehavior<TView, TBehavior>(IServiceProvider Services) : IRegisteredBehavior
where TView : VisualElement
where TBehavior : Behavior
{
public Type ViewType => typeof(TView);

public Behavior GetBehavior() => Services.GetRequiredService<TBehavior>();
}
42 changes: 42 additions & 0 deletions src/MauiMicroMvvm/Common/MvvmHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.Maui.Controls;

namespace MauiMicroMvvm.Common;

public static class MvvmHelpers
{
public static void InvokeViewViewModelAction<T>(object? value, Action<T> action)
{
if (value is T valueAsT)
{
action(valueAsT);
}

if (value is BindableObject bindable)
{
InvokeViewViewModelAction(bindable.BindingContext, action);
}
}

public static async Task InvokeViewViewModelActionAsync<T>(object? value, Func<T, Task> action)
{
if (value is T valueAsT)
{
await action(valueAsT);
}

if (value is BindableObject bindable)
{
await InvokeViewViewModelActionAsync(bindable.BindingContext, action);
}
}

public static void Destroy(object? page)
{
InvokeViewViewModelAction<IDisposable>(page, x => x.Dispose());
}

public static Task DestroyAsync(object? page)
{
return InvokeViewViewModelActionAsync<IAsyncDisposable>(page, x => x.DisposeAsync().AsTask());
}
}
62 changes: 42 additions & 20 deletions src/MauiMicroMvvm/Internals/AppLifecycleBehavior.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel;
using MauiMicroMvvm.Common;
using MauiMicroMvvm.Xaml;

namespace MauiMicroMvvm.Internals;
Expand All @@ -8,13 +9,15 @@ public class AppLifecycleBehavior : Behavior
{
private bool _didAppear;
private bool _isVisible;
private Window _window;
public Page Page { get; set; }
private Window? _window;
public Page? Page { get; set; }

public BindableObject View { get; set; }
public BindableObject? View { get; set; }

protected override void OnAttachedTo(BindableObject bindable)
{
ArgumentNullException.ThrowIfNull(Page);
ArgumentNullException.ThrowIfNull(View);
base.OnAttachedTo(bindable);
Page.Appearing += OnAppearing;
Page.Disappearing += OnDisappearing;
Expand All @@ -34,13 +37,19 @@ protected override void OnAttachedTo(BindableObject bindable)
}
}

protected override void OnDetachingFrom(BindableObject bindable)
protected override async void OnDetachingFrom(BindableObject bindable)
{
ArgumentNullException.ThrowIfNull(Page);
ArgumentNullException.ThrowIfNull(View);

base.OnDetachingFrom(bindable);
Page.Appearing -= OnAppearing;
Page.Disappearing -= OnDisappearing;
Page.PropertyChanged -= OnPagePropertyChanged;
View.PropertyChanged -= OnViewPropertyChanged;

MvvmHelpers.Destroy(View);
await MvvmHelpers.DestroyAsync(View);
if (_window is not null)
{
_window.Resumed -= OnResumed;
Expand All @@ -50,8 +59,11 @@ protected override void OnDetachingFrom(BindableObject bindable)
Page = null;
}

private void OnViewPropertyChanged(object sender, PropertyChangedEventArgs e)
private void OnViewPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(Page);
ArgumentNullException.ThrowIfNull(View);

if (e.PropertyName != MauiMicro.SharedContextProperty.PropertyName)
return;

Expand All @@ -60,8 +72,11 @@ private void OnViewPropertyChanged(object sender, PropertyChangedEventArgs e)
MauiMicro.SetSharedContext(Page, value);
}

private void OnPagePropertyChanged(object sender, PropertyChangedEventArgs e)
private void OnPagePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
ArgumentNullException.ThrowIfNull(Page);
ArgumentNullException.ThrowIfNull(View);

if (e.PropertyName != MauiMicro.SharedContextProperty.PropertyName)
return;

Expand All @@ -70,32 +85,39 @@ private void OnPagePropertyChanged(object sender, PropertyChangedEventArgs e)
MauiMicro.SetSharedContext(View, value);
}

private void OnResumed(object sender, EventArgs e)
private void OnResumed(object? sender, EventArgs e)
{
if (_isVisible && View.BindingContext is IAppLifecycle lifecycle)
lifecycle.OnResume();
MvvmHelpers.InvokeViewViewModelAction<IAppLifecycle>(View, x => x.OnResume());
}

private void OnStopped(object sender, EventArgs e)
private void OnStopped(object? sender, EventArgs e)
{
if (_isVisible && View.BindingContext is IAppLifecycle lifecycle)
lifecycle.OnSleep();
MvvmHelpers.InvokeViewViewModelAction<IAppLifecycle>(View, x => x.OnSleep());
}

private void OnAppearing(object sender, EventArgs e)
private void OnAppearing(object? sender, EventArgs e)
{
if (!_didAppear && View.BindingContext is IViewModelActivation initialize)
initialize.OnFirstLoad();
if (!_didAppear)
{
MvvmHelpers.InvokeViewViewModelAction<IViewModelActivation>(View, x => x.OnFirstLoad());
}

_didAppear = true;
if (View.BindingContext is IViewLifecycle lifecycle)
lifecycle.OnAppearing();

if (!_isVisible)
{
MvvmHelpers.InvokeViewViewModelAction<IViewLifecycle>(View, x => x.OnAppearing());
}

_isVisible = true;
}

private void OnDisappearing(object sender, EventArgs e)
private void OnDisappearing(object? sender, EventArgs e)
{
if (View.BindingContext is IViewLifecycle lifecycle)
lifecycle.OnDisappearing();
if (_isVisible)
{
MvvmHelpers.InvokeViewViewModelAction<IViewLifecycle>(View, x => x.OnDisappearing());
}

_isVisible = false;
}
Expand Down
Loading

0 comments on commit b91dea2

Please sign in to comment.