More modernization

- Split generic "common" libraries into specific libraries
- Use other packages in lieu of custom code
- General cleanup
This commit is contained in:
2023-04-05 16:06:38 -04:00
parent f480a6c373
commit b5f570688d
46 changed files with 1210 additions and 656 deletions

View File

@@ -1,12 +1,12 @@
using System;
using FeedCenter.Properties;
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using FeedCenter.Properties;
namespace FeedCenter
{
public partial class MainWindow : IDisposable
public partial class MainWindow
{
private void DisplayCategory()
{
@@ -96,12 +96,5 @@ namespace FeedCenter
Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty;
}
public void Dispose()
{
_mainTimer?.Dispose();
_feedReadWorker?.Dispose();
_commandLineListener?.Dispose();
}
}
}
}

View File

@@ -1,42 +1,38 @@
using Common.IO;
using System;
using System;
namespace FeedCenter
{
public partial class MainWindow
{
private InterprocessMessageListener _commandLineListener;
private void HandleCommandLine(object sender, InterprocessMessageListener.InterprocessMessageEventArgs e)
private void HandleCommandLine(string commandLine)
{
// If the command line is blank then ignore it
if (e.Message.Length == 0)
if (commandLine.Length == 0)
return;
// Pad the command line with a trailing space just to be lazy in parsing
var commandLine = e.Message + " ";
commandLine += " ";
// Look for the feed URL in the command line
var startPosition = commandLine.IndexOf("feed://", StringComparison.Ordinal);
// If we found one then we should extract and process it
if (startPosition > 0)
{
// Advance past the protocol
startPosition += 7;
// If nothing was found then exit
if (startPosition <= 0) return;
// Starting at the URL position look for the next space
var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal);
// Advance past the protocol
startPosition += 7;
// Extract the feed URL
var feedUrl = commandLine.Substring(startPosition, endPosition - startPosition);
// Starting at the URL position look for the next space
var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal);
// Add the HTTP protocol by default
feedUrl = "http://" + feedUrl;
// Extract the feed URL
var feedUrl = commandLine.Substring(startPosition, endPosition - startPosition);
// Create a new feed using the URL
HandleNewFeed(feedUrl);
}
// Add the HTTP protocol by default
feedUrl = "http://" + feedUrl;
// Create a new feed using the URL
HandleNewFeed(feedUrl);
}
}
}
}

View File

@@ -1,20 +1,29 @@
using System;
using FeedCenter.Options;
using System;
using System.Linq;
using System.Net;
using Common.Internet;
using FeedCenter.Options;
namespace FeedCenter
{
public partial class MainWindow
{
private delegate void NewFeedDelegate(string feedUrl);
private static string GetAbsoluteUrlString(string baseUrl, string url)
{
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
uri = new Uri(new Uri(baseUrl), uri);
return uri.ToString();
}
private void HandleNewFeed(string feedUrl)
{
// Create and configure the new feed
var feed = Feed.Create(_database);
feed.Source = feedUrl;
feed.Category = _database.DefaultCategory;
feed.Enabled = true;
// Try to detect the feed type
var feedTypeResult = feed.DetectFeedType();
@@ -32,7 +41,7 @@ namespace FeedCenter
// Look for all RSS or atom links in the document
var rssLinks = htmlDocument.DocumentNode.Descendants("link")
.Where(n => n.Attributes["type"] != null && (n.Attributes["type"].Value == "application/rss+xml" || n.Attributes["type"].Value == "application/atom+xml"))
.Select(n => new Tuple<string, string>(UrlHelper.GetAbsoluteUrlString(feed.Source, n.Attributes["href"].Value), WebUtility.HtmlDecode(n.Attributes["title"]?.Value ?? feedUrl)))
.Select(n => new Tuple<string, string>(GetAbsoluteUrlString(feed.Source, n.Attributes["href"].Value), WebUtility.HtmlDecode(n.Attributes["title"]?.Value ?? feedUrl)))
.Distinct()
.ToList();
@@ -91,4 +100,4 @@ namespace FeedCenter
}
}
}
}
}

View File

