diff --git a/Tests/UnitTests/Serialization.cs b/Tests/UnitTests/Serialization.cs index 6f97ced1..aad7791e 100644 --- a/Tests/UnitTests/Serialization.cs +++ b/Tests/UnitTests/Serialization.cs @@ -1,7 +1,9 @@ using COMPASS.Models; using COMPASS.Services; using COMPASS.Tools; -using Ionic.Zip; +using SharpCompress.Archives; +using SharpCompress.Archives.Zip; +using SharpCompress.Common; using System.Text.Json; namespace Tests.UnitTests @@ -65,12 +67,12 @@ public async Task CheckSatchelInfoVersion() MinTagsVersion = "1.0.0", }; - var zip = new ZipFile(); + using var zip = ZipArchive.Create(); zip.AddEntry(Constants.SatchelInfoFileName, JsonSerializer.Serialize(info)); zip.AddEntry(Constants.TagsFileName, "pseudo data"); var path = Path.GetTempPath() + Guid.NewGuid().ToString() + Constants.SatchelExtension; - zip.Save(path); + zip.SaveTo(path, CompressionType.None); //Because satchel does not contain a codexInfo file, should work var collection = await IOService.OpenSatchel(path); @@ -79,7 +81,7 @@ public async Task CheckSatchelInfoVersion() //Now add a codex file zip.AddEntry(Constants.CodicesFileName, "Not important"); - zip.Save(path); + zip.SaveTo(path, CompressionType.None); //Now that the codex file is added, should be null collection = await IOService.OpenSatchel(path); diff --git a/src/Models/CodexCollection.cs b/src/Models/CodexCollection.cs index ba4ffacc..819ffd2d 100644 --- a/src/Models/CodexCollection.cs +++ b/src/Models/CodexCollection.cs @@ -21,8 +21,11 @@ public class CodexCollection : ObservableObject public CodexCollection(string collectionDirectory) { _directoryName = collectionDirectory; + _preferencesService = PreferencesService.GetInstance(); } + private PreferencesService _preferencesService; + public static string CollectionsPath => Path.Combine(SettingsViewModel.CompassDataPath, "Collections"); public string FullDataPath => Path.Combine(CollectionsPath, DirectoryName); public string CodicesDataFilePath => Path.Combine(FullDataPath, Constants.CodicesFileName); @@ -90,7 +93,7 @@ public int Load(bool MakeStartupCollection = true) if (!loadedInfo) { result -= 4; } if (MakeStartupCollection) { - Properties.Settings.Default.StartupCollection = DirectoryName; + _preferencesService.Preferences.UIState.StartupCollection = DirectoryName; Logger.Info($"Loaded {DirectoryName}"); } return result; @@ -252,7 +255,7 @@ public void Save() bool savedTags = SaveTags(); bool savedCodices = SaveCodices(); bool savedInfo = SaveInfo(); - Properties.Settings.Default.Save(); + _preferencesService.SavePreferences(); if (savedCodices || savedTags || savedInfo) { @@ -269,7 +272,7 @@ public bool SaveTags() } try { - using var writer = XmlWriter.Create(TagsDataFilePath, SettingsViewModel.XmlWriteSettings); + using var writer = XmlWriter.Create(TagsDataFilePath, XmlService.XmlWriteSettings); XmlSerializer serializer = new(typeof(List)); serializer.Serialize(writer, RootTags); } @@ -296,7 +299,7 @@ public bool SaveCodices() try { - using var writer = XmlWriter.Create(CodicesDataFilePath, SettingsViewModel.XmlWriteSettings); + using var writer = XmlWriter.Create(CodicesDataFilePath, XmlService.XmlWriteSettings); XmlSerializer serializer = new(typeof(ObservableCollection)); serializer.Serialize(writer, AllCodices); } @@ -318,7 +321,7 @@ public bool SaveInfo() Info.PrepareSave(); try { - using var writer = XmlWriter.Create(CollectionInfoFilePath, SettingsViewModel.XmlWriteSettings); + using var writer = XmlWriter.Create(CollectionInfoFilePath, XmlService.XmlWriteSettings); XmlSerializer serializer = new(typeof(CollectionInfo)); serializer.Serialize(writer, Info); } diff --git a/src/Models/CodexProperty.cs b/src/Models/CodexProperty.cs index 8d4ca429..cce2bfa2 100644 --- a/src/Models/CodexProperty.cs +++ b/src/Models/CodexProperty.cs @@ -1,19 +1,16 @@ using CommunityToolkit.Mvvm.ComponentModel; +using COMPASS.Models.XmlDtos; using COMPASS.Tools; using COMPASS.ViewModels.Sources; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Xml.Serialization; namespace COMPASS.Models { public class CodexProperty : ObservableObject { - //Empty ctor for serialization - public CodexProperty() { } - public CodexProperty(string propName, Func isEmpty, Action setProp, List defaultSources, string? label = null) { Name = propName; @@ -23,13 +20,25 @@ public CodexProperty(string propName, Func isEmpty, Action? _isEmpty; - [XmlIgnore] public Func IsEmpty { get => _isEmpty ??= Codex.Properties.First(prop => prop.Name == Name).IsEmpty; @@ -37,11 +46,9 @@ public Func IsEmpty } private Func? _getProp; - [XmlIgnore] public Func GetProp => _getProp ??= codex => codex.GetPropertyValue(Name); private Action? _setProp; - [XmlIgnore] public Action SetProp { get => _setProp ??= Codex.Properties.First(prop => prop.Name == Name).SetProp; @@ -60,8 +67,6 @@ private List DefaultSourcePriority /// /// Ordered List of sources that can set this prop, named for data binding /// - [XmlIgnore] - public ObservableCollection SourcePriorityNamed { get => _sourcePriorityNamed ??= new(SourcePriority.Select(source => new NamedMetaDataSource(source))); @@ -74,18 +79,16 @@ public ObservableCollection SourcePriorityNamed public List SourcePriority { get; set; } = new(); private MetaDataOverwriteMode _overwriteMode = MetaDataOverwriteMode.IfEmpty; - public MetaDataOverwriteMode? OverwriteMode + public MetaDataOverwriteMode OverwriteMode { get => _overwriteMode; - set - { - if (value is not null) - { - SetProperty(ref _overwriteMode, (MetaDataOverwriteMode)value); - } - } + set => SetProperty(ref _overwriteMode, value); } + #endregion + + #region Mapping + public void UpdateSources() { // If a new possible source was not found in the save, add it @@ -99,9 +102,18 @@ public void UpdateSources() SourcePriority.RemoveAll(source => !DefaultSourcePriority.Contains(source)); } - public void PrepareForSave() => - //Use order from NameMetaDataSources (which was reordered by user) - SourcePriority = SourcePriorityNamed.Select(namedSource => namedSource.Source).ToList(); + public CodexPropertyDto ToDto() + { + CodexPropertyDto dto = new() + { + Name = Name, + OverwriteMode = OverwriteMode, + //Use order from NameMetaDataSources (which was reordered by user) + SourcePriority = SourcePriorityNamed.Select(namedSource => namedSource.Source).ToList(), + }; + + return dto; + } #endregion } diff --git a/src/Models/GlobalPreferences.cs b/src/Models/GlobalPreferences.cs deleted file mode 100644 index 66e88022..00000000 --- a/src/Models/GlobalPreferences.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Xml.Serialization; - -namespace COMPASS.Models -{ - - /// - /// Class that contains all the global preferences, ready to be serialized - /// - [XmlRoot("SerializablePreferences")] - public class GlobalPreferences - { - public List? OpenFilePriorityIDs { get; set; } - public List CodexProperties { get; set; } = new(); - - public void CompleteLoading() - { - //In versions 1.6.0 and lower, label was stored instead of name - var useLabel = CodexProperties.All(prop => string.IsNullOrEmpty(prop.Name) && !string.IsNullOrEmpty(prop.Label)); - if (useLabel) - { - for (int i = 0; i < CodexProperties.Count; i++) - { - CodexProperty prop = CodexProperties[i]; - var foundProp = Codex.Properties.Find(p => p.Label == prop.Label); - if (foundProp != null) - { - foundProp.OverwriteMode = prop.OverwriteMode; - CodexProperties[i] = foundProp; - } - } - } - - - foreach (var defaultProp in Codex.Properties) - { - CodexProperty? prop = CodexProperties.Find(p => p.Name == defaultProp.Name); - // Add Preferences from defaults if they weren't found on the loaded Preferences - if (prop is null) - { - prop = defaultProp; - CodexProperties.Add(prop); - } - prop.UpdateSources(); - } - } - } -} diff --git a/src/Models/Preferences/CardLayoutPreferences.cs b/src/Models/Preferences/CardLayoutPreferences.cs new file mode 100644 index 00000000..88f73d8a --- /dev/null +++ b/src/Models/Preferences/CardLayoutPreferences.cs @@ -0,0 +1,84 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace COMPASS.Models.Preferences +{ + public class CardLayoutPreferences : ObservableObject + { + private bool _showTitle = true; + public bool ShowTitle + { + get => _showTitle; + set => SetProperty(ref _showTitle, value); + } + + public bool ShowAuthor + { + get => Properties.Settings.Default.CardShowAuthor; + set + { + Properties.Settings.Default.CardShowAuthor = value; + OnPropertyChanged(); + } + } + + public bool ShowPublisher + { + get => Properties.Settings.Default.CardShowPublisher; + set + { + Properties.Settings.Default.CardShowPublisher = value; + OnPropertyChanged(); + } + } + + public bool ShowReleaseDate + { + get => Properties.Settings.Default.CardShowRelease; + set + { + Properties.Settings.Default.CardShowRelease = value; + OnPropertyChanged(); + } + } + + public bool ShowVersion + { + get => Properties.Settings.Default.CardShowVersion; + set + { + Properties.Settings.Default.CardShowVersion = value; + OnPropertyChanged(); + } + } + + public bool ShowRating + { + get => Properties.Settings.Default.CardShowRating; + set + { + Properties.Settings.Default.CardShowRating = value; + OnPropertyChanged(); + } + } + + public bool ShowTags + { + get => Properties.Settings.Default.CardShowTags; + set + { + Properties.Settings.Default.CardShowTags = value; + OnPropertyChanged(); + } + } + + public bool ShowFileIcons + { + get => Properties.Settings.Default.CardShowFileIcons; + set + { + Properties.Settings.Default.CardShowFileIcons = value; + OnPropertyChanged(); + } + } + } +} diff --git a/src/Models/Preferences/HomeLayoutPreferences.cs b/src/Models/Preferences/HomeLayoutPreferences.cs new file mode 100644 index 00000000..8955f195 --- /dev/null +++ b/src/Models/Preferences/HomeLayoutPreferences.cs @@ -0,0 +1,30 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace COMPASS.Models.Preferences +{ + public class HomeLayoutPreferences : ObservableObject + { + public double TileWidth + { + get => Properties.Settings.Default.HomeCoverSize; + set + { + Properties.Settings.Default.HomeCoverSize = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(TileHeight)); + } + } + + public double TileHeight => (int)(TileWidth * 4 / 3); + + public bool ShowTitle + { + get => Properties.Settings.Default.HomeShowTitle; + set + { + Properties.Settings.Default.HomeShowTitle = value; + OnPropertyChanged(); + } + } + } +} diff --git a/src/Models/Preferences/ListLayoutPreferences.cs b/src/Models/Preferences/ListLayoutPreferences.cs new file mode 100644 index 00000000..4907fa36 --- /dev/null +++ b/src/Models/Preferences/ListLayoutPreferences.cs @@ -0,0 +1,114 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace COMPASS.Models.Preferences +{ + public class ListLayoutPreferences : ObservableObject + { + private bool _showTitle = true; + public bool ShowTitle + { + get => _showTitle; + set => SetProperty(ref _showTitle, value); + } + + public bool ShowAuthor + { + get => Properties.Settings.Default.ListShowAuthor; + set + { + Properties.Settings.Default.ListShowAuthor = value; + OnPropertyChanged(); + } + } + + public bool ShowPublisher + { + get => Properties.Settings.Default.ListShowPublisher; + set + { + Properties.Settings.Default.ListShowPublisher = value; + OnPropertyChanged(); + } + } + + public bool ShowReleaseDate + { + get => Properties.Settings.Default.ListShowRelease; + set + { + Properties.Settings.Default.ListShowRelease = value; + OnPropertyChanged(); + } + } + + public bool ShowDateAdded + { + get => Properties.Settings.Default.ListShowDateAdded; + set + { + Properties.Settings.Default.ListShowDateAdded = value; + OnPropertyChanged(); + } + } + + public bool ShowVersion + { + get => Properties.Settings.Default.ListShowVersion; + set + { + Properties.Settings.Default.ListShowVersion = value; + OnPropertyChanged(); + } + } + + public bool ShowRating + { + get => Properties.Settings.Default.ListShowRating; + set + { + Properties.Settings.Default.ListShowRating = value; + OnPropertyChanged(); + } + } + + public bool ShowISBN + { + get => Properties.Settings.Default.ListShowISBN; + set + { + Properties.Settings.Default.ListShowISBN = value; + OnPropertyChanged(); + } + } + + public bool ShowTags + { + get => Properties.Settings.Default.ListShowTags; + set + { + Properties.Settings.Default.ListShowTags = value; + OnPropertyChanged(); + } + } + + public bool ShowFileIcons + { + get => Properties.Settings.Default.ListShowFileIcons; + set + { + Properties.Settings.Default.ListShowFileIcons = value; + OnPropertyChanged(); + } + } + + public bool ShowEditIcon + { + get => Properties.Settings.Default.ListShowEditIcon; + set + { + Properties.Settings.Default.ListShowEditIcon = value; + OnPropertyChanged(); + } + } + } +} diff --git a/src/Models/Preferences/Preferences.cs b/src/Models/Preferences/Preferences.cs new file mode 100644 index 00000000..c849e0c8 --- /dev/null +++ b/src/Models/Preferences/Preferences.cs @@ -0,0 +1,174 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using COMPASS.Models.XmlDtos; +using COMPASS.ViewModels; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace COMPASS.Models.Preferences +{ + public class Preferences : ObservableObject + { + public Preferences() + { + _openCodexPriority = new(_openCodexFunctions); + CodexProperties = Codex.Properties.ToList(); + ListLayoutPreferences = new(); + CardLayoutPreferences = new(); + TileLayoutPreferences = new(); + HomeLayoutPreferences = new(); + UIState = new UIState(); + AutoLinkFolderTagSameName = true; + } + + public Preferences(PreferencesDto dto) + { + _openCodexPriority = MapCodexPriority(dto.OpenFilePriorityIDs); + CodexProperties = MapCodexProperties(dto.CodexProperties); + ListLayoutPreferences = dto.ListLayoutPreferences; + CardLayoutPreferences = dto.CardLayoutPreferences; + TileLayoutPreferences = dto.TileLayoutPreferences; + HomeLayoutPreferences = dto.HomeLayoutPreferences; + AutoLinkFolderTagSameName = dto.AutoLinkFolderTagSameName; + UIState = dto.UIState; + } + + #region Constants + + //list with possible functions to open a file + private static readonly List> _openCodexFunctions = new() + { + new PreferableFunction("Web Version", CodexViewModel.OpenCodexOnline,0), + new PreferableFunction("Local File", CodexViewModel.OpenCodexLocally,1) + }; + #endregion + + #region Properties + + private ObservableCollection> _openCodexPriority; + /// + /// Priority in which to try and open a code, (online or offline) + /// + public ObservableCollection> OpenCodexPriority + { + get => _openCodexPriority; + set => SetProperty(ref _openCodexPriority, value); + } + + public List CodexProperties { get; set; } + + public ListLayoutPreferences ListLayoutPreferences { get; set; } + public CardLayoutPreferences CardLayoutPreferences { get; set; } + public TileLayoutPreferences TileLayoutPreferences { get; set; } + public HomeLayoutPreferences HomeLayoutPreferences { get; set; } + + public UIState UIState { get; set; } + + public bool AutoLinkFolderTagSameName + { + get => Properties.Settings.Default.AutoLinkFolderTagSameName; + set + { + Properties.Settings.Default.AutoLinkFolderTagSameName = value; + OnPropertyChanged(); + } + } + + + + #endregion + + #region Mapping + + /// + /// Map Codex open priority from dto + /// + /// + /// + private static ObservableCollection> MapCodexPriority(List? priorityIds) + { + if (priorityIds is null) + { + return new(_openCodexFunctions); + } + + return new(_openCodexFunctions.OrderBy(pf => + { + //if preferences doesn't have file priorities, put them in default order + if (priorityIds is null) + { + return pf.ID; + } + + //get index in user preference + int index = priorityIds.IndexOf(pf.ID); + + //if it was not found in preference, use its default ID + if (index < 0) + { + return pf.ID; + } + + return index; + })); + } + + /// + /// Map codex metadata properties from dto + /// + /// + /// + private static List MapCodexProperties(List propertyDtos) + { +#pragma warning disable CS0612 // Type or member "Label" is obsolete + + //In versions 1.6.0 and lower, label was stored instead of name + var useLabel = propertyDtos.All(prop => string.IsNullOrEmpty(prop.Name) && !string.IsNullOrEmpty(prop.Label)); + if (useLabel) + { + for (int i = 0; i < propertyDtos.Count; i++) + { + CodexPropertyDto propDto = propertyDtos[i]; + var foundProp = Codex.Properties.Find(p => p.Label == propDto.Label); + if (foundProp != null) + { + propDto.Name = foundProp.Name; + } + } + } +#pragma warning restore CS0612 // Type or member "Label" is obsolete + + var props = new List(); + + foreach (var defaultProp in Codex.Properties) + { + CodexPropertyDto? propDto = propertyDtos.Find(p => p.Name == defaultProp.Name); + // Add Preferences from defaults if they weren't found on the loaded Preferences + CodexProperty prop = propDto is null ? defaultProp : new(propDto, defaultProp); + props.Add(prop); + } + + return props; + } + + public PreferencesDto ToDto() + { + PreferencesDto dto = new() + { + OpenFilePriorityIDs = OpenCodexPriority.Select(pf => pf.ID).ToList(), + CodexProperties = CodexProperties.Select(prop => prop.ToDto()).ToList(), + ListLayoutPreferences = ListLayoutPreferences, + CardLayoutPreferences = CardLayoutPreferences, + TileLayoutPreferences = TileLayoutPreferences, + HomeLayoutPreferences = HomeLayoutPreferences, + UIState = UIState, + AutoLinkFolderTagSameName = AutoLinkFolderTagSameName, + }; + + return dto; + } + + #endregion + + } +} diff --git a/src/Models/Preferences/TileLayoutPreferences.cs b/src/Models/Preferences/TileLayoutPreferences.cs new file mode 100644 index 00000000..52f8d659 --- /dev/null +++ b/src/Models/Preferences/TileLayoutPreferences.cs @@ -0,0 +1,49 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace COMPASS.Models.Preferences +{ + public class TileLayoutPreferences : ObservableObject + { + public enum DataOption + { + Title, + Author, + Publisher, + Rating + } + + public double TileWidth + { + get => Properties.Settings.Default.TileCoverSize; + set + { + Properties.Settings.Default.TileCoverSize = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(TileHeight)); + } + } + + public double TileHeight => (int)(TileWidth * 4 / 3); + + public bool ShowExtraData + { + get => Properties.Settings.Default.TileShowExtraData; + set + { + Properties.Settings.Default.TileShowExtraData = value; + OnPropertyChanged(); + } + } + + public DataOption DisplayedData + { + get => (DataOption)Properties.Settings.Default.TileDisplayedData; + set + { + Properties.Settings.Default.TileDisplayedData = (int)value; + OnPropertyChanged(); + + } + } + } +} \ No newline at end of file diff --git a/src/Models/Preferences/UIState.cs b/src/Models/Preferences/UIState.cs new file mode 100644 index 00000000..37507eee --- /dev/null +++ b/src/Models/Preferences/UIState.cs @@ -0,0 +1,47 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using COMPASS.ViewModels.Layouts; +using System.ComponentModel; + +namespace COMPASS.Models.Preferences +{ + public class UIState : ObservableObject + { + public LayoutViewModel.Layout StartupLayout + { + get => (LayoutViewModel.Layout)Properties.Settings.Default.PreferedLayout; + set => Properties.Settings.Default.PreferedLayout = (int)value; + } + public string StartupCollection + { + get => Properties.Settings.Default.StartupCollection; + set => Properties.Settings.Default.StartupCollection = value; + } + public int StartupTab + { + get => Properties.Settings.Default.SelectedTab; + set => Properties.Settings.Default.SelectedTab = value; + } + + public bool ShowCodexInfoPanel + { + get => Properties.Settings.Default.ShowCodexInfo; + set => Properties.Settings.Default.ShowCodexInfo = value; + } + public bool AutoHideCodexInfoPanel + { + get => Properties.Settings.Default.AutoHideCodexInfo; + set => Properties.Settings.Default.AutoHideCodexInfo = value; + } + + public string SortProperty + { + get => Properties.Settings.Default.SortProperty; + set => Properties.Settings.Default.SortProperty = value; + } + public ListSortDirection SortDirection + { + get => (ListSortDirection)Properties.Settings.Default.SortDirection; + set => Properties.Settings.Default.SortDirection = (int)value; + } + } +} diff --git a/src/Models/XmlDtos/CodexPropertyDto.cs b/src/Models/XmlDtos/CodexPropertyDto.cs new file mode 100644 index 00000000..24045f62 --- /dev/null +++ b/src/Models/XmlDtos/CodexPropertyDto.cs @@ -0,0 +1,26 @@ +using COMPASS.ViewModels.Sources; +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace COMPASS.Models.XmlDtos +{ + [XmlRoot("CodexProperty")] + public class CodexPropertyDto + { + public string Name { get; set; } = string.Empty; + + [Obsolete] + public string Label { get; set; } = string.Empty; + + + #region Import Sources + + public List SourcePriority { get; set; } = new(); + + public MetaDataOverwriteMode OverwriteMode { get; set; } = MetaDataOverwriteMode.IfEmpty; + + + #endregion + } +} diff --git a/src/Models/XmlDtos/PreferencesDto.cs b/src/Models/XmlDtos/PreferencesDto.cs new file mode 100644 index 00000000..4f66ea82 --- /dev/null +++ b/src/Models/XmlDtos/PreferencesDto.cs @@ -0,0 +1,30 @@ +using COMPASS.Models.Preferences; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace COMPASS.Models.XmlDtos +{ + + /// + /// Class that contains all the global preferences, ready to be serialized + /// + [XmlRoot("SerializablePreferences")] + public class PreferencesDto + { + public List? OpenFilePriorityIDs { get; set; } + + [XmlArray(ElementName = "CodexProperties")] + [XmlArrayItem(ElementName = "CodexProperty")] + public List CodexProperties { get; set; } = new(); + + + public ListLayoutPreferences ListLayoutPreferences { get; set; } = new(); + public CardLayoutPreferences CardLayoutPreferences { get; set; } = new(); + public TileLayoutPreferences TileLayoutPreferences { get; set; } = new(); + public HomeLayoutPreferences HomeLayoutPreferences { get; set; } = new(); + + public UIState UIState { get; set; } = new(); + + public bool AutoLinkFolderTagSameName { get; set; } = true; + } +} diff --git a/src/Properties/Settings.Designer.cs b/src/Properties/Settings.Designer.cs index b47a93f6..748e7eb6 100644 --- a/src/Properties/Settings.Designer.cs +++ b/src/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace COMPASS.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/src/Resources/Controls/EnhancedDataGrid.cs b/src/Resources/Controls/EnhancedDataGrid.cs index 97c0271d..04a84db1 100644 --- a/src/Resources/Controls/EnhancedDataGrid.cs +++ b/src/Resources/Controls/EnhancedDataGrid.cs @@ -1,5 +1,6 @@ //https://bengribaudo.com/blog/2012/03/14/1942/saving-restoring-wpf-datagrid-columns-size-sorting-and-order +using COMPASS.Services; using Newtonsoft.Json; using System; using System.Collections; @@ -51,6 +52,8 @@ public ObservableCollection? ColumnInfo } private void UpdateColumnInfo() { + PreferencesService prefsService = PreferencesService.GetInstance(); + updatingColumnInfo = true; ColumnInfo = new ObservableCollection(Columns.Select((x) => new ColumnInfo(x))); //persist data @@ -60,8 +63,8 @@ private void UpdateColumnInfo() SortDescription sd = Items.SortDescriptions.FirstOrDefault(); if (!string.IsNullOrEmpty(sd.PropertyName)) { - Properties.Settings.Default["SortProperty"] = sd.PropertyName; - Properties.Settings.Default["SortDirection"] = (int)sd.Direction; + prefsService.Preferences.UIState.SortProperty = sd.PropertyName; + prefsService.Preferences.UIState.SortDirection = sd.Direction; } Properties.Settings.Default["DataGridCollumnInfo"] = json; @@ -90,8 +93,10 @@ protected override void OnPreviewMouseLeftButtonUp(System.Windows.Input.MouseBut public void ApplySorting() { - int direction = (int)Properties.Settings.Default["SortDirection"]; - string prop = (string)Properties.Settings.Default["SortProperty"]; + PreferencesService prefsService = PreferencesService.GetInstance(); + + ListSortDirection direction = prefsService.Preferences.UIState.SortDirection; + string prop = prefsService.Preferences.UIState.SortProperty; if (ColumnInfo is null) return; foreach (var column in Columns) @@ -99,7 +104,7 @@ public void ApplySorting() //var realColumn = Columns.FirstOrDefault(x => column.Header == x.Header); if (column.SortMemberPath == prop) { - column.SortDirection = (ListSortDirection?)direction; + column.SortDirection = direction; return; } } diff --git a/src/Services/CoverService.cs b/src/Services/CoverService.cs index d0bf46f7..2a052f02 100644 --- a/src/Services/CoverService.cs +++ b/src/Services/CoverService.cs @@ -27,7 +27,7 @@ public static async Task GetCover(Codex codex, ChooseMetaDataViewModel? chooseMe ID = codex.ID, }; - CodexProperty coverProp = SettingsViewModel.GetInstance().MetaDataPreferences.First(prop => prop.Name == nameof(Codex.CoverArt)); + CodexProperty coverProp = PreferencesService.GetInstance().Preferences.CodexProperties.First(prop => prop.Name == nameof(Codex.CoverArt)); if (coverProp.OverwriteMode == MetaDataOverwriteMode.Ask) { diff --git a/src/Services/EnvironmentVarsService.cs b/src/Services/EnvironmentVarsService.cs new file mode 100644 index 00000000..4a9129b7 --- /dev/null +++ b/src/Services/EnvironmentVarsService.cs @@ -0,0 +1,18 @@ +using System; +using System.IO; + +namespace COMPASS.Services +{ + public static class EnvironmentVarsService + { + //vars + const string ENV_KEY_CompassDataPath = "COMPASS_DATA_PATH"; + + private static string _defaultDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "COMPASS"); + public static string CompassDataPath + { + get => Environment.GetEnvironmentVariable(ENV_KEY_CompassDataPath) ?? _defaultDataPath; + set => Environment.SetEnvironmentVariable(ENV_KEY_CompassDataPath, value, EnvironmentVariableTarget.User); //This only works on windows, so set up DI for this + } + } +} diff --git a/src/Services/PreferencesService.cs b/src/Services/PreferencesService.cs new file mode 100644 index 00000000..c4e9ba7e --- /dev/null +++ b/src/Services/PreferencesService.cs @@ -0,0 +1,66 @@ +using COMPASS.Models; +using COMPASS.Models.Preferences; +using COMPASS.Models.XmlDtos; +using COMPASS.Tools; +using COMPASS.ViewModels; +using System; +using System.IO; +using System.Xml; +using System.Xml.Serialization; + +namespace COMPASS.Services +{ + public class PreferencesService + { + #region singleton pattern + private PreferencesService() { } + private static PreferencesService? _prefService; + public static PreferencesService GetInstance() => _prefService ??= new PreferencesService(); + #endregion + + public string PreferencesFilePath => Path.Combine(SettingsViewModel.CompassDataPath, "Preferences.xml"); + + private Preferences? _preferences; + public Preferences Preferences => _preferences ??= LoadPreferences() ?? new Preferences(); + + public void SavePreferences() + { + Properties.Settings.Default.Save(); + + if (_preferences == null) return; //don't save when they aren't loaded + PreferencesDto dto = _preferences.ToDto(); + using var writer = XmlWriter.Create(PreferencesFilePath, XmlService.XmlWriteSettings); + XmlSerializer serializer = new(typeof(PreferencesDto)); + serializer.Serialize(writer, dto); + } + + public Preferences? LoadPreferences() + { + if (File.Exists(PreferencesFilePath)) + { + //Label of codexProperties should still be deserialized for backwards compatibility + var overrides = new XmlAttributeOverrides(); + var overwriteIgnore = new XmlAttributes { XmlIgnore = false }; + overrides.Add(typeof(CodexProperty), nameof(CodexProperty.Label), overwriteIgnore); + + using var reader = new StreamReader(PreferencesFilePath); + XmlSerializer serializer = new(typeof(PreferencesDto), overrides); + if (serializer.Deserialize(reader) is PreferencesDto prefsDto) + { + return prefsDto is null ? new() : new(prefsDto); + } + else + { + Logger.Error($"{PreferencesFilePath} could not be read.", new Exception()); + return null; + } + } + else + { + Logger.Warn($"{PreferencesFilePath} does not exist.", new FileNotFoundException()); + return null; + } + } + + } +} diff --git a/src/Services/XmlService.cs b/src/Services/XmlService.cs new file mode 100644 index 00000000..226a5f39 --- /dev/null +++ b/src/Services/XmlService.cs @@ -0,0 +1,9 @@ +using System.Xml; + +namespace COMPASS.Services +{ + public class XmlService + { + public static XmlWriterSettings XmlWriteSettings { get; private set; } = new() { Indent = true }; + } +} diff --git a/src/ViewModels/ChooseMetaDataViewModel.cs b/src/ViewModels/ChooseMetaDataViewModel.cs index c500d988..0acbc7aa 100644 --- a/src/ViewModels/ChooseMetaDataViewModel.cs +++ b/src/ViewModels/ChooseMetaDataViewModel.cs @@ -17,7 +17,7 @@ public class ChooseMetaDataViewModel : WizardViewModel private List _codicesWithMadeChoices = new(); public List PropsToAsk => - SettingsViewModel.GetInstance().MetaDataPreferences + PreferencesService.GetInstance().Preferences.CodexProperties .Where(prop => prop.OverwriteMode == MetaDataOverwriteMode.Ask) .ToList(); diff --git a/src/ViewModels/CodexEditViewModel.cs b/src/ViewModels/CodexEditViewModel.cs index 003a8812..4550787b 100644 --- a/src/ViewModels/CodexEditViewModel.cs +++ b/src/ViewModels/CodexEditViewModel.cs @@ -165,12 +165,11 @@ private async Task FetchCoverAsync() { ShowLoading = true; //make it so cover always gets overwritten if this case, store old value first - CodexProperty coverProp = SettingsViewModel.GetInstance().MetaDataPreferences.First(prop => prop.Name == nameof(Codex.CoverArt)); - Debug.Assert(coverProp.OverwriteMode != null, "coverProp.OverwriteMode != null"); - MetaDataOverwriteMode curSetting = (MetaDataOverwriteMode)coverProp.OverwriteMode; + CodexProperty coverProp = PreferencesService.GetInstance().Preferences.CodexProperties.First(prop => prop.Name == nameof(Codex.CoverArt)); + MetaDataOverwriteMode curSetting = coverProp.OverwriteMode; coverProp.OverwriteMode = MetaDataOverwriteMode.Always; //get the cover - await Task.Run(() => CoverService.GetCover(TempCodex)); + await CoverService.GetCover(TempCodex); //Restore cover preference coverProp.OverwriteMode = curSetting; ShowLoading = false; diff --git a/src/ViewModels/CodexInfoViewModel.cs b/src/ViewModels/CodexInfoViewModel.cs index 1ed5d3b4..9f90ecdc 100644 --- a/src/ViewModels/CodexInfoViewModel.cs +++ b/src/ViewModels/CodexInfoViewModel.cs @@ -1,5 +1,6 @@ using CommunityToolkit.Mvvm.Input; using COMPASS.Models; +using COMPASS.Services; namespace COMPASS.ViewModels { @@ -9,15 +10,18 @@ public class CodexInfoViewModel : ViewModelBase public CodexInfoViewModel(MainViewModel mvm) { MVM = mvm; + _preferencesService = PreferencesService.GetInstance(); } + private PreferencesService _preferencesService; + //whether or not the codex info panel is active public bool ShowCodexInfo { - get => Properties.Settings.Default.ShowCodexInfo; + get => _preferencesService.Preferences.UIState.ShowCodexInfoPanel; set { - Properties.Settings.Default.ShowCodexInfo = value; + _preferencesService.Preferences.UIState.ShowCodexInfoPanel = value; OnPropertyChanged(nameof(ShowInfo)); OnPropertyChanged(); } @@ -29,10 +33,10 @@ public bool ShowCodexInfo public bool AutoHide { - get => Properties.Settings.Default.AutoHideCodexInfo; + get => _preferencesService.Preferences.UIState.AutoHideCodexInfoPanel; set { - Properties.Settings.Default.AutoHideCodexInfo = value; + _preferencesService.Preferences.UIState.AutoHideCodexInfoPanel = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowInfo)); } diff --git a/src/ViewModels/CodexViewModel.cs b/src/ViewModels/CodexViewModel.cs index 5f795126..1ee0f22a 100644 --- a/src/ViewModels/CodexViewModel.cs +++ b/src/ViewModels/CodexViewModel.cs @@ -26,7 +26,7 @@ public class CodexViewModel : ViewModelBase, IDropTarget //Open Codex wherever public static bool OpenCodex(Codex codex) { - bool success = PreferableFunction.TryFunctions(SettingsViewModel.GetInstance().OpenCodexPriority, codex); + bool success = PreferableFunction.TryFunctions(PreferencesService.GetInstance().Preferences.OpenCodexPriority, codex); if (!success) { messageDialog.Show("Could not open item, please check local path or URL", "Could not open item"); @@ -409,15 +409,14 @@ private static async Task GetMetaData(Codex codex, ChooseMetaDataViewModel choos metaDataFromSource.Add(MetaDataSource.PDF, pdfData); } - // Now use bits and pieces of the Codices in MetaDataFromSource to set the actual metadata based on preferences - var properties = SettingsViewModel.GetInstance().MetaDataPreferences; + // Now use bits and pieces of the Codices in MetaDataFromSource to set the actual metadata based on preferences //Codex with metadata that will be shown to the user, and asked if they want to use it Codex toAsk = new(); bool shouldAsk = false; //Iterate over all the properties and set them - foreach (var prop in properties) + foreach (var prop in PreferencesService.GetInstance().Preferences.CodexProperties) { if (prop.OverwriteMode == MetaDataOverwriteMode.Never) continue; diff --git a/src/ViewModels/CollectionViewModel.cs b/src/ViewModels/CollectionViewModel.cs index 98f90b6f..9cfc826b 100644 --- a/src/ViewModels/CollectionViewModel.cs +++ b/src/ViewModels/CollectionViewModel.cs @@ -1,6 +1,5 @@ using CommunityToolkit.Mvvm.Input; using COMPASS.Models; -using COMPASS.Properties; using COMPASS.Services; using COMPASS.Tools; using COMPASS.ViewModels.Import; @@ -24,6 +23,7 @@ public class CollectionViewModel : ViewModelBase public CollectionViewModel(MainViewModel? mainViewModel) { MainVM = mainViewModel; + _preferencesService = PreferencesService.GetInstance(); //only to avoid null references, should be overwritten as soon as the UI loads, which calls refresh _filterVM = new(new()); @@ -44,6 +44,8 @@ public CollectionViewModel(MainViewModel? mainViewModel) Debug.Assert(_currentCollection is not null, "Current Collection should never be null after loading Initial Collection"); } + private PreferencesService _preferencesService; + #region Properties public MainViewModel? MainVM { get; init; } @@ -130,9 +132,9 @@ private void LoadInitialCollection() } //otherwise, open startup collection - else if (AllCodexCollections.Any(collection => collection.DirectoryName == Settings.Default.StartupCollection)) + else if (AllCodexCollections.Any(collection => collection.DirectoryName == _preferencesService.Preferences.UIState.StartupCollection)) { - var startupCollection = AllCodexCollections.First(collection => collection.DirectoryName == Settings.Default.StartupCollection); + var startupCollection = AllCodexCollections.First(collection => collection.DirectoryName == _preferencesService.Preferences.UIState.StartupCollection); initSuccess = TryLoadCollection(startupCollection); if (!initSuccess) { @@ -144,7 +146,7 @@ private void LoadInitialCollection() //in case startup collection no longer exists, pick first one that does exists else { - Logger.Warn($"The collection {Settings.Default.StartupCollection} could not be found.", new DirectoryNotFoundException()); + Logger.Warn($"The collection {_preferencesService.Preferences.UIState.StartupCollection} could not be found.", new DirectoryNotFoundException()); var firstCollection = AllCodexCollections.First(); initSuccess = TryLoadCollection(firstCollection); if (!initSuccess) diff --git a/src/ViewModels/FilterViewModel.cs b/src/ViewModels/FilterViewModel.cs index c3301efc..9454ab56 100644 --- a/src/ViewModels/FilterViewModel.cs +++ b/src/ViewModels/FilterViewModel.cs @@ -1,6 +1,6 @@ using CommunityToolkit.Mvvm.Input; using COMPASS.Models; -using COMPASS.Properties; +using COMPASS.Services; using COMPASS.Tools; using FuzzySharp; using GongSolutions.Wpf.DragDrop; @@ -40,6 +40,8 @@ public FilterViewModel(ObservableCollection allCodices) #region Fields + PreferencesService _preferencesService = PreferencesService.GetInstance(); + private ObservableCollection _allCodices; private readonly int _itemsShown = 15; public int ItemsShown => Math.Min(_itemsShown, FilteredCodices?.Count ?? 0); @@ -210,11 +212,10 @@ public int MinRating public ListSortDirection SortDirection { - get => (ListSortDirection)Settings.Default[nameof(SortDirection)]; + get => _preferencesService.Preferences.UIState.SortDirection; set { - Settings.Default[nameof(SortDirection)] = (int)value; - Settings.Default.Save(); + _preferencesService.Preferences.UIState.SortDirection = value; ApplySorting(); OnPropertyChanged(); } @@ -222,11 +223,10 @@ public ListSortDirection SortDirection public string SortProperty { - get => (string)Settings.Default[nameof(SortProperty)]; + get => _preferencesService.Preferences.UIState.SortProperty; set { - Settings.Default[nameof(SortProperty)] = value; - Settings.Default.Save(); + _preferencesService.Preferences.UIState.SortProperty = value; ApplySorting(); OnPropertyChanged(); } diff --git a/src/ViewModels/Layouts/CardLayoutViewModel.cs b/src/ViewModels/Layouts/CardLayoutViewModel.cs index cc926664..19873183 100644 --- a/src/ViewModels/Layouts/CardLayoutViewModel.cs +++ b/src/ViewModels/Layouts/CardLayoutViewModel.cs @@ -1,95 +1,19 @@ -namespace COMPASS.ViewModels.Layouts +using COMPASS.Models.Preferences; +using COMPASS.Services; + +namespace COMPASS.ViewModels.Layouts { public class CardLayoutViewModel : LayoutViewModel { public CardLayoutViewModel() : base() { LayoutType = Layout.Card; + Preferences = PreferencesService.GetInstance().Preferences.CardLayoutPreferences; } - public override bool DoVirtualization => Properties.Settings.Default.DoVirtualizationCard + public override bool DoVirtualization => Properties.Settings.Default.DoVirtualizationCard && MainViewModel.CollectionVM.CurrentCollection.AllCodices.Count > Properties.Settings.Default.VirtualizationThresholdCard; - #region Options - - private bool _showTitle = true; - public bool ShowTitle - { - get => _showTitle; - set => SetProperty(ref _showTitle, value); - } - - public bool ShowAuthor - { - get => Properties.Settings.Default.CardShowAuthor; - set - { - Properties.Settings.Default.CardShowAuthor = value; - OnPropertyChanged(); - } - } - - public bool ShowPublisher - { - get => Properties.Settings.Default.CardShowPublisher; - set - { - Properties.Settings.Default.CardShowPublisher = value; - OnPropertyChanged(); - } - } - - public bool ShowReleaseDate - { - get => Properties.Settings.Default.CardShowRelease; - set - { - Properties.Settings.Default.CardShowRelease = value; - OnPropertyChanged(); - } - } - - public bool ShowVersion - { - get => Properties.Settings.Default.CardShowVersion; - set - { - Properties.Settings.Default.CardShowVersion = value; - OnPropertyChanged(); - } - } - - public bool ShowRating - { - get => Properties.Settings.Default.CardShowRating; - set - { - Properties.Settings.Default.CardShowRating = value; - OnPropertyChanged(); - } - } - - public bool ShowTags - { - get => Properties.Settings.Default.CardShowTags; - set - { - Properties.Settings.Default.CardShowTags = value; - OnPropertyChanged(); - } - } - - public bool ShowFileIcons - { - get => Properties.Settings.Default.CardShowFileIcons; - set - { - Properties.Settings.Default.CardShowFileIcons = value; - OnPropertyChanged(); - } - } - - #endregion - + public CardLayoutPreferences Preferences { get; init; } } } diff --git a/src/ViewModels/Layouts/HomeLayoutViewModel.cs b/src/ViewModels/Layouts/HomeLayoutViewModel.cs index ed089986..ca30aa71 100644 --- a/src/ViewModels/Layouts/HomeLayoutViewModel.cs +++ b/src/ViewModels/Layouts/HomeLayoutViewModel.cs @@ -1,35 +1,18 @@ -namespace COMPASS.ViewModels.Layouts +using COMPASS.Models.Preferences; +using COMPASS.Services; + +namespace COMPASS.ViewModels.Layouts { internal class HomeLayoutViewModel : LayoutViewModel { public HomeLayoutViewModel() : base() { LayoutType = Layout.Home; + Preferences = PreferencesService.GetInstance().Preferences.HomeLayoutPreferences; } public override bool DoVirtualization => false; - public double TileWidth - { - get => Properties.Settings.Default.HomeCoverSize; - set - { - Properties.Settings.Default.HomeCoverSize = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(TileHeight)); - } - } - - public double TileHeight => (int)(TileWidth * 4 / 3); - - public bool ShowTitle - { - get => Properties.Settings.Default.HomeShowTitle; - set - { - Properties.Settings.Default.HomeShowTitle = value; - OnPropertyChanged(); - } - } + public HomeLayoutPreferences Preferences { get; set; } } } diff --git a/src/ViewModels/Layouts/LayoutViewModel.cs b/src/ViewModels/Layouts/LayoutViewModel.cs index d5f805cf..717dbaa1 100644 --- a/src/ViewModels/Layouts/LayoutViewModel.cs +++ b/src/ViewModels/Layouts/LayoutViewModel.cs @@ -1,4 +1,5 @@ using COMPASS.Models; +using COMPASS.Services; using COMPASS.ViewModels.Import; using GongSolutions.Wpf.DragDrop; using System; @@ -22,18 +23,16 @@ public enum Layout // but I don't see the point, seems a lot of boilerplate without real advantages public static LayoutViewModel GetLayout(Layout? layout = null) { - layout ??= (Layout)Properties.Settings.Default.PreferedLayout; - Properties.Settings.Default.PreferedLayout = (int)layout; - LayoutViewModel? newLayout = layout switch + layout ??= PreferencesService.GetInstance().Preferences.UIState.StartupLayout; + PreferencesService.GetInstance().Preferences.UIState.StartupLayout = (Layout)layout; + return layout switch { Layout.Home => new HomeLayoutViewModel(), Layout.List => new ListLayoutViewModel(), Layout.Card => new CardLayoutViewModel(), Layout.Tile => new TileLayoutViewModel(), - _ => null + _ => throw new NotImplementedException(layout.ToString()) }; - if (newLayout == null) throw new NotImplementedException(layout.ToString()); - return newLayout; } public void UpdateDoVirtualization() => OnPropertyChanged(nameof(DoVirtualization)); diff --git a/src/ViewModels/Layouts/ListLayoutViewModel.cs b/src/ViewModels/Layouts/ListLayoutViewModel.cs index 4d75aa3a..a719c279 100644 --- a/src/ViewModels/Layouts/ListLayoutViewModel.cs +++ b/src/ViewModels/Layouts/ListLayoutViewModel.cs @@ -1,126 +1,21 @@ -namespace COMPASS.ViewModels.Layouts +using COMPASS.Models.Preferences; +using COMPASS.Services; + +namespace COMPASS.ViewModels.Layouts { public class ListLayoutViewModel : LayoutViewModel { public ListLayoutViewModel() { LayoutType = Layout.List; + Preferences = PreferencesService.GetInstance().Preferences.ListLayoutPreferences; } public override bool DoVirtualization => Properties.Settings.Default.DoVirtualizationList && MainViewModel.CollectionVM.CurrentCollection.AllCodices.Count > Properties.Settings.Default.VirtualizationThresholdList; - #region ViewOptions - - private bool _showTitle = true; - public bool ShowTitle - { - get => _showTitle; - set => SetProperty(ref _showTitle, value); - } - - public bool ShowAuthor - { - get => Properties.Settings.Default.ListShowAuthor; - set - { - Properties.Settings.Default.ListShowAuthor = value; - OnPropertyChanged(); - } - } - - public bool ShowPublisher - { - get => Properties.Settings.Default.ListShowPublisher; - set - { - Properties.Settings.Default.ListShowPublisher = value; - OnPropertyChanged(); - } - } - - public bool ShowReleaseDate - { - get => Properties.Settings.Default.ListShowRelease; - set - { - Properties.Settings.Default.ListShowRelease = value; - OnPropertyChanged(); - } - } - - public bool ShowDateAdded - { - get => Properties.Settings.Default.ListShowDateAdded; - set - { - Properties.Settings.Default.ListShowDateAdded = value; - OnPropertyChanged(); - } - } - - public bool ShowVersion - { - get => Properties.Settings.Default.ListShowVersion; - set - { - Properties.Settings.Default.ListShowVersion = value; - OnPropertyChanged(); - } - } - - public bool ShowRating - { - get => Properties.Settings.Default.ListShowRating; - set - { - Properties.Settings.Default.ListShowRating = value; - OnPropertyChanged(); - } - } - - public bool ShowISBN - { - get => Properties.Settings.Default.ListShowISBN; - set - { - Properties.Settings.Default.ListShowISBN = value; - OnPropertyChanged(); - } - } - - public bool ShowTags - { - get => Properties.Settings.Default.ListShowTags; - set - { - Properties.Settings.Default.ListShowTags = value; - OnPropertyChanged(); - } - } - - public bool ShowFileIcons - { - get => Properties.Settings.Default.ListShowFileIcons; - set - { - Properties.Settings.Default.ListShowFileIcons = value; - OnPropertyChanged(); - } - } - - public bool ShowEditIcon - { - get => Properties.Settings.Default.ListShowEditIcon; - set - { - Properties.Settings.Default.ListShowEditIcon = value; - OnPropertyChanged(); - } - } - - #endregion + public ListLayoutPreferences Preferences { get; } } } diff --git a/src/ViewModels/Layouts/TileLayoutViewModel.cs b/src/ViewModels/Layouts/TileLayoutViewModel.cs index 755bff0d..8010558d 100644 --- a/src/ViewModels/Layouts/TileLayoutViewModel.cs +++ b/src/ViewModels/Layouts/TileLayoutViewModel.cs @@ -1,57 +1,19 @@ -namespace COMPASS.ViewModels.Layouts +using COMPASS.Models.Preferences; +using COMPASS.Services; + +namespace COMPASS.ViewModels.Layouts { public class TileLayoutViewModel : LayoutViewModel { public TileLayoutViewModel() { LayoutType = Layout.Tile; + Preferences = PreferencesService.GetInstance().Preferences.TileLayoutPreferences; } - public override bool DoVirtualization => Properties.Settings.Default.DoVirtualizationTile + public override bool DoVirtualization => Properties.Settings.Default.DoVirtualizationTile && MainViewModel.CollectionVM.CurrentCollection.AllCodices.Count > Properties.Settings.Default.VirtualizationThresholdTile; - public enum DataOption - { - Title, - Author, - Publisher, - Rating - } - - #region Properties - public double TileWidth - { - get => Properties.Settings.Default.TileCoverSize; - set - { - Properties.Settings.Default.TileCoverSize = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(TileHeight)); - } - } - - public double TileHeight => (int)(TileWidth * 4 / 3); - - public bool ShowExtraData - { - get => Properties.Settings.Default.TileShowExtraData; - set - { - Properties.Settings.Default.TileShowExtraData = value; - OnPropertyChanged(); - } - } - - public DataOption DisplayedData - { - get => (DataOption)Properties.Settings.Default.TileDisplayedData; - set - { - Properties.Settings.Default.TileDisplayedData = (int)value; - OnPropertyChanged(); - } - } - - #endregion + public TileLayoutPreferences Preferences { get; set; } } } diff --git a/src/ViewModels/LeftDockViewModel.cs b/src/ViewModels/LeftDockViewModel.cs index 56f52415..797ffc6d 100644 --- a/src/ViewModels/LeftDockViewModel.cs +++ b/src/ViewModels/LeftDockViewModel.cs @@ -13,9 +13,12 @@ public class LeftDockViewModel : ViewModelBase, IDealsWithTabControl public LeftDockViewModel(MainViewModel mainViewModel) { _mainVM = mainViewModel; + _preferencesService = PreferencesService.GetInstance(); } private MainViewModel _mainVM; + private PreferencesService _preferencesService; + public MainViewModel MainVM { get => _mainVM; @@ -24,10 +27,10 @@ public MainViewModel MainVM public int SelectedTab { - get => Properties.Settings.Default.SelectedTab; + get => _preferencesService.Preferences.UIState.StartupTab; set { - Properties.Settings.Default.SelectedTab = value; + _preferencesService.Preferences.UIState.StartupTab = value; OnPropertyChanged(); if (value > 0) Collapsed = false; } diff --git a/src/ViewModels/SettingsViewModel.cs b/src/ViewModels/SettingsViewModel.cs index aa4f0d0b..32db145b 100644 --- a/src/ViewModels/SettingsViewModel.cs +++ b/src/ViewModels/SettingsViewModel.cs @@ -2,6 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using COMPASS.Models; +using COMPASS.Models.Preferences; using COMPASS.Services; using COMPASS.Tools; using COMPASS.ViewModels.Import; @@ -11,7 +12,6 @@ using SharpCompress.Archives.Zip; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.IO; @@ -20,8 +20,6 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Data; -using System.Xml; -using System.Xml.Serialization; namespace COMPASS.ViewModels { @@ -29,11 +27,10 @@ public class SettingsViewModel : ObservableObject { private SettingsViewModel() { - //Set defaults - _openCodexPriority = new(_openCodexFunctions); + _preferencesService = PreferencesService.GetInstance(); - LoadGlobalPreferences(); - _allPreferences.CompleteLoading(); + //Save the compass data path into an env var, needed for cross platform transition + EnvironmentVarsService.CompassDataPath = Properties.Settings.Default.CompassDataPath; } #region singleton pattern @@ -41,83 +38,20 @@ private SettingsViewModel() public static SettingsViewModel GetInstance() => _settingsVM ??= new SettingsViewModel(); #endregion + PreferencesService _preferencesService; + public MainViewModel? MVM { get; set; } #region Load and Save Settings - public static string PreferencesFilePath => Path.Combine(CompassDataPath, "Preferences.xml"); - public static XmlWriterSettings XmlWriteSettings { get; private set; } = new() { Indent = true }; - private static GlobalPreferences _allPreferences = new(); - private void PreparePreferencesForSave() - { - //Prep Open Codex Priority for save - _allPreferences.OpenFilePriorityIDs = OpenCodexPriority.Select(pf => pf.ID).ToList(); + public Preferences Preferences => _preferencesService.Preferences; - //Prep Codex Properties for saves - foreach (CodexProperty prop in _allPreferences.CodexProperties) - { - prop.PrepareForSave(); - } - } - - public void SavePreferences() + public void ApplyPreferences() { - PreparePreferencesForSave(); - using var writer = XmlWriter.Create(PreferencesFilePath, XmlWriteSettings); - XmlSerializer serializer = new(typeof(GlobalPreferences)); - serializer.Serialize(writer, _allPreferences); - //Convert list back to dict because dict does not support two way binding MainViewModel.CollectionVM.CurrentCollection.Info.FiletypePreferences = FiletypePreferences.ToDictionary(x => x.Key, x => x.Value); - } - - public void LoadGlobalPreferences() - { - if (File.Exists(PreferencesFilePath)) - { - using (var reader = new StreamReader(PreferencesFilePath)) - { - //Label of codexProperties should still be deserialized for backwards compatibility - var overrides = new XmlAttributeOverrides(); - var overwriteIgnore = new XmlAttributes { XmlIgnore = false }; - overrides.Add(typeof(CodexProperty), nameof(CodexProperty.Label), overwriteIgnore); - XmlSerializer serializer = new(typeof(GlobalPreferences), overrides); - if (serializer.Deserialize(reader) is GlobalPreferences prefs) - { - _allPreferences = prefs; - } - else - { - Logger.Error($"{PreferencesFilePath} could not be read.", new Exception()); - return; - } - } - //put openFilePriority in right order - OpenCodexPriority = new(_openCodexFunctions.OrderBy(pf => - { - //if preferences doesn't have file priorities, put them in default order - if (_allPreferences.OpenFilePriorityIDs is null) - { - return pf.ID; - } - - //get index in user preference - int index = _allPreferences.OpenFilePriorityIDs.IndexOf(pf.ID); - - //if it was not found in preference, use its default ID - if (index < 0) - { - return pf.ID; - } - - return index; - })); - } - else - { - Logger.Warn($"{PreferencesFilePath} does not exist.", new FileNotFoundException()); - } + _preferencesService.SavePreferences(); } public void Refresh() @@ -130,22 +64,6 @@ public void Refresh() #region Tab: Preferences - #region File Source Preference - //list with possible functions to open a file - private readonly List> _openCodexFunctions = new() - { - new PreferableFunction("Web Version", CodexViewModel.OpenCodexOnline,0), - new PreferableFunction("Local File", CodexViewModel.OpenCodexLocally,1) - }; - //same ordered version of the list - private ObservableCollection> _openCodexPriority; - public ObservableCollection> OpenCodexPriority - { - get => _openCodexPriority; - set => SetProperty(ref _openCodexPriority, value); - } - #endregion - #region Virtualization Preferences public bool DoVirtualizationList @@ -378,10 +296,10 @@ private void DetectFolderTagPairs() public bool AutoLinkFolderTagSameName { - get => Properties.Settings.Default.AutoLinkFolderTagSameName; + get => _preferencesService.Preferences.AutoLinkFolderTagSameName; set { - Properties.Settings.Default.AutoLinkFolderTagSameName = value; + _preferencesService.Preferences.AutoLinkFolderTagSameName = value; OnPropertyChanged(); } } @@ -390,7 +308,7 @@ public bool AutoLinkFolderTagSameName #endregion #region Tab: Metadata - public List MetaDataPreferences => _allPreferences.CodexProperties; + public List MetaDataPreferences => Preferences.CodexProperties; #endregion #region Tab: Data @@ -505,6 +423,7 @@ public static string CompassDataPath set { Properties.Settings.Default.CompassDataPath = value; + EnvironmentVarsService.CompassDataPath = value; Properties.Settings.Default.Save(); } } @@ -708,8 +627,8 @@ public async Task BackupLocalFiles() _lw.Show(); //save first + ApplyPreferences(); MainViewModel.CollectionVM.CurrentCollection.Save(); - SavePreferences(); await Task.Run(() => CompressUserDataToZip(targetPath)); @@ -739,7 +658,7 @@ public async Task RestoreBackup() await Task.Run(() => ExtractZip(targetPath)); //restore collection that was open - MainViewModel.CollectionVM.CurrentCollection = new(Properties.Settings.Default.StartupCollection); + MainViewModel.CollectionVM.CurrentCollection = new(_preferencesService.Preferences.UIState.StartupCollection); _lw?.Close(); } } diff --git a/src/ViewModels/Sources/FileSourceViewModel.cs b/src/ViewModels/Sources/FileSourceViewModel.cs index a24c21b0..07f24d6b 100644 --- a/src/ViewModels/Sources/FileSourceViewModel.cs +++ b/src/ViewModels/Sources/FileSourceViewModel.cs @@ -1,4 +1,5 @@ using COMPASS.Models; +using COMPASS.Services; using COMPASS.Tools; using FuzzySharp; using System.Diagnostics; @@ -10,6 +11,12 @@ namespace COMPASS.ViewModels.Sources { public class FileSourceViewModel : SourceViewModel { + public FileSourceViewModel() + { + _preferencesService = PreferencesService.GetInstance(); + } + + private PreferencesService _preferencesService; public override MetaDataSource Source => MetaDataSource.File; public override Task FetchCover(Codex codex) => throw new System.NotImplementedException(); @@ -33,7 +40,7 @@ public override Task GetMetaData(Codex codex) } } - if (Properties.Settings.Default.AutoLinkFolderTagSameName) + if (_preferencesService.Preferences.AutoLinkFolderTagSameName) { foreach (Tag tag in MainViewModel.CollectionVM.CurrentCollection.AllTags) { diff --git a/src/Views/CardLayout.xaml b/src/Views/CardLayout.xaml index e4eacf75..faaa300e 100644 --- a/src/Views/CardLayout.xaml +++ b/src/Views/CardLayout.xaml @@ -92,7 +92,7 @@ Mode=OneWay, TargetNullValue=Media\\CoverPlaceholder.png }" HorizontalAlignment="Center" MaxHeight="{Binding ActualHeight, ElementName=PropGrid}" Stretch="UniformToFill"/> @@ -102,7 +102,7 @@