More cleanup and fixes

This commit is contained in:
2023-04-12 11:35:19 -04:00
parent 64d0f770ca
commit a81cf5e69f
28 changed files with 472 additions and 473 deletions

View File

@@ -185,6 +185,9 @@ public static class LegacyDatabase
{ {
foreach (var category in categories) foreach (var category in categories)
{ {
if (category.Name == Category.DefaultName)
category.IsDefault = true;
category.Feeds = feeds.Where(f => f.CategoryId == category.Id).ToList(); category.Feeds = feeds.Where(f => f.CategoryId == category.Id).ToList();
} }

View File

@@ -26,4 +26,4 @@ namespace FeedCenter.Data
base.OnCollectionChanged(e); base.OnCollectionChanged(e);
} }
} }
} }

View File

@@ -8,9 +8,9 @@ namespace FeedCenter
{ {
public class FeedCenterEntities public class FeedCenterEntities
{ {
public Realm Realm { get; private set; } public Realm RealmInstance { get; }
public RealmObservableCollection<Category> Categories { get; private set; } public RealmObservableCollection<Category> Categories { get; }
public RealmObservableCollection<Feed> Feeds { get; private set; } public RealmObservableCollection<Feed> Feeds { get; private set; }
public RealmObservableCollection<Setting> Settings { get; private set; } public RealmObservableCollection<Setting> Settings { get; private set; }
@@ -18,26 +18,31 @@ namespace FeedCenter
{ {
var realmConfiguration = new RealmConfiguration($"{Database.DatabaseFile}"); var realmConfiguration = new RealmConfiguration($"{Database.DatabaseFile}");
Realm = Realm.GetInstance(realmConfiguration); RealmInstance = Realm.GetInstance(realmConfiguration);
Settings = new RealmObservableCollection<Setting>(Realm); Settings = new RealmObservableCollection<Setting>(RealmInstance);
Feeds = new RealmObservableCollection<Feed>(Realm); Feeds = new RealmObservableCollection<Feed>(RealmInstance);
Categories = new RealmObservableCollection<Category>(Realm); Categories = new RealmObservableCollection<Category>(RealmInstance);
if (!Categories.Any()) if (!Categories.Any())
{ {
Realm.Write(() => Categories.Add(Category.CreateDefault())); RealmInstance.Write(() => Categories.Add(Category.CreateDefault()));
} }
} }
public void Refresh() public void Refresh()
{ {
Realm.Refresh(); RealmInstance.Refresh();
} }
public void SaveChanges(Action action) public void SaveChanges(Action action)
{ {
Realm.Write(action); RealmInstance.Write(action);
}
public Transaction BeginTransaction()
{
return RealmInstance.BeginWrite();
} }
public Category DefaultCategory public Category DefaultCategory

View File

@@ -65,7 +65,7 @@ namespace FeedCenter
var feedWindow = new FeedWindow(); var feedWindow = new FeedWindow();
feedWindow.Display(_database, feed, GetWindow(this)); feedWindow.Display(feed, GetWindow(this));
} }
private void DeleteSelectedFeed() private void DeleteSelectedFeed()

View File

@@ -1,33 +1,90 @@
using Realms; using Realms;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace FeedCenter namespace FeedCenter
{ {
public class Category : RealmObject public class Category : RealmObject, INotifyDataErrorInfo
{ {
private const string DefaultCategoryName = "< default >"; public const string DefaultName = "< default >";
private readonly Dictionary<string, List<string>> _errorsByPropertyName = new();
[PrimaryKey] [PrimaryKey]
[MapTo("ID")] public Guid Id { get; set; } = Guid.NewGuid();
public Guid Id { get; set; }
public string Name { get; set; } [MapTo("Name")]
private string RawName { get; set; } = string.Empty;
public string Name
{
get => RawName;
set
{
RawName = value;
ValidateName();
RaisePropertyChanged();
}
}
[Ignored] [Ignored]
public ICollection<Feed> Feeds { get; set; } public ICollection<Feed> Feeds { get; set; }
public static Category Create()
{
return new Category { Id = Guid.NewGuid() };
}
public static Category CreateDefault() 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 // ReSharper disable once UnusedMember.Global
public int SortKey => IsDefault ? 0 : 1; public int SortKey => IsDefault ? 0 : 1;
public bool HasErrors => _errorsByPropertyName.Any();
public event EventHandler<DataErrorsChangedEventArgs> 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<string>();
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);
}
} }
} }

View File

@@ -1,4 +1,5 @@
using ChrisKaczor.ApplicationUpdate; using ChrisKaczor.ApplicationUpdate;
using FeedCenter.Data;
using FeedCenter.FeedParsers; using FeedCenter.FeedParsers;
using FeedCenter.Properties; using FeedCenter.Properties;
using FeedCenter.Xml; using FeedCenter.Xml;
@@ -118,9 +119,9 @@ namespace FeedCenter
private static HttpClient _httpClient; 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 #region Reading

View File