@@ -1,4 +1,6 @@
using System;
using CKaczor.InstalledBrowsers;
using FeedCenter.Properties;
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -49,19 +51,19 @@ namespace FeedCenter
// Get the feed item
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
// Open the item link
if (BrowserCommon.OpenLink(feedItem.Link))
{
// The feed item has been read and is no longer new
_database.SaveChanges(() =>
{
feedItem.BeenRead = true;
feedItem.New = false;
});
// Try to open the item link
if (!InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
return;
// Remove the item from the list
LinkTextList.Items.Remove(feedItem);
}
// The feed item has been read and is no longer new
_database.SaveChanges(() =>
{
feedItem.BeenRead = true;
feedItem.New = false;
});
// Remove the item from the list
LinkTextList.Items.Remove(feedItem);
}
private void HandleFeedButtonClick(object sender, RoutedEventArgs e)
@@ -130,4 +132,4 @@ namespace FeedCenter
DisplayFeed();
}
}
}
}

View File

@@ -1,4 +1,4 @@
using Common.Update;
using CKaczor.ApplicationUpdate;
using FeedCenter.Properties;
using System;
using System.Collections.Generic;
@@ -113,8 +113,8 @@ namespace FeedCenter
// Set the text to match the number of errors
FeedErrorsLink.Text = feedErrorCount == 1
? Properties.Resources.FeedErrorLink
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
? Properties.Resources.FeedErrorLink
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
}
private static void HandleFeedReadWorkerStart(object sender, DoWorkEventArgs e)
@@ -123,10 +123,10 @@ namespace FeedCenter
var database = new FeedCenterEntities();
// Get the worker
var worker = (BackgroundWorker)sender;
var worker = (BackgroundWorker) sender;
// Get the input information
var workerInput = (FeedReadWorkerInput)e.Argument ?? new FeedReadWorkerInput { Feed = null, ForceRead = false };
var workerInput = (FeedReadWorkerInput) e.Argument ?? new FeedReadWorkerInput { Feed = null, ForceRead = false };
// Setup for progress
var currentProgress = 0;
@@ -179,4 +179,4 @@ namespace FeedCenter
Thread.Sleep(Settings.Default.ProgressSleepInterval * 3);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using FeedCenter.Properties;
using CKaczor.InstalledBrowsers;
using FeedCenter.Properties;
using System.Windows;
using System.Windows.Input;
@@ -26,7 +27,7 @@ namespace FeedCenter
{
// Open the link for the current feed on a left double click
if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left)
BrowserCommon.OpenLink(_currentFeed.Link);
InstalledBrowser.OpenLink(Settings.Default.Browser, _currentFeed.Link);
}
}
}
}

View File

