Adds some VM tests

New tooltip in Textbox with button control
New welcome page in Settings (shown when noting is selected)
Settings are now grouped
This commit is contained in:
BONNEVILLE Geoffroy
2017-11-27 15:26:36 +01:00
parent 42ac04b02c
commit fcbda1e33d
23 changed files with 214 additions and 67 deletions

View File

@@ -1,6 +1,5 @@
using System;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.UI.Xaml.Controls;
using ModernKeePass.Exceptions;
using ModernKeePass.Interfaces;

View File

@@ -31,6 +31,19 @@ namespace ModernKeePass.Common
};
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
public static void ShowGenericToast(string title, string text)
{
var notificationXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var toastElements = notificationXml.GetElementsByTagName("text");
toastElements[0].AppendChild(notificationXml.CreateTextNode(title));
toastElements[1].AppendChild(notificationXml.CreateTextNode(text));
var toast = new ToastNotification(notificationXml)
{
ExpirationTime = DateTime.Now.AddSeconds(5)
};
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}

View File

@@ -71,7 +71,11 @@ namespace ModernKeePass.Controls
{
ValidationChecking?.Invoke(this, new EventArgs());
if (UpdateKey) Model.UpdateKey();
if (UpdateKey)
{
Model.UpdateKey();
ValidationChecked?.Invoke(this, new PasswordEventArgs(Model.RootGroup));
}
else
{
var oldLabel = ButtonLabel;

View File

@@ -6,18 +6,6 @@ namespace ModernKeePass.Controls
{
public class TextBoxWithButton : TextBox
{
/*public Symbol ButtonSymbol
{
get { return (Symbol)GetValue(ButtonSymbolProperty); }
set { SetValue(ButtonSymbolProperty, value); }
}
public static readonly DependencyProperty ButtonSymbolProperty =
DependencyProperty.Register(
"ButtonSymbol",
typeof(Symbol),
typeof(TextBoxWithButton),
new PropertyMetadata(Symbol.Delete, (o, args) => { }));*/
public string ButtonSymbol
{
get { return (string)GetValue(ButtonSymbolProperty); }
@@ -31,6 +19,18 @@ namespace ModernKeePass.Controls
new PropertyMetadata("", (o, args) => { }));
public event EventHandler<RoutedEventArgs> ButtonClick;
public string ButtonTooltip
{
get { return (string)GetValue(ButtonTooltipProperty); }
set { SetValue(ButtonTooltipProperty, value); }
}
public static readonly DependencyProperty ButtonTooltipProperty =
DependencyProperty.Register(
"ButtonTooltip",
typeof(string),
typeof(TextBoxWithButton),
new PropertyMetadata(string.Empty, (o, args) => { }));
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();

View File

@@ -136,6 +136,9 @@
<Compile Include="Pages\SettingsPageFrames\SettingsSecurityPage.xaml.cs">
<DependentUpon>SettingsSecurityPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\SettingsPageFrames\SettingsWelcomePage.xaml.cs">
<DependentUpon>SettingsWelcomePage.xaml</DependentUpon>
</Compile>
<Compile Include="TemplateSelectors\FirstItemDataTemplateSelector.cs" />
<Compile Include="Controls\ListViewWithDisable.cs" />
<Compile Include="Controls\CompositeKeyUserControl.xaml.cs">
@@ -268,6 +271,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\SettingsPageFrames\SettingsWelcomePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Styles\HamburgerButtonStyle.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@@ -69,17 +69,17 @@ namespace ModernKeePass.Pages.BasePages
{
// When this is a new page, select the first item automatically unless logical page
// navigation is being used (see the logical page navigation #region below.)
if (!UsingLogicalPageNavigation() && ListViewSource.View != null)
if (!UsingLogicalPageNavigation())
{
ListViewSource.View.MoveCurrentToFirst();
ListViewSource.View?.MoveCurrentToFirst();
}
}
else
{
// Restore the previously saved state associated with this page
if (e.PageState.ContainsKey("SelectedItem") && ListViewSource.View != null)
if (e.PageState.ContainsKey("SelectedItem"))
{
ListViewSource.View.MoveCurrentTo(e.PageState["SelectedItem"]);
ListViewSource.View?.MoveCurrentTo(e.PageState["SelectedItem"]);
}
}
}

View File

@@ -428,7 +428,7 @@
</Style>
</StackPanel.Resources>
<TextBlock TextWrapping="Wrap" Text="User name or login" FontSize="18"/>
<local:TextBoxWithButton HorizontalAlignment="Left" Text="{Binding UserName, Mode=TwoWay}" Width="350" Height="32" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="&#xE16F;">
<local:TextBoxWithButton HorizontalAlignment="Left" Text="{Binding UserName, Mode=TwoWay}" Width="350" Height="32" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="&#xE16F;" ButtonTooltip="Copy">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ButtonClick">
<actions:ClipboardAction Text="{Binding UserName}" />
@@ -437,7 +437,7 @@
</local:TextBoxWithButton>
<TextBlock TextWrapping="Wrap" Text="Password" FontSize="18"/>
<PasswordBox HorizontalAlignment="Left" Password="{Binding Password, Mode=TwoWay}" Width="350" Height="32" IsPasswordRevealButtonEnabled="True" Visibility="{Binding IsRevealPassword, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Style="{StaticResource PasswordBoxWithButtonStyle}" />
<local:TextBoxWithButton HorizontalAlignment="Left" Text="{Binding Password, Mode=TwoWay}" Width="350" Height="32" Visibility="{Binding IsRevealPassword, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="&#xE16F;">
<local:TextBoxWithButton HorizontalAlignment="Left" Text="{Binding Password, Mode=TwoWay}" Width="350" Height="32" Visibility="{Binding IsRevealPassword, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource TextBoxWithButtonStyle}" ButtonSymbol="&#xE16F;" ButtonTooltip="Copy">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ButtonClick">
<actions:ClipboardAction Text="{Binding Password}" />
@@ -447,7 +447,7 @@
<ProgressBar Value="{Binding PasswordComplexityIndicator, ConverterParameter=0\,128, Converter={StaticResource ProgressBarLegalValuesConverter}}" Maximum="128" Width="350" HorizontalAlignment="Left" Foreground="{Binding PasswordComplexityIndicator, ConverterParameter=128, Converter={StaticResource DoubleToForegroungBrushComplexityConverter}}" />
<CheckBox HorizontalAlignment="Left" Margin="-3,0,0,0" Content="Show password" IsChecked="{Binding IsRevealPassword, Mode=TwoWay}" IsEnabled="{Binding IsRevealPasswordEnabled}" />
<TextBlock TextWrapping="Wrap" Text="URL" FontSize="18"/>
<local:TextBoxWithButton x:Name="UrlTextBox" HorizontalAlignment="Left" Text="{Binding Url, Mode=TwoWay}" Height="32" Width="350" MaxLength="256" Style="{StaticResource TextBoxWithButtonStyle}" ButtonClick="UrlButton_Click" ButtonSymbol="&#xE111;" />
<local:TextBoxWithButton x:Name="UrlTextBox" HorizontalAlignment="Left" Text="{Binding Url, Mode=TwoWay}" Height="32" Width="350" MaxLength="256" Style="{StaticResource TextBoxWithButtonStyle}" ButtonClick="UrlButton_Click" ButtonSymbol="&#xE111;" ButtonTooltip="Navigate to URL" />
<TextBlock TextWrapping="Wrap" Text="Notes" FontSize="18"/>
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Notes, Mode=TwoWay}" Width="350" Height="200" AcceptsReturn="True" IsSpellCheckEnabled="True" />
<CheckBox FontSize="18" IsChecked="{Binding HasExpirationDate, Mode=TwoWay}" Content="Expiration date"/>
@@ -467,14 +467,12 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
x:Name="BackButton"
Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}"
Height="50"
Width="50"
VerticalAlignment="Center"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"

View File

@@ -270,7 +270,6 @@
Command="{Binding NavigationHelper.GoBackCommand, ElementName=PageRoot}"
Height="50"
Width="50"
VerticalAlignment="Center"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"

View File

@@ -32,7 +32,6 @@ namespace ModernKeePass.Pages
{
base.OnNavigatedTo(e);
DataContext = new MainVm(Frame, MenuFrame);
//if (Model.SelectedItem == null) MenuFrame.Navigate(typeof(WelcomePage));
}
}
}