@@ -20,7 +20,7 @@ namespace FeedCenter
private void HandleNewFeed(string feedUrl) private void HandleNewFeed(string feedUrl)
{ {
// Create and configure the new feed // Create and configure the new feed
var feed = Feed.Create(_database); var feed = Feed.Create();
feed.Source = feedUrl; feed.Source = feedUrl;
feed.Category = _database.DefaultCategory; feed.Category = _database.DefaultCategory;
@@ -85,7 +85,7 @@ namespace FeedCenter
// Feed read failed - create a new feed window // Feed read failed - create a new feed window
var feedForm = new FeedWindow(); var feedForm = new FeedWindow();
var dialogResult = feedForm.Display(_database, feed, this); var dialogResult = feedForm.Display(feed, this);
// Display the new feed form // Display the new feed form
if (dialogResult.HasValue && dialogResult.Value) if (dialogResult.HasValue && dialogResult.Value)

View File

@@ -145,7 +145,7 @@ namespace FeedCenter
var feedWindow = new FeedWindow(); var feedWindow = new FeedWindow();
// Display the feed window and get the result // 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 OK was clicked...
if (result.HasValue && result.Value) if (result.HasValue && result.Value)

View File

@@ -1,36 +1,26 @@
using ChrisKaczor.ApplicationUpdate; using ChrisKaczor.ApplicationUpdate;
using System.Reflection; using System.Reflection;
namespace FeedCenter.Options namespace FeedCenter.Options;
public partial class AboutOptionsPanel
{ {
public partial class AboutOptionsPanel public AboutOptionsPanel()
{ {
public AboutOptionsPanel() InitializeComponent();
{
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;
} }
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;
} }

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using FeedCenter.Data;
namespace FeedCenter.Options namespace FeedCenter.Options
{ {
@@ -17,11 +18,11 @@ namespace FeedCenter.Options
InitializeComponent(); InitializeComponent();
} }
public void Display(Window window, FeedCenterEntities database) public void Display(Window window)
{ {
_checkedListBoxItems = new List<CheckedListItem<Feed>>(); _checkedListBoxItems = new List<CheckedListItem<Feed>>();
foreach (var feed in database.Feeds) foreach (var feed in Database.Entities.Feeds)
_checkedListBoxItems.Add(new CheckedListItem<Feed> { Item = feed }); _checkedListBoxItems.Add(new CheckedListItem<Feed> { Item = feed });
_collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems }; _collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems };

View File

@@ -6,7 +6,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 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" xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox"
d:DataContext="{d:DesignInstance Type=feedCenter:Category}" d:DataContext="{d:DesignInstance Type=feedCenter:Category}"
Title="CategoryWindow" Title="CategoryWindow"
@@ -18,40 +17,31 @@
FocusManager.FocusedElement="{Binding ElementName=NameTextBox}" FocusManager.FocusedElement="{Binding ElementName=NameTextBox}"
controls:ControlBox.HasMinimizeButton="False" controls:ControlBox.HasMinimizeButton="False"
controls:ControlBox.HasMaximizeButton="False"> controls:ControlBox.HasMaximizeButton="False">
<Grid Margin="8"> <Grid Margin="6,3,6,6">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{x:Static properties:Resources.feedCategoryLabel}" <StackPanel
HorizontalAlignment="Left" Grid.Row="0"
Grid.Column="0" Grid.Column="0">
Grid.Row="0" <Label Content="{x:Static properties:Resources.categoryNameLabel}"
Target="{Binding ElementName=NameTextBox}" Padding="0"
VerticalAlignment="Center" Margin="0,0,0,1"
VerticalContentAlignment="Center" /> Target="{Binding ElementName=NameTextBox}" />
<TextBox Name="NameTextBox" <TextBox Name="NameTextBox"
VerticalAlignment="Center" VerticalAlignment="Center"
Grid.Row="0" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}">
Grid.Column="1"> </TextBox>
<TextBox.Text> </StackPanel>
<Binding Path="Name" UpdateSourceTrigger="Explicit" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<validation:RequiredValidationRule></validation:RequiredValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<StackPanel <StackPanel
Grid.Column="1" Grid.Column="0"
Grid.Row="2" Grid.Row="1"
Orientation="Horizontal" Orientation="Horizontal"
Margin="0,4,0,0" Margin="0,5,0,0"
HorizontalAlignment="Right"> HorizontalAlignment="Right">
<Button Content="{x:Static properties:Resources.OkayButton}" <Button Content="{x:Static properties:Resources.OkayButton}"
Height="23" Height="23"

View File

@@ -1,5 +1,6 @@
using ChrisKaczor.Wpf.Validation; using ChrisKaczor.Wpf.Validation;
using System.Windows; using System.Windows;
using FeedCenter.Data;
namespace FeedCenter.Options namespace FeedCenter.Options
{ {
@@ -29,8 +30,16 @@ namespace FeedCenter.Options
private void HandleOkayButtonClick(object sender, RoutedEventArgs e) private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
{ {
var transaction = Database.Entities.BeginTransaction();
if (!this.IsValid()) if (!this.IsValid())
{
transaction.Rollback();
return; return;
}
transaction.Commit();
Database.Entities.Refresh();
// Dialog is good // Dialog is good
DialogResult = true; DialogResult = true;

View File

@@ -19,7 +19,8 @@
Name="LockWindowCheckBox" Name="LockWindowCheckBox"
VerticalAlignment="Top" VerticalAlignment="Top"
Width="300" Width="300"
Grid.ColumnSpan="2" /> Grid.ColumnSpan="2"
Click="LockWindowCheckBox_Click" />
<CheckBox Content="{x:Static properties:Resources.displayEmptyFeedsCheckBox}" <CheckBox Content="{x:Static properties:Resources.displayEmptyFeedsCheckBox}"
Height="16" Height="16"
HorizontalAlignment="Left" HorizontalAlignment="Left"
@@ -28,7 +29,8 @@
VerticalAlignment="Top" VerticalAlignment="Top"
Width="300" Width="300"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Grid.Column="0" /> Grid.Column="0"
Click="DisplayEmptyFeedsCheckBox_Click" />
<Label Grid.Column="0" <Label Grid.Column="0"
Content="{x:Static properties:Resources.toolbarLocationLabel}" Content="{x:Static properties:Resources.toolbarLocationLabel}"
VerticalAlignment="Top" VerticalAlignment="Top"
@@ -39,7 +41,8 @@
<ComboBox Margin="8,53,0,0" <ComboBox Margin="8,53,0,0"
Name="ToolbarLocationComboBox" Name="ToolbarLocationComboBox"
VerticalAlignment="Top" VerticalAlignment="Top"
Grid.Column="1"> Grid.Column="1"
SelectionChanged="ToolbarLocationComboBox_SelectionChanged">
<ComboBoxItem Content="{x:Static properties:Resources.Top}" <ComboBoxItem Content="{x:Static properties:Resources.Top}"
Tag="{x:Static Dock.Top}" /> Tag="{x:Static Dock.Top}" />
<ComboBoxItem Content="{x:Static properties:Resources.Bottom}" <ComboBoxItem Content="{x:Static properties:Resources.Bottom}"
@@ -55,7 +58,8 @@
<ComboBox Margin="8,86,0,0" <ComboBox Margin="8,86,0,0"
Name="MultipleLineDisplayComboBox" Name="MultipleLineDisplayComboBox"
VerticalAlignment="Top" VerticalAlignment="Top"
Grid.Column="1"> Grid.Column="1"
SelectionChanged="MultipleLineDisplayComboBox_SelectionChanged">
<ComboBoxItem Content="{x:Static properties:Resources.multipleLineDisplayNormal}" <ComboBoxItem Content="{x:Static properties:Resources.multipleLineDisplayNormal}"
Tag="{x:Static options:MultipleLineDisplay.Normal}" /> Tag="{x:Static options:MultipleLineDisplay.Normal}" />
<ComboBoxItem Content="{x:Static properties:Resources.multipleLineDisplaySingleLine}" <ComboBoxItem Content="{x:Static properties:Resources.multipleLineDisplaySingleLine}"
@@ -64,4 +68,4 @@
Tag="{x:Static options:MultipleLineDisplay.FirstLine}" /> Tag="{x:Static options:MultipleLineDisplay.FirstLine}" />
</ComboBox> </ComboBox>
</Grid> </Grid>
</options:OptionsPanelBase> </options:OptionsPanelBase>

View File

@@ -2,45 +2,58 @@
using System.Linq; using System.Linq;
using System.Windows.Controls; using System.Windows.Controls;
namespace FeedCenter.Options namespace FeedCenter.Options;
public partial class DisplayOptionsPanel
{ {
public partial class DisplayOptionsPanel public DisplayOptionsPanel()
{ {
public DisplayOptionsPanel() InitializeComponent();
{
InitializeComponent();
}
public override void LoadPanel(FeedCenterEntities database)
{
base.LoadPanel(database);
LockWindowCheckBox.IsChecked = Settings.Default.WindowLocked;
DisplayEmptyFeedsCheckBox.IsChecked = Settings.Default.DisplayEmptyFeeds;
ToolbarLocationComboBox.SelectedItem = ToolbarLocationComboBox.Items.Cast<ComboBoxItem>().First(comboBoxItem => (Dock) comboBoxItem.Tag == Settings.Default.ToolbarLocation);
MultipleLineDisplayComboBox.SelectedItem = MultipleLineDisplayComboBox.Items.Cast<ComboBoxItem>().First(comboBoxItem => (MultipleLineDisplay) comboBoxItem.Tag == Settings.Default.MultipleLineDisplay);
}
public override bool ValidatePanel()
{
return true;
}
public override void SavePanel()
{
if (LockWindowCheckBox.IsChecked.HasValue && Settings.Default.WindowLocked != LockWindowCheckBox.IsChecked.Value)
Settings.Default.WindowLocked = LockWindowCheckBox.IsChecked.Value;
if (DisplayEmptyFeedsCheckBox.IsChecked.HasValue && Settings.Default.DisplayEmptyFeeds != DisplayEmptyFeedsCheckBox.IsChecked.Value)
Settings.Default.DisplayEmptyFeeds = DisplayEmptyFeedsCheckBox.IsChecked.Value;
var dock = (Dock) ((ComboBoxItem) ToolbarLocationComboBox.SelectedItem).Tag;
Settings.Default.ToolbarLocation = dock;
var multipleLineDisplay = (MultipleLineDisplay) ((ComboBoxItem) MultipleLineDisplayComboBox.SelectedItem).Tag;
Settings.Default.MultipleLineDisplay = multipleLineDisplay;
}
public override string CategoryName => Properties.Resources.optionCategoryDisplay;
} }
}
public override void LoadPanel()
{
base.LoadPanel();
LockWindowCheckBox.IsChecked = Settings.Default.WindowLocked;
DisplayEmptyFeedsCheckBox.IsChecked = Settings.Default.DisplayEmptyFeeds;
ToolbarLocationComboBox.SelectedItem = ToolbarLocationComboBox.Items.Cast<ComboBoxItem>().First(comboBoxItem => (Dock) comboBoxItem.Tag == Settings.Default.ToolbarLocation);
MultipleLineDisplayComboBox.SelectedItem = MultipleLineDisplayComboBox.Items.Cast<ComboBoxItem>().First(comboBoxItem => (MultipleLineDisplay) comboBoxItem.Tag == Settings.Default.MultipleLineDisplay);
MarkLoaded();
}
public override string CategoryName => Properties.Resources.optionCategoryDisplay;
private void LockWindowCheckBox_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (!HasLoaded) return;
if (LockWindowCheckBox.IsChecked.HasValue && Settings.Default.WindowLocked != LockWindowCheckBox.IsChecked.Value)
Settings.Default.WindowLocked = LockWindowCheckBox.IsChecked.Value;
}
private void DisplayEmptyFeedsCheckBox_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (!HasLoaded) return;
if (DisplayEmptyFeedsCheckBox.IsChecked.HasValue && Settings.Default.DisplayEmptyFeeds != DisplayEmptyFeedsCheckBox.IsChecked.Value)
Settings.Default.DisplayEmptyFeeds = DisplayEmptyFeedsCheckBox.IsChecked.Value;
}
private void ToolbarLocationComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!HasLoaded) return;
var dock = (Dock) ((ComboBoxItem) ToolbarLocationComboBox.SelectedItem).Tag;
Settings.Default.ToolbarLocation = dock;
}
private void MultipleLineDisplayComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!HasLoaded) return;
var multipleLineDisplay = (MultipleLineDisplay) ((ComboBoxItem) MultipleLineDisplayComboBox.SelectedItem).Tag;
Settings.Default.MultipleLineDisplay = multipleLineDisplay;
}
}

