More UI updates

This commit is contained in:
2023-04-16 12:57:17 -04:00
parent 5c0c84a068
commit d6a2fd5a46
47 changed files with 3695 additions and 3768 deletions

View File

@@ -8,8 +8,8 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Windows.Threading; using System.Windows.Threading;
namespace FeedCenter namespace FeedCenter;
{
public partial class App public partial class App
{ {
// ReSharper disable ConvertPropertyToExpressionBody // ReSharper disable ConvertPropertyToExpressionBody
@@ -125,4 +125,3 @@ namespace FeedCenter
Log.Logger.Error(e.Exception, "Exception"); Log.Logger.Error(e.Exception, "Exception");
} }
} }
}

View File

@@ -1,7 +1,7 @@
using System.IO; using System.IO;
namespace FeedCenter.Data namespace FeedCenter.Data;
{
public static class Database public static class Database
{ {
public static string DatabaseFile { get; set; } public static string DatabaseFile { get; set; }
@@ -22,4 +22,3 @@ namespace FeedCenter.Data
Loaded = true; Loaded = true;
} }
} }
}

View File

@@ -2,8 +2,8 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
namespace FeedCenter.Data namespace FeedCenter.Data;
{
public class RealmObservableCollection<T> : ObservableCollection<T> where T : IRealmObject public class RealmObservableCollection<T> : ObservableCollection<T> where T : IRealmObject
{ {
private readonly Realm _realm; private readonly Realm _realm;
@@ -26,4 +26,3 @@ namespace FeedCenter.Data
base.OnCollectionChanged(e); base.OnCollectionChanged(e);
} }
} }
}

View File

@@ -4,8 +4,8 @@ using Realms;
using System; using System;
using System.Linq; using System.Linq;
namespace FeedCenter namespace FeedCenter;
{
public class FeedCenterEntities public class FeedCenterEntities
{ {
public Realm RealmInstance { get; } public Realm RealmInstance { get; }
@@ -50,4 +50,3 @@ namespace FeedCenter
get { return Categories.First(c => c.IsDefault); } get { return Categories.First(c => c.IsDefault); }
} }
} }
}

View File

@@ -132,7 +132,7 @@
<PackageReference Include="ChrisKaczor.Wpf.Controls.HtmlTextBlock" Version="1.0.2" /> <PackageReference Include="ChrisKaczor.Wpf.Controls.HtmlTextBlock" Version="1.0.2" />
<PackageReference Include="ChrisKaczor.Wpf.Controls.Link" Version="1.0.3" /> <PackageReference Include="ChrisKaczor.Wpf.Controls.Link" Version="1.0.3" />
<PackageReference Include="ChrisKaczor.Wpf.Controls.Toolbar" Version="1.0.2" /> <PackageReference Include="ChrisKaczor.Wpf.Controls.Toolbar" Version="1.0.2" />
<PackageReference Include="ChrisKaczor.Wpf.Validation" Version="1.0.2" /> <PackageReference Include="ChrisKaczor.Wpf.Validation" Version="1.0.3" />
<PackageReference Include="ChrisKaczor.Wpf.Windows.ControlBox" Version="1.0.2" /> <PackageReference Include="ChrisKaczor.Wpf.Windows.ControlBox" Version="1.0.2" />
<PackageReference Include="ChrisKaczor.Wpf.Windows.SnappingWindow" Version="1.0.2" /> <PackageReference Include="ChrisKaczor.Wpf.Windows.SnappingWindow" Version="1.0.2" />
<PackageReference Include="Dapper" Version="2.0.123" /> <PackageReference Include="Dapper" Version="2.0.123" />

View File

@@ -14,12 +14,24 @@
FocusManager.FocusedElement="{Binding ElementName=FeedDataGrid}" FocusManager.FocusedElement="{Binding ElementName=FeedDataGrid}"
controlBox:ControlBox.HasMaximizeButton="False" controlBox:ControlBox.HasMaximizeButton="False"
controlBox:ControlBox.HasMinimizeButton="False"> controlBox:ControlBox.HasMinimizeButton="False">
<Grid> <Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Margin="6">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DataGrid AutoGenerateColumns="False" <DataGrid Grid.Row="0"
Grid.Column="0"
AutoGenerateColumns="False"
x:Name="FeedDataGrid" x:Name="FeedDataGrid"
CanUserReorderColumns="False" CanUserReorderColumns="False"
GridLinesVisibility="None" GridLinesVisibility="None"
@@ -27,16 +39,11 @@
IsReadOnly="True" IsReadOnly="True"
CanUserResizeRows="False" CanUserResizeRows="False"
HeadersVisibility="Column" HeadersVisibility="Column"
Margin="6" BorderThickness="1,1,1,1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
Background="{x:Null}" Background="{x:Null}"
CanUserSortColumns="True" CanUserSortColumns="True"
MouseDoubleClick="HandleMouseDoubleClick"> MouseDoubleClick="HandleMouseDoubleClick">
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="BorderThickness"
Value="0" />
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}" <DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}"
Binding="{Binding Item2}" Binding="{Binding Item2}"
@@ -44,22 +51,24 @@
SortDirection="Ascending" /> SortDirection="Ascending" />
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
<StackPanel
Grid.Column="0"
Grid.Row="1"
Orientation="Horizontal"
Margin="0,5,0,0"
HorizontalAlignment="Right">
<Button Content="{x:Static my:Resources.OkayButton}" <Button Content="{x:Static my:Resources.OkayButton}"
Height="23" HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="75"
Margin="0,0,5,0"
IsDefault="True" IsDefault="True"
Width="75" Click="HandleOkayButtonClick" />
Click="HandleOkayButtonClick"
Margin="0,0,90,10"
Grid.Row="1"
VerticalAlignment="Bottom"
HorizontalAlignment="Right" />
<Button Content="{x:Static my:Resources.CancelButton}" <Button Content="{x:Static my:Resources.CancelButton}"
Height="23" HorizontalAlignment="Right"
IsCancel="True"
Width="75"
Margin="0,0,10,10"
Grid.Row="1"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
HorizontalAlignment="Right" /> Width="75"
IsCancel="True" />
</StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@@ -2,8 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows; using System.Windows;
namespace FeedCenter namespace FeedCenter;
{
public partial class FeedChooserWindow public partial class FeedChooserWindow
{ {
private string _returnLink; private string _returnLink;
@@ -49,4 +49,3 @@ namespace FeedCenter
} }
} }
} }
}

