diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DialogFragmentBase.cs b/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DialogFragmentBase.cs index cb0e6b74b..41df16f14 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DialogFragmentBase.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DialogFragmentBase.cs @@ -17,7 +17,7 @@ namespace Softeq.XToolkit.WhiteLabel.Droid.Dialogs { public abstract class DialogFragmentBase : DialogFragment, IBindable, IDialogFragment - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { private readonly Lazy _contextProviderLazy = Dependencies.Container.Resolve>(); diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DroidFragmentDialogService.cs b/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DroidFragmentDialogService.cs index 6775a7165..47fb89ae9 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DroidFragmentDialogService.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Dialogs/DroidFragmentDialogService.cs @@ -56,21 +56,21 @@ public Task ShowDialogAsync(ActionSheetDialogConfig config) public Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { return ShowForViewModelAsync(parameters).WaitUntilDismissed(); } public Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { return ShowForViewModelAsync(parameters).WaitUntilDismissed(); } public async Task ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var viewModel = CreateViewModel(parameters); @@ -81,7 +81,7 @@ public async Task ShowForViewModelAsync( public async Task> ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var viewModel = CreateViewModel(parameters); @@ -109,7 +109,7 @@ private TViewModel CreateViewModel( } protected virtual Task ShowDialogAsync(TViewModel viewModel) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var dialogFragment = (DialogFragmentBase) _viewLocator.GetView(viewModel, ViewType.DialogFragment); dialogFragment.Show(); diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Internal/IInstanceStorage.cs b/Softeq.XToolkit.WhiteLabel.Droid/Internal/IInstanceStorage.cs new file mode 100644 index 000000000..8f685871c --- /dev/null +++ b/Softeq.XToolkit.WhiteLabel.Droid/Internal/IInstanceStorage.cs @@ -0,0 +1,46 @@ +// Developed by Softeq Development Corporation +// http://www.softeq.com + +using System.Collections.Generic; + +namespace Softeq.XToolkit.WhiteLabel.Droid.Internal +{ + /// + /// Defines the contract for a storage that stores instances of different classes. + /// + internal interface IInstanceStorage + { + /// + /// Returns an existing instance from the store. + /// + /// The type of the instance to get. + /// The instance unique key. + /// Stored instance. + T Get(string key) where T : class; + + /// + /// Adds a instance to the store by . + /// + /// The type of the instance to add. + /// The instance unique key. + /// The instance to add. + void Add(string key, T viewModel) where T : class; + + /// + /// Removes an existing instance from the store by . + /// + /// The instance unique key. + void Remove(string key); + + /// + /// Removes an existing instances from the store by . + /// + /// The collection of instance unique keys. + void Remove(IEnumerable keys); + + /// + /// Clears store. + /// + void Clear(); + } +} diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Internal/IViewModelStore.cs b/Softeq.XToolkit.WhiteLabel.Droid/Internal/IViewModelStore.cs deleted file mode 100644 index 684e026df..000000000 --- a/Softeq.XToolkit.WhiteLabel.Droid/Internal/IViewModelStore.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Developed by Softeq Development Corporation -// http://www.softeq.com - -using System.Collections.Generic; -using Softeq.XToolkit.WhiteLabel.Mvvm; - -namespace Softeq.XToolkit.WhiteLabel.Droid.Internal -{ - /// - /// Defines the contract for a store that keeps view models. - /// - internal interface IViewModelStore - { - /// - /// Returns an existing instance from the store. - /// - /// The type of the view model to get. - /// The view model unique key. - /// The view model instance. - TViewModel Get(string key) where TViewModel : class, IViewModelBase; - - /// - /// Adds a instance to the store by . - /// - /// The type of the view model to add. - /// The view model unique key. - /// The view model to add. - void Add(string key, IViewModelBase viewModel); - - /// - /// Removes an existing view model instance from the store by . - /// - /// The view model unique key. - void Remove(string key); - - /// - /// Removes an existing view model instances from the store by . - /// - /// The collection of view model unique keys. - void Remove(IReadOnlyList keys); - - /// - /// Clears store. - /// - void Clear(); - } -} diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelCache.cs b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelCache.cs index 866160ef9..4714b5643 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelCache.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelCache.cs @@ -2,25 +2,18 @@ // 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> _cache; - - static ViewModelCache() - { - _cache = new Dictionary>(); - } + private static readonly Dictionary> _cache = + new Dictionary>(); internal static TViewModel? Get(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); } @@ -28,11 +21,11 @@ static ViewModelCache() 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(); + _cache[containerId] = new Dictionary(); } _cache[containerId][key] = viewModel; @@ -40,18 +33,16 @@ internal static void Add(string containerId, string key, IViewModelBase viewMode 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 keys) + internal static void Remove(string containerId, IEnumerable keys) { - if (_cache.ContainsKey(containerId)) + if (_cache.TryGetValue(containerId, out var container)) { - var container = _cache[containerId]; - foreach (var key in keys) { container.Remove(key); diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStoreFragment.cs b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStorageFragment.cs similarity index 86% rename from Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStoreFragment.cs rename to Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStorageFragment.cs index c82e6a1d8..bff912283 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStoreFragment.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStorageFragment.cs @@ -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"; @@ -19,7 +18,7 @@ internal sealed class ViewModelStoreFragment : Fragment, IViewModelStore /// public TViewModel Get(string fragmentName) - where TViewModel : class, IViewModelBase + where TViewModel : class { var viewModel = ViewModelCache.Get(ViewModelStoreId, fragmentName); @@ -34,7 +33,8 @@ public TViewModel Get(string fragmentName) } /// - public void Add(string fragmentName, IViewModelBase viewModel) + public void Add(string fragmentName, TViewModel viewModel) + where TViewModel : class { ViewModelCache.Add(ViewModelStoreId, fragmentName, viewModel); } @@ -46,7 +46,7 @@ public void Remove(string fragmentName) } /// - public void Remove(IReadOnlyList fragmentNames) + public void Remove(IEnumerable fragmentNames) { ViewModelCache.Remove(ViewModelStoreId, fragmentNames); } @@ -58,7 +58,7 @@ public void Clear() } /// - public override void OnCreate(Bundle savedInstanceState) + public override void OnCreate(Bundle? savedInstanceState) { base.OnCreate(savedInstanceState); diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStore.cs b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStore.cs index d96934243..ee1e4aea8 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStore.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Internal/ViewModelStore.cs @@ -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() diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Navigation/DroidFrameNavigationService.cs b/Softeq.XToolkit.WhiteLabel.Droid/Navigation/DroidFrameNavigationService.cs index 8f0dcaa0f..041c42bd5 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Navigation/DroidFrameNavigationService.cs +++ b/Softeq.XToolkit.WhiteLabel.Droid/Navigation/DroidFrameNavigationService.cs @@ -32,7 +32,7 @@ public DroidFrameNavigationService( protected FrameNavigationConfig? Config { get; private set; } - private IViewModelStore CurrentStore + private IInstanceStorage CurrentStore { get { diff --git a/Softeq.XToolkit.WhiteLabel.Droid/Softeq.XToolkit.WhiteLabel.Droid.csproj b/Softeq.XToolkit.WhiteLabel.Droid/Softeq.XToolkit.WhiteLabel.Droid.csproj index 7c9557910..a67ae2392 100644 --- a/Softeq.XToolkit.WhiteLabel.Droid/Softeq.XToolkit.WhiteLabel.Droid.csproj +++ b/Softeq.XToolkit.WhiteLabel.Droid/Softeq.XToolkit.WhiteLabel.Droid.csproj @@ -84,6 +84,7 @@ + @@ -102,8 +103,8 @@ - - + + diff --git a/Softeq.XToolkit.WhiteLabel.Droid/ViewComponents/ViewModelComponent.cs b/Softeq.XToolkit.WhiteLabel.Droid/ViewComponents/ViewModelComponent.cs new file mode 100644 index 000000000..5870a2308 --- /dev/null +++ b/Softeq.XToolkit.WhiteLabel.Droid/ViewComponents/ViewModelComponent.cs @@ -0,0 +1,100 @@ +// Developed by Softeq Development Corporation +// http://www.softeq.com + +using System; +using AndroidX.Fragment.App; + +namespace Softeq.XToolkit.WhiteLabel.Droid.ViewComponents +{ + /// + /// Component, which encapsulates logic of storing/restoring ViewModel instance within FragmentManager + /// + /// + /// Type of the ViewModel instance + /// + public sealed class ViewModelComponent where TViewModel : class + { + private TViewModel? _viewModel; + + /// + /// Initializes a new instance of the class. + /// + /// + /// Key identifier, which will be used for storing/restoring TViewModel instance. + /// + public ViewModelComponent(string viewModelKey) + { + ViewModelKey = viewModelKey; + } + + /// + /// Gets current instance of TViewModel, or throws exceptions if instance is not assigned. + /// + /// + /// ViewModel instance is not assigned either because it wasn't initialized using + /// method, or wasn't restored + /// properly using method. + /// + public TViewModel ViewModel => _viewModel ?? throw new InvalidOperationException("ViewModel instance is not assigned"); + + /// + /// Gets key identifier witch used for storing/restoring TViewModel instance. + /// + public string ViewModelKey { get; } + + /// + /// Initializes with an instance of ViewModel. + /// + /// + /// ViewModel instance to store. + /// + /// + /// ViewModelComponent is already initialized with an instance of ViewModel. + /// + public void Initialize(TViewModel viewModel) + { + if (_viewModel != null) + { + throw new InvalidOperationException("ViewModelComponent should be initialized only once"); + } + + _viewModel = viewModel; + } + + /// + /// Saves current ViewModel instance within storage, associated with provided FragmentManager. + /// + /// + /// Fragment manager where ViewModel should be stored. + /// + public void SaveViewModel(FragmentManager fragmentManager) + { + var viewModelStore = Internal.ViewModelStore.Of(fragmentManager); + viewModelStore.Add(ViewModelKey, ViewModel); + } + + /// + /// Restores ViewModel instance from storage, associated with provided FragmentManager. + /// + /// + /// Fragment manager where ViewModel has been stored. + /// + public void RestoreViewModel(FragmentManager fragmentManager) + { + var viewModelStore = Internal.ViewModelStore.Of(fragmentManager); + _viewModel = viewModelStore.Get(ViewModelKey); + } + + /// + /// Removes ViewModel instance from storage, associated with provided FragmentManager. + /// + /// + /// Fragment manager from where ViewModel should be removed. + /// + public void ClearViewModel(FragmentManager fragmentManager) + { + var viewModelStore = Internal.ViewModelStore.Of(fragmentManager); + viewModelStore.Remove(ViewModelKey); + } + } +} diff --git a/Softeq.XToolkit.WhiteLabel.Forms/Navigation/FormsDialogsService.cs b/Softeq.XToolkit.WhiteLabel.Forms/Navigation/FormsDialogsService.cs index d4998033e..b6e5afdad 100644 --- a/Softeq.XToolkit.WhiteLabel.Forms/Navigation/FormsDialogsService.cs +++ b/Softeq.XToolkit.WhiteLabel.Forms/Navigation/FormsDialogsService.cs @@ -73,21 +73,21 @@ public Task ShowDialogAsync(ActionSheetDialogConfig config) } public Task ShowForViewModel(IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { throw new NotImplementedException(); } public Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { throw new NotImplementedException(); } public async Task ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var result = await ShowForViewModelAsync(parameters).ConfigureAwait(false); return result; @@ -95,7 +95,7 @@ public async Task ShowForViewModelAsync( public async Task> ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var result = await ShowForViewModelImplAsync(parameters).ConfigureAwait(false); return result; @@ -103,7 +103,7 @@ public async Task> ShowForViewModelAsync> ShowForViewModelImplAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { var viewModel = _container.Resolve(); viewModel.ApplyParameters(parameters); diff --git a/Softeq.XToolkit.WhiteLabel.iOS/Services/StoryboardDialogsService.cs b/Softeq.XToolkit.WhiteLabel.iOS/Services/StoryboardDialogsService.cs index 4df6d0684..f400a9fe0 100644 --- a/Softeq.XToolkit.WhiteLabel.iOS/Services/StoryboardDialogsService.cs +++ b/Softeq.XToolkit.WhiteLabel.iOS/Services/StoryboardDialogsService.cs @@ -67,21 +67,21 @@ public virtual Task ShowDialogAsync(ActionSheetDialogConfig config) public Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { return ShowForViewModelAsync(parameters).WaitUntilDismissed(); } public Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { return ShowForViewModelAsync(parameters).WaitUntilDismissed(); } public async Task ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { try { @@ -101,7 +101,7 @@ public async Task ShowForViewModelAsync( public async Task> ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { try { diff --git a/Softeq.XToolkit.WhiteLabel/Navigation/DialogsServiceExtensions.cs b/Softeq.XToolkit.WhiteLabel/Navigation/DialogsServiceExtensions.cs index bbe7278cc..7af4319f0 100644 --- a/Softeq.XToolkit.WhiteLabel/Navigation/DialogsServiceExtensions.cs +++ b/Softeq.XToolkit.WhiteLabel/Navigation/DialogsServiceExtensions.cs @@ -22,7 +22,7 @@ public static class DialogsServiceExtensions /// cannot be . /// public static DialogFluentNavigator For(this IDialogsService dialogsService) - where T : IDialogViewModel + where T : class, IDialogViewModel { if (dialogsService == null) { diff --git a/Softeq.XToolkit.WhiteLabel/Navigation/FluentNavigators/DialogFluentNavigator.cs b/Softeq.XToolkit.WhiteLabel/Navigation/FluentNavigators/DialogFluentNavigator.cs index 69c09d48a..081ca03eb 100644 --- a/Softeq.XToolkit.WhiteLabel/Navigation/FluentNavigators/DialogFluentNavigator.cs +++ b/Softeq.XToolkit.WhiteLabel/Navigation/FluentNavigators/DialogFluentNavigator.cs @@ -13,7 +13,7 @@ namespace Softeq.XToolkit.WhiteLabel.Navigation.FluentNavigators /// /// Type of ViewModel to perform navigation to. public class DialogFluentNavigator : FluentNavigatorBase - where TViewModel : IDialogViewModel + where TViewModel : class, IDialogViewModel { private readonly IDialogsService _dialogsService; diff --git a/Softeq.XToolkit.WhiteLabel/Navigation/IDialogsService.cs b/Softeq.XToolkit.WhiteLabel/Navigation/IDialogsService.cs index 0f91de378..53bf676b2 100644 --- a/Softeq.XToolkit.WhiteLabel/Navigation/IDialogsService.cs +++ b/Softeq.XToolkit.WhiteLabel/Navigation/IDialogsService.cs @@ -28,19 +28,19 @@ Task ShowDialogAsync( [Obsolete("Please use ShowForViewModelAsync syntax instead")] Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel; + where TViewModel : class, IDialogViewModel; [Obsolete("Please use ShowForViewModelAsync syntax instead")] Task ShowForViewModel( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel; + where TViewModel : class, IDialogViewModel; Task ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel; + where TViewModel : class, IDialogViewModel; Task> ShowForViewModelAsync( IEnumerable? parameters = null) - where TViewModel : IDialogViewModel; + where TViewModel : class, IDialogViewModel; } }