View File

@@ -1,4 +1,5 @@
using ChrisKaczor.Wpf.Validation; using ChrisKaczor.Wpf.Validation;
using FeedCenter.Data;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -14,10 +15,10 @@ namespace FeedCenter.Options
InitializeComponent(); InitializeComponent();
} }
public bool? Display(FeedCenterEntities database, Feed feed, Window owner) public bool? Display(Feed feed, Window owner)
{ {
// Bind the category combo box // Bind the category combo box
CategoryComboBox.ItemsSource = database.Categories; CategoryComboBox.ItemsSource = Database.Entities.Categories;
// Set the data context // Set the data context
DataContext = feed; DataContext = feed;
@@ -85,4 +86,4 @@ namespace FeedCenter.Options
Close(); Close();
} }
} }
} }

View File

@@ -6,6 +6,7 @@
xmlns:options="clr-namespace:FeedCenter.Options" xmlns:options="clr-namespace:FeedCenter.Options"
xmlns:properties="clr-namespace:FeedCenter.Properties" xmlns:properties="clr-namespace:FeedCenter.Properties"
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link" xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
xmlns:feedCenter="clr-namespace:FeedCenter"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="311" d:DesignHeight="311"
d:DesignWidth="425"> d:DesignWidth="425">
@@ -65,7 +66,8 @@
IsReadOnly="True" IsReadOnly="True"
HeadersVisibility="Column" HeadersVisibility="Column"
AllowDrop="True" AllowDrop="True"
Background="{x:Null}"> Background="{x:Null}"
d:DataContext="{d:DesignInstance Type=feedCenter:Category }">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" <DataGridTextColumn Binding="{Binding Name}"
Header="{x:Static properties:Resources.CategoryNameColumnHeader}" Header="{x:Static properties:Resources.CategoryNameColumnHeader}"
@@ -75,11 +77,13 @@
<DataGrid.ItemContainerStyle> <DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow"> <Style TargetType="DataGridRow">
<EventSetter Event="Drop" <EventSetter Event="Drop"
Handler="HandleTextBlockDrop" /> Handler="CategoryListBox_Drop" />
<EventSetter Event="DragEnter" <EventSetter Event="DragEnter"
Handler="HandleTextBlockDragEnter" /> Handler="CategoryListBox_DragEnter" />
<EventSetter Event="DragLeave" <EventSetter Event="DragLeave"
Handler="HandleTextBlockDragLeave" /> Handler="CategoryListBox_DragLeave" />
<EventSetter Event="MouseDoubleClick"
Handler="CategoryListBox_MouseDoubleClick" />
</Style> </Style>
</DataGrid.ItemContainerStyle> </DataGrid.ItemContainerStyle>
<DataGrid.CellStyle> <DataGrid.CellStyle>