@@ -2,13 +2,13 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:FeedCenter.Properties"
xmlns:windows="clr-namespace:Common.Wpf.Windows;assembly=Common.Wpf"
xmlns:toolbar="clr-namespace:Common.Wpf.Toolbar;assembly=Common.Wpf"
xmlns:splitButton="clr-namespace:Common.Wpf.Toolbar.SplitButton;assembly=Common.Wpf"
xmlns:linkControl="clr-namespace:Common.Wpf.LinkControl;assembly=Common.Wpf"
xmlns:htmlTextBlock="clr-namespace:Common.Wpf.HtmlTextBlock;assembly=Common.Wpf"
xmlns:windows="clr-namespace:CKaczor.Wpf.Windows;assembly=Wpf.Windows.SnappingWindow"
xmlns:toolbar="clr-namespace:CKaczor.Wpf.Controls.Toolbar;assembly=Wpf.Controls.Toolbar"
xmlns:splitButton="clr-namespace:CKaczor.Wpf.Controls.Toolbar;assembly=Wpf.Controls.Toolbar"
xmlns:htmlTextBlock="clr-namespace:CKaczor.Wpf.Controls;assembly=Wpf.Controls.HtmlTextBlock"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:nameBasedGrid="clr-namespace:NameBasedGrid;assembly=NameBasedGrid"
xmlns:controls="clr-namespace:CKaczor.Wpf.Controls;assembly=Wpf.Controls.Link"
Title="MainWindow"
Height="360"
Width="252"
@@ -80,18 +80,19 @@
FontFamily="Marlett"
Content="r"
FontSize="8"
Grid.Column="1"></Button>
Grid.Column="1">
</Button>
</Grid>
<linkControl:LinkControl Name="NewVersionLink"
Height="21"
nameBasedGrid:NameBasedGrid.Row="NewVersionRow"
Text="{x:Static properties:Resources.NewVersionLink}"
Background="AntiqueWhite"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Visibility="Collapsed"
Click="HandleNewVersionLinkClick">
</linkControl:LinkControl>
<controls:Link Name="NewVersionLink"
Height="21"
nameBasedGrid:NameBasedGrid.Row="NewVersionRow"
Text="{x:Static properties:Resources.NewVersionLink}"
Background="AntiqueWhite"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Visibility="Collapsed"
Click="HandleNewVersionLinkClick">
</controls:Link>
<Grid Name="CategoryGrid"
Height="21"
nameBasedGrid:NameBasedGrid.Row="CategoryRow"
@@ -186,12 +187,14 @@
<Setter Property="Panel.Background"
TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
<DynamicResource
ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
<DynamicResource
ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="Panel.Cursor"
@@ -295,17 +298,17 @@
</splitButton:SplitButton>
</ToolBar>
</ToolBarTray>
<linkControl:LinkControl Name="FeedErrorsLink"
Height="21"
nameBasedGrid:NameBasedGrid.Row="FeedErrorsRow"
Text="{x:Static properties:Resources.FeedErrorsLink}"
ToolTip="{x:Static properties:Resources.showErrorsToolbarButton}"
Background="AntiqueWhite"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Visibility="Collapsed"
Click="HandleShowErrorsButtonClick">
</linkControl:LinkControl>
<controls:Link Name="FeedErrorsLink"
Height="21"
nameBasedGrid:NameBasedGrid.Row="FeedErrorsRow"
Text="{x:Static properties:Resources.FeedErrorsLink}"
ToolTip="{x:Static properties:Resources.showErrorsToolbarButton}"
Background="AntiqueWhite"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Visibility="Collapsed"
Click="HandleShowErrorsButtonClick">
</controls:Link>
</nameBasedGrid:NameBasedGrid>
</Border>
</windows:SnappingWindow>
</windows:SnappingWindow>

View File