View File

@@ -2,7 +2,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:FeedCenter.Properties" xmlns:my="clr-namespace:FeedCenter.Properties"
xmlns:linkControl="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link" xmlns:linkControl="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
xmlns:controlBox="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" xmlns:controlBox="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:feedCenter="clr-namespace:FeedCenter"
mc:Ignorable="d"
x:Class="FeedCenter.FeedErrorWindow" x:Class="FeedCenter.FeedErrorWindow"
Title="{x:Static my:Resources.FeedErrorWindow}" Title="{x:Static my:Resources.FeedErrorWindow}"
Height="300" Height="300"
@@ -11,29 +13,40 @@
Icon="/FeedCenter;component/Resources/Application.ico" Icon="/FeedCenter;component/Resources/Application.ico"
controlBox:ControlBox.HasMaximizeButton="False" controlBox:ControlBox.HasMaximizeButton="False"
controlBox:ControlBox.HasMinimizeButton="False"> controlBox:ControlBox.HasMinimizeButton="False">
<Grid> <Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Margin="6">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="225*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DataGrid AutoGenerateColumns="False" <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<DataGrid Grid.Row="0"
Grid.Column="0"
AutoGenerateColumns="False"
x:Name="FeedDataGrid" x:Name="FeedDataGrid"
CanUserReorderColumns="False" CanUserReorderColumns="False"
GridLinesVisibility="None" GridLinesVisibility="None"
SelectionMode="Single" SelectionMode="Single"
IsReadOnly="True" IsReadOnly="True"
CanUserResizeRows="False" CanUserResizeRows="False"
BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
HeadersVisibility="Column" HeadersVisibility="Column"
Margin="6,6,6,0"
Background="{x:Null}" Background="{x:Null}"
CanUserSortColumns="True"> CanUserSortColumns="True"
<DataGrid.CellStyle> d:DataContext="{d:DesignInstance Type=feedCenter:Feed}" SelectionChanged="FeedDataGrid_SelectionChanged">
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="BorderThickness"
Value="0" />
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}" <DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}"
Binding="{Binding Name}" Binding="{Binding Name}"
@@ -49,7 +62,6 @@
</DataGrid> </DataGrid>
<Border Grid.Row="1" <Border Grid.Row="1"
BorderThickness="1,0,1,1" BorderThickness="1,0,1,1"
Margin="6,0,6,3"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"> BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"> Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
@@ -80,19 +92,12 @@
ToolTip="{x:Static my:Resources.OpenFeed}" /> ToolTip="{x:Static my:Resources.OpenFeed}" />
</StackPanel> </StackPanel>
</Border> </Border>
<Grid DockPanel.Dock="Right" <Button
Grid.Row="2" Grid.Row="2"
Margin="6,3,6,6"> Grid.Column="0"
<Grid.ColumnDefinitions> Margin="0,6,0,0"
<ColumnDefinition Width="*" /> Content="{x:Static my:Resources.CloseButton}"
<ColumnDefinition Width="Auto" /> HorizontalAlignment="Right"
<ColumnDefinition Width="Auto" /> IsCancel="True" />
</Grid.ColumnDefinitions>
<Button Content="{x:Static my:Resources.CloseButton}"
Height="23"
IsCancel="True"
Width="75"
Grid.Column="2" />
</Grid>
</Grid> </Grid>
</Window> </Window>

View File

@@ -9,8 +9,8 @@ using FeedCenter.Data;
using FeedCenter.Options; using FeedCenter.Options;
using FeedCenter.Properties; using FeedCenter.Properties;
namespace FeedCenter namespace FeedCenter;
{
public partial class FeedErrorWindow public partial class FeedErrorWindow
{ {
private CollectionViewSource _collectionViewSource; private CollectionViewSource _collectionViewSource;
@@ -81,10 +81,12 @@ namespace FeedCenter
private void SetFeedButtonStates() private void SetFeedButtonStates()
{ {
EditFeedButton.IsEnabled = FeedDataGrid.SelectedItem != null; var feed = FeedDataGrid.SelectedItem as Feed;
DeleteFeedButton.IsEnabled = FeedDataGrid.SelectedItem != null;
RefreshCurrent.IsEnabled = FeedDataGrid.SelectedItem != null; EditFeedButton.IsEnabled = feed != null;
OpenPage.IsEnabled = FeedDataGrid.SelectedItem != null; DeleteFeedButton.IsEnabled = feed != null;
RefreshCurrent.IsEnabled = feed != null;
OpenPage.IsEnabled = feed != null && !string.IsNullOrEmpty(feed.Link);
OpenFeed.IsEnabled = FeedDataGrid.SelectedItem != null; OpenFeed.IsEnabled = FeedDataGrid.SelectedItem != null;
} }
@@ -132,5 +134,9 @@ namespace FeedCenter
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
IsEnabled = true; IsEnabled = true;
} }
private void FeedDataGrid_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
SetFeedButtonStates();
} }
} }

View File

@@ -2,8 +2,8 @@
using System; using System;
using System.Xml; using System.Xml;
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
internal class AtomParser : FeedParserBase internal class AtomParser : FeedParserBase
{ {
public AtomParser(Feed feed) : base(feed) { } public AtomParser(Feed feed) : base(feed) { }
@@ -140,4 +140,3 @@ namespace FeedCenter.FeedParsers
return node.Attributes[attributeName, node.NamespaceURI] ?? node.Attributes[attributeName]; return node.Attributes[attributeName, node.NamespaceURI] ?? node.Attributes[attributeName];
} }
} }
}

View File

@@ -1,8 +1,7 @@
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
internal enum FeedParseError internal enum FeedParseError
{ {
Unknown = 0, Unknown = 0,
InvalidXml = 1 InvalidXml = 1
} }
}