View File

@@ -7,58 +7,42 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Xml; using System.Xml;
using FeedCenter.Data;
namespace FeedCenter.Options namespace FeedCenter.Options
{ {
public partial class FeedsOptionsPanel public partial class FeedsOptionsPanel
{ {
#region Constructor
public FeedsOptionsPanel() public FeedsOptionsPanel()
{ {
InitializeComponent(); InitializeComponent();
} }
#endregion public override void LoadPanel()
#region OptionsPanelBase overrides
public override void LoadPanel(FeedCenterEntities database)
{ {
base.LoadPanel(database); base.LoadPanel();
var collectionViewSource = new CollectionViewSource { Source = Database.Categories }; var collectionViewSource = new CollectionViewSource { Source = Database.Entities.Categories };
collectionViewSource.SortDescriptions.Add(new SortDescription("SortKey", ListSortDirection.Ascending)); collectionViewSource.SortDescriptions.Add(new SortDescription("SortKey", ListSortDirection.Ascending));
collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
collectionViewSource.IsLiveSortingRequested = true;
CategoryListBox.ItemsSource = collectionViewSource.View; CategoryListBox.ItemsSource = collectionViewSource.View;
CategoryListBox.SelectedIndex = 0; CategoryListBox.SelectedIndex = 0;
} }
public override bool ValidatePanel()
{
return true;
}
public override void SavePanel()
{ }
public override string CategoryName => Properties.Resources.optionCategoryFeeds; public override string CategoryName => Properties.Resources.optionCategoryFeeds;
#endregion
#region Feed list management
private void SetFeedButtonStates() private void SetFeedButtonStates()
{ {
AddFeedButton.IsEnabled = true; AddFeedButton.IsEnabled = true;
EditFeedButton.IsEnabled = (FeedListBox.SelectedItem != null); EditFeedButton.IsEnabled = FeedListBox.SelectedItem != null;
DeleteFeedButton.IsEnabled = (FeedListBox.SelectedItem != null); DeleteFeedButton.IsEnabled = FeedListBox.SelectedItem != null;
} }
private void AddFeed() private void AddFeed()
{ {
var feed = Feed.Create(Database); var feed = Feed.Create();
var category = (Category) CategoryListBox.SelectedItem; var category = (Category) CategoryListBox.SelectedItem;
@@ -66,16 +50,16 @@ namespace FeedCenter.Options
var feedWindow = new FeedWindow(); var feedWindow = new FeedWindow();
var result = feedWindow.Display(Database, feed, Window.GetWindow(this)); var result = feedWindow.Display(feed, Window.GetWindow(this));
if (result.HasValue && result.Value) if (!result.HasValue || !result.Value)
{ return;
Database.Feeds.Add(feed);
FeedListBox.SelectedItem = feed; Database.Entities.Feeds.Add(feed);
SetFeedButtonStates(); FeedListBox.SelectedItem = feed;
}
SetFeedButtonStates();
} }
private void EditSelectedFeed() private void EditSelectedFeed()
@@ -87,22 +71,18 @@ namespace FeedCenter.Options
var feedWindow = new FeedWindow(); var feedWindow = new FeedWindow();
feedWindow.Display(Database, feed, Window.GetWindow(this)); feedWindow.Display(feed, Window.GetWindow(this));
} }
private void DeleteSelectedFeed() private void DeleteSelectedFeed()
{ {
var feed = (Feed) FeedListBox.SelectedItem; var feed = (Feed) FeedListBox.SelectedItem;
Database.Feeds.Remove(feed); Database.Entities.Feeds.Remove(feed);
SetFeedButtonStates(); SetFeedButtonStates();
} }
#endregion
#region Feed event handlers
private void HandleAddFeedButtonClick(object sender, RoutedEventArgs e) private void HandleAddFeedButtonClick(object sender, RoutedEventArgs e)
{ {
AddFeed(); AddFeed();
@@ -128,15 +108,11 @@ namespace FeedCenter.Options
ExportFeeds(); ExportFeeds();
} }
#endregion private static void ExportFeeds()
#region Feed import and export
private void ExportFeeds()
{ {
// Setup the save file dialog
var saveFileDialog = new SaveFileDialog var saveFileDialog = new SaveFileDialog
{ {
FileName = Properties.Resources.ApplicationName,
Filter = Properties.Resources.ImportExportFilter, Filter = Properties.Resources.ImportExportFilter,
FilterIndex = 0, FilterIndex = 0,
OverwritePrompt = true OverwritePrompt = true
@@ -147,7 +123,6 @@ namespace FeedCenter.Options
if (!result.GetValueOrDefault(false)) if (!result.GetValueOrDefault(false))
return; return;
// Setup the writer settings
var writerSettings = new XmlWriterSettings var writerSettings = new XmlWriterSettings
{ {
Indent = true, Indent = true,
@@ -155,48 +130,32 @@ namespace FeedCenter.Options
ConformanceLevel = ConformanceLevel.Document ConformanceLevel = ConformanceLevel.Document
}; };
// Create an XML writer for the file chosen
var xmlWriter = XmlWriter.Create(saveFileDialog.FileName, writerSettings); var xmlWriter = XmlWriter.Create(saveFileDialog.FileName, writerSettings);
// Start the opml element
xmlWriter.WriteStartElement("opml"); xmlWriter.WriteStartElement("opml");
// Start the body element
xmlWriter.WriteStartElement("body"); xmlWriter.WriteStartElement("body");
// Loop over each feed foreach (var feed in Database.Entities.Feeds.OrderBy(feed => feed.Name))
foreach (var feed in Database.Feeds.OrderBy(feed => feed.Name))
{ {
// Start the outline element
xmlWriter.WriteStartElement("outline"); xmlWriter.WriteStartElement("outline");
// Write the title
xmlWriter.WriteAttributeString("title", feed.Title); xmlWriter.WriteAttributeString("title", feed.Title);
// Write the HTML link
xmlWriter.WriteAttributeString("htmlUrl", feed.Link); xmlWriter.WriteAttributeString("htmlUrl", feed.Link);
// Write the XML link
xmlWriter.WriteAttributeString("xmlUrl", feed.Source); xmlWriter.WriteAttributeString("xmlUrl", feed.Source);
// End the outline element
xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement();
} }
// End the body element
xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement();
// End the opml element
xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement();
// Flush and close the writer
xmlWriter.Flush(); xmlWriter.Flush();
xmlWriter.Close(); xmlWriter.Close();
} }
private void ImportFeeds() private static void ImportFeeds()
{ {
// Setup the open file dialog
var openFileDialog = new OpenFileDialog var openFileDialog = new OpenFileDialog
{ {
Filter = Properties.Resources.ImportExportFilter, Filter = Properties.Resources.ImportExportFilter,
@@ -208,44 +167,36 @@ namespace FeedCenter.Options
if (!result.GetValueOrDefault(false)) if (!result.GetValueOrDefault(false))
return; return;
// Setup the reader settings
var xmlReaderSettings = new XmlReaderSettings { IgnoreWhitespace = true }; var xmlReaderSettings = new XmlReaderSettings { IgnoreWhitespace = true };
// Create an XML reader for the file chosen
var xmlReader = XmlReader.Create(openFileDialog.FileName, xmlReaderSettings); var xmlReader = XmlReader.Create(openFileDialog.FileName, xmlReaderSettings);
try try
{ {
// Read the first node
xmlReader.Read(); xmlReader.Read();
// Read the OPML node
xmlReader.ReadStartElement("opml"); xmlReader.ReadStartElement("opml");
// Read the body node
xmlReader.ReadStartElement("body"); xmlReader.ReadStartElement("body");
// Read all outline nodes
while (xmlReader.NodeType != XmlNodeType.EndElement) while (xmlReader.NodeType != XmlNodeType.EndElement)
{ {
// Create a new feed var feed = Feed.Create();
var feed = Feed.Create(Database); feed.Category = Database.Entities.Categories.First(c => c.IsDefault);
feed.Category = Database.Categories.First(c => c.IsDefault);
// Loop over all attributes
while (xmlReader.MoveToNextAttribute()) while (xmlReader.MoveToNextAttribute())
{ {
// Handle the attibute
switch (xmlReader.Name.ToLower()) switch (xmlReader.Name.ToLower())
{ {
case "title": case "title":
feed.Title = xmlReader.Value; feed.Title = xmlReader.Value;
break; break;
// ReSharper disable once StringLiteralTypo
case "htmlurl": case "htmlurl":
feed.Link = xmlReader.Value; feed.Link = xmlReader.Value;
break; break;
// ReSharper disable once StringLiteralTypo
case "xmlurl": case "xmlurl":
feed.Source = xmlReader.Value; feed.Source = xmlReader.Value;
break; break;
@@ -256,24 +207,18 @@ namespace FeedCenter.Options
} }
} }
// Fill in defaults for optional fields
if (string.IsNullOrEmpty(feed.Name)) if (string.IsNullOrEmpty(feed.Name))
feed.Name = feed.Title; feed.Name = feed.Title;
// Add the feed to the main list Database.Entities.Feeds.Add(feed);
Database.Feeds.Add(feed);
// Move back to the element node
xmlReader.MoveToElement(); xmlReader.MoveToElement();
// Skip to the next node
xmlReader.Skip(); xmlReader.Skip();
} }
// End the body node
xmlReader.ReadEndElement(); xmlReader.ReadEndElement();
// End the OPML node
xmlReader.ReadEndElement(); xmlReader.ReadEndElement();
} }
finally finally
@@ -282,33 +227,32 @@ namespace FeedCenter.Options
} }
} }
#endregion
#region Category list management
private void SetCategoryButtonStates() private void SetCategoryButtonStates()
{ {
AddCategoryButton.IsEnabled = true; AddCategoryButton.IsEnabled = true;
EditCategoryButton.IsEnabled = (CategoryListBox.SelectedItem != null && CategoryListBox.SelectedItem != Database.DefaultCategory);
DeleteCategoryButton.IsEnabled = (CategoryListBox.SelectedItem != null && CategoryListBox.SelectedItem != Database.DefaultCategory); var selectedId = ((Category) CategoryListBox.SelectedItem).Id;
EditCategoryButton.IsEnabled = CategoryListBox.SelectedItem != null && selectedId != Database.Entities.DefaultCategory.Id;
DeleteCategoryButton.IsEnabled = CategoryListBox.SelectedItem != null && selectedId != Database.Entities.DefaultCategory.Id;
} }
private void AddCategory() private void AddCategory()
{ {
var category = Category.Create(); var category = new Category();
var categoryWindow = new CategoryWindow(); var categoryWindow = new CategoryWindow();
var result = categoryWindow.Display(category, Window.GetWindow(this)); var result = categoryWindow.Display(category, Window.GetWindow(this));
if (result.HasValue && result.Value) if (!result.HasValue || !result.Value)
{ return;
Database.SaveChanges(() => Database.Categories.Add(category));
CategoryListBox.SelectedItem = category; Database.Entities.SaveChanges(() => Database.Entities.Categories.Add(category));
SetCategoryButtonStates(); CategoryListBox.SelectedItem = category;
}
SetCategoryButtonStates();
} }
private void EditSelectedCategory() private void EditSelectedCategory()
@@ -325,7 +269,7 @@ namespace FeedCenter.Options
private void DeleteSelectedCategory() private void DeleteSelectedCategory()
{ {
var defaultCategory = Database.DefaultCategory; var defaultCategory = Database.Entities.DefaultCategory;
var category = (Category) CategoryListBox.SelectedItem; var category = (Category) CategoryListBox.SelectedItem;
@@ -338,15 +282,11 @@ namespace FeedCenter.Options
else else
CategoryListBox.SelectedIndex = index + 1; CategoryListBox.SelectedIndex = index + 1;
Database.SaveChanges(() => Database.Categories.Remove(category)); Database.Entities.SaveChanges(() => Database.Entities.Categories.Remove(category));
SetCategoryButtonStates(); SetCategoryButtonStates();
} }
#endregion
#region Category event handlers
private void HandleAddCategoryButtonClick(object sender, RoutedEventArgs e) private void HandleAddCategoryButtonClick(object sender, RoutedEventArgs e)
{ {
AddCategory(); AddCategory();
@@ -362,15 +302,13 @@ namespace FeedCenter.Options
DeleteSelectedCategory(); DeleteSelectedCategory();
} }
#endregion
private CollectionViewSource _collectionViewSource; private CollectionViewSource _collectionViewSource;
private void HandleCategoryListBoxSelectionChanged(object sender, SelectionChangedEventArgs e) private void HandleCategoryListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (_collectionViewSource == null) if (_collectionViewSource == null)
{ {
_collectionViewSource = new CollectionViewSource { Source = Database.Feeds }; _collectionViewSource = new CollectionViewSource { Source = Database.Entities.Feeds };
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); _collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
_collectionViewSource.Filter += HandleCollectionViewSourceFilter; _collectionViewSource.Filter += HandleCollectionViewSourceFilter;
@@ -392,16 +330,16 @@ namespace FeedCenter.Options
var feed = (Feed) e.Item; var feed = (Feed) e.Item;
e.Accepted = (feed.Category.Id == selectedCategory.Id); e.Accepted = feed.Category.Id == selectedCategory.Id;
} }
private void HandleTextBlockDrop(object sender, DragEventArgs e) private void CategoryListBox_Drop(object sender, DragEventArgs e)
{ {
var feedList = (List<Feed>) e.Data.GetData(typeof(List<Feed>)); var feedList = (List<Feed>) e.Data.GetData(typeof(List<Feed>));
var category = (Category) ((DataGridRow) sender).Item; var category = (Category) ((DataGridRow) sender).Item;
foreach (var feed in feedList) foreach (var feed in feedList!)
feed.Category = category; feed.Category = category;
_collectionViewSource.View.Refresh(); _collectionViewSource.View.Refresh();
@@ -413,22 +351,22 @@ namespace FeedCenter.Options
private void HandleListBoxItemPreviewMouseMove(object sender, MouseEventArgs e) private void HandleListBoxItemPreviewMouseMove(object sender, MouseEventArgs e)
{ {
if (e.LeftButton == MouseButtonState.Pressed) if (e.LeftButton != MouseButtonState.Pressed)
{ return;
var selectedItems = FeedListBox.SelectedItems.Cast<Feed>().ToList();
DragDrop.DoDragDrop(FeedListBox, selectedItems, DragDropEffects.Move); var selectedItems = FeedListBox.SelectedItems.Cast<Feed>().ToList();
}
DragDrop.DoDragDrop(FeedListBox, selectedItems, DragDropEffects.Move);
} }
private void HandleTextBlockDragEnter(object sender, DragEventArgs e) private void CategoryListBox_DragEnter(object sender, DragEventArgs e)
{ {
var dataGridRow = (DataGridRow) sender; var dataGridRow = (DataGridRow) sender;
dataGridRow.FontWeight = FontWeights.Bold; dataGridRow.FontWeight = FontWeights.Bold;
} }
private void HandleTextBlockDragLeave(object sender, DragEventArgs e) private void CategoryListBox_DragLeave(object sender, DragEventArgs e)
{ {
var dataGridRow = (DataGridRow) sender; var dataGridRow = (DataGridRow) sender;
@@ -443,7 +381,7 @@ namespace FeedCenter.Options
private void HandleMultipleEditClick(object sender, RoutedEventArgs e) private void HandleMultipleEditClick(object sender, RoutedEventArgs e)
{ {
var bulkFeedWindow = new BulkFeedWindow(); var bulkFeedWindow = new BulkFeedWindow();
bulkFeedWindow.Display(Window.GetWindow(this), Database); bulkFeedWindow.Display(Window.GetWindow(this));
} }
private void HandleFeedListPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void HandleFeedListPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
@@ -458,5 +396,13 @@ namespace FeedCenter.Options
if (dataGridRow != null && FeedListBox.SelectedItems.Contains(dataGridRow.Item)) if (dataGridRow != null && FeedListBox.SelectedItems.Contains(dataGridRow.Item))
e.Handled = true; e.Handled = true;
} }
private void CategoryListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (!EditCategoryButton.IsEnabled)
return;
EditSelectedCategory();
}
} }
} }