@@ -1,9 +1,8 @@
using Common.Debug;
using Common.Helpers;
using Common.IO;
using Common.Update;
using CKaczor.ApplicationUpdate;
using CKaczor.Wpf.Application;
using FeedCenter.Data;
using FeedCenter.Properties;
using Serilog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -14,7 +13,7 @@ using System.Windows.Media;
namespace FeedCenter
{
public partial class MainWindow
public partial class MainWindow : IDisposable
{
private FeedCenterEntities _database;
private int _feedIndex;
@@ -28,6 +27,21 @@ namespace FeedCenter
InitializeComponent();
}
protected override async void OnClosed(EventArgs e)
{
base.OnClosed(e);
await SingleInstance.Stop();
}
public void Dispose()
{
_mainTimer?.Dispose();
_feedReadWorker?.Dispose();
GC.SuppressFinalize(this);
}
public async void Initialize()
{
// Setup the update handler
@@ -52,12 +66,12 @@ namespace FeedCenter
// Setup the database
_database = Database.Entities;
// Initialize the command line listener
_commandLineListener = new InterprocessMessageListener(Properties.Resources.ApplicationName);
_commandLineListener.MessageReceived += HandleCommandLine;
// Initialize the single instance listener
SingleInstance.MessageReceived += SingleInstance_MessageReceived;
await SingleInstance.StartAsync(App.Name);
// Handle any command line we were started with
HandleCommandLine(null, new InterprocessMessageListener.InterprocessMessageEventArgs(Environment.CommandLine));
HandleCommandLine(Environment.CommandLine);
// Create a timer to keep track of things we need to do
InitializeTimer();
@@ -73,7 +87,12 @@ namespace FeedCenter
if (UpdateCheck.UpdateAvailable)
NewVersionLink.Visibility = Visibility.Visible;
Tracer.WriteLine("MainForm creation finished");
Log.Logger.Information("MainForm creation finished");
}
private void SingleInstance_MessageReceived(object sender, string commandLine)
{
HandleCommandLine(commandLine);
}
#region Setting events
@@ -87,30 +106,36 @@ namespace FeedCenter
return;
}
if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.MultipleLineDisplay))
switch (e.PropertyName)
{
// Update the current feed
DisplayFeed();
}
else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.WindowLocked))
{
// Update the window for the new window lock value
HandleWindowLockState();
}
else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.ToolbarLocation))
{
// Update the window for the toolbar location
switch (Settings.Default.ToolbarLocation)
{
case Dock.Top:
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "TopToolbarRow");
case nameof(Settings.Default.MultipleLineDisplay):
// Update the current feed
DisplayFeed();
break;
case nameof(Settings.Default.WindowLocked):
// Update the window for the new window lock value
HandleWindowLockState();
break;
case nameof(Settings.Default.ToolbarLocation):
// Update the window for the toolbar location
switch (Settings.Default.ToolbarLocation)
{
case Dock.Top:
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "TopToolbarRow");
break;
case Dock.Bottom:
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "BottomToolbarRow");
break;
case Dock.Bottom:
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "BottomToolbarRow");
break;
}
break;
case Dock.Left:
case Dock.Right:
throw new NotSupportedException();
default:
throw new ArgumentOutOfRangeException(nameof(Settings.Default.ToolbarLocation));
}
break;
}
}
@@ -124,15 +149,15 @@ namespace FeedCenter
var feedCount = _feedList?.Count() ?? 0;
// Set button states
PreviousToolbarButton.IsEnabled = (feedCount > 1);
NextToolbarButton.IsEnabled = (feedCount > 1);
RefreshToolbarButton.IsEnabled = (feedCount > 0);
FeedButton.IsEnabled = (feedCount > 0);
OpenAllToolbarButton.IsEnabled = (feedCount > 0);
MarkReadToolbarButton.IsEnabled = (feedCount > 0);
FeedLabel.Visibility = (feedCount == 0 ? Visibility.Hidden : Visibility.Visible);
FeedButton.Visibility = (feedCount > 1 ? Visibility.Hidden : Visibility.Visible);
CategoryGrid.Visibility = (_database.Categories.Count() > 1 ? Visibility.Visible : Visibility.Collapsed);
PreviousToolbarButton.IsEnabled = feedCount > 1;
NextToolbarButton.IsEnabled = feedCount > 1;
RefreshToolbarButton.IsEnabled = feedCount > 0;
FeedButton.IsEnabled = feedCount > 0;
OpenAllToolbarButton.IsEnabled = feedCount > 0;
MarkReadToolbarButton.IsEnabled = feedCount > 0;
FeedLabel.Visibility = feedCount == 0 ? Visibility.Hidden : Visibility.Visible;
FeedButton.Visibility = feedCount > 1 ? Visibility.Hidden : Visibility.Visible;
CategoryGrid.Visibility = _database.Categories.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
}
private void InitializeDisplay()
@@ -196,7 +221,7 @@ namespace FeedCenter
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
// If the current feed has unread items then we can display it
if (_currentFeed.Items.Count(item => !item.BeenRead) > 0)
if (_currentFeed.Items.Any(item => !item.BeenRead))
{
found = true;
break;
@@ -204,8 +229,7 @@ namespace FeedCenter
// Increment the index and adjust if we've gone around the end
_feedIndex = (_feedIndex + 1) % feedCount;
}
while (_feedIndex != startIndex);
} while (_feedIndex != startIndex);
// If nothing was found then clear the current feed
if (!found)
@@ -263,7 +287,7 @@ namespace FeedCenter
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
// If the current feed has unread items then we can display it
if (_currentFeed.Items.Count(item => !item.BeenRead) > 0)
if (_currentFeed.Items.Any(item => !item.BeenRead))
{
found = true;
break;
@@ -275,8 +299,7 @@ namespace FeedCenter
// If we've gone below the start of the list then reset to the end
if (_feedIndex < 0)
_feedIndex = feedCount - 1;
}
while (_feedIndex != startIndex);
} while (_feedIndex != startIndex);
// If nothing was found then clear the current feed
if (!found)
@@ -395,4 +418,4 @@ namespace FeedCenter
#endregion
}
}
}