View File

@@ -1,7 +1,7 @@
using System; using System;
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
internal class FeedParseException : ApplicationException internal class FeedParseException : ApplicationException
{ {
public FeedParseException(FeedParseError feedParseError) public FeedParseException(FeedParseError feedParseError)
@@ -11,4 +11,3 @@ namespace FeedCenter.FeedParsers
public FeedParseError ParseError { get; set; } public FeedParseError ParseError { get; set; }
} }
}

View File

@@ -3,8 +3,8 @@ using System;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
[Serializable] [Serializable]
internal class InvalidFeedFormatException : ApplicationException internal class InvalidFeedFormatException : ApplicationException
{ {
@@ -158,4 +158,3 @@ namespace FeedCenter.FeedParsers
#endregion #endregion
} }
}

View File

@@ -2,8 +2,8 @@
using Serilog; using Serilog;
using System.Xml; using System.Xml;
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
internal class RdfParser : FeedParserBase internal class RdfParser : FeedParserBase
{ {
public RdfParser(Feed feed) : base(feed) { } public RdfParser(Feed feed) : base(feed) { }
@@ -111,4 +111,3 @@ namespace FeedCenter.FeedParsers
return feedItem; return feedItem;
} }
} }
}

View File

@@ -3,8 +3,8 @@ using Serilog;
using System; using System;
using System.Xml; using System.Xml;
namespace FeedCenter.FeedParsers namespace FeedCenter.FeedParsers;
{
internal class RssParser : FeedParserBase internal class RssParser : FeedParserBase
{ {
public RssParser(Feed feed) : base(feed) { } public RssParser(Feed feed) : base(feed) { }
@@ -120,4 +120,3 @@ namespace FeedCenter.FeedParsers
return feedItem; return feedItem;
} }
} }
}

View File

@@ -6,8 +6,8 @@ using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Realms; using Realms;
namespace FeedCenter namespace FeedCenter;
{
public class Category : RealmObject, INotifyDataErrorInfo public class Category : RealmObject, INotifyDataErrorInfo
{ {
public const string DefaultName = "< default >"; public const string DefaultName = "< default >";
@@ -73,4 +73,3 @@ namespace FeedCenter
_dataErrorDictionary.AddError(nameof(Name), "Name cannot be empty"); _dataErrorDictionary.AddError(nameof(Name), "Name cannot be empty");
} }
} }
}

View File

@@ -3,8 +3,8 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
namespace FeedCenter namespace FeedCenter;
{
internal class DataErrorDictionary : Dictionary<string, List<string>> internal class DataErrorDictionary : Dictionary<string, List<string>>
{ {
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
@@ -40,4 +40,3 @@ namespace FeedCenter
OnErrorsChanged(propertyName); OnErrorsChanged(propertyName);
} }
} }
}

View File

@@ -20,8 +20,8 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace FeedCenter namespace FeedCenter;
{
#region Enumerations #region Enumerations
public enum MultipleOpenAction public enum MultipleOpenAction
@@ -52,7 +52,8 @@ namespace FeedCenter
Timeout, Timeout,
ConnectionFailed, ConnectionFailed,
ServerError, ServerError,
Moved Moved,
TemporarilyUnavailable
} }
#endregion #endregion
@@ -135,7 +136,26 @@ namespace FeedCenter
} }
} }
public string Password { get; set; } [MapTo("Password")]
public string RawPassword { get; set; }
public string Password
{
get => RawPassword;
set
{
RawPassword = value;
if (!Authenticate)
{
_dataErrorDictionary.ClearErrors(nameof(Password));
return;
}
ValidateString(nameof(Password), RawPassword);
RaisePropertyChanged();
}
}
[MapTo("Name")] [MapTo("Name")]
private string RawName { get; set; } = string.Empty; private string RawName { get; set; } = string.Empty;
@@ -156,7 +176,27 @@ namespace FeedCenter
} }
public string Title { get; set; } public string Title { get; set; }
public string Username { get; set; }
[MapTo("Username")]
public string RawUsername { get; set; }
public string Username
{
get => RawUsername;
set
{
RawUsername = value;
if (!Authenticate)
{
_dataErrorDictionary.ClearErrors(nameof(Username));
return;
}
ValidateString(nameof(Username), RawUsername);
RaisePropertyChanged();
}
}
public bool HasErrors => _dataErrorDictionary.Any(); public bool HasErrors => _dataErrorDictionary.Any();
@@ -228,7 +268,18 @@ namespace FeedCenter
return new Tuple<FeedType, string>(FeedType.Unknown, string.Empty); return new Tuple<FeedType, string>(FeedType.Unknown, string.Empty);
} }
return new Tuple<FeedType, string>(FeedParserBase.DetectFeedType(retrieveResult.Item2), retrieveResult.Item2); var feedType = FeedType.Unknown;
try
{
feedType = FeedParserBase.DetectFeedType(retrieveResult.Item2);
}
catch
{
// Ignore
}
return new Tuple<FeedType, string>(feedType, retrieveResult.Item2);
} }
private Tuple<FeedReadResult, string> RetrieveFeed() private Tuple<FeedReadResult, string> RetrieveFeed()
@@ -299,6 +350,9 @@ namespace FeedCenter
switch (httpRequestException.StatusCode) switch (httpRequestException.StatusCode)
{ {
case HttpStatusCode.ServiceUnavailable:
return Tuple.Create(FeedReadResult.TemporarilyUnavailable, string.Empty);
case HttpStatusCode.InternalServerError: case HttpStatusCode.InternalServerError:
return Tuple.Create(FeedReadResult.ServerError, string.Empty); return Tuple.Create(FeedReadResult.ServerError, string.Empty);
@@ -319,16 +373,12 @@ namespace FeedCenter
if (httpRequestException.InnerException is not SocketException socketException) if (httpRequestException.InnerException is not SocketException socketException)
return Tuple.Create(FeedReadResult.UnknownError, string.Empty); return Tuple.Create(FeedReadResult.UnknownError, string.Empty);
switch (socketException.SocketErrorCode) return socketException.SocketErrorCode switch
{ {
case SocketError.NoData: SocketError.NoData => Tuple.Create(FeedReadResult.NoResponse, string.Empty),
return Tuple.Create(FeedReadResult.NoResponse, string.Empty); SocketError.HostNotFound => Tuple.Create(FeedReadResult.NotFound, string.Empty),
_ => Tuple.Create(FeedReadResult.UnknownError, string.Empty)
case SocketError.HostNotFound: };
return Tuple.Create(FeedReadResult.NotFound, string.Empty);
}
return Tuple.Create(FeedReadResult.UnknownError, string.Empty);
} }
catch (WebException webException) catch (WebException webException)
{ {
@@ -447,4 +497,3 @@ namespace FeedCenter
#endregion #endregion
} }
}