View File

@@ -26,7 +26,8 @@
VerticalAlignment="Top" VerticalAlignment="Top"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Margin="0,5" Margin="0,5"
Grid.ColumnSpan="2" /> Grid.ColumnSpan="2"
Click="StartWithWindowsCheckBox_Click" />
<Label Content="{x:Static properties:Resources.defaultBrowserLabel}" <Label Content="{x:Static properties:Resources.defaultBrowserLabel}"
Target="{Binding ElementName=BrowserComboBox}" Target="{Binding ElementName=BrowserComboBox}"
Grid.Column="0" Grid.Column="0"
@@ -37,7 +38,8 @@
<ComboBox Name="BrowserComboBox" <ComboBox Name="BrowserComboBox"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
VerticalContentAlignment="Center"> VerticalContentAlignment="Center"
SelectionChanged="BrowserComboBox_SelectionChanged">
</ComboBox> </ComboBox>
<Label Content="{x:Static properties:Resources.defaultUserAgentLabel}" <Label Content="{x:Static properties:Resources.defaultUserAgentLabel}"
Target="{Binding ElementName=BrowserComboBox}" Target="{Binding ElementName=BrowserComboBox}"
@@ -49,8 +51,8 @@
<ComboBox Name="UserAgentComboBox" <ComboBox Name="UserAgentComboBox"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
VerticalContentAlignment="Center"> VerticalContentAlignment="Center"
SelectionChanged="UserAgentComboBox_SelectionChanged">
</ComboBox> </ComboBox>
</Grid> </Grid>
</options:OptionsPanelBase> </options:OptionsPanelBase>

