<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A34EE0F0-649D-41C8-8489-B6F1CC6924EE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tango.Core</RootNamespace>
<AssemblyName>Tango.Core</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Build\Core\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Build\Core\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
<HintPath>..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.19.8.16603, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.19.8.16603, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="SimpleValidator, Version=0.6.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SimpleValidator.0.6.1.0\lib\net40\SimpleValidator.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity.Design" />
<Reference Include="System.Data.SQLite, Version=1.0.108.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.SQLite.Core.1.0.108.0\lib\net46\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite.EF6, Version=1.0.108.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.SQLite.EF6.1.0.108.0\lib\net46\System.Data.SQLite.EF6.dll</HintPath>
</Reference>
<Reference Include="System.Data.SQLite.Linq, Version=1.0.108.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.SQLite.Linq.1.0.108.0\lib\net46\System.Data.SQLite.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Windows" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\GlobalVersionInfo.cs">
<Link>GlobalVersionInfo.cs</Link>
</Compile>
<None Include="ActiveDirectoryAuthenticationProvider.cs" />
<Compile Include="Commands\RelayCommand.cs" />
<Compile Include="Components\DataBaseDescriptionsHelper.cs" />
<Compile Include="Components\FrameworkElementSerializer.cs" />
<Compile Include="Components\PidController.cs" />
<Compile Include="ConcurrentList.cs" />
<Compile Include="CoreSettings.cs" />
<Compile Include="Cryptography\BasicHashGenerator.cs" />
<Compile Include="Cryptography\ICryptographer.cs" />
<Compile Include="Cryptography\IDecryptor.cs" />
<Compile Include="Cryptography\IEncryptor.cs" />
<Compile Include="Cryptography\IHashGenerator.cs" />
<Compile using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Tango.PPC.Common.Notifications;
using Tango.Core;
using System.Collections.Concurrent;
using System.Windows.Media.Imaging;
using Tango.SharedUI.Helpers;
using System.Timers;
using Tango.Core.Commands;
using Tango.Touch.Controls;
using Tango.SharedUI;
using System.Reflection;
using Tango.Core.DI;
using System.ComponentModel;
using System.Windows.Data;
namespace Tango.PPC.UI.Notifications
{
/// <summary>
/// Represents the default PPC notification provider.
/// </summary>
/// <seealso cref="Tango.Core.ExtendedObject" />
/// <seealso cref="Tango.PPC.Common.Notifications.INotificationProvider" />
public class DefaultNotificationProvider : ExtendedObject, INotificationProvider
{
private ConcurrentQueue<PendingNotification<MessageBoxVM, bool>> _pendingMessageBoxes;
private ConcurrentQueue<PendingNotification<DialogAndView, DialogViewVM>> _pendingDialogs;
private List<AppButton> _appButtons;
private bool _notificationsVisible;
/// <summary>
/// Gets or sets a value indicating whether to allow notifications visibility.
/// </summary>
public bool NotificationsVisible
{
get { return _notificationsVisible; }
set { _notificationsVisible = value; RaisePropertyChangedAuto(); }
}
/// <summary>
/// Gets the collection of notification items.
/// </summary>
public ObservableCollection<NotificationItem> NotificationItems { get; private set; }
/// <summary>
/// Gets the notification items view.
/// </summary>
public ICollectionView NotificationItemsView { get; private set; }
/// <summary>
/// Gets the collection of taskbar items.
/// </summary>
public ObservableCollection<TaskBarItem> TaskBarItems { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="DefaultNotificationProvider"/> class.
/// </summary>
public DefaultNotificationProvider()
{
NotificationsVisible = true;
NotificationItems = new ObservableCollection<NotificationItem>();
TaskBarItems = new ObservableCollection<TaskBarItem>();
_pendingMessageBoxes = new ConcurrentQueue<PendingNotification<MessageBoxVM, bool>>();
_pendingDialogs = new ConcurrentQueue<PendingNotification<DialogAndView, DialogViewVM>>();
_appButtons = new List<AppButton>();
PopNotificationCommand = new RelayCommand<NotificationItem>((x) => PopNotification(x));
NotificationItems.EnableCrossThreadOperations();
NotificationItemsView = CollectionViewSource.GetDefaultView(NotificationItems);
NotificationItemsView.SortDescriptions.Add(new SortDescription(nameof(NotificationItem.Priority), ListSortDirection.Descending));
}
private MessageBoxVM _currentMessageBox;
/// <summary>
/// Gets the current message box if any.
/// </summary>
public MessageBoxVM CurrentMessageBox
{
get { return _currentMessageBox; }
private set
{
_currentMessageBox = value;
RaisePropertyChangedAuto();
RaisePropertyChanged(nameof(HasMessageBox));
}
}
/// <summary>
/// Gets a value indicating whether a message box is available.
/// </summary>
public bool HasMessageBox
{
get
{
return CurrentMessageBox != null;
}
}
private FrameworkElement _currentDialog;
/// <summary>
/// Gets the current dialog if any.
/// </summary>
public FrameworkElement CurrentDialog
{
get { return _currentDialog; }
private set
{
_currentDialog = value;
RaisePropertyChangedAuto();
RaisePropertyChanged(nameof(HasDialog));
}
}
private AppButton _currentAppButton;
/// <summary>
/// Gets the current app button.
/// </summary>
public AppButton CurrentAppButton
{
get { return _currentAppButton; }
private set { _currentAppButton = value; RaisePropertyChangedAuto(); }
}
/// <summary>
/// Gets a value indicating whether a dialog is available.
/// </summary>
public bool HasDialog
{
get
{
return CurrentDialog != null;
}
}
/// <summary>
/// Shows an error message box.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Task ShowError(string message)
{
return ShowMessageBox(new MessageBoxVM()
{
Message = message,
Icon = TouchIconKind.AlertCircleOutline,
Title = "Error",
Brush = Application.Current.Resources["TangoMessageBoxErrorBrush"] as Brush,
HeaderBrush = Application.Current.Resources["TangoMessageBoxHeaderErrorBrush"] as Brush,
});
}
/// <summary>
/// Shows an information message box.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Task ShowInfo(string message)
{
return ShowMessageBox(new MessageBoxVM()
{
Message = message,
Icon = TouchIconKind.AlertCircleOutline,
Title = "Information",
Brush = Application.Current.Resources["TangoMessageBoxInfoBrush"] as Brush,
HeaderBrush = Application.Current.Resources["TangoMessageBoxHeaderInfoBrush"] as Brush,
});
}
/// <summary>
/// Shows warning message box.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Task ShowWarning(string message)
{
return ShowMessageBox(new MessageBoxVM()
{
Message = message,
Icon = TouchIconKind.AlertCircleOutline,
Title = "Warning",
Brush = Application.Current.Resources["TangoMessageBoxWarningBrush"] as Brush,
HeaderBrush = Application.Current.Resources["TangoMessageBoxHeaderWarningBrush"] as Brush,
});
}
/// <summary>
/// Shows a question message box.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Task<bool> ShowQuestion(string message)
{
return ShowMessageBox(new MessageBoxVM()
{
Message = message,
Icon = TouchIconKind.QuestionCircleRegular,
Title = "Confirm",
HasCancel = true,
Brush = Application.Current.Resources["TangoMessageBoxQuestionBrush"] as Brush,
HeaderBrush = Application.Current.Resources["TangoMessageBoxHeaderQuestionBrush"] as Brush,
});
}
/// <summary>
/// Shows a success message box.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Task ShowSuccess(string message)
{
return ShowMessageBox(new MessageBoxVM()
{
Message = message,
Icon = TouchIconKind.Check,
Title = "Success",
Brush = Application.Current.Resources["TangoMessageBoxSuccessBrush"] as Brush,
HeaderBrush = Application.Current.Resources["TangoMessageBoxHeaderSuccessBrush"] as Brush,
});
}
/// <summary>
/// Shows the message box.
/// </summary>
/// <param name="vm">The view model.</param>
/// <returns></returns>
private Task<bool> ShowMessageBox(MessageBoxVM vm)
{
ReleaseGlobalBusyMessage();
LogManager.Log($"Displaying MessagBox '{vm.Message}'.");
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
vm.Accepted += () => { OnMessageBoxClosed(); source.SetResult(true); };
vm.Canceled += () => { OnMessageBoxClosed(); source.SetResult(false); };
if (CurrentMessageBox == null)
{
CurrentMessageBox = vm;
}
else
{
_pendingMessageBoxes.Enqueue(new PendingNotification<MessageBoxVM, bool>(vm, source));
}
return source.Task;
}
/// <summary>
/// Called when the message box has been closed.
/// </summary>
private void OnMessageBoxClosed()
{
LogManager.Log("MessageBox closed.");
CurrentMessageBox = null;
if (_pendingMessageBoxes.Count > 0)
{
PendingNotification<MessageBoxVM, bool> p = null;
if (_pendingMessageBoxes.TryDequeue(out p))
{
CurrentMessageBox = p.Item;
}
}
}
/// <summary>
/// Inserts the notification item to the bottom of the notifications collection.
/// </summary>
/// <param name="item">The item.</param>
/// <returns></returns>
public NotificationItem PushNotification(NotificationItem item)
{
LogManager.Log($"Pushing NotificationItem '{item.GetType().Name}'.");
item.RemoveAction = () => { PopNotification(item); };
NotificationItems.Insert(0, item);
RaisePropertyChanged(nameof(HasNotificationItems));
return item;
}
/// <summary>
/// Pushes the notification.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public NotificationItem PushNotification<T>() where T : NotificationItem
{
return PushNotification(Activator.CreateInstance<T>());
}
/// <summary>
/// Removed the specified notification item.
/// </summary>
/// <param name="item">The item.</param>
public void PopNotification(NotificationItem item)
{
LogManager.Log($"Popping out NotificationItem '{item.GetType().Name}'.");
NotificationItems.Remove(item);
RaisePropertyChanged(nameof(HasNotificationItems));
}
/// <summary>
/// Gets a value indicating whether this instance has notification items.
/// </summary>
public bool HasNotificationItems
{
get
{
return NotificationItems.Count > 0;
}
}
/// <summary>
/// Gets the pop notification command.
/// </summary>
public RelayCommand<NotificationItem> PopNotificationCommand { get; private set; }
/// <summary>
/// Displays the specified dialog in a modal design.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="datacontext">The data context.</param>
/// <param name="view">The view.</param>
/// <returns></returns>
public async Task<T> ShowDialog<T>(T datacontext, FrameworkElement view) where T : DialogViewVM
{
view.DataContext = datacontext;
TangoIOC.Default.Inject(datacontext);
view.Loaded += (_, __) =>
{
view.DataContext = datacontext;
datacontext.OnShow();
};
TaskCompletionSource<DialogViewVM> source = new TaskCompletionSource<DialogViewVM>();
datacontext.Accepted += () => { OnDialogClosed(); source.SetResult(datacontext); };
datacontext.Canceled += () => { OnDialogClosed(); source.SetResult(datacontext); };
if (CurrentDialog == null)
{
CurrentDialog = view;
}
else
{
_pendingDialogs.Enqueue(new PendingNotification<DialogAndView, DialogViewVM>(new DialogAndView(datacontext, view), source));
}
var result = await source.Task;
return result as T;
}
/// <summary>
/// Called when [dialog closed].
/// </summary>
private void OnDialogClosed()
{
CurrentDialog = null;
if (_pendingDialogs.Count > 0)
{
PendingNotification<DialogAndView, DialogViewVM> p = null;
if (_pendingDialogs.TryDequeue(out p))
{
CurrentDialog = p.Item.View;
}
}
}
/// <summary>
/// Displays the specified dialog in a modal design.
/// The notification provider will try to locate the view automatically using conventions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="datacontext">The data context.</param>
/// <returns></returns>
public Task<T> ShowDialog<T>(T datacontext) where T : DialogViewVM
{
var callingAssembly = datacontext.GetType().Assembly;
String viewName = datacontext.GetType().FullName.Replace("VM", "");
var viewType = callingAssembly.GetType(viewName);
if (viewType == null)
{
throw new NullReferenceException("View type for " + datacontext.GetType().Name + " could not be found!");
}
var view = Activator.CreateInstance(viewType) as FrameworkElement;
if (view == null)
{
throw new NullReferenceException("The view " + viewType.ToString() + " is not of type framework element.");
}
return ShowDialog<T>(datacontext, view);
}
/// <summary>
/// Displays the specified dialog in a modal design.
/// The data context instance will be automatically created.
/// The notification provider will try to locate the view automatically using conventions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public Task<T> ShowDialog<T>() where T : DialogViewVM
{
return ShowDialog<T>(Activator.CreateInstance<T>());
}
/// <summary>
/// Sets the global busy message.
/// </summary>
/// <param name="message">The message.</param>
public void SetGlobalBusyMessage(string message)
{
GlobalBusyMessage = message;
IsInGlobalBusyState = true;
RaisePropertyChanged(nameof(IsInGlobalBusyState));
RaisePropertyChanged(nameof(GlobalBusyMessage));
}
/// <summary>
/// Releases the global busy message.
/// </summary>
public void ReleaseGlobalBusyMessage()
{
GlobalBusyMessage = null;
IsInGlobalBusyState = false;
RaisePropertyChanged(nameof(IsInGlobalBusyState));
RaisePropertyChanged(nameof(GlobalBusyMessage));
}
/// <summary>
/// Gets the current global busy message.
/// </summary>
public string GlobalBusyMessage { get; private set; }
/// <summary>
/// Gets a value indicating whether this instance is in global busy state.
/// </summary>
public bool IsInGlobalBusyState { get; private set; }
private AppBarItem _currentAppBarItem;
/// <summary>
/// Gets the current application bar item.
/// </summary>
public AppBarItem CurrentAppBarItem
{
get { return _currentAppBarItem; }
set { _currentAppBarItem = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasAppBarItem)); }
}
/// <summary>
/// Gets a value indicating whether this instance has application bar item.
/// </summary>
public bool HasAppBarItem
{
get { return CurrentAppBarItem != null; }
}
/// <summary>
/// Pushes the application bar item.
/// </summary>
/// <param name="appBarItem">The application bar item.</param>
/// <returns></returns>
public AppBarItem PushAppBarItem(AppBarItem appBarItem)
{
LogManager.Log($"Pushing AppBarItem '{appBarItem.GetType().Name}'.");
CurrentAppBarItem = appBarItem;
appBarItem.RemoveAction = () => PopAppBarItem(appBarItem);
return appBarItem;
}
/// <summary>
/// Pushes the application bar item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public AppBarItem PushAppBarItem<T>() where T : AppBarItem
{
return PushAppBarItem(Activator.CreateInstance<T>());
}
/// <summary>
/// Pops the application bar item.
/// </summary>
/// <param name="appBarItem">The application bar item.</param>
public void PopAppBarItem(AppBarItem appBarItem)
{
LogManager.Log($"Popping out AppBarItem '{appBarItem.GetType().Name}'.");
CurrentAppBarItem = null;
}
/// <summary>
/// Pushes the task bar item.
/// </summary>
/// <param name="taskBarItem">The task bar item.</param>
/// <returns></returns>
public TaskBarItem PushTaskBarItem(TaskBarItem taskBarItem)
{
TaskBarItems.Add(taskBarItem);
return taskBarItem;
}
/// <summary>
/// Handles the Push Task Bar Item event.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public TaskBarItem PushTaskBarItem<T>() where T : TaskBarItem
{
return PushTaskBarItem(Activator.CreateInstance<T>());
}
/// <summary>
/// Pops the task bar item.
/// </summary>
/// <param name="taskBarItem"></param>
public void PopTaskBarItem(TaskBarItem taskBarItem)
{
TaskBarItems.Remove(taskBarItem);
}
/// <summary>
/// Pushes the app button.
/// </summary>
/// <param name="appButton">The app button.</param>
public void PushAppButton(AppButton appButton)
{
_appButtons.Insert(0, appButton);
CurrentAppButton = appButton;
}
/// <summary>
/// Pops the app button.
/// </summary>
/// <param name="appButton">The app button.</param>
public void PopAppButton(AppButton appButton)
{
_appButtons.RemoveAll(x => x == appButton);
CurrentAppButton = _appButtons.FirstOrDefault();
}
}
}