View File

@@ -3,8 +3,8 @@ using System.Text.RegularExpressions;
using FeedCenter.Options; using FeedCenter.Options;
using Realms; using Realms;
namespace FeedCenter namespace FeedCenter;
{
public partial class FeedItem : RealmObject public partial class FeedItem : RealmObject
{ {
public bool BeenRead { get; set; } public bool BeenRead { get; set; }
@@ -83,4 +83,3 @@ namespace FeedCenter
[GeneratedRegex("\\t")] [GeneratedRegex("\\t")]
private static partial Regex TabRegex(); private static partial Regex TabRegex();
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void DisplayCategory() private void DisplayCategory()
@@ -97,4 +97,3 @@ namespace FeedCenter
Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty; Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty;
} }
} }
}

View File

@@ -1,7 +1,7 @@
using System; using System;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void HandleCommandLine(string commandLine) private void HandleCommandLine(string commandLine)
@@ -35,4 +35,3 @@ namespace FeedCenter
HandleNewFeed(feedUrl); HandleNewFeed(feedUrl);
} }
} }
}

View File

@@ -3,8 +3,8 @@ using System.Linq;
using System.Net; using System.Net;
using System.Windows; using System.Windows;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private readonly string[] _chromeExtensions = { "chrome-extension://ehojfdcmnajoklleckniaifaijfnkpbi/subscribe.html?", "chrome-extension://nlbjncdgjeocebhnmkbbbdekmmmcbfjd/subscribe.html?" }; private readonly string[] _chromeExtensions = { "chrome-extension://ehojfdcmnajoklleckniaifaijfnkpbi/subscribe.html?", "chrome-extension://nlbjncdgjeocebhnmkbbbdekmmmcbfjd/subscribe.html?" };
@@ -52,4 +52,3 @@ namespace FeedCenter
Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data); Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data);
} }
} }
}

View File

@@ -2,9 +2,10 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading;
namespace FeedCenter;
namespace FeedCenter
{
public partial class MainWindow public partial class MainWindow
{ {
private delegate void NewFeedDelegate(string feedUrl); private delegate void NewFeedDelegate(string feedUrl);
@@ -63,7 +64,17 @@ namespace FeedCenter
} }
// Read the feed for the first time // Read the feed for the first time
var feedReadResult = feed.Read(); var feedReadResult = feed.Read(true);
// Check to see if this might be rate limited
if (feedReadResult == FeedReadResult.TemporarilyUnavailable)
{
// Wait a second
Thread.Sleep(1000);
// Try to read again
feedReadResult = feed.Read(true);
}
// See if we read the feed okay // See if we read the feed okay
if (feedReadResult == FeedReadResult.Success) if (feedReadResult == FeedReadResult.Success)
@@ -77,6 +88,11 @@ namespace FeedCenter
// Show a tip // Show a tip
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info); NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info);
_currentFeed = feed;
// Refresh the database to current settings
ResetDatabase();
// Re-initialize the feed display // Re-initialize the feed display
DisplayFeed(); DisplayFeed();
} }
@@ -88,15 +104,19 @@ namespace FeedCenter
var dialogResult = feedForm.Display(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)
{ return;
// Add the feed to the feed table // Add the feed to the feed table
_database.SaveChanges(() => _database.Feeds.Add(feed)); _database.SaveChanges(() => _database.Feeds.Add(feed));
_currentFeed = feed;
// Refresh the database to current settings
ResetDatabase();
// Re-initialize the feed display // Re-initialize the feed display
DisplayFeed(); DisplayFeed();
} }
} }
} }
}
}

View File

@@ -6,8 +6,8 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void HandleLinkTextListMouseUp(object sender, MouseButtonEventArgs e) private void HandleLinkTextListMouseUp(object sender, MouseButtonEventArgs e)
@@ -132,4 +132,3 @@ namespace FeedCenter
DisplayFeed(); DisplayFeed();
} }
} }
}

View File

@@ -7,8 +7,8 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private BackgroundWorker _feedReadWorker; private BackgroundWorker _feedReadWorker;
@@ -194,4 +194,3 @@ namespace FeedCenter
Thread.Sleep(Settings.Default.ProgressSleepInterval * 3); Thread.Sleep(Settings.Default.ProgressSleepInterval * 3);
} }
} }
}

View File

@@ -3,8 +3,8 @@ using FeedCenter.Properties;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void HandleHeaderLabelMouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void HandleHeaderLabelMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
@@ -30,4 +30,3 @@ namespace FeedCenter
InstalledBrowser.OpenLink(Settings.Default.Browser, _currentFeed.Link); InstalledBrowser.OpenLink(Settings.Default.Browser, _currentFeed.Link);
} }
} }
}

View File

@@ -11,8 +11,8 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow : IDisposable public partial class MainWindow : IDisposable
{ {
private Category _currentCategory; private Category _currentCategory;
@@ -426,4 +426,3 @@ namespace FeedCenter
#endregion #endregion
} }
}

View File

@@ -2,8 +2,8 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private Timer _mainTimer; private Timer _mainTimer;
@@ -56,4 +56,3 @@ namespace FeedCenter
StartTimer(); StartTimer();
} }
} }
}

View File

