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; using Tango.Logging; namespace Tango.PPC.UI.Notifications { /// /// Represents the default PPC notification provider. /// /// /// public class DefaultNotificationProvider : ExtendedObject, INotificationProvider { private ConcurrentQueue> _pendingMessageBoxes; private ConcurrentQueue> _pendingDialogs; private List _appButtons; private bool _notificationsVisible; /// /// Gets or sets a value indicating whether to allow notifications visibility. /// public bool NotificationsVisible { get { return _notificationsVisible; } set { _notificationsVisible = value; RaisePropertyChangedAuto(); } } /// /// Gets the collection of notification items. /// public ObservableCollection NotificationItems { get; private set; } /// /// Gets the application bar items. /// public ObservableCollection AppBarItems { get; private set; } /// /// Gets the notification items view. /// public ICollectionView NotificationItemsView { get; private set; } /// /// Gets the collection of taskbar items. /// public ObservableCollection TaskBarItems { get; private set; } /// /// Initializes a new instance of the class. /// public DefaultNotificationProvider() { NotificationsVisible = true; NotificationItems = new ObservableCollection(); AppBarItems = new ObservableCollection(); CollectionViewSource.GetDefaultView(AppBarItems).SortDescriptions.Add(new SortDescription(nameof(AppBarItem.Priority), ListSortDirection.Ascending)); TaskBarItems = new ObservableCollection(); _pendingMessageBoxes = new ConcurrentQueue>(); _pendingDialogs = new ConcurrentQueue>(); _appButtons = new List(); PopNotificationCommand = new RelayCommand((x) => PopNotification(x)); NotificationItems.EnableCrossThreadOperations(); NotificationItemsView = CollectionViewSource.GetDefaultView(NotificationItems); NotificationItemsView.SortDescriptions.Add(new SortDescription(nameof(NotificationItem.Priority), ListSortDirection.Descending)); } private MessageBoxVM _currentMessageBox; /// /// Gets the current message box if any. /// public MessageBoxVM CurrentMessageBox { get { return _currentMessageBox; } private set { _currentMessageBox = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasMessageBox)); RaisePropertyChanged(nameof(HasDialogOrMessage)); } } /// /// Gets a value indicating whether a message box is available. /// public bool HasMessageBox { get { return CurrentMessageBox != null; } } private FrameworkElement _currentDialog; /// /// Gets the current dialog if any. /// public FrameworkElement CurrentDialog { get { return _currentDialog; } private set { _currentDialog = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(HasDialog)); RaisePropertyChanged(nameof(HasDialogOrMessage)); } } private AppButton _currentAppButton; /// /// Gets the current app button. /// public AppButton CurrentAppButton { get { return _currentAppButton; } private set { _currentAppButton = value; RaisePropertyChangedAuto(); } } /// /// Gets a value indicating whether a dialog is available. /// public bool HasDialog { get { return CurrentDialog != null; } } public bool HasDialogOrMessage { get { return HasDialog || HasMessageBox; } } /// /// Shows an error message box. /// /// The message. /// 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, }); } /// /// Shows an information message box. /// /// The message. /// 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, }); } /// /// Shows warning message box. /// /// The message. /// 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, }); } /// /// Shows a question message box. /// /// The message. /// public Task 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, }); } /// /// Shows a success message box. /// /// The message. /// 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, }); } /// /// Shows the message box. /// /// The view model. /// private Task ShowMessageBox(MessageBoxVM vm) { ReleaseGlobalBusyMessage(); LogManager.Log($"Displaying MessagBox '{vm.Message}'."); TaskCompletionSource source = new TaskCompletionSource(); vm.Accepted += () => { OnMessageBoxClosed(); source.SetResult(true); }; vm.Canceled += () => { OnMessageBoxClosed(); source.SetResult(false); }; if (CurrentMessageBox == null) { CurrentMessageBox = vm; } else { _pendingMessageBoxes.Enqueue(new PendingNotification(vm, source)); } return source.Task; } /// /// Called when the message box has been closed. /// private void OnMessageBoxClosed() { LogManager.Log("MessageBox closed."); CurrentMessageBox = null; if (_pendingMessageBoxes.Count > 0) { PendingNotification p = null; if (_pendingMessageBoxes.TryDequeue(out p)) { CurrentMessageBox = p.Item; } } } /// /// Inserts the notification item to the bottom of the notifications collection. /// /// The item. /// public NotificationItem PushNotification(NotificationItem item) { item.Time = DateTime.Now; LogManager.Log($"Pushing NotificationItem '{item.GetType().Name}'."); item.RemoveAction = () => { PopNotification(item); }; NotificationItems.Insert(0, item); RaisePropertyChanged(nameof(HasNotificationItems)); RaisePropertyChanged(nameof(NotificationItems)); return item; } /// /// Pushes the notification. /// /// /// public NotificationItem PushNotification() where T : NotificationItem { return PushNotification(Activator.CreateInstance()); } /// /// Removed the specified notification item. /// /// The item. public void PopNotification(NotificationItem item) { LogManager.Log($"Popping out NotificationItem '{item.GetType().Name}'."); NotificationItems.Remove(item); RaisePropertyChanged(nameof(HasNotificationItems)); RaisePropertyChanged(nameof(NotificationItems)); } /// /// Gets a value indicating whether this instance has notification items. /// public bool HasNotificationItems { get { return NotificationItems.Count > 0; } } /// /// Gets the pop notification command. /// public RelayCommand PopNotificationCommand { get; private set; } /// /// Displays the specified dialog in a modal design. /// /// /// The data context. /// The view. /// public async Task ShowDialog(T datacontext, FrameworkElement view) where T : DialogViewVM { TaskCompletionSource source = new TaskCompletionSource(); InvokeUI(() => { view.DataContext = datacontext; TangoIOC.Default.Inject(datacontext); view.Loaded += (_, __) => { view.DataContext = datacontext; datacontext.OnShow(); }; datacontext.Accepted += () => { OnDialogClosed(); source.SetResult(datacontext); }; datacontext.Canceled += () => { OnDialogClosed(); source.SetResult(datacontext); }; if (CurrentDialog == null) { CurrentDialog = view; } else { _pendingDialogs.Enqueue(new PendingNotification(new DialogAndView(datacontext, view), source)); } }); var result = await source.Task; return result as T; } /// /// Called when [dialog closed]. /// private void OnDialogClosed() { CurrentDialog = null; if (_pendingDialogs.Count > 0) { PendingNotification p = null; if (_pendingDialogs.TryDequeue(out p)) { CurrentDialog = p.Item.View; } } } /// /// Displays the specified dialog in a modal design. /// The notification provider will try to locate the view automatically using conventions. /// /// /// The data context. /// public Task ShowDialog(T datacontext) where T : DialogViewVM { TaskCompletionSource source = new TaskCompletionSource(); InvokeUI(async () => { 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."); } T result = await ShowDialog(datacontext, view); source.SetResult(result); }); return source.Task; } /// /// 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. /// /// /// public Task ShowDialog() where T : DialogViewVM { TaskCompletionSource source = new TaskCompletionSource(); InvokeUI(async () => { var result = await ShowDialog(Activator.CreateInstance()); source.SetResult(result); }); return source.Task; } /// /// Sets the global busy message. /// /// The message. public void SetGlobalBusyMessage(string message) { GlobalBusyMessage = message; IsInGlobalBusyState = true; RaisePropertyChanged(nameof(IsInGlobalBusyState)); RaisePropertyChanged(nameof(GlobalBusyMessage)); } /// /// Releases the global busy message. /// public void ReleaseGlobalBusyMessage() { GlobalBusyMessage = null; IsInGlobalBusyState = false; RaisePropertyChanged(nameof(IsInGlobalBusyState)); RaisePropertyChanged(nameof(GlobalBusyMessage)); } /// /// Gets the current global busy message. /// public string GlobalBusyMessage { get; private set; } /// /// Gets a value indicating whether this instance is in global busy state. /// public bool IsInGlobalBusyState { get; private set; } /// /// Gets a value indicating whether this instance has application bar item. /// public bool HasAppBarItems { get { return AppBarItems.Count > 0; } } /// /// Pushes the application bar item. /// /// The application bar item. /// public AppBarItem PushAppBarItem(AppBarItem appBarItem) { LogManager.Log($"Pushing AppBarItem '{appBarItem.GetType().Name}'."); AppBarItems.Add(appBarItem); appBarItem.RemoveAction = () => PopAppBarItem(appBarItem); RaisePropertyChanged(nameof(HasAppBarItems)); return appBarItem; } /// /// Pushes the application bar item. /// /// /// public T PushAppBarItem() where T : AppBarItem { return PushAppBarItem(Activator.CreateInstance()) as T; } /// /// Pops the application bar item. /// /// The application bar item. public void PopAppBarItem(AppBarItem appBarItem) { InvokeUI(() => { LogManager.Log($"Popping out AppBarItem '{appBarItem.GetType().Name}'."); AppBarItems.Remove(appBarItem); RaisePropertyChanged(nameof(HasAppBarItems)); }); } /// /// Pushes the task bar item. /// /// The task bar item. /// public TaskBarItem PushTaskBarItem(TaskBarItem taskBarItem) { TaskBarItems.Add(taskBarItem); return taskBarItem; } /// /// Handles the Push Task Bar Item event. /// /// /// public TaskBarItem PushTaskBarItem() where T : TaskBarItem { return PushTaskBarItem(Activator.CreateInstance()); } /// /// Pops the task bar item. /// /// public void PopTaskBarItem(TaskBarItem taskBarItem) { TaskBarItems.Remove(taskBarItem); } /// /// Pushes the app button. /// /// The app button. public void PushAppButton(AppButton appButton) { if (appButton != null) { LogManager.Log($"Pushing app button '{appButton.GetType().Name}'..."); } _appButtons.Insert(0, appButton); CurrentAppButton = appButton; } /// /// Pops the app button. /// /// The app button. public void PopAppButton(AppButton appButton) { if (appButton != null) { LogManager.Log($"Popping app button '{appButton.GetType().Name}'..."); } else { LogManager.Log("Popping app button 'null' ??", LogCategory.Warning); } _appButtons.RemoveAll(x => x == appButton); CurrentAppButton = _appButtons.FirstOrDefault(); } } }