Skip to content

Commit

Permalink
Implement ViewModelComponent (#437)
Browse files Browse the repository at this point in the history
* Implement ViewModelComponent with unified logic for storing/restoring/cleaning view models

* Update interface of Forms'  implementation of DialogsService

* Add documentation for ViewModelComponent class

* Update storage naming

* Throw exception if component is re-initialized
  • Loading branch information
TimofeyBurak authored Mar 26, 2021
1 parent d96d058 commit 7c0e75a
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace Softeq.XToolkit.WhiteLabel.Droid.Dialogs
{
public abstract class DialogFragmentBase<TViewModel> : DialogFragment, IBindable, IDialogFragment
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
private readonly Lazy<IContextProvider> _contextProviderLazy = Dependencies.Container.Resolve<Lazy<IContextProvider>>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@ public Task<string> ShowDialogAsync(ActionSheetDialogConfig config)

public Task<TResult> ShowForViewModel<TViewModel, TResult>(
IEnumerable<NavigationParameterModel>? parameters = null)
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
return ShowForViewModelAsync<TViewModel, TResult>(parameters).WaitUntilDismissed();
}

public Task ShowForViewModel<TViewModel>(
IEnumerable<NavigationParameterModel>? parameters = null)
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
return ShowForViewModelAsync<TViewModel>(parameters).WaitUntilDismissed();
}

public async Task<IDialogResult> ShowForViewModelAsync<TViewModel>(
IEnumerable<NavigationParameterModel>? parameters = null)
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
var viewModel = CreateViewModel<TViewModel>(parameters);