@@ -8,8 +8,8 @@ using ChrisKaczor.InstalledBrowsers;
using FeedCenter.Options; using FeedCenter.Options;
using FeedCenter.Properties; using FeedCenter.Properties;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void HandlePreviousToolbarButtonClick(object sender, RoutedEventArgs e) private void HandlePreviousToolbarButtonClick(object sender, RoutedEventArgs e)
@@ -233,4 +233,3 @@ namespace FeedCenter
MarkAllItemsAsRead(); MarkAllItemsAsRead();
} }
} }
}

View File

@@ -2,8 +2,8 @@
using FeedCenter.Properties; using FeedCenter.Properties;
using System.Windows; using System.Windows;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private static void InitializeUpdate() private static void InitializeUpdate()
@@ -37,4 +37,3 @@ namespace FeedCenter
UpdateCheck.DisplayUpdateInformation(true); UpdateCheck.DisplayUpdateInformation(true);
} }
} }
}

View File

@@ -7,8 +7,8 @@ using System.Windows.Controls;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
namespace FeedCenter namespace FeedCenter;
{
public partial class MainWindow public partial class MainWindow
{ {
private void LoadWindowSettings() private void LoadWindowSettings()
@@ -170,4 +170,3 @@ namespace FeedCenter
Settings.Default.PropertyChanged += HandlePropertyChanged; Settings.Default.PropertyChanged += HandlePropertyChanged;
} }
} }
}

View File

@@ -1,8 +1,8 @@
using FeedCenter.Properties; using FeedCenter.Properties;
using System.Windows.Forms; using System.Windows.Forms;
namespace FeedCenter namespace FeedCenter;
{
internal static class NotificationIcon internal static class NotificationIcon
{ {
private static MainWindow _mainForm; private static MainWindow _mainForm;
@@ -75,4 +75,3 @@ namespace FeedCenter
_notificationIcon.ShowBalloonTip(timeout, Resources.ApplicationDisplayName, text, icon); _notificationIcon.ShowBalloonTip(timeout, Resources.ApplicationDisplayName, text, icon);
} }
} }
}

View File

@@ -6,8 +6,8 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using FeedCenter.Data; using FeedCenter.Data;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public partial class BulkFeedWindow public partial class BulkFeedWindow
{ {
private List<CheckedListItem<Feed>> _checkedListBoxItems; private List<CheckedListItem<Feed>> _checkedListBoxItems;
@@ -98,4 +98,3 @@ namespace FeedCenter.Options
OpenComboBox.IsEnabled = !OpenComboBox.IsEnabled; OpenComboBox.IsEnabled = !OpenComboBox.IsEnabled;
} }
} }
}

View File

@@ -8,6 +8,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:options="clr-namespace:FeedCenter.Options"
d:DataContext="{d:DesignInstance Type=feedCenter:Category}" d:DataContext="{d:DesignInstance Type=feedCenter:Category}"
Title="CategoryWindow" Title="CategoryWindow"
Width="300" Width="300"
@@ -28,42 +29,23 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
<Grid Margin="6"> <StackPanel Margin="6"
<Grid.RowDefinitions> options:Spacing.Vertical="5">
<RowDefinition Height="Auto" /> <TextBox mah:TextBoxHelper.UseFloatingWatermark="True"
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Row="0"
Grid.Column="0">
<TextBox Name="NameTextBox"
VerticalAlignment="Center"
mah:TextBoxHelper.UseFloatingWatermark="True"
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.categoryNameLabel}" mah:TextBoxHelper.Watermark="{x:Static properties:Resources.categoryNameLabel}"
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}"> mah:TextBoxHelper.SelectAllOnFocus="True"
</TextBox> Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
</StackPanel>
<StackPanel <StackPanel
Grid.Column="0" options:Spacing.Horizontal="5"
Grid.Row="1"
Orientation="Horizontal" Orientation="Horizontal"
Margin="0,5,0,0"
HorizontalAlignment="Right"> HorizontalAlignment="Right">
<Button Content="{x:Static properties:Resources.OkayButton}" <Button Content="{x:Static properties:Resources.OkayButton}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="75" Width="75"
Margin="0,0,5,0"
IsDefault="True" IsDefault="True"
Click="HandleOkayButtonClick" /> Click="HandleOkayButtonClick" />
<Button Content="{x:Static properties:Resources.CancelButton}" <Button Content="{x:Static properties:Resources.CancelButton}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="75" Width="75"
IsCancel="True" /> IsCancel="True" />
</StackPanel> </StackPanel>
</Grid> </StackPanel>
</Window> </Window>

View File

@@ -2,8 +2,8 @@
using ChrisKaczor.Wpf.Validation; using ChrisKaczor.Wpf.Validation;
using FeedCenter.Data; using FeedCenter.Data;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public partial class CategoryWindow public partial class CategoryWindow
{ {
public CategoryWindow() public CategoryWindow()
@@ -48,4 +48,3 @@ namespace FeedCenter.Options
Close(); Close();
} }
} }
}

View File