View File

@@ -1,132 +1,104 @@
using ChrisKaczor.InstalledBrowsers; using ChrisKaczor.InstalledBrowsers;
using ChrisKaczor.Wpf.Application; using ChrisKaczor.Wpf.Application;
using ChrisKaczor.Wpf.Validation;
using System.Collections.Generic;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Controls.Primitives;
internal class UserAgentItem namespace FeedCenter.Options;
{
internal string Caption { get; set; }
internal string UserAgent { get; set; }
}
namespace FeedCenter.Options public partial class GeneralOptionsPanel
{ {
public partial class GeneralOptionsPanel public GeneralOptionsPanel()
{ {
public GeneralOptionsPanel() InitializeComponent();
}
public override string CategoryName => Properties.Resources.optionCategoryGeneral;
public override void LoadPanel()
{
base.LoadPanel();
var settings = Properties.Settings.Default;
StartWithWindowsCheckBox.IsChecked = settings.StartWithWindows;
LoadBrowserComboBox(BrowserComboBox, settings.Browser);
LoadUserAgentComboBox(UserAgentComboBox, settings.DefaultUserAgent);
MarkLoaded();
}
private static void LoadBrowserComboBox(Selector selector, string selected)
{
selector.SelectedIndex = 0;
ComboBoxItem selectedItem = null;
var browsers = InstalledBrowser.GetInstalledBrowsers(true);
foreach (var browser in browsers)
{ {
InitializeComponent(); var item = new ComboBoxItem { Content = browser.Value.Name, Tag = browser.Key };
selector.Items.Add(item);
if (browser.Key == selected)
selectedItem = item;
} }
public override string CategoryName => Properties.Resources.optionCategoryGeneral; if (selectedItem != null)
selector.SelectedItem = selectedItem;
}
public override void LoadPanel(FeedCenterEntities database) private static void LoadUserAgentComboBox(Selector selector, string selected)
{
selector.SelectedIndex = 0;
ComboBoxItem selectedItem = null;
var userAgents = UserAgentItem.GetUserAgents();
foreach (var userAgent in userAgents)
{ {
base.LoadPanel(database); var item = new ComboBoxItem { Content = userAgent.Caption, Tag = userAgent.UserAgent };
var settings = Properties.Settings.Default; selector.Items.Add(item);
StartWithWindowsCheckBox.IsChecked = settings.StartWithWindows; if (userAgent.UserAgent == selected)
selectedItem = item;
LoadBrowserComboBox(BrowserComboBox, settings.Browser);
LoadUserAgentComboBox(UserAgentComboBox, settings.DefaultUserAgent);
} }
public override bool ValidatePanel() if (selectedItem != null)
{ selector.SelectedItem = selectedItem;
return true; }
}
public override void SavePanel() private void StartWithWindowsCheckBox_Click(object sender, System.Windows.RoutedEventArgs e)
{ {
var settings = Properties.Settings.Default; if (!HasLoaded) return;
if (StartWithWindowsCheckBox.IsChecked.HasValue && var settings = Properties.Settings.Default;
settings.StartWithWindows != StartWithWindowsCheckBox.IsChecked.Value)
settings.StartWithWindows = StartWithWindowsCheckBox.IsChecked.Value;
System.Windows.Application.Current.SetStartWithWindows(settings.StartWithWindows); if (StartWithWindowsCheckBox.IsChecked.HasValue &&
settings.StartWithWindows != StartWithWindowsCheckBox.IsChecked.Value)
settings.StartWithWindows = StartWithWindowsCheckBox.IsChecked.Value;
settings.Browser = (string) ((ComboBoxItem) BrowserComboBox.SelectedItem).Tag; System.Windows.Application.Current.SetStartWithWindows(settings.StartWithWindows);
}
settings.DefaultUserAgent = (string) ((ComboBoxItem) UserAgentComboBox.SelectedItem).Tag; private void BrowserComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!HasLoaded) return;
var expressions = this.GetBindingExpressions(new[] { UpdateSourceTrigger.Explicit }); var settings = Properties.Settings.Default;
this.UpdateAllSources(expressions);
}
private static void LoadBrowserComboBox(ComboBox comboBox, string selected) settings.Browser = (string) ((ComboBoxItem) BrowserComboBox.SelectedItem).Tag;
{ }
comboBox.SelectedIndex = 0;
ComboBoxItem selectedItem = null; private void UserAgentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!HasLoaded) return;
var browsers = InstalledBrowser.GetInstalledBrowsers(true); var settings = Properties.Settings.Default;
foreach (var browser in browsers)
{
var item = new ComboBoxItem { Content = browser.Value.Name, Tag = browser.Key };
comboBox.Items.Add(item); settings.DefaultUserAgent = (string) ((ComboBoxItem) UserAgentComboBox.SelectedItem).Tag;
if (browser.Key == selected)
selectedItem = item;
}
if (selectedItem != null)
comboBox.SelectedItem = selectedItem;
}
private static void LoadUserAgentComboBox(ComboBox comboBox, string selected)
{
comboBox.SelectedIndex = 0;
ComboBoxItem selectedItem = null;
var userAgents = GetUserAgents();
foreach (var userAgent in userAgents)
{
var item = new ComboBoxItem { Content = userAgent.Caption, Tag = userAgent.UserAgent };
comboBox.Items.Add(item);
if (userAgent.UserAgent == selected)
selectedItem = item;
}
if (selectedItem != null)
comboBox.SelectedItem = selectedItem;
}
private static List<UserAgentItem> GetUserAgents()
{
var userAgents = new List<UserAgentItem>
{
new()
{
Caption = Properties.Resources.DefaultUserAgentCaption,
UserAgent = string.Empty
},
new()
{
Caption = "Windows RSS Platform 2.0",
UserAgent = "Windows-RSS-Platform/2.0 (MSIE 9.0; Windows NT 6.1)"
},
new()
{
Caption = "Feedly 1.0",
UserAgent = "Feedly/1.0"
},
new()
{
Caption = "curl",
UserAgent = "curl/7.47.0"
}
};
return userAgents;
}
} }
} }