View File

@@ -1,4 +1,5 @@
using FeedCenter.Options;
using CKaczor.InstalledBrowsers;
using FeedCenter.Options;
using FeedCenter.Properties;
using System.IO;
using System.Linq;
@@ -26,9 +27,6 @@ namespace FeedCenter
// Create a new list of feed items
var feedItems = (from FeedItem feedItem in LinkTextList.Items select feedItem).ToList();
// Get the browser
var browser = BrowserCommon.FindBrowser(Settings.Default.Browser);
// Cache the settings object
var settings = Settings.Default;
@@ -39,7 +37,7 @@ namespace FeedCenter
foreach (var feedItem in feedItems)
{
// Try to open the link
if (BrowserCommon.OpenLink(browser, feedItem.Link))
if (InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
{
// Mark the feed as read
_database.SaveChanges(() => feedItem.BeenRead = true);
@@ -236,9 +234,9 @@ namespace FeedCenter
textWriter.Flush();
textWriter.Close();
BrowserCommon.OpenLink(fileName);
InstalledBrowser.OpenLink(Settings.Default.Browser, fileName);
MarkAllItemsAsRead();
}
}
}
}

View File

@@ -1,4 +1,4 @@
using Common.Update;
using CKaczor.ApplicationUpdate;
using FeedCenter.Properties;
using System.Windows;
@@ -8,12 +8,13 @@ namespace FeedCenter
{
private static void InitializeUpdate()
{
UpdateCheck.ApplicationName = Properties.Resources.ApplicationDisplayName;
UpdateCheck.UpdateServerType = ServerType.GitHub;
UpdateCheck.UpdateServer = Settings.Default.VersionLocation;
UpdateCheck.ApplicationShutdown = ApplicationShutdown;
UpdateCheck.ApplicationCurrentMessage = ApplicationCurrentMessage;
UpdateCheck.ApplicationUpdateMessage = ApplicationUpdateMessage;
UpdateCheck.Initialize(ServerType.GitHub,
Settings.Default.VersionLocation,
string.Empty,
Properties.Resources.ApplicationDisplayName,
ApplicationShutdown,
ApplicationCurrentMessage,
ApplicationUpdateMessage);
}
private static bool ApplicationUpdateMessage(string title, string message)
@@ -33,8 +34,7 @@ namespace FeedCenter
private void HandleNewVersionLinkClick(object sender, RoutedEventArgs e)
{
// Display update information
UpdateCheck.DisplayUpdateInformation(true);
}
}
}
}

View File

@@ -1,11 +1,11 @@
using FeedCenter.Properties;
using DebounceThrottle;
using FeedCenter.Properties;
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using Common.Helpers;
namespace FeedCenter
{
@@ -90,25 +90,22 @@ namespace FeedCenter
SaveWindowSettings();
// Save settings
_database.SaveChanges(() => Settings.Default.Save());
_database.SaveChanges(Settings.Default.Save);
// Get rid of the notification icon
NotificationIcon.Dispose();
}
private DelayedMethod _windowStateDelay;
private readonly DebounceDispatcher _updateWindowSettingsDispatcher = new(500);
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
{
_windowStateDelay ??= new DelayedMethod(500, UpdateWindowSettings);
_windowStateDelay.Reset();
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
}
private void HandleWindowLocationChanged(object sender, EventArgs e)
{
_windowStateDelay ??= new DelayedMethod(500, UpdateWindowSettings);
_windowStateDelay.Reset();
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
}
private void UpdateBorder()
@@ -152,6 +149,7 @@ namespace FeedCenter
}
private bool _activated;
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
@@ -172,4 +170,4 @@ namespace FeedCenter
Settings.Default.PropertyChanged += HandlePropertyChanged;
}
}
}
}