@@ -6,9 +6,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance Type=feedCenter:Feed}" d:DataContext="{d:DesignInstance Type=feedCenter:Feed}"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:options="clr-namespace:FeedCenter.Options"
mc:Ignorable="d" mc:Ignorable="d"
Title="FeedWindow" Title="FeedWindow"
Height="300" Height="350"
Width="450" Width="450"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/FeedCenter;component/Resources/Application.ico" Icon="/FeedCenter;component/Resources/Application.ico"
@@ -23,175 +25,117 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
<Grid> <Grid Margin="6">
<TabControl Name="OptionsTabControl"
Margin="12,12,12,41">
<TabItem Header="{x:Static properties:Resources.generalTab}">
<Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<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.feedUrlLabel}" <TabControl Name="OptionsTabControl"
VerticalContentAlignment="Center"
Target="{Binding ElementName=UrlTextBox}"
Margin="6"
Padding="0" />
<TextBox Name="UrlTextBox"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="0"
Margin="6" mah:HeaderedControlHelper.HeaderFontSize="16"
mah:TabControlHelper.Underlined="SelectedTabItem">
<TabItem Header="{x:Static properties:Resources.generalTab}">
<StackPanel Margin="0,4"
options:Spacing.Vertical="8">
<TextBox Name="UrlTextBox"
mah:TextBoxHelper.UseFloatingWatermark="True"
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.feedUrlLabel}"
mah:TextBoxHelper.SelectAllOnFocus="True"
Text="{Binding Path=Source, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" /> Text="{Binding Path=Source, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
<Label Content="{x:Static properties:Resources.feedNameLabel}"
VerticalContentAlignment="Center"
Target="{Binding ElementName=NameTextBox}"
Grid.Row="1"
Grid.Column="0"
Margin="6"
Padding="0" />
<TextBox Name="NameTextBox" <TextBox Name="NameTextBox"
Grid.Column="1" mah:TextBoxHelper.UseFloatingWatermark="True"
Grid.Row="1" mah:TextBoxHelper.Watermark="{x:Static properties:Resources.feedNameLabel}"
Margin="6" mah:TextBoxHelper.SelectAllOnFocus="True"
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" /> Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
<Label Content="{x:Static properties:Resources.feedCategoryLabel}" <ComboBox Name="CategoryComboBox"
Target="{Binding ElementName=CategoryComboBox}"
VerticalContentAlignment="Center"
Grid.Row="2"
Grid.Column="0"
Margin="6"
Padding="0" />
<ComboBox Grid.Column="1"
Name="CategoryComboBox"
DisplayMemberPath="Name" DisplayMemberPath="Name"
SelectedValuePath="ID" SelectedValuePath="Id"
SelectedValue="{Binding Path=Category.Id}" SelectedValue="{Binding Path=CategoryId}"
Grid.Row="2" mah:TextBoxHelper.UseFloatingWatermark="True"
Margin="6" /> mah:TextBoxHelper.Watermark="{x:Static properties:Resources.feedCategoryLabel}" />
<CheckBox Grid.ColumnSpan="2"
Grid.Column="0" <CheckBox Name="ReadIntervalCheckBox"
Name="ReadIntervalCheckBox"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
IsChecked="{Binding Path=Enabled, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" IsChecked="{Binding Path=Enabled, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}">
Grid.Row="3" <StackPanel Orientation="Horizontal">
Margin="6">
<DockPanel>
<Label Content="{x:Static properties:Resources.feedReadIntervalPrefix}" <Label Content="{x:Static properties:Resources.feedReadIntervalPrefix}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Margin="0,0,5,0" Margin="0,0,5,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Padding="0" /> Padding="0" />
<TextBox Width="50" <mah:NumericUpDown Width="100"
Text="{Binding Path=CheckInterval, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" Maximum="10080"
IsEnabled="{Binding ElementName=ReadIntervalCheckBox, Path=IsChecked}" /> Minimum="1"
IsEnabled="{Binding ElementName=ReadIntervalCheckBox, Path=IsChecked}"
Value="{Binding CheckInterval, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
<Label Content="{x:Static properties:Resources.feedReadIntervalSuffix}" <Label Content="{x:Static properties:Resources.feedReadIntervalSuffix}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Margin="5,0,0,0" Margin="5,0,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Padding="0" /> Padding="0" />
</DockPanel> </StackPanel>
</CheckBox> </CheckBox>
</Grid> </StackPanel>
</TabItem> </TabItem>
<TabItem Header="{x:Static properties:Resources.readingTab}"> <TabItem Header="{x:Static properties:Resources.readingTab}">
<Grid> <StackPanel Margin="0,4"
<Grid.ColumnDefinitions> options:Spacing.Vertical="8">
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Content="{x:Static properties:Resources.openLabel}"
Target="{Binding ElementName=OpenComboBox}"
Padding="0"
VerticalContentAlignment="Center"
Margin="6" />
<ComboBox Name="OpenComboBox" <ComboBox Name="OpenComboBox"
VerticalContentAlignment="Center"
SelectedValue="{Binding Path=MultipleOpenAction, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}" SelectedValue="{Binding Path=MultipleOpenAction, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}"
SelectedValuePath="Tag" SelectedValuePath="Tag"
Grid.Row="0" mah:TextBoxHelper.UseFloatingWatermark="True"
Grid.Column="1" mah:TextBoxHelper.Watermark="{x:Static properties:Resources.openLabel}">
Margin="6">
<ComboBoxItem Content="{x:Static properties:Resources.openAllSingleToolbarButton}" <ComboBoxItem Content="{x:Static properties:Resources.openAllSingleToolbarButton}"
Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" /> Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" />
<ComboBoxItem Content="{x:Static properties:Resources.openAllMultipleToolbarButton}" <ComboBoxItem Content="{x:Static properties:Resources.openAllMultipleToolbarButton}"
Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" /> Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" />
</ComboBox> </ComboBox>
</Grid> </StackPanel>
</TabItem> </TabItem>
<TabItem Header="{x:Static properties:Resources.authenticationTab}"> <TabItem Header="{x:Static properties:Resources.authenticationTab}">
<Grid> <StackPanel Margin="0,4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox Content="{x:Static properties:Resources.requiresAuthenticationCheckBox}" <CheckBox Content="{x:Static properties:Resources.requiresAuthenticationCheckBox}"
Margin="0,0,0,4"
Name="RequiresAuthenticationCheckBox" Name="RequiresAuthenticationCheckBox"
Grid.ColumnSpan="2" IsChecked="{Binding Path=Authenticate, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
Grid.Row="0"
Grid.Column="0"
IsChecked="{Binding Path=Authenticate, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}"
Margin="6" />
<Label Content="{x:Static properties:Resources.authenticationUserNameLabel}"
Target="{Binding ElementName=AuthenticationUserNameTextBox}"
VerticalContentAlignment="Center"
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}"
Grid.Row="1"
Grid.Column="0"
Margin="6"
Padding="20,0,0,0" />
<TextBox Name="AuthenticationUserNameTextBox" <TextBox Name="AuthenticationUserNameTextBox"
Grid.Column="1" Margin="25,0,0,4"
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}" IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}"
Grid.Row="1" mah:TextBoxHelper.UseFloatingWatermark="True"
Margin="6" mah:TextBoxHelper.Watermark="{x:Static properties:Resources.authenticationUserNameLabel}"
Text="{Binding Path=Username, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" /> Text="{Binding Path=Username, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
<Label Content="{x:Static properties:Resources.authenticationPasswordLabel}"
Target="{Binding ElementName=AuthenticationPasswordTextBox}"
VerticalContentAlignment="Center"
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}"
Grid.Row="2"
Grid.Column="0"
Margin="6"
Padding="20,0,0,0" />
<PasswordBox Name="AuthenticationPasswordTextBox" <PasswordBox Name="AuthenticationPasswordTextBox"
Grid.Column="1" Margin="25,0,0,8"
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}" Style="{StaticResource MahApps.Styles.PasswordBox.Button.Revealed}"
Grid.Row="2" mah:PasswordBoxBindingBehavior.Password="{Binding Password, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True}"
Margin="6" /> mah:TextBoxHelper.UseFloatingWatermark="True"
</Grid> mah:TextBoxHelper.Watermark="{x:Static properties:Resources.authenticationPasswordLabel}"
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}" />
</StackPanel>
</TabItem> </TabItem>
</TabControl> </TabControl>
<StackPanel
Grid.Column="0"
Grid.Row="1"
Orientation="Horizontal"
Margin="0,5,0,0"
HorizontalAlignment="Right">
<Button Content="{x:Static properties:Resources.OkayButton}" <Button Content="{x:Static properties:Resources.OkayButton}"
Height="23"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
Width="75" Width="75"
Margin="0,0,5,0"
IsDefault="True" IsDefault="True"
Margin="0,0,93,12"
Click="HandleOkayButtonClick" /> Click="HandleOkayButtonClick" />
<Button Content="{x:Static properties:Resources.CancelButton}" <Button Content="{x:Static properties:Resources.CancelButton}"
Height="23"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
Width="75" Width="75"
IsCancel="True" IsCancel="True" />
Margin="0,0,12,12" /> </StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,13 +1,9 @@
using System.Linq; using ChrisKaczor.Wpf.Validation;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using ChrisKaczor.Wpf.Validation;
using FeedCenter.Data; using FeedCenter.Data;
using System.Windows;
namespace FeedCenter.Options;
namespace FeedCenter.Options
{
public partial class FeedWindow public partial class FeedWindow
{ {
public FeedWindow() public FeedWindow()
@@ -17,19 +13,14 @@ namespace FeedCenter.Options
public bool? Display(Feed feed, Window owner) public bool? Display(Feed feed, Window owner)
{ {
// Bind the category combo box
CategoryComboBox.ItemsSource = Database.Entities.Categories; CategoryComboBox.ItemsSource = Database.Entities.Categories;
// Set the data context
DataContext = feed; DataContext = feed;
// Set the title based on the state of the feed
Title = string.IsNullOrWhiteSpace(feed.Link) ? Properties.Resources.FeedWindowAdd : Properties.Resources.FeedWindowEdit; Title = string.IsNullOrWhiteSpace(feed.Link) ? Properties.Resources.FeedWindowAdd : Properties.Resources.FeedWindowEdit;
// Set the window owner
Owner = owner; Owner = owner;
// Show the dialog and result the result
return ShowDialog(); return ShowDialog();
} }
@@ -37,60 +28,17 @@ namespace FeedCenter.Options
{ {
var transaction = Database.Entities.BeginTransaction(); var transaction = Database.Entities.BeginTransaction();
var feed = (Feed) DataContext; if (!this.IsValid(OptionsTabControl))
// Get a list of all framework elements and explicit binding expressions
var bindingExpressions = this.GetBindingExpressions(new[] { UpdateSourceTrigger.Explicit });
// Loop over each binding expression and clear any existing error
this.ClearAllValidationErrors(bindingExpressions);
// Force all explicit bindings to update the source
this.UpdateAllSources(bindingExpressions);
// See if there are any errors
var hasError = bindingExpressions.Any(b => b.BindingExpression.HasError);
// If there was an error then set focus to the bad controls
if (hasError)
{ {
// Get the first framework element with an error
var firstErrorElement = bindingExpressions.First(b => b.BindingExpression.HasError).FrameworkElement;
// Loop over each tab item
foreach (TabItem tabItem in OptionsTabControl.Items)
{
// Cast the content as visual
var content = (Visual) tabItem.Content;
// See if the control with the error is a descendant
if (firstErrorElement.IsDescendantOf(content))
{
// Select the tab
tabItem.IsSelected = true;
break;
}
}
// Set focus
firstErrorElement.Focus();
transaction.Rollback(); transaction.Rollback();
return; return;
} }
if (RequiresAuthenticationCheckBox.IsChecked.GetValueOrDefault(false))
feed.Password = AuthenticationPasswordTextBox.Password;
transaction.Commit(); transaction.Commit();
Database.Entities.Refresh(); Database.Entities.Refresh();
// Dialog is good
DialogResult = true; DialogResult = true;
// Close the dialog
Close(); Close();
} }
} }
}

