From 045994a12d09736e9b995fdd72eb9e810af8c91f Mon Sep 17 00:00:00 2001 From: CascadePass <106619481+CascadePass@users.noreply.github.com> Date: Mon, 4 Aug 2025 12:50:53 -0700 Subject: [PATCH 1/2] Remove shared status controller Now that status is being communicated via toasts and cards, there's no need for the old status bar controlling system. --- CPAP-Exporter.Tests/StatusTests.cs | 42 ------ .../ViewModels/StatusBarViewModelTests.cs | 41 ------ .../Infrastructure/Interfaces/IStatus.cs | 9 -- CPAP-Exporter.UI/Infrastructure/Status.cs | 50 ------- .../ApplicationComponentProvider.cs | 9 -- .../Pages/OpenFiles/OpenFilesViewModel.cs | 13 +- .../Pages/SavedFiles/SavedFileViewModel.cs | 8 +- .../Pages/SavedFiles/SavedFilesViewModel.cs | 15 +- .../SelectNights/SelectNightsViewModel.cs | 8 +- .../SelectSignals/SelectSignalsViewModel.cs | 4 +- .../ViewModels/NavigationViewModel.cs | 4 - .../ViewModels/StatusBarViewModel.cs | 130 ------------------ CPAP-Exporter.UI/Views/BannerStrip.xaml | 13 -- CPAP-Exporter.UI/Views/BannerStrip.xaml.cs | 28 ---- CPAP-Exporter.UI/Views/StatusStrip.xaml | 51 ------- CPAP-Exporter.UI/Views/StatusStrip.xaml.cs | 66 --------- 16 files changed, 25 insertions(+), 466 deletions(-) delete mode 100644 CPAP-Exporter.Tests/StatusTests.cs delete mode 100644 CPAP-Exporter.Tests/ViewModels/StatusBarViewModelTests.cs delete mode 100644 CPAP-Exporter.UI/Infrastructure/Interfaces/IStatus.cs delete mode 100644 CPAP-Exporter.UI/Infrastructure/Status.cs delete mode 100644 CPAP-Exporter.UI/ViewModels/StatusBarViewModel.cs delete mode 100644 CPAP-Exporter.UI/Views/BannerStrip.xaml delete mode 100644 CPAP-Exporter.UI/Views/BannerStrip.xaml.cs delete mode 100644 CPAP-Exporter.UI/Views/StatusStrip.xaml delete mode 100644 CPAP-Exporter.UI/Views/StatusStrip.xaml.cs diff --git a/CPAP-Exporter.Tests/StatusTests.cs b/CPAP-Exporter.Tests/StatusTests.cs deleted file mode 100644 index 57403ba..0000000 --- a/CPAP-Exporter.Tests/StatusTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace CascadePass.CPAPExporter.UI.Tests -{ - [TestClass] - public class StatusTests - { - private Status status; - - [TestInitialize] - public void SetUp() - { - status = new Status(); - } - - [TestMethod] - public void StatusText_SetAndGet_ReturnsCorrectValue() - { - string expected = "Test Status"; - - status.StatusText = expected; - - Assert.AreEqual(expected, status.StatusText); - } - - [TestMethod] - public void StatusText_SetProperty_RaisesPropertyChangedEvent() - { - bool eventRaised = false; - - status.PropertyChanged += (sender, e) => - { - if (e.PropertyName == nameof(Status.StatusText)) - { - eventRaised = true; - } - }; - - status.StatusText = "New Status"; - - Assert.IsTrue(eventRaised, "PropertyChanged event was not raised."); - } - } -} diff --git a/CPAP-Exporter.Tests/ViewModels/StatusBarViewModelTests.cs b/CPAP-Exporter.Tests/ViewModels/StatusBarViewModelTests.cs deleted file mode 100644 index 94cd707..0000000 --- a/CPAP-Exporter.Tests/ViewModels/StatusBarViewModelTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace CascadePass.CPAPExporter.UI.Tests -{ - [TestClass] - public class StatusBarViewModelTests - { - [TestMethod] - public void StatusBarViewModel_NoWindow() - { - StatusBarViewModel statusBarViewModel = new(); - - Assert.IsNull(statusBarViewModel.MainWindow); - } - - [TestMethod] - public void FontSize_Get_NoWindow() - { - StatusBarViewModel statusBarViewModel = new(); - - Assert.AreEqual(default, statusBarViewModel.FontSize); - } - - [TestMethod] - [ExpectedException(typeof(System.InvalidOperationException))] - public void FontSize_Set_NoWindow() - { - StatusBarViewModel statusBarViewModel = new(); - statusBarViewModel.FontSize = 12; - } - - [TestMethod] - public void Version_IsValid() - { - object version = new StatusBarViewModel().Version; - - Console.WriteLine($"new StatusBarViewModel().Version == {version}"); - - Assert.IsNotNull(version); - Assert.IsInstanceOfType(version); - } - } -} diff --git a/CPAP-Exporter.UI/Infrastructure/Interfaces/IStatus.cs b/CPAP-Exporter.UI/Infrastructure/Interfaces/IStatus.cs deleted file mode 100644 index 3e303e8..0000000 --- a/CPAP-Exporter.UI/Infrastructure/Interfaces/IStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace CascadePass.CPAPExporter -{ - public interface IStatus - { - string StatusText { get; set; } - - StatusProgressBar ProgressBar { get; set; } - } -} diff --git a/CPAP-Exporter.UI/Infrastructure/Status.cs b/CPAP-Exporter.UI/Infrastructure/Status.cs deleted file mode 100644 index 41a6565..0000000 --- a/CPAP-Exporter.UI/Infrastructure/Status.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace CascadePass.CPAPExporter -{ - public class Status : Observable, IStatus - { - private string statusText; - private StatusProgressBar statusProgressBar; - - public string StatusText - { - get => this.statusText; - set => this.SetPropertyValue(ref this.statusText, value, nameof(this.StatusText)); - } - - public StatusProgressBar ProgressBar - { - get => this.statusProgressBar; - set => this.SetPropertyValue(ref this.statusProgressBar, value, nameof(this.ProgressBar)); - } - } - - public class StatusProgressBar : ViewModel - { - private int min, max, curent; - - public StatusProgressBar(int minimmum, int maximum, int currentValue) - { - this.Min = minimmum; - this.Max = maximum; - this.Current = currentValue; - } - - public int Min - { - get => this.min; - set => this.SetPropertyValue(ref this.min, value, nameof(this.Min)); - } - - public int Max - { - get => this.max; - set => this.SetPropertyValue(ref this.max, value, nameof(this.Max)); - } - - public int Current - { - get => this.curent; - set => this.SetPropertyValue(ref this.curent, value, nameof(this.Current)); - } - } -} diff --git a/CPAP-Exporter.UI/Infrastructure/Testability/ApplicationComponentProvider.cs b/CPAP-Exporter.UI/Infrastructure/Testability/ApplicationComponentProvider.cs index f9242f0..4f9987a 100644 --- a/CPAP-Exporter.UI/Infrastructure/Testability/ApplicationComponentProvider.cs +++ b/CPAP-Exporter.UI/Infrastructure/Testability/ApplicationComponentProvider.cs @@ -4,19 +4,10 @@ public static class ApplicationComponentProvider { static ApplicationComponentProvider() { - ApplicationComponentProvider.Status = new Status(); ApplicationComponentProvider.PageViewModelProvider = new PageViewModelProvider(); ApplicationComponentProvider.CpapSourceValidator = new CpapSourceValidator(); } - public static IStatus Status - { - get; -#if DEBUG - set; -#endif - } - public static IPageViewModelProvider PageViewModelProvider { get; diff --git a/CPAP-Exporter.UI/Pages/OpenFiles/OpenFilesViewModel.cs b/CPAP-Exporter.UI/Pages/OpenFiles/OpenFilesViewModel.cs index 1a7de09..14855ab 100644 --- a/CPAP-Exporter.UI/Pages/OpenFiles/OpenFilesViewModel.cs +++ b/CPAP-Exporter.UI/Pages/OpenFiles/OpenFilesViewModel.cs @@ -1,7 +1,9 @@ using System.IO; using System.Windows; +using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Media.Imaging; namespace CascadePass.CPAPExporter { @@ -159,8 +161,6 @@ public void Load(string folder) this.ExportParameters.Reports.Clear(); } - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.ReadingFolder, folder); - this.OnAdvancePage(); } @@ -174,13 +174,15 @@ internal bool CanImportFrom(string folder) if (!Directory.Exists(folder)) { - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FolderDoesNotExist, folder); + this.StatusContent = new WarningToast(string.Format(Resources.FolderDoesNotExist, folder)); + //ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FolderDoesNotExist, folder); return false; } if (!ApplicationComponentProvider.CpapSourceValidator.IsCpapFolderStructure(folder)) { - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FolderIsNotPAP, folder); + //ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FolderIsNotPAP, folder); + this.StatusContent = new WarningToast(string.Format(Resources.FolderIsNotPAP, folder)); return false; } @@ -202,7 +204,8 @@ internal string FindImportableParentFolder(string folder) if (dir.Parent is null) { - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.NoPapData, folder); + //ApplicationComponentProvider.Status.StatusText = string.Format(Resources.NoPapData, folder); + this.StatusContent = new WarningToast(string.Format(Resources.NoPapData, folder)); return null; } diff --git a/CPAP-Exporter.UI/Pages/SavedFiles/SavedFileViewModel.cs b/CPAP-Exporter.UI/Pages/SavedFiles/SavedFileViewModel.cs index cca6c88..128b885 100644 --- a/CPAP-Exporter.UI/Pages/SavedFiles/SavedFileViewModel.cs +++ b/CPAP-Exporter.UI/Pages/SavedFiles/SavedFileViewModel.cs @@ -139,11 +139,15 @@ public void DeleteFile() this.IsDeleted = true; this.OnFileDeleted(this, EventArgs.Empty); - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FileWasDeleted, this.Filename); + //ApplicationComponentProvider.Status.StatusText = string.Format(Resources.FileWasDeleted, this.Filename); } catch (Exception ex) { - ApplicationComponentProvider.Status.StatusText = ex.Message; + //ApplicationComponentProvider.Status.StatusText = ex.Message; + var window = Application.Current?.MainWindow; + var viewModel = window?.DataContext as PageViewModel; + + Application.Current.Dispatcher.Invoke(() => { viewModel.StatusContent = new ErrorToast(ex.Message); }); } } diff --git a/CPAP-Exporter.UI/Pages/SavedFiles/SavedFilesViewModel.cs b/CPAP-Exporter.UI/Pages/SavedFiles/SavedFilesViewModel.cs index b10693d..3e297fe 100644 --- a/CPAP-Exporter.UI/Pages/SavedFiles/SavedFilesViewModel.cs +++ b/CPAP-Exporter.UI/Pages/SavedFiles/SavedFilesViewModel.cs @@ -84,7 +84,10 @@ public void PerformExportAsync(string folder) public void PerformExport(string folder) { - ApplicationComponentProvider.Status.StatusText = Resources.Working; + Application.Current.Dispatcher.Invoke(() => + { + this.StatusContent = new BusyToast(); + }); try { @@ -125,7 +128,7 @@ [.. this.ExportParameters.Reports.Where(r => r.IsSelected).Select(r => r.DailyRe } catch (Exception ex) { - ApplicationComponentProvider.Status.StatusText = ex.Message; + Application.Current.Dispatcher.Invoke(() => { this.StatusContent = new ErrorToast(ex.Message); }); if (Debugger.IsAttached) { @@ -133,8 +136,7 @@ [.. this.ExportParameters.Reports.Where(r => r.IsSelected).Select(r => r.DailyRe } } - ApplicationComponentProvider.Status.ProgressBar = null; - ApplicationComponentProvider.Status.StatusText = string.Empty; + Application.Current.Dispatcher.Invoke(() => { this.StatusContent = null; }); } #region Button click implementations @@ -186,14 +188,13 @@ private void Exporter_Progress(object sender, ExportProgressEventArgs e) { if (this.Dispatcher?.CheckAccess() ?? true) { - ApplicationComponentProvider.Status.ProgressBar = new(0, e.ExpectedRows, e.CurrentRowIndex); - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.RowsWritten, e.CurrentRowIndex.ToString("#,##0")); + // Update progress bar } else { this.Dispatcher.Invoke(() => { - ApplicationComponentProvider.Status.ProgressBar = new(0, e.ExpectedRows, e.CurrentRowIndex); + // Update progress bar }); } } diff --git a/CPAP-Exporter.UI/Pages/SelectNights/SelectNightsViewModel.cs b/CPAP-Exporter.UI/Pages/SelectNights/SelectNightsViewModel.cs index ef53f59..f9825a5 100644 --- a/CPAP-Exporter.UI/Pages/SelectNights/SelectNightsViewModel.cs +++ b/CPAP-Exporter.UI/Pages/SelectNights/SelectNightsViewModel.cs @@ -206,11 +206,9 @@ public void LoadFromFolder(string folder, bool replaceExisting) internal void ConsumeReports(List reports, string folder) { - ApplicationComponentProvider.Status.ProgressBar = new(0, reports.Count - 1, 0); - for (int i = 0; i < reports.Count; i++) { - ApplicationComponentProvider.Status.ProgressBar.Current = i; + // Update progress bar var report = reports[i]; @@ -219,16 +217,12 @@ internal void ConsumeReports(List reports, string folder) this.AddReport(report, folder); } } - - ApplicationComponentProvider.Status.ProgressBar = null; } internal DailyReportViewModel AddReport(DailyReport report, string folder) { ArgumentNullException.ThrowIfNull(report, nameof(report)); - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.AddingDate, report.ReportDate); - DailyReportViewModel reportViewModel = new(report, this.IsAllSelected, folder); this.Reports.Add(reportViewModel); diff --git a/CPAP-Exporter.UI/Pages/SelectSignals/SelectSignalsViewModel.cs b/CPAP-Exporter.UI/Pages/SelectSignals/SelectSignalsViewModel.cs index 7753718..a1feb6c 100644 --- a/CPAP-Exporter.UI/Pages/SelectSignals/SelectSignalsViewModel.cs +++ b/CPAP-Exporter.UI/Pages/SelectSignals/SelectSignalsViewModel.cs @@ -86,7 +86,7 @@ public string GenerateSampleCSV() catch (Exception ex) { #if DEBUG - ApplicationComponentProvider.Status.StatusText = ex.Message; + this.StatusContent = new ErrorToast(ex.Message); #endif } } @@ -133,7 +133,7 @@ private void ConsumeExportParameters() } } - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.SignalsAvailable, this.ExportParameters.Signals.Count); + this.StatusContent = new InfoToast(string.Format(Resources.SignalsAvailable, this.Signals.Count)); } protected override void OnPropertyChanged(string propertyName) diff --git a/CPAP-Exporter.UI/ViewModels/NavigationViewModel.cs b/CPAP-Exporter.UI/ViewModels/NavigationViewModel.cs index ce84b36..f1422c2 100644 --- a/CPAP-Exporter.UI/ViewModels/NavigationViewModel.cs +++ b/CPAP-Exporter.UI/ViewModels/NavigationViewModel.cs @@ -237,16 +237,12 @@ public void ShowSignals() this.CurrentView = new SelectSignalsView { DataContext = viewModel }; this.CurrentStep = NavigationStep.SelectSignals; - - ApplicationComponentProvider.Status.StatusText = string.Format(Resources.SignalsAvailable, viewModel.Signals.Count); } public void ShowExportSettings() { this.CurrentView = new OptionsView() { DataContext = new ExportOptionsPageViewModel(this.ExportParameters) }; this.CurrentStep = NavigationStep.Settings; - - ApplicationComponentProvider.Status.StatusText = Resources.ReadyToExport; } public void Export() diff --git a/CPAP-Exporter.UI/ViewModels/StatusBarViewModel.cs b/CPAP-Exporter.UI/ViewModels/StatusBarViewModel.cs deleted file mode 100644 index 61dc4d4..0000000 --- a/CPAP-Exporter.UI/ViewModels/StatusBarViewModel.cs +++ /dev/null @@ -1,130 +0,0 @@ -using System.Diagnostics; -using System.Windows; - -namespace CascadePass.CPAPExporter -{ - public class StatusBarViewModel : ViewModel - { - #region Fields - - private MainWindow mainWindow; - private Version version; - private IPageViewModelProvider pageViewModelProvider; - private DelegateCommand viewReleasesPageCommand, aboutBoxCommand, viewHashesCommand; - - #endregion - - #region Constructors - - public StatusBarViewModel() - { - this.Version = this.GetType().Assembly.GetName().Version; - - this.pageViewModelProvider = ApplicationComponentProvider.PageViewModelProvider; - - if (ApplicationComponentProvider.Status is Observable observable) - { - observable.PropertyChanged += Observable_PropertyChanged; - } - } - - public StatusBarViewModel(MainWindow mainWindow, NavigationViewModel navigationViewModel) : this() - { - this.MainWindow = mainWindow; - this.NavigationViewModel = navigationViewModel; - } - - #endregion - - public MainWindow MainWindow - { - get => this.mainWindow; - set => this.SetPropertyValue(ref this.mainWindow, value, nameof(this.MainWindow)); - } - - public NavigationViewModel NavigationViewModel { get; set; } - - public PageViewModel CurrentViewModel => this.MainWindow?.PageViewer.DataContext is PageViewModel ? this.PageViewModelProvider.GetViewModel(this.MainWindow?.PageViewer) : null; - - public string StatusText => ApplicationComponentProvider.Status.StatusText; - - public StatusProgressBar ProgressBarInfo => ApplicationComponentProvider.Status.ProgressBar; - - public bool IsProgressBarVisible => ApplicationComponentProvider.Status.ProgressBar != null; - - public double FontSize - { - get => this.MainWindow?.FontSize ?? default; - set - { - if (this.MainWindow != null) - { - this.MainWindow.FontSize = value; - } - else - { - throw new InvalidOperationException(Resources.Validation_MainWindow_Null); - } - } - } - - public Version Version - { - get => this.version; - set => this.SetPropertyValue(ref this.version, value, nameof(this.Version)); - } - - public IPageViewModelProvider PageViewModelProvider - { - get => this.pageViewModelProvider; -#if DEBUG - set => this.SetPropertyValue(ref this.pageViewModelProvider, value, nameof(this.PageViewModelProvider)); -#endif - } - - public DelegateCommand ViewReleasesPageCommand => this.viewReleasesPageCommand ??= new DelegateCommand(this.ViewReleasesPage); - - public DelegateCommand ViewAboutBoxCommand => this.aboutBoxCommand ??= new DelegateCommand(this.ShowAboutBox); - - public DelegateCommand ViewHashesCommand => this.viewHashesCommand ??= new DelegateCommand(this.ViewHashes); - - - private void ViewReleasesPage() - { - try - { - Process.Start("https://github.com/CascadePass/CPAP-Exporter/releases"); - } - catch (Exception) - { - } - } - - private void ShowAboutBox() - { - MessageBox.Show( - "Acknowledgements:" + Environment.NewLine + Environment.NewLine + - "EEGKit: https://github.com/EEGKit/cpap-lib" + Environment.NewLine + Environment.NewLine + - "StagPoint: https://github.com/EEGKit/StagPoint.EuropeanDataFormat.Net", - - $"{Resources.Window_Title} v{this.Version}", - - MessageBoxButton.OK, - - MessageBoxImage.Information - ); - } - - private void ViewHashes() - { - this.NavigationViewModel?.ShowHashView(); - } - - private void Observable_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - this.OnPropertyChanged(nameof(this.StatusText)); - this.OnPropertyChanged(nameof(this.IsProgressBarVisible)); - this.OnPropertyChanged(nameof(this.ProgressBarInfo)); - } - } -} diff --git a/CPAP-Exporter.UI/Views/BannerStrip.xaml b/CPAP-Exporter.UI/Views/BannerStrip.xaml deleted file mode 100644 index 32e3fcb..0000000 --- a/CPAP-Exporter.UI/Views/BannerStrip.xaml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/CPAP-Exporter.UI/Views/BannerStrip.xaml.cs b/CPAP-Exporter.UI/Views/BannerStrip.xaml.cs deleted file mode 100644 index 3c76340..0000000 --- a/CPAP-Exporter.UI/Views/BannerStrip.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace CascadePass.CPAPExporter -{ - /// - /// Interaction logic for BannerStrip.xaml - /// - public partial class BannerStrip : UserControl - { - public BannerStrip() - { - InitializeComponent(); - } - } -} diff --git a/CPAP-Exporter.UI/Views/StatusStrip.xaml b/CPAP-Exporter.UI/Views/StatusStrip.xaml deleted file mode 100644 index 62381e4..0000000 --- a/CPAP-Exporter.UI/Views/StatusStrip.xaml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -