From b8b41121e370f847f689d672b19250b6622d4b22 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 20 Sep 2020 19:52:28 +0100 Subject: [PATCH] Add dialog to update database statistics. --- RomRepoMgr/Resources/Localization.Designer.cs | 42 +++ RomRepoMgr/Resources/Localization.es.resx | 22 ++ RomRepoMgr/Resources/Localization.resx | 22 ++ RomRepoMgr/ViewModels/MainWindowViewModel.cs | 20 ++ RomRepoMgr/ViewModels/UpdateStatsViewModel.cs | 260 ++++++++++++++++++ RomRepoMgr/Views/MainWindow.xaml | 4 + RomRepoMgr/Views/UpdateStats.xaml | 129 +++++++++ RomRepoMgr/Views/UpdateStats.xaml.cs | 45 +++ 8 files changed, 544 insertions(+) create mode 100644 RomRepoMgr/ViewModels/UpdateStatsViewModel.cs create mode 100644 RomRepoMgr/Views/UpdateStats.xaml create mode 100644 RomRepoMgr/Views/UpdateStats.xaml.cs diff --git a/RomRepoMgr/Resources/Localization.Designer.cs b/RomRepoMgr/Resources/Localization.Designer.cs index 0283d64..417ba5b 100644 --- a/RomRepoMgr/Resources/Localization.Designer.cs +++ b/RomRepoMgr/Resources/Localization.Designer.cs @@ -710,5 +710,47 @@ namespace RomRepoMgr.Resources { return ResourceManager.GetString("RomSetCategoryLabel", resourceCulture); } } + + internal static string DatabaseMenuText { + get { + return ResourceManager.GetString("DatabaseMenuText", resourceCulture); + } + } + + internal static string DatabaseMenuUpdateStatsText { + get { + return ResourceManager.GetString("DatabaseMenuUpdateStatsText", resourceCulture); + } + } + + internal static string UpdateStatsConfirmationDialogText { + get { + return ResourceManager.GetString("UpdateStatsConfirmationDialogText", resourceCulture); + } + } + + internal static string UpdateStatsTitle { + get { + return ResourceManager.GetString("UpdateStatsTitle", resourceCulture); + } + } + + internal static string CalculatingStatisticsForRomSet { + get { + return ResourceManager.GetString("CalculatingStatisticsForRomSet", resourceCulture); + } + } + + internal static string RemovingOldStatistics { + get { + return ResourceManager.GetString("RemovingOldStatistics", resourceCulture); + } + } + + internal static string RetrievingRomSetsFromDatabase { + get { + return ResourceManager.GetString("RetrievingRomSetsFromDatabase", resourceCulture); + } + } } } diff --git a/RomRepoMgr/Resources/Localization.es.resx b/RomRepoMgr/Resources/Localization.es.resx index 5208600..1861a13 100644 --- a/RomRepoMgr/Resources/Localization.es.resx +++ b/RomRepoMgr/Resources/Localization.es.resx @@ -346,4 +346,26 @@ Categoría + + Recuperando sets de ROMs de la base de datos... + + + Eliminando estadísticas antiguas + + + Calculando estadísticas para {0} - {1} ({2}) + + + Base de datos + + + Actualizar estadísticas + + + ¿Quieres actualizar las estadísticas de los sets de ROMs en la base de datos? +Tardará mucho tiempo... + + + Actualizando estadísticas de sets de ROMs + \ No newline at end of file diff --git a/RomRepoMgr/Resources/Localization.resx b/RomRepoMgr/Resources/Localization.resx index 1603050..451cc70 100644 --- a/RomRepoMgr/Resources/Localization.resx +++ b/RomRepoMgr/Resources/Localization.resx @@ -352,4 +352,26 @@ Do you want to delete the file? Category + + Database + + + Update statistics + + + Do you want to update ROM set statistics in database? +This will take a long time... + + + Updating ROM sets statistics + + + Calculating statistics for {0} - {1} ({2}) + + + Removing old statistics + + + Retrieving ROM sets from database... + \ No newline at end of file diff --git a/RomRepoMgr/ViewModels/MainWindowViewModel.cs b/RomRepoMgr/ViewModels/MainWindowViewModel.cs index d862354..fa0b128 100644 --- a/RomRepoMgr/ViewModels/MainWindowViewModel.cs +++ b/RomRepoMgr/ViewModels/MainWindowViewModel.cs @@ -65,6 +65,7 @@ namespace RomRepoMgr.ViewModels ExportRomsCommand = ReactiveCommand.Create(ExecuteExportRomsCommand); MountCommand = ReactiveCommand.Create(ExecuteMountCommand); UmountCommand = ReactiveCommand.Create(ExecuteUmountCommand); + UpdateStatsCommand = ReactiveCommand.Create(ExecuteUpdateStatsCommand); RomSets = new ObservableCollection(romSets); } @@ -101,6 +102,8 @@ namespace RomRepoMgr.ViewModels public string HelpMenuText => Localization.HelpMenuText; public string HelpMenuAboutText => Localization.HelpMenuAboutText; public string FilesystemMenuUmountText => Localization.FilesystemMenuUmountText; + public string DatabaseMenuText => Localization.DatabaseMenuText; + public string DatabaseMenuUpdateStatsText => Localization.DatabaseMenuUpdateStatsText; public bool NativeMenuSupported => NativeMenu.GetIsNativeMenuExported((Application.Current.ApplicationLifetime as @@ -118,6 +121,7 @@ namespace RomRepoMgr.ViewModels public ReactiveCommand ExportRomsCommand { get; } public ReactiveCommand MountCommand { get; } public ReactiveCommand UmountCommand { get; } + public ReactiveCommand UpdateStatsCommand { get; } public Vfs Vfs { @@ -347,5 +351,21 @@ namespace RomRepoMgr.ViewModels void VfsOnUmounted(object sender, EventArgs e) => Vfs = null; void ExecuteUmountCommand() => Vfs?.Umount(); + + async void ExecuteUpdateStatsCommand() + { + ButtonResult result = await MessageBoxManager. + GetMessageBoxStandardWindow(Localization.DatabaseMenuUpdateStatsText, + Localization.UpdateStatsConfirmationDialogText, + ButtonEnum.YesNo, Icon.Database).ShowDialog(_view); + + if(result == ButtonResult.No) + return; + + var view = new UpdateStats(); + var viewModel = new UpdateStatsViewModel(view); + view.DataContext = viewModel; + await view.ShowDialog(_view); + } } } \ No newline at end of file diff --git a/RomRepoMgr/ViewModels/UpdateStatsViewModel.cs b/RomRepoMgr/ViewModels/UpdateStatsViewModel.cs new file mode 100644 index 0000000..c35e063 --- /dev/null +++ b/RomRepoMgr/ViewModels/UpdateStatsViewModel.cs @@ -0,0 +1,260 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Threading.Tasks; +using Avalonia.Threading; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using ReactiveUI; +using RomRepoMgr.Core.Models; +using RomRepoMgr.Database; +using RomRepoMgr.Database.Models; +using RomRepoMgr.Resources; +using RomRepoMgr.Views; + +namespace RomRepoMgr.ViewModels +{ + public sealed class UpdateStatsViewModel : ViewModelBase + { + readonly UpdateStats _view; + bool _canClose; + double _currentValue; + bool _indeterminateProgress; + double _maximumValue; + double _minimumValue; + bool _progressVisible; + RomSetModel _selectedRomSet; + string _statusMessage; + + public UpdateStatsViewModel(UpdateStats view) + { + _view = view; + CloseCommand = ReactiveCommand.Create(ExecuteCloseCommand); + IndeterminateProgress = true; + ProgressVisible = false; + RomSets = new ObservableCollection(); + } + + [NotNull] + public string Title => Localization.UpdateStatsTitle; + public string RomSetNameLabel => Localization.RomSetNameLabel; + public string RomSetVersionLabel => Localization.RomSetVersionLabel; + public string RomSetAuthorLabel => Localization.RomSetAuthorLabel; + public string RomSetCategoryLabel => Localization.RomSetCategoryLabel; + public string RomSetDateLabel => Localization.RomSetDateLabel; + public string RomSetDescriptionLabel => Localization.RomSetDescriptionLabel; + public string RomSetCommentLabel => Localization.RomSetCommentLabel; + public string RomSetTotalMachinesLabel => Localization.RomSetTotalMachinesLabel; + public string RomSetCompleteMachinesLabel => Localization.RomSetCompleteMachinesLabel; + public string RomSetIncompleteMachinesLabel => Localization.RomSetIncompleteMachinesLabel; + public string RomSetTotalRomsLabel => Localization.RomSetTotalRomsLabel; + public string RomSetHaveRomsLabel => Localization.RomSetHaveRomsLabel; + public string RomSetMissRomsLabel => Localization.RomSetMissRomsLabel; + + public string StatusMessage + { + get => _statusMessage; + set => this.RaiseAndSetIfChanged(ref _statusMessage, value); + } + + public bool IndeterminateProgress + { + get => _indeterminateProgress; + set => this.RaiseAndSetIfChanged(ref _indeterminateProgress, value); + } + + public double MaximumValue + { + get => _maximumValue; + set => this.RaiseAndSetIfChanged(ref _maximumValue, value); + } + + public double MinimumValue + { + get => _minimumValue; + set => this.RaiseAndSetIfChanged(ref _minimumValue, value); + } + + public double CurrentValue + { + get => _currentValue; + set => this.RaiseAndSetIfChanged(ref _currentValue, value); + } + + public bool ProgressVisible + { + get => _progressVisible; + set => this.RaiseAndSetIfChanged(ref _progressVisible, value); + } + + public RomSetModel SelectedRomSet + { + get => _selectedRomSet; + set => this.RaiseAndSetIfChanged(ref _selectedRomSet, value); + } + + public bool CanClose + { + get => _canClose; + set => this.RaiseAndSetIfChanged(ref _canClose, value); + } + + public ObservableCollection RomSets { get; } + + public string CloseLabel => Localization.CloseLabel; + public ReactiveCommand CloseCommand { get; } + + internal void OnOpened() => Task.Run(() => + { + using var ctx = Context.Create(Settings.Settings.Current.DatabasePath); + + Dispatcher.UIThread.Post(() => + { + StatusMessage = Localization.RetrievingRomSetsFromDatabase; + ProgressVisible = true; + IndeterminateProgress = true; + }); + + long romSetCount = ctx.RomSets.LongCount(); + + Dispatcher.UIThread.Post(() => + { + StatusMessage = Localization.RemovingOldStatistics; + }); + + ctx.Database.ExecuteSqlRaw("DELETE FROM \"RomSetStats\""); + + Dispatcher.UIThread.Post(() => + { + IndeterminateProgress = false; + MinimumValue = 0; + MaximumValue = romSetCount; + CurrentValue = 0; + }); + + long pos = 0; + + foreach(RomSet romSet in ctx.RomSets) + { + long currentPos = pos; + + Dispatcher.UIThread.Post(() => + { + StatusMessage = string.Format(Localization.CalculatingStatisticsForRomSet, romSet.Name, + romSet.Version, romSet.Description); + + CurrentValue = currentPos; + }); + + try + { + RomSetStat stats = ctx.RomSets.Where(r => r.Id == romSet.Id).Select(r => new RomSetStat + { + RomSetId = r.Id, + TotalMachines = r.Machines.Count, + CompleteMachines = + r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 && + m.Files.All(f => f.File.IsInRepo)) + + r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 && + m.Disks.All(f => f.Disk.IsInRepo)) + + r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 && + m.Files.All(f => f.File.IsInRepo) && + m.Disks.All(f => f.Disk.IsInRepo)), + IncompleteMachines = + r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count == 0 && + m.Files.Any(f => !f.File.IsInRepo)) + + r.Machines.Count(m => m.Disks.Count > 0 && m.Files.Count == 0 && + m.Disks.Any(f => !f.Disk.IsInRepo)) + + r.Machines.Count(m => m.Files.Count > 0 && m.Disks.Count > 0 && + (m.Files.Any(f => !f.File.IsInRepo) || + m.Disks.Any(f => !f.Disk.IsInRepo))), + TotalRoms = r.Machines.Sum(m => m.Files.Count) + r.Machines.Sum(m => m.Disks.Count) + + r.Machines.Sum(m => m.Medias.Count), + HaveRoms = r.Machines.Sum(m => m.Files.Count(f => f.File.IsInRepo)) + + r.Machines.Sum(m => m.Disks.Count(f => f.Disk.IsInRepo)) + + r.Machines.Sum(m => m.Medias.Count(f => f.Media.IsInRepo)), + MissRoms = r.Machines.Sum(m => m.Files.Count(f => !f.File.IsInRepo)) + + r.Machines.Sum(m => m.Disks.Count(f => !f.Disk.IsInRepo)) + + r.Machines.Sum(m => m.Medias.Count(f => !f.Media.IsInRepo)) + }).FirstOrDefault(); + + ctx.RomSetStats.Add(stats); + + Dispatcher.UIThread.Post(() => + { + RomSets.Add(new RomSetModel + { + Id = romSet.Id, + Author = romSet.Author, + Comment = romSet.Comment, + Date = romSet.Date, + Description = romSet.Description, + Filename = romSet.Filename, + Homepage = romSet.Homepage, + Name = romSet.Name, + Sha384 = romSet.Sha384, + Version = romSet.Version, + TotalMachines = stats.TotalMachines, + CompleteMachines = stats.CompleteMachines, + IncompleteMachines = stats.IncompleteMachines, + TotalRoms = stats.TotalRoms, + HaveRoms = stats.HaveRoms, + MissRoms = stats.MissRoms, + Category = romSet.Category + }); + }); + } + catch(Exception) + { + // Ignored + } + + pos++; + } + + Dispatcher.UIThread.Post(() => + { + StatusMessage = Localization.SavingChangesToDatabase; + ProgressVisible = true; + IndeterminateProgress = true; + }); + + ctx.SaveChanges(); + + Dispatcher.UIThread.Post(() => + { + StatusMessage = Localization.Finished; + ProgressVisible = false; + CanClose = true; + }); + }); + + void ExecuteCloseCommand() => _view.Close(); + } +} \ No newline at end of file diff --git a/RomRepoMgr/Views/MainWindow.xaml b/RomRepoMgr/Views/MainWindow.xaml index 8cb9bd9..7872ed0 100644 --- a/RomRepoMgr/Views/MainWindow.xaml +++ b/RomRepoMgr/Views/MainWindow.xaml @@ -41,6 +41,10 @@ + + + + diff --git a/RomRepoMgr/Views/UpdateStats.xaml b/RomRepoMgr/Views/UpdateStats.xaml new file mode 100644 index 0000000..15b6d0a --- /dev/null +++ b/RomRepoMgr/Views/UpdateStats.xaml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RomRepoMgr/Views/UpdateStats.xaml.cs b/RomRepoMgr/Views/UpdateStats.xaml.cs new file mode 100644 index 0000000..0d76d01 --- /dev/null +++ b/RomRepoMgr/Views/UpdateStats.xaml.cs @@ -0,0 +1,45 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using System; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using RomRepoMgr.ViewModels; + +namespace RomRepoMgr.Views +{ + public sealed class UpdateStats : Window + { + public UpdateStats() => InitializeComponent(); + + void InitializeComponent() => AvaloniaXamlLoader.Load(this); + + protected override void OnOpened(EventArgs e) + { + base.OnOpened(e); + (DataContext as UpdateStatsViewModel)?.OnOpened(); + } + } +} \ No newline at end of file