View File

@@ -9,8 +9,8 @@ using System.Xml;
using FeedCenter.Data; using FeedCenter.Data;
using Microsoft.Win32; using Microsoft.Win32;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public partial class FeedsOptionsPanel public partial class FeedsOptionsPanel
{ {
private CollectionViewSource _collectionViewSource; private CollectionViewSource _collectionViewSource;
@@ -422,4 +422,3 @@ namespace FeedCenter.Options
SetFeedButtonStates(); SetFeedButtonStates();
} }
} }
}

View File

@@ -1,9 +1,8 @@
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public enum MultipleLineDisplay public enum MultipleLineDisplay
{ {
Normal, Normal,
SingleLine, SingleLine,
FirstLine FirstLine
} }
}

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Controls; using System.Windows.Controls;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public partial class OptionsWindow public partial class OptionsWindow
{ {
private readonly List<OptionsPanelBase> _optionPanels = new(); private readonly List<OptionsPanelBase> _optionPanels = new();
@@ -73,4 +73,3 @@ namespace FeedCenter.Options
} }
} }
} }
}

View File

@@ -1,7 +1,7 @@
using Realms; using Realms;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public class Setting : RealmObject public class Setting : RealmObject
{ {
[PrimaryKey] [PrimaryKey]
@@ -11,4 +11,3 @@ namespace FeedCenter.Options
[Ignored] [Ignored]
public string Version { get; set; } public string Version { get; set; }
} }
}