Expand All @@ -81,7 +81,7 @@ public async Task<IDialogResult> ShowForViewModelAsync<TViewModel>(

public async Task<IDialogResult<TResult>> ShowForViewModelAsync<TViewModel, TResult>(
IEnumerable<NavigationParameterModel>? parameters = null)
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
var viewModel = CreateViewModel<TViewModel>(parameters);

Expand Down Expand Up @@ -109,7 +109,7 @@ private TViewModel CreateViewModel<TViewModel>(
}

protected virtual Task<object> ShowDialogAsync<TViewModel>(TViewModel viewModel)
where TViewModel : IDialogViewModel
where TViewModel : class, IDialogViewModel
{
var dialogFragment = (DialogFragmentBase<TViewModel>) _viewLocator.GetView(viewModel, ViewType.DialogFragment);
dialogFragment.Show();
Expand Down
46 changes: 46 additions & 0 deletions Softeq.XToolkit.WhiteLabel.Droid/Internal/IInstanceStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com

using System.Collections.Generic;

namespace Softeq.XToolkit.WhiteLabel.Droid.Internal
{
/// <summary>
/// Defines the contract for a storage that stores instances of different classes.
/// </summary>
internal interface IInstanceStorage
{
/// <summary>
/// Returns an existing <typeparamref name="T"/> instance from the store.
/// </summary>
/// <typeparam name="T">The type of the instance to get.</typeparam>
/// <param name="key">The instance unique key.</param>
/// <returns>Stored instance.</returns>
T Get<T>(string key) where T : class;

/// <summary>
/// Adds a <typeparamref name="T"/> instance to the store by <paramref name="key"/>.
/// </summary>
/// <typeparam name="T">The type of the instance to add.</typeparam>
/// <param name="key">The instance unique key.</param>
/// <param name="viewModel">The instance to add.</param>
void Add<T>(string key, T viewModel) where T : class;

/// <summary>
/// Removes an existing instance from the store by <paramref name="key"/>.
/// </summary>
/// <param name="key">The instance unique key.</param>
void Remove(string key);

/// <summary>
/// Removes an existing instances from the store by <paramref name="keys"/>.
/// </summary>
/// <param name="keys">The collection of instance unique keys.</param>
void Remove(IEnumerable<string> keys);

/// <summary>
/// Clears store.
/// </summary>
void Clear();
}
}
47 changes: 0 additions & 47 deletions Softeq.XToolkit.WhiteLabel.Droid/Internal/IViewModelStore.cs

This file was deleted.

29 changes: 10 additions & 19 deletions Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,47 @@
// http://www.softeq.com

using System.Collections.Generic;
using Softeq.XToolkit.WhiteLabel.Mvvm;

namespace Softeq.XToolkit.WhiteLabel.Droid.Internal
{
internal static class ViewModelCache
{
private static readonly Dictionary<string, Dictionary<string, IViewModelBase>> _cache;

static ViewModelCache()
{
_cache = new Dictionary<string, Dictionary<string, IViewModelBase>>();
}
private static readonly Dictionary<string, Dictionary<string, object>> _cache =
new Dictionary<string, Dictionary<string, object>>();

internal static TViewModel? Get<TViewModel>(string containerId, string key)
where TViewModel : class, IViewModelBase
where TViewModel : class
{
var container = _cache.GetValueOrDefault(containerId);

if (container != null)
if (_cache.TryGetValue(containerId, out var container))
{
return (TViewModel) container.GetValueOrDefault(key);
}

return null;
}

internal static void Add(string containerId, string key, IViewModelBase viewModel)
internal static void Add(string containerId, string key, object viewModel)
{
if (!_cache.ContainsKey(containerId))
{
_cache[containerId] = new Dictionary<string, IViewModelBase>();
_cache[containerId] = new Dictionary<string, object>();
}

_cache[containerId][key] = viewModel;
}

internal static void Remove(string containerId, string key)
{
if (_cache.ContainsKey(containerId))
if (_cache.TryGetValue(containerId, out var container))
{
_cache[containerId].Remove(key);
container.Remove(key);
}
}

internal static void Remove(string containerId, IReadOnlyCollection<string> keys)
internal static void Remove(string containerId, IEnumerable<string> keys)
{
if (_cache.ContainsKey(containerId))
if (_cache.TryGetValue(containerId, out var container))
{
var container = _cache[containerId];

foreach (var key in keys)
{
container.Remove(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
using System.Collections.Generic;
using Android.OS;
using AndroidX.Fragment.App;
using Softeq.XToolkit.WhiteLabel.Mvvm;

namespace Softeq.XToolkit.WhiteLabel.Droid.Internal
{
internal sealed class ViewModelStoreFragment : Fragment, IViewModelStore
internal sealed class ViewModelStorageFragment : Fragment, IInstanceStorage
{
private const string ViewModelStoreIdKey = "WL_ViewModelStoreId";

Expand All @@ -19,7 +18,7 @@ internal sealed class ViewModelStoreFragment : Fragment, IViewModelStore

/// <inheritdoc />
public TViewModel Get<TViewModel>(string fragmentName)
where TViewModel : class, IViewModelBase
where TViewModel : class
{
var viewModel = ViewModelCache.Get<TViewModel>(ViewModelStoreId, fragmentName);

Expand All @@ -34,7 +33,8 @@ public TViewModel Get<TViewModel>(string fragmentName)
}

/// <inheritdoc />
public void Add(string fragmentName, IViewModelBase viewModel)
public void Add<TViewModel>(string fragmentName, TViewModel viewModel)
where TViewModel : class
{
ViewModelCache.Add(ViewModelStoreId, fragmentName, viewModel);
}
Expand All @@ -46,7 +46,7 @@ public void Remove(string fragmentName)
}

/// <inheritdoc />
public void Remove(IReadOnlyList<string> fragmentNames)
public void Remove(IEnumerable<string> fragmentNames)
{
ViewModelCache.Remove(ViewModelStoreId, fragmentNames);
}
Expand All @@ -58,7 +58,7 @@ public void Clear()
}

/// <inheritdoc />
public override void OnCreate(Bundle savedInstanceState)
public override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);

Expand Down
8 changes: 4 additions & 4 deletions Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ internal static class ViewModelStore
{
private const string ViewModelStoreTag = "WL_ViewModelStore";

internal static IViewModelStore Of(FragmentManager fragmentManager)
internal static IInstanceStorage Of(FragmentManager fragmentManager)
{
return Get(fragmentManager);
}

private static IViewModelStore Get(FragmentManager fragmentManager)
private static IInstanceStorage Get(FragmentManager fragmentManager)
{
if (fragmentManager.IsDestroyed)
{
throw new InvalidOperationException("View Model store has been destroyed");
}

var viewModelStore = (ViewModelStoreFragment?) fragmentManager.FindFragmentByTag(ViewModelStoreTag);
var viewModelStore = (ViewModelStorageFragment?) fragmentManager.FindFragmentByTag(ViewModelStoreTag);

if (viewModelStore == null)
{
viewModelStore = new ViewModelStoreFragment();
viewModelStore = new ViewModelStorageFragment();

fragmentManager
.BeginTransaction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public DroidFrameNavigationService(

protected FrameNavigationConfig? Config { get; private set; }

private IViewModelStore CurrentStore
private IInstanceStorage CurrentStore
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<Compile Include="ViewComponents\IViewComponent.cs" />
<Compile Include="ViewComponents\ToastContainerComponent.cs" />
<Compile Include="ViewComponents\ToolbarComponent.cs" />
<Compile Include="ViewComponents\ViewModelComponent.cs" />
<Compile Include="Views\BottomNavigationFragmentBase.cs" />
<Compile Include="Navigation\StartActivityAttribute.cs" />
<Compile Include="Navigation\IViewLocator.cs" />
Expand All @@ -102,8 +103,8 @@
<Compile Include="Internal\ViewModelStore.cs" />
<Compile Include="Internal\BackStack.cs" />
<Compile Include="Internal\ViewModelCache.cs" />
<Compile Include="Internal\ViewModelStoreFragment.cs" />
<Compile Include="Internal\IViewModelStore.cs" />
<Compile Include="Internal\ViewModelStorageFragment.cs" />
<Compile Include="Internal\IInstanceStorage.cs" />
<Compile Include="Views\ToolbarFragmentBase.cs" />
<Compile Include="Navigation\BackPressedCallback.cs" />
<Compile Include="Dialogs\IDialogFragment.cs" />
Expand Down
Loading

0 comments on commit 7c0e75a

Please sign in to comment.