using InABox.Clients; using InABox.Core; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; using System.IO; using System.Windows.Media; using System.Windows.Media.Imaging; using InABox.WPF; namespace InABox.Wpf; public enum MessageWindowButtonPosition { Left, Right } public enum MessageWindowResult { None, OK, Cancel, Yes, No, Other } public class MessageWindowButton : INotifyPropertyChanged { public delegate void MessageWindowButtonDelegate(MessageWindow window, MessageWindowButton button); public MessageWindowButtonPosition Position { get; set; } private string _content; public string Content { get => _content; [MemberNotNull(nameof(_content))] set { _content = value; OnPropertyChanged(); } } public MessageWindowButtonDelegate Action { get; set; } public MessageWindowButton(string content, MessageWindowButtonDelegate action, MessageWindowButtonPosition position) { Content = content; Action = action; Position = position; } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } /// /// Interaction logic for MessageWindow.xaml /// public partial class MessageWindow : Window, INotifyPropertyChanged { public ObservableCollection Buttons { get; private set; } = new(); public IEnumerable LeftButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Left); public IEnumerable RightButtons => Buttons.Where(x => x.Position == MessageWindowButtonPosition.Right); private string _message = ""; public string Message { get => _message; set { _message = value; OnPropertyChanged(); } } public ImageSource? _image = null; public ImageSource? Image { get => _image; set { _image = value; OnPropertyChanged(); } } private string _details = ""; public string Details { get => _details; set { _details = value; OnPropertyChanged(); } } public static readonly DependencyProperty ShowDetailsProperty = DependencyProperty.Register(nameof(ShowDetails), typeof(bool), typeof(MessageWindow)); public bool ShowDetails { get => (bool)GetValue(ShowDetailsProperty); set => SetValue(ShowDetailsProperty, value); } public MessageWindowResult Result { get; set; } = MessageWindowResult.None; public object? OtherResult { get; set; } public MessageWindow() { InitializeComponent(); Buttons.CollectionChanged += Buttons_CollectionChanged; } private void Button_Click(object sender, RoutedEventArgs e) { if (sender is not Button button || button.Tag is not MessageWindowButton winButton) return; winButton.Action(this, winButton); } private void Buttons_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { OnPropertyChanged(nameof(LeftButtons)); OnPropertyChanged(nameof(RightButtons)); } public MessageWindow AddButton(MessageWindowButton button) { Buttons.Add(button); return this; } public MessageWindow AddOKButton(string content = "OK") { Buttons.Add(new MessageWindowButton(content, OKButton_Click, MessageWindowButtonPosition.Right)); return this; } public MessageWindow AddCancelButton(string content = "Cancel") { Buttons.Add(new MessageWindowButton(content, CancelButton_Click, MessageWindowButtonPosition.Right)); return this; } public MessageWindow AddYesButton(string content = "Yes") { Buttons.Add(new MessageWindowButton(content, YesButton_Click, MessageWindowButtonPosition.Right)); return this; } public MessageWindow AddNoButton(string content = "No") { Buttons.Add(new MessageWindowButton(content, NoButton_Click, MessageWindowButtonPosition.Right)); return this; } private void YesButton_Click(MessageWindow window, MessageWindowButton button) { Result = MessageWindowResult.Yes; Close(); } private void NoButton_Click(MessageWindow window, MessageWindowButton button) { Result = MessageWindowResult.No; Close(); } private void CancelButton_Click(MessageWindow window, MessageWindowButton button) { Result = MessageWindowResult.Cancel; Close(); } private void OKButton_Click(MessageWindow window, MessageWindowButton button) { Result = MessageWindowResult.OK; Close(); } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #region Static Constructors public static readonly BitmapImage _warning = InABox.Wpf.Resources.warning.AsBitmapImage(); public static BitmapImage WarningImage => _warning; public static MessageWindow New() { return new MessageWindow(); } public static MessageWindow NewMessage(string message, string title, ImageSource? image = null) { return new MessageWindow() .Title(title) .Message(message) .Image(image) .AddOKButton(); } public static void ShowMessage(string message, string title, ImageSource? image = null) { NewMessage(message, title, image).Display(); } public static MessageWindow NewOKCancel(string message, string title, ImageSource? image = null) { return new MessageWindow() .Title(title) .Message(message) .Image(image) .AddOKButton() .AddCancelButton(); } public static bool ShowOKCancel(string message, string title, ImageSource? image = null) { return NewOKCancel(message, title, image) .Display() .Result == MessageWindowResult.OK; } public static MessageWindow NewYesNo(string message, string title, ImageSource? image = null) { return new MessageWindow() .Title(title) .Message(message) .Image(image) .AddYesButton() .AddNoButton(); } public static bool ShowYesNo(string message, string title, ImageSource? image = null) { return NewYesNo(message, title, image) .Display() .Result == MessageWindowResult.Yes; } public static MessageWindow NewYesNoCancel(string message, string title, ImageSource? image = null) { return new MessageWindow() .Title(title) .Message(message) .Image(image) .AddYesButton() .AddNoButton() .AddCancelButton(); } public static MessageWindowResult ShowYesNoCancel(string message, string title, ImageSource? image = null) { return NewYesNoCancel(message, title, image) .Display().Result; } /// /// Display a message box for an exception, giving options to view the logs. /// /// The message to display. Set to to default to the exception message. /// /// /// If , also logs the exception. public static MessageWindow NewError(string? message, Exception exception, string title = "Error", bool shouldLog = true, ImageSource? image = null) { if (shouldLog) { CoreUtils.LogException(ClientFactory.UserID, exception); } var window = new MessageWindow() .Message(message ?? exception.Message) .Title(title) .Details(CoreUtils.FormatException(exception)) .Image(image ?? _warning) .AddButton(new MessageWindowButton("Show Logs", ShowLogs_Click, MessageWindowButtonPosition.Left)); var showDetailsButton = new MessageWindowButton("Show Details", (win, button) => { win.ShowDetails = !win.ShowDetails; button.Content = win.ShowDetails ? "Hide Details" : "Show Details"; }, MessageWindowButtonPosition.Left); return window.AddButton(showDetailsButton) .AddOKButton(); } /// /// Display a message box for a non-exception error, giving options to view the logs. /// /// The message to display. Set to to default to the exception message. /// /// /// If , also logs the exception. public static MessageWindow NewError(string message, string? details = null, string title = "Error", bool shouldLog = true, ImageSource? image = null) { if (shouldLog) { Logger.Send(LogType.Error, ClientFactory.UserID, details ?? message); } var window = new MessageWindow() .Message(message) .Title(title); if(details is not null) { window.Details(details); } window.Image(image ?? _warning) .AddButton(new MessageWindowButton("Show Logs", ShowLogs_Click, MessageWindowButtonPosition.Left)); if(details is not null) { var showDetailsButton = new MessageWindowButton("Show Details", (win, button) => { win.ShowDetails = !win.ShowDetails; button.Content = win.ShowDetails ? "Hide Details" : "Show Details"; }, MessageWindowButtonPosition.Left); window.AddButton(showDetailsButton); } return window.AddOKButton(); } public static void ShowError(string? message, Exception exception, string title = "Error", bool shouldLog = true, ImageSource? image = null) { NewError(message, exception, title, shouldLog, image).Display(); } public static void ShowError(string message, string details, string title = "Error", bool shouldLog = true, ImageSource? image = null) { NewError(message, details, title, shouldLog, image).Display(); } private static void ShowLogs_Click(MessageWindow window, MessageWindowButton button) { var console = new MessageWindowConsole("Logs", Path.Combine(CoreUtils.GetPath(), string.Format("{0:yyyy-MM-dd}.log", DateTime.Today))); console.ShowDialog(); } #endregion } public static class MessageWindowBuilder { public static MessageWindow Title(this MessageWindow window, string title) { window.Title = title; return window; } public static MessageWindow Message(this MessageWindow window, string message) { window.Message = message; return window; } public static MessageWindow Image(this MessageWindow window, ImageSource? image) { window.Image = image; return window; } public static MessageWindow Icon(this MessageWindow window, ImageSource image) { window.Icon = image; return window; } public static MessageWindow Details(this MessageWindow window, string details) { window.Details = details; return window; } public static MessageWindow Display(this MessageWindow window) { window.ShowDialog(); return window; } } public class MessageWindowConsole : Console.Console { public string FileName { get; set; } public MessageWindowConsole(string description, string file) : base(description) { FileName = file; ConsoleControl.AllowLoadLogButton = false; } protected override void OnLoaded() { base.OnLoaded(); if (File.Exists(FileName)) { var lines = File.ReadLines(FileName); ConsoleControl.LoadLogEntries(lines); } } protected override string GetLogDirectory() { return CoreUtils.GetPath(); } }