View File

@@ -1,8 +1,8 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Windows; using System.Windows;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public class Spacing public class Spacing
{ {
public static double GetHorizontal(DependencyObject obj) public static double GetHorizontal(DependencyObject obj)
@@ -52,4 +52,3 @@ namespace FeedCenter.Options
DependencyProperty.RegisterAttached("Horizontal", typeof(double), typeof(Spacing), DependencyProperty.RegisterAttached("Horizontal", typeof(double), typeof(Spacing),
new UIPropertyMetadata(0d, HorizontalChangedCallback)); new UIPropertyMetadata(0d, HorizontalChangedCallback));
} }
}

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace FeedCenter.Options namespace FeedCenter.Options;
{
public class UserAgentItem public class UserAgentItem
{ {
public string Caption { get; set; } public string Caption { get; set; }
@@ -31,4 +31,3 @@ namespace FeedCenter.Options
} }
}; };
} }
}

View File

@@ -134,7 +134,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to _Password:. /// Looks up a localized string similar to Password.
/// </summary> /// </summary>
public static string authenticationPasswordLabel { public static string authenticationPasswordLabel {
get { get {
@@ -152,7 +152,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to _User name:. /// Looks up a localized string similar to User name.
/// </summary> /// </summary>
public static string authenticationUserNameLabel { public static string authenticationUserNameLabel {
get { get {
@@ -679,7 +679,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to _Category:. /// Looks up a localized string similar to Category.
/// </summary> /// </summary>
public static string feedCategoryLabel { public static string feedCategoryLabel {
get { get {
@@ -760,7 +760,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Feed _name:. /// Looks up a localized string similar to Name.
/// </summary> /// </summary>
public static string feedNameLabel { public static string feedNameLabel {
get { get {
@@ -868,7 +868,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Feed _URL:. /// Looks up a localized string similar to URL.
/// </summary> /// </summary>
public static string feedUrlLabel { public static string feedUrlLabel {
get { get {
@@ -1102,7 +1102,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to &quot;Open all&quot; _action:. /// Looks up a localized string similar to &quot;Open all&quot; action.
/// </summary> /// </summary>
public static string openLabel { public static string openLabel {
get { get {

View File

@@ -266,7 +266,7 @@
<value>Authentication</value> <value>Authentication</value>
</data> </data>
<data name="feedNameLabel" xml:space="preserve"> <data name="feedNameLabel" xml:space="preserve">
<value>Feed _name:</value> <value>Name</value>
</data> </data>
<data name="feedReadIntervalPrefix" xml:space="preserve"> <data name="feedReadIntervalPrefix" xml:space="preserve">
<value>_Refresh feed every</value> <value>_Refresh feed every</value>
@@ -275,7 +275,7 @@
<value>minutes</value> <value>minutes</value>
</data> </data>
<data name="feedUrlLabel" xml:space="preserve"> <data name="feedUrlLabel" xml:space="preserve">
<value>Feed _URL:</value> <value>URL</value>
</data> </data>
<data name="FeedWindowAdd" xml:space="preserve"> <data name="FeedWindowAdd" xml:space="preserve">
<value>Add Feed</value> <value>Add Feed</value>
@@ -293,10 +293,10 @@
<value>_Check for a new version on startup</value> <value>_Check for a new version on startup</value>
</data> </data>
<data name="authenticationPasswordLabel" xml:space="preserve"> <data name="authenticationPasswordLabel" xml:space="preserve">
<value>_Password:</value> <value>Password</value>
</data> </data>
<data name="authenticationUserNameLabel" xml:space="preserve"> <data name="authenticationUserNameLabel" xml:space="preserve">
<value>_User name:</value> <value>User name</value>
</data> </data>
<data name="requiresAuthenticationCheckBox" xml:space="preserve"> <data name="requiresAuthenticationCheckBox" xml:space="preserve">
<value>_Feed requires authentication</value> <value>_Feed requires authentication</value>
@@ -353,7 +353,7 @@
<value>&lt; Windows Default &gt;</value> <value>&lt; Windows Default &gt;</value>
</data> </data>
<data name="feedCategoryLabel" xml:space="preserve"> <data name="feedCategoryLabel" xml:space="preserve">
<value>_Category:</value> <value>Category</value>
</data> </data>
<data name="optionCategoryCategories" xml:space="preserve"> <data name="optionCategoryCategories" xml:space="preserve">
<value>Categories</value> <value>Categories</value>
@@ -407,7 +407,7 @@
<value>Reading</value> <value>Reading</value>
</data> </data>
<data name="openLabel" xml:space="preserve"> <data name="openLabel" xml:space="preserve">
<value>"Open all" _action:</value> <value>"Open all" action</value>
</data> </data>
<data name="DatabaseUpdate_5" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="DatabaseUpdate_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Scripts\DatabaseUpdate_5.sqlce;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> <value>..\Scripts\DatabaseUpdate_5.sqlce;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>

View File

@@ -3,8 +3,8 @@ using FeedCenter.Options;
using System; using System;
using System.Linq; using System.Linq;
namespace FeedCenter namespace FeedCenter;
{
public static class SettingsStore public static class SettingsStore
{ {
public static object OpenDataStore() public static object OpenDataStore()
@@ -53,4 +53,3 @@ namespace FeedCenter
}); });
} }
} }
}

View File

@@ -3,8 +3,8 @@ using System;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
namespace FeedCenter namespace FeedCenter;
{
public static class SystemConfiguration public static class SystemConfiguration
{ {
private static bool UseDebugPath => Environment.CommandLine.IndexOf("/debugPath", StringComparison.InvariantCultureIgnoreCase) != -1; private static bool UseDebugPath => Environment.CommandLine.IndexOf("/debugPath", StringComparison.InvariantCultureIgnoreCase) != -1;
@@ -32,4 +32,3 @@ namespace FeedCenter
} }
} }
} }
}