View File

@@ -10,11 +10,10 @@
x:Class="ModernKeePass.Pages.SettingsPage"
mc:Ignorable="d">
<Page.Resources>
<CollectionViewSource x:Name="MenuItemsSource" Source="{Binding MenuItems}" >
</CollectionViewSource>
<CollectionViewSource x:Name="MenuItemsSource" Source="{Binding MenuItems}" IsSourceGrouped="True" />
</Page.Resources>
<Page.DataContext>
<viewModels:SettingsVM />
<viewModels:SettingsVm />
</Page.DataContext>
<Page.Background>
@@ -74,9 +73,12 @@
<GroupStyle HidesIfEmpty="True">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Background="DarkGray" Margin="20,0,0,0">
<Border Height="1" Width="300" HorizontalAlignment="Stretch"/>
</Grid>
<StackPanel Margin="20,0,0,0">
<TextBlock Text="{Binding Key}" />
<Grid Background="DarkGray">
<Border Height="1" Width="300" HorizontalAlignment="Stretch"/>
</Grid>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>

View File

@@ -1,4 +1,5 @@
using Windows.UI.Xaml.Controls;
using ModernKeePass.Pages.SettingsPageFrames;
using ModernKeePass.ViewModels;
// The Split Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234234
@@ -11,7 +12,7 @@ namespace ModernKeePass.Pages
/// </summary>
public sealed partial class SettingsPage
{
public new SettingsVM Model => (SettingsVM)DataContext;
public new SettingsVm Model => (SettingsVm)DataContext;
public SettingsPage()
{
@@ -24,8 +25,7 @@ namespace ModernKeePass.Pages
{
ListView_SelectionChanged(sender, e);
var selectedItem = Model.SelectedItem as ListMenuItemVm;
if (selectedItem == null) return;
MenuFrame?.Navigate(selectedItem.PageType);
MenuFrame?.Navigate(selectedItem == null ? typeof(SettingsWelcomePage) : selectedItem.PageType);
}
}
}