View File

@@ -1,27 +1,19 @@
using System; using System.Windows.Controls;
using System.Windows.Controls;
namespace FeedCenter.Options namespace FeedCenter.Options;
public class OptionsPanelBase : UserControl
{ {
public class OptionsPanelBase : UserControl public bool HasLoaded { get; private set; }
public virtual void LoadPanel()
{ {
protected FeedCenterEntities Database { get; private set; }
public virtual void LoadPanel(FeedCenterEntities database)
{
Database = database;
}
public virtual bool ValidatePanel()
{
throw new NotImplementedException();
}
public virtual void SavePanel()
{
throw new NotImplementedException();
}
public virtual string CategoryName => null;
} }
}
public void MarkLoaded()
{
HasLoaded = true;
}
public virtual string CategoryName => null;
}

View File

@@ -17,15 +17,7 @@
<ContentControl Margin="144,12,12,41" <ContentControl Margin="144,12,12,41"
Name="ContentControl" Name="ContentControl"
IsTabStop="False" /> IsTabStop="False" />
<Button Content="{x:Static properties:Resources.OkayButton}" <Button Content="{x:Static properties:Resources.CloseButton}"
Height="23"
HorizontalAlignment="Right"
Margin="0,0,93,12"
VerticalAlignment="Bottom"
Width="75"
IsDefault="True"
Click="HandleOkayButtonClick" />
<Button Content="{x:Static properties:Resources.CancelButton}"
Margin="0,0,12,12" Margin="0,0,12,12"
Height="23" Height="23"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"

View File

