diff --git a/Application/Data/LegacyDatabase.cs b/Application/Data/LegacyDatabase.cs index 768d5d3..d48b2d9 100644 --- a/Application/Data/LegacyDatabase.cs +++ b/Application/Data/LegacyDatabase.cs @@ -185,6 +185,9 @@ public static class LegacyDatabase { foreach (var category in categories) { + if (category.Name == Category.DefaultName) + category.IsDefault = true; + category.Feeds = feeds.Where(f => f.CategoryId == category.Id).ToList(); } diff --git a/Application/Data/RealmObservableCollection.cs b/Application/Data/RealmObservableCollection.cs index 02eef85..5ccd46a 100644 --- a/Application/Data/RealmObservableCollection.cs +++ b/Application/Data/RealmObservableCollection.cs @@ -26,4 +26,4 @@ namespace FeedCenter.Data base.OnCollectionChanged(e); } } -} +} \ No newline at end of file diff --git a/Application/Entities.cs b/Application/Entities.cs index 39f0005..4153af6 100644 --- a/Application/Entities.cs +++ b/Application/Entities.cs @@ -8,9 +8,9 @@ namespace FeedCenter { public class FeedCenterEntities { - public Realm Realm { get; private set; } + public Realm RealmInstance { get; } - public RealmObservableCollection Categories { get; private set; } + public RealmObservableCollection Categories { get; } public RealmObservableCollection Feeds { get; private set; } public RealmObservableCollection Settings { get; private set; } @@ -18,26 +18,31 @@ namespace FeedCenter { var realmConfiguration = new RealmConfiguration($"{Database.DatabaseFile}"); - Realm = Realm.GetInstance(realmConfiguration); + RealmInstance = Realm.GetInstance(realmConfiguration); - Settings = new RealmObservableCollection(Realm); - Feeds = new RealmObservableCollection(Realm); - Categories = new RealmObservableCollection(Realm); + Settings = new RealmObservableCollection(RealmInstance); + Feeds = new RealmObservableCollection(RealmInstance); + Categories = new RealmObservableCollection(RealmInstance); if (!Categories.Any()) { - Realm.Write(() => Categories.Add(Category.CreateDefault())); + RealmInstance.Write(() => Categories.Add(Category.CreateDefault())); } } public void Refresh() { - Realm.Refresh(); + RealmInstance.Refresh(); } public void SaveChanges(Action action) { - Realm.Write(action); + RealmInstance.Write(action); + } + + public Transaction BeginTransaction() + { + return RealmInstance.BeginWrite(); } public Category DefaultCategory diff --git a/Application/FeedErrorWindow.xaml.cs b/Application/FeedErrorWindow.xaml.cs index 38e30f3..1414bf7 100644 --- a/Application/FeedErrorWindow.xaml.cs +++ b/Application/FeedErrorWindow.xaml.cs @@ -65,7 +65,7 @@ namespace FeedCenter var feedWindow = new FeedWindow(); - feedWindow.Display(_database, feed, GetWindow(this)); + feedWindow.Display(feed, GetWindow(this)); } private void DeleteSelectedFeed() diff --git a/Application/Feeds/Category.cs b/Application/Feeds/Category.cs index 1789bea..b2de669 100644 --- a/Application/Feeds/Category.cs +++ b/Application/Feeds/Category.cs @@ -1,33 +1,90 @@ using Realms; using System; +using System.Collections; using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; namespace FeedCenter { - public class Category : RealmObject + public class Category : RealmObject, INotifyDataErrorInfo { - private const string DefaultCategoryName = "< default >"; + public const string DefaultName = "< default >"; + + private readonly Dictionary> _errorsByPropertyName = new(); [PrimaryKey] - [MapTo("ID")] - public Guid Id { get; set; } - public string Name { get; set; } + public Guid Id { get; set; } = Guid.NewGuid(); + + [MapTo("Name")] + private string RawName { get; set; } = string.Empty; + + public string Name + { + get => RawName; + set + { + RawName = value; + + ValidateName(); + RaisePropertyChanged(); + } + } [Ignored] public ICollection Feeds { get; set; } - public static Category Create() - { - return new Category { Id = Guid.NewGuid() }; - } public static Category CreateDefault() { - return new Category { Id = Guid.NewGuid(), Name = DefaultCategoryName }; + return new Category { Name = DefaultName, IsDefault = true }; } - public bool IsDefault => Name == DefaultCategoryName; + public bool IsDefault { get; internal set; } // ReSharper disable once UnusedMember.Global public int SortKey => IsDefault ? 0 : 1; + + public bool HasErrors => _errorsByPropertyName.Any(); + + public event EventHandler ErrorsChanged; + + public IEnumerable GetErrors(string propertyName) + { + return _errorsByPropertyName.TryGetValue(propertyName, out var value) ? value : null; + } + + private void OnErrorsChanged(string propertyName) + { + ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); + } + + private void ValidateName() + { + ClearErrors(nameof(Name)); + + if (string.IsNullOrWhiteSpace(Name)) + AddError(nameof(Name), "Name cannot be empty"); + } + + private void AddError(string propertyName, string error) + { + if (!_errorsByPropertyName.ContainsKey(propertyName)) + _errorsByPropertyName[propertyName] = new List(); + + if (_errorsByPropertyName[propertyName].Contains(error)) + return; + + _errorsByPropertyName[propertyName].Add(error); + OnErrorsChanged(propertyName); + } + + private void ClearErrors(string propertyName) + { + if (!_errorsByPropertyName.ContainsKey(propertyName)) + return; + + _errorsByPropertyName.Remove(propertyName); + OnErrorsChanged(propertyName); + } } -} +} \ No newline at end of file diff --git a/Application/Feeds/Feed.cs b/Application/Feeds/Feed.cs index c232cb4..83e4ec7 100644 --- a/Application/Feeds/Feed.cs +++ b/Application/Feeds/Feed.cs @@ -1,4 +1,5 @@ using ChrisKaczor.ApplicationUpdate; +using FeedCenter.Data; using FeedCenter.FeedParsers; using FeedCenter.Properties; using FeedCenter.Xml; @@ -118,9 +119,9 @@ namespace FeedCenter private static HttpClient _httpClient; - public static Feed Create(FeedCenterEntities database) + public static Feed Create() { - return new Feed { Id = Guid.NewGuid(), CategoryId = database.DefaultCategory.Id }; + return new Feed { Id = Guid.NewGuid(), CategoryId = Database.Entities.DefaultCategory.Id }; } #region Reading diff --git a/Application/MainWindow/FeedCreation.cs b/Application/MainWindow/FeedCreation.cs index 044e3b6..48a5222 100644 --- a/Application/MainWindow/FeedCreation.cs +++ b/Application/MainWindow/FeedCreation.cs @@ -20,7 +20,7 @@ namespace FeedCenter private void HandleNewFeed(string feedUrl) { // Create and configure the new feed - var feed = Feed.Create(_database); + var feed = Feed.Create(); feed.Source = feedUrl; feed.Category = _database.DefaultCategory; @@ -85,7 +85,7 @@ namespace FeedCenter // Feed read failed - create a new feed window var feedForm = new FeedWindow(); - var dialogResult = feedForm.Display(_database, feed, this); + var dialogResult = feedForm.Display(feed, this); // Display the new feed form if (dialogResult.HasValue && dialogResult.Value) diff --git a/Application/MainWindow/Toolbar.cs b/Application/MainWindow/Toolbar.cs index cf2ba87..231b188 100644 --- a/Application/MainWindow/Toolbar.cs +++ b/Application/MainWindow/Toolbar.cs @@ -145,7 +145,7 @@ namespace FeedCenter var feedWindow = new FeedWindow(); // Display the feed window and get the result - var result = feedWindow.Display(_database, _currentFeed, this); + var result = feedWindow.Display(_currentFeed, this); // If OK was clicked... if (result.HasValue && result.Value) diff --git a/Application/Options/AboutOptionsPanel.xaml.cs b/Application/Options/AboutOptionsPanel.xaml.cs index 3d08e24..fbea6bb 100644 --- a/Application/Options/AboutOptionsPanel.xaml.cs +++ b/Application/Options/AboutOptionsPanel.xaml.cs @@ -1,36 +1,26 @@ using ChrisKaczor.ApplicationUpdate; using System.Reflection; -namespace FeedCenter.Options +namespace FeedCenter.Options; + +public partial class AboutOptionsPanel { - public partial class AboutOptionsPanel + public AboutOptionsPanel() { - public AboutOptionsPanel() - { - InitializeComponent(); - } - - public override void LoadPanel(FeedCenterEntities database) - { - base.LoadPanel(database); - - ApplicationNameLabel.Text = Properties.Resources.ApplicationDisplayName; - - var version = UpdateCheck.LocalVersion.ToString(); - VersionLabel.Text = string.Format(Properties.Resources.Version, version); - - CompanyLabel.Text = ((AssemblyCompanyAttribute) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false)[0]).Company; - } - - public override bool ValidatePanel() - { - return true; - } - - public override void SavePanel() - { - } - - public override string CategoryName => Properties.Resources.optionCategoryAbout; + InitializeComponent(); } + + public override void LoadPanel() + { + base.LoadPanel(); + + ApplicationNameLabel.Text = Properties.Resources.ApplicationDisplayName; + + var version = UpdateCheck.LocalVersion.ToString(); + VersionLabel.Text = string.Format(Properties.Resources.Version, version); + + CompanyLabel.Text = ((AssemblyCompanyAttribute) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false)[0]).Company; + } + + public override string CategoryName => Properties.Resources.optionCategoryAbout; } \ No newline at end of file diff --git a/Application/Options/BulkFeedWindow.xaml.cs b/Application/Options/BulkFeedWindow.xaml.cs index 14f301a..f0b8a01 100644 --- a/Application/Options/BulkFeedWindow.xaml.cs +++ b/Application/Options/BulkFeedWindow.xaml.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; +using FeedCenter.Data; namespace FeedCenter.Options { @@ -17,11 +18,11 @@ namespace FeedCenter.Options InitializeComponent(); } - public void Display(Window window, FeedCenterEntities database) + public void Display(Window window) { _checkedListBoxItems = new List>(); - foreach (var feed in database.Feeds) + foreach (var feed in Database.Entities.Feeds) _checkedListBoxItems.Add(new CheckedListItem { Item = feed }); _collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems }; diff --git a/Application/Options/CategoryWindow.xaml b/Application/Options/CategoryWindow.xaml index 5d89236..e3a71e4 100644 --- a/Application/Options/CategoryWindow.xaml +++ b/Application/Options/CategoryWindow.xaml @@ -6,7 +6,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:validation="clr-namespace:ChrisKaczor.Wpf.Validation;assembly=ChrisKaczor.Wpf.Validation" xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" d:DataContext="{d:DesignInstance Type=feedCenter:Category}" Title="CategoryWindow" @@ -18,40 +17,31 @@ FocusManager.FocusedElement="{Binding ElementName=NameTextBox}" controls:ControlBox.HasMinimizeButton="False" controls:ControlBox.HasMaximizeButton="False"> - + - - -