View File

@@ -8,7 +8,12 @@
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Change database security options" />
<local:CompositeKeyUserControl UpdateKey="True" ButtonLabel="Update master key" />
<TextBlock FontSize="14" Text="Change database security options" Margin="5,0,0,0" />
<TextBlock TextWrapping="WrapWholeWords" Margin="5,0,0,0">
<Run Text="Here, you may change your database password, key file, or both. Just click on on" />
<Run Text="Update master key" FontWeight="SemiBold" />
<Run Text="when you're done. Please make sure to remember the password you choose here!" />
</TextBlock>
<local:CompositeKeyUserControl Margin="0,20,0,0" UpdateKey="True" ButtonLabel="Update master key" ValidationChecked="CompositeKeyUserControl_OnValidationChecked" />
</StackPanel>
</Page>

View File

@@ -1,5 +1,8 @@
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
using ModernKeePass.Common;
using ModernKeePass.Events;
namespace ModernKeePass.Pages
{
/// <summary>
@@ -11,5 +14,10 @@ namespace ModernKeePass.Pages
{
InitializeComponent();
}
private void CompositeKeyUserControl_OnValidationChecked(object sender, PasswordEventArgs e)
{
ToastNotificationHelper.ShowGenericToast("Composite key", "Database successfully updated.");
}
}
}

View File

@@ -0,0 +1,14 @@
<Page
x:Class="ModernKeePass.Pages.SettingsPageFrames.SettingsWelcomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock FontSize="24" VerticalAlignment="Center" Margin="10,-70,0,0" Text="Settings" />
<TextBlock VerticalAlignment="Center" FontSize="14" Margin="5,0,0,0" Text="Here, you may change the application or the database settings." />
<TextBlock VerticalAlignment="Center" FontSize="14" Margin="5,0,0,0" Text="Select a setting pane on the left to access the options." />
</StackPanel>
</Page>

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ModernKeePass.Pages.SettingsPageFrames
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SettingsWelcomePage : Page
{
public SettingsWelcomePage()
{
this.InitializeComponent();
}
}
}

View File

@@ -222,7 +222,11 @@
Visibility="Collapsed"
FontSize="{TemplateBinding FontSize}"
Content="{TemplateBinding ButtonSymbol}"
VerticalAlignment="Stretch"/>
VerticalAlignment="Stretch">
<ToolTipService.ToolTip>
<ToolTip Content="{TemplateBinding ButtonTooltip}" />
</ToolTipService.ToolTip>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>

View File

@@ -1,7 +1,6 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -117,6 +116,7 @@ namespace ModernKeePass.ViewModels
var pwEntry = new PwEntry(true, true);
_pwGroup.AddEntry(pwEntry, true);
var newEntry = new EntryVm(pwEntry, this) {IsEditMode = true};
newEntry.GeneratePassword();
Entries.Add(newEntry);
return newEntry;
}

View File

@@ -11,7 +11,7 @@ namespace ModernKeePass.ViewModels
public string Title { get; set; }
public int Group { get; set; } = 0;
public string Group { get; set; } = "_";
public Type PageType { get; set; }
public Symbol SymbolIcon { get; set; }
public bool IsEnabled { get; set; } = true;

View File

@@ -12,12 +12,12 @@ namespace ModernKeePass.ViewModels
{
public class MainVm : NotifyPropertyChangedBase, IHasSelectableObject
{
private IOrderedEnumerable<IGrouping<int, MainMenuItemVm>> _mainMenuItems;
private IOrderedEnumerable<IGrouping<string, MainMenuItemVm>> _mainMenuItems;
private MainMenuItemVm _selectedItem;
public string Name { get; } = Package.Current.DisplayName;
public IOrderedEnumerable<IGrouping<int, MainMenuItemVm>> MainMenuItems
public IOrderedEnumerable<IGrouping<string, MainMenuItemVm>> MainMenuItems
{
get { return _mainMenuItems; }
set { SetProperty(ref _mainMenuItems, value); }
@@ -86,7 +86,7 @@ namespace ModernKeePass.ViewModels
PageType = typeof(GroupDetailPage),
Destination = referenceFrame,
Parameter = database.RootGroup,
Group = 1,
Group = "Databases",
SymbolIcon = Symbol.ProtectedDocument
});

View File

@@ -1,5 +1,4 @@
using System.ComponentModel;
using Windows.Storage;
using Windows.Storage;
using Windows.Storage.AccessCache;
using Windows.UI.Xaml;
using ModernKeePass.Common;
@@ -7,7 +6,7 @@ using ModernKeePass.Interfaces;
namespace ModernKeePass.ViewModels
{
public class OpenVm: INotifyPropertyChanged
public class OpenVm: NotifyPropertyChangedBase
{
public bool ShowPasswordBox => _database?.Status == (int) DatabaseHelper.DatabaseStatus.Opening;
@@ -23,19 +22,12 @@ namespace ModernKeePass.ViewModels
if (database == null || database.Status != (int) DatabaseHelper.DatabaseStatus.Opening) return;
OpenFile(database.DatabaseFile);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void OpenFile(StorageFile file)
{
_database.DatabaseFile = file;
NotifyPropertyChanged("Name");
NotifyPropertyChanged("ShowPasswordBox");
OnPropertyChanged("Name");
OnPropertyChanged("ShowPasswordBox");
AddToRecentList(file);
}

View File

@@ -7,11 +7,19 @@ using ModernKeePass.Pages;
namespace ModernKeePass.ViewModels
{
public class SettingsVM : NotifyPropertyChangedBase, IHasSelectableObject
public class SettingsVm : NotifyPropertyChangedBase, IHasSelectableObject
{
private ListMenuItemVm _selectedItem;
public ObservableCollection<ListMenuItemVm> MenuItems { get; set; }
//public ObservableCollection<ListMenuItemVm> MenuItems { get; set; }
private IOrderedEnumerable<IGrouping<string, ListMenuItemVm>> _menuItems;
public IOrderedEnumerable<IGrouping<string, ListMenuItemVm>> MenuItems
{
get { return _menuItems; }
set { SetProperty(ref _menuItems, value); }
}
public ISelectableModel SelectedItem
{
get { return _selectedItem; }
@@ -32,15 +40,17 @@ namespace ModernKeePass.ViewModels
}
}
public SettingsVM()
public SettingsVm()
{
MenuItems = new ObservableCollection<ListMenuItemVm>
var menuItems = new ObservableCollection<ListMenuItemVm>
{
new ListMenuItemVm { Title = "Database", SymbolIcon = Symbol.Setting, PageType = typeof(SettingsDatabasePage), IsSelected = true },
new ListMenuItemVm { Title = "Security", SymbolIcon = Symbol.Permissions, PageType = typeof(SettingsSecurityPage) },
new ListMenuItemVm { Title = "General", Group = "Database", SymbolIcon = Symbol.Setting, PageType = typeof(SettingsDatabasePage), IsSelected = true },
new ListMenuItemVm { Title = "Security", Group = "Database", SymbolIcon = Symbol.Permissions, PageType = typeof(SettingsSecurityPage) },
//new ListMenuItemVm { Title = "General", SymbolIcon = Symbol.Edit, PageType = typeof(SettingsGeneralPage) }
};
SelectedItem = MenuItems.FirstOrDefault(m => m.IsSelected);
SelectedItem = menuItems.FirstOrDefault(m => m.IsSelected);
MenuItems = from item in menuItems group item by item.Group into grp orderby grp.Key select grp;
}
}
}

View File

@@ -35,7 +35,7 @@ namespace ModernKeePassApp.Test.Mock
public void Close()
{
throw new NotImplementedException();
Status = 0;
}
public void CreateRecycleBin()
@@ -45,7 +45,7 @@ namespace ModernKeePassApp.Test.Mock
public void Open(CompositeKey key, bool createNew)
{
throw new NotImplementedException();
Status = 2;
}
public void Save()

View File

@@ -1,5 +1,7 @@
using System.Linq;
using System;
using System.Linq;
using Windows.ApplicationModel;
using Windows.Storage.AccessCache;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using ModernKeePass.ViewModels;
using ModernKeePassApp.Test.Mock;
@@ -28,13 +30,74 @@ namespace ModernKeePassApp.Test
database.Status = 1;
mainVm = new MainVm(null, null, database);
Assert.IsNotNull(mainVm.SelectedItem);
Assert.AreEqual("Open", ((MainMenuItemVm)mainVm.SelectedItem).Title);
Assert.AreEqual("Open", ((MainMenuItemVm) mainVm.SelectedItem).Title);
database.Status = 2;
mainVm = new MainVm(null, null, database);
Assert.IsNotNull(mainVm.SelectedItem);
Assert.AreEqual(2, mainVm.MainMenuItems.Count());
Assert.AreEqual("Save", ((MainMenuItemVm)mainVm.SelectedItem).Title);
Assert.AreEqual("Save", ((MainMenuItemVm) mainVm.SelectedItem).Title);
}
[TestMethod]
public void TestCompositeKeyVm()
{
var database = new DatabaseHelperMock();
var compositeKeyVm = new CompositeKeyVm(database);
Assert.IsTrue(compositeKeyVm.OpenDatabase(false).GetAwaiter().GetResult());
compositeKeyVm.StatusType = 1;
compositeKeyVm.Password = "test";
Assert.AreEqual(0, compositeKeyVm.StatusType);
Assert.AreEqual(15.0, compositeKeyVm.PasswordComplexityIndicator);
}
[TestMethod]
public void TestOpenVm()
{
var database = new DatabaseHelperMock
{
Status = 1,
DatabaseFile = Package.Current.InstalledLocation.GetFileAsync(@"Databases\TestDatabase.kdbx")
.GetAwaiter().GetResult()
};
var openVm = new OpenVm(database);
Assert.IsTrue(openVm.ShowPasswordBox);
Assert.AreEqual("MockDatabase", openVm.Name);
}
/*[TestMethod]
public void TestNewVm()
{
}*/
[TestMethod]
public void TestRecentVm()
{
var mru = StorageApplicationPermissions.MostRecentlyUsedList;
mru.Add(Package.Current.InstalledLocation.GetFileAsync(@"Databases\TestDatabase.kdbx")
.GetAwaiter().GetResult(), "MockDatabase");
var recentVm = new RecentVm();
Assert.IsTrue(recentVm.RecentItems.Count == 1);
recentVm.SelectedItem = recentVm.RecentItems.FirstOrDefault();
Assert.IsTrue(recentVm.SelectedItem.IsSelected);
mru.Clear();
}
/*[TestMethod]
public void TestSaveVm()
{
}*/
[TestMethod]
public void TestSettingsVm()
{
var settingsVm = new SettingsVm();
Assert.AreEqual(1, settingsVm.MenuItems.Count());
var firstGroup = settingsVm.MenuItems.FirstOrDefault();
Assert.AreEqual(2, firstGroup.Count());
Assert.IsNotNull(settingsVm.SelectedItem);
var selectedItem = (ListMenuItemVm) settingsVm.SelectedItem;
Assert.AreEqual("General", selectedItem.Title);
}
}
}