@@ -1,22 +1,13 @@
using FeedCenter.Data; using FeedCenter.Data;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
namespace FeedCenter.Options namespace FeedCenter.Options
{ {
public partial class OptionsWindow public partial class OptionsWindow
{ {
#region Member variables
private readonly List<OptionsPanelBase> _optionPanels = new(); private readonly List<OptionsPanelBase> _optionPanels = new();
private readonly FeedCenterEntities _database = Database.Entities;
#endregion
#region Constructor
public OptionsWindow() public OptionsWindow()
{ {
InitializeComponent(); InitializeComponent();
@@ -28,10 +19,6 @@ namespace FeedCenter.Options
LoadCategories(); LoadCategories();
} }
#endregion
#region Category handling
private void AddCategories() private void AddCategories()
{ {
_optionPanels.Add(new GeneralOptionsPanel()); _optionPanels.Add(new GeneralOptionsPanel());
@@ -47,7 +34,7 @@ namespace FeedCenter.Options
foreach (var optionsPanel in _optionPanels) foreach (var optionsPanel in _optionPanels)
{ {
// Tell the panel to load itself // Tell the panel to load itself
optionsPanel.LoadPanel(_database); optionsPanel.LoadPanel();
// Add the panel to the category ist // Add the panel to the category ist
CategoryListBox.Items.Add(new CategoryListItem(optionsPanel)); CategoryListBox.Items.Add(new CategoryListItem(optionsPanel));
@@ -72,10 +59,6 @@ namespace FeedCenter.Options
SelectCategory(((CategoryListItem) CategoryListBox.SelectedItem).Panel); SelectCategory(((CategoryListItem) CategoryListBox.SelectedItem).Panel);
} }
#endregion
#region Category list item
private class CategoryListItem private class CategoryListItem
{ {
public OptionsPanelBase Panel { get; } public OptionsPanelBase Panel { get; }
@@ -90,40 +73,5 @@ namespace FeedCenter.Options
return Panel.CategoryName; return Panel.CategoryName;
} }
} }
#endregion
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
{
// Loop over each panel and ask them to validate
foreach (var optionsPanel in _optionPanels)
{
// If validation fails...
if (!optionsPanel.ValidatePanel())
{
// ...select the right category
SelectCategory(optionsPanel);
// Stop validation
return;
}
}
// Loop over each panel and ask them to save
foreach (var optionsPanel in _optionPanels)
{
// Save!
optionsPanel.SavePanel();
}
// Save the actual settings
_database.SaveChanges(() => { });
Properties.Settings.Default.Save();
DialogResult = true;
// Close the window
Close();
}
} }
} }

View File

@@ -11,7 +11,8 @@
<Grid> <Grid>
<CheckBox Content="{x:Static properties:Resources.checkVersionOnStartupCheckBox}" <CheckBox Content="{x:Static properties:Resources.checkVersionOnStartupCheckBox}"
Name="CheckVersionOnStartupCheckBox" Name="CheckVersionOnStartupCheckBox"
VerticalAlignment="Top" /> VerticalAlignment="Top"
Click="CheckVersionOnStartupCheckBox_Click" />
<Button Content="{x:Static properties:Resources.checkVersionNowButton}" <Button Content="{x:Static properties:Resources.checkVersionNowButton}"
Height="23" Height="23"
HorizontalAlignment="Left" HorizontalAlignment="Left"
@@ -20,4 +21,4 @@
Width="75" Width="75"
Click="HandleCheckVersionNowButtonClick" /> Click="HandleCheckVersionNowButtonClick" />
</Grid> </Grid>
</options:OptionsPanelBase> </options:OptionsPanelBase>

View File

@@ -1,37 +1,35 @@
using ChrisKaczor.ApplicationUpdate; using ChrisKaczor.ApplicationUpdate;
namespace FeedCenter.Options namespace FeedCenter.Options;
public partial class UpdateOptionsPanel
{ {
public partial class UpdateOptionsPanel public UpdateOptionsPanel()
{ {
public UpdateOptionsPanel() InitializeComponent();
{ }
InitializeComponent();
}
public override void LoadPanel(FeedCenterEntities database) public override void LoadPanel()
{ {
base.LoadPanel(database); base.LoadPanel();
CheckVersionOnStartupCheckBox.IsChecked = Properties.Settings.Default.CheckVersionAtStartup; CheckVersionOnStartupCheckBox.IsChecked = Properties.Settings.Default.CheckVersionAtStartup;
}
public override bool ValidatePanel() MarkLoaded();
{ }
return true;
}
public override void SavePanel() public override string CategoryName => Properties.Resources.optionCategoryUpdate;
{
if (CheckVersionOnStartupCheckBox.IsChecked.HasValue && Properties.Settings.Default.CheckVersionAtStartup != CheckVersionOnStartupCheckBox.IsChecked.Value)
Properties.Settings.Default.CheckVersionAtStartup = CheckVersionOnStartupCheckBox.IsChecked.Value;
}
public override string CategoryName => Properties.Resources.optionCategoryUpdate; private void HandleCheckVersionNowButtonClick(object sender, System.Windows.RoutedEventArgs e)
{
UpdateCheck.DisplayUpdateInformation(true);
}
private void HandleCheckVersionNowButtonClick(object sender, System.Windows.RoutedEventArgs e) private void CheckVersionOnStartupCheckBox_Click(object sender, System.Windows.RoutedEventArgs e)
{ {
UpdateCheck.DisplayUpdateInformation(true); if (!HasLoaded) return;
}
if (CheckVersionOnStartupCheckBox.IsChecked.HasValue && Properties.Settings.Default.CheckVersionAtStartup != CheckVersionOnStartupCheckBox.IsChecked.Value)
Properties.Settings.Default.CheckVersionAtStartup = CheckVersionOnStartupCheckBox.IsChecked.Value;
} }
} }

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
namespace FeedCenter.Options
{
internal class UserAgentItem
{
internal string Caption { get; set; }
internal string UserAgent { get; set; }
internal static List<UserAgentItem> GetUserAgents()
{
var userAgents = new List<UserAgentItem>
{
new()
{
Caption = Properties.Resources.DefaultUserAgentCaption,
UserAgent = string.Empty
},
new()
{
Caption = "Windows RSS Platform 2.0",
UserAgent = "Windows-RSS-Platform/2.0 (MSIE 9.0; Windows NT 6.1)"
},
new()
{
Caption = "Feedly 1.0",
UserAgent = "Feedly/1.0"
},
new()
{
Caption = "curl",
UserAgent = "curl/7.47.0"
}
};
return userAgents;
}
}
}

View File

@@ -214,6 +214,15 @@ namespace FeedCenter.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to _Name:.
/// </summary>
public static string categoryNameLabel {
get {
return ResourceManager.GetString("categoryNameLabel", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Add Category. /// Looks up a localized string similar to Add Category.
/// </summary> /// </summary>

View File

@@ -535,4 +535,7 @@
<data name="SplashMigratingLegacyDatabase" xml:space="preserve"> <data name="SplashMigratingLegacyDatabase" xml:space="preserve">
<value>Migrating legacy database...</value> <value>Migrating legacy database...</value>
</data> </data>
<data name="categoryNameLabel" xml:space="preserve">
<value>_Name:</value>
</data>
</root> </root>

View File

@@ -1,11 +1,30 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TextBox}"> <Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder x:Name="placeholder" />
<TextBlock FontSize="14"
Margin="2,0"
Foreground="White"
Background="Red"
TextAlignment="Center"
Width="16"
Text="!"
ToolTip="{Binding AdornedElement.(Validation.Errors)[0].ErrorContent, ElementName=placeholder}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers> <Style.Triggers>
<Trigger Property="Validation.HasError" <Trigger Property="Validation.HasError"
Value="true"> Value="true">
<Setter Property="ToolTip" <Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" /> Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
<Setter Property="Margin"
Value="0,0,18,0" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>