mirror of
https://github.com/ckaczor/FeedCenter.git
synced 2026-01-14 01:25:38 -05:00
More UI updates
This commit is contained in:
@@ -4,28 +4,47 @@ using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private void DisplayCategory()
|
||||
{
|
||||
private void DisplayCategory()
|
||||
{
|
||||
CategoryLabel.Text = string.Format(Properties.Resources.CategoryFilterHeader, _currentCategory == null ? Properties.Resources.AllCategory : _currentCategory.Name);
|
||||
}
|
||||
CategoryLabel.Text = string.Format(Properties.Resources.CategoryFilterHeader, _currentCategory == null ? Properties.Resources.AllCategory : _currentCategory.Name);
|
||||
}
|
||||
|
||||
private void HandleCategoryButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create a new context menu
|
||||
var contextMenu = new ContextMenu();
|
||||
private void HandleCategoryButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create a new context menu
|
||||
var contextMenu = new ContextMenu();
|
||||
|
||||
// Create the "all" menu item
|
||||
var menuItem = new MenuItem
|
||||
// Create the "all" menu item
|
||||
var menuItem = new MenuItem
|
||||
{
|
||||
Header = Properties.Resources.AllCategory,
|
||||
Tag = null,
|
||||
|
||||
// Set the current item to bold
|
||||
FontWeight = _currentCategory == null ? FontWeights.Bold : FontWeights.Normal
|
||||
};
|
||||
|
||||
// Handle the click
|
||||
menuItem.Click += HandleCategoryMenuItemClick;
|
||||
|
||||
// Add the item to the list
|
||||
contextMenu.Items.Add(menuItem);
|
||||
|
||||
// Loop over each feed
|
||||
foreach (var category in _database.Categories.OrderBy(category => category.Name))
|
||||
{
|
||||
// Create a menu item
|
||||
menuItem = new MenuItem
|
||||
{
|
||||
Header = Properties.Resources.AllCategory,
|
||||
Tag = null,
|
||||
Header = category.Name,
|
||||
Tag = category,
|
||||
|
||||
// Set the current item to bold
|
||||
FontWeight = _currentCategory == null ? FontWeights.Bold : FontWeights.Normal
|
||||
FontWeight = category.Id == _currentCategory?.Id ? FontWeights.Bold : FontWeights.Normal
|
||||
};
|
||||
|
||||
// Handle the click
|
||||
@@ -33,68 +52,48 @@ namespace FeedCenter
|
||||
|
||||
// Add the item to the list
|
||||
contextMenu.Items.Add(menuItem);
|
||||
|
||||
// Loop over each feed
|
||||
foreach (var category in _database.Categories.OrderBy(category => category.Name))
|
||||
{
|
||||
// Create a menu item
|
||||
menuItem = new MenuItem
|
||||
{
|
||||
Header = category.Name,
|
||||
Tag = category,
|
||||
|
||||
// Set the current item to bold
|
||||
FontWeight = category.Id == _currentCategory?.Id ? FontWeights.Bold : FontWeights.Normal
|
||||
};
|
||||
|
||||
// Handle the click
|
||||
menuItem.Click += HandleCategoryMenuItemClick;
|
||||
|
||||
// Add the item to the list
|
||||
contextMenu.Items.Add(menuItem);
|
||||
}
|
||||
|
||||
// Set the context menu placement to this button
|
||||
contextMenu.PlacementTarget = this;
|
||||
|
||||
// Open the context menu
|
||||
contextMenu.IsOpen = true;
|
||||
}
|
||||
|
||||
private void HandleCategoryMenuItemClick(object sender, RoutedEventArgs e)
|
||||
// Set the context menu placement to this button
|
||||
contextMenu.PlacementTarget = this;
|
||||
|
||||
// Open the context menu
|
||||
contextMenu.IsOpen = true;
|
||||
}
|
||||
|
||||
private void HandleCategoryMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get the menu item clicked
|
||||
var menuItem = (MenuItem) sender;
|
||||
|
||||
// Get the category from the menu item tab
|
||||
var category = (Category) menuItem.Tag;
|
||||
|
||||
// If the category changed then reset the current feed to the first in the category
|
||||
if (_currentCategory?.Id != category?.Id)
|
||||
{
|
||||
// Get the menu item clicked
|
||||
var menuItem = (MenuItem) sender;
|
||||
|
||||
// Get the category from the menu item tab
|
||||
var category = (Category) menuItem.Tag;
|
||||
|
||||
// If the category changed then reset the current feed to the first in the category
|
||||
if (_currentCategory?.Id != category?.Id)
|
||||
{
|
||||
_currentFeed = category == null ? _database.Feeds.FirstOrDefault() : category.Feeds.FirstOrDefault();
|
||||
}
|
||||
|
||||
// Set the current category
|
||||
_currentCategory = category;
|
||||
|
||||
// Get the current feed list to match the category
|
||||
_feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id);
|
||||
|
||||
// Refresh the feed index
|
||||
_feedIndex = -1;
|
||||
|
||||
// Get the first feed
|
||||
NextFeed();
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayCategory();
|
||||
DisplayFeed();
|
||||
|
||||
Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty;
|
||||
_currentFeed = category == null ? _database.Feeds.FirstOrDefault() : category.Feeds.FirstOrDefault();
|
||||
}
|
||||
|
||||
// Set the current category
|
||||
_currentCategory = category;
|
||||
|
||||
// Get the current feed list to match the category
|
||||
_feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id);
|
||||
|
||||
// Refresh the feed index
|
||||
_feedIndex = -1;
|
||||
|
||||
// Get the first feed
|
||||
NextFeed();
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayCategory();
|
||||
DisplayFeed();
|
||||
|
||||
Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private void HandleCommandLine(string commandLine)
|
||||
{
|
||||
private void HandleCommandLine(string commandLine)
|
||||
{
|
||||
// If the command line is blank then ignore it
|
||||
if (commandLine.Length == 0)
|
||||
return;
|
||||
// If the command line is blank then ignore it
|
||||
if (commandLine.Length == 0)
|
||||
return;
|
||||
|
||||
// Pad the command line with a trailing space just to be lazy in parsing
|
||||
commandLine += " ";
|
||||
// Pad the command line with a trailing space just to be lazy in parsing
|
||||
commandLine += " ";
|
||||
|
||||
// Look for the feed URL in the command line
|
||||
var startPosition = commandLine.IndexOf("feed://", StringComparison.Ordinal);
|
||||
// Look for the feed URL in the command line
|
||||
var startPosition = commandLine.IndexOf("feed://", StringComparison.Ordinal);
|
||||
|
||||
// If nothing was found then exit
|
||||
if (startPosition <= 0) return;
|
||||
// If nothing was found then exit
|
||||
if (startPosition <= 0) return;
|
||||
|
||||
// Advance past the protocol
|
||||
startPosition += 7;
|
||||
// Advance past the protocol
|
||||
startPosition += 7;
|
||||
|
||||
// Starting at the URL position look for the next space
|
||||
var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal);
|
||||
// Starting at the URL position look for the next space
|
||||
var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal);
|
||||
|
||||
// Extract the feed URL
|
||||
var feedUrl = commandLine[startPosition..endPosition];
|
||||
// Extract the feed URL
|
||||
var feedUrl = commandLine[startPosition..endPosition];
|
||||
|
||||
// Add the HTTP protocol by default
|
||||
feedUrl = "http://" + feedUrl;
|
||||
// Add the HTTP protocol by default
|
||||
feedUrl = "http://" + feedUrl;
|
||||
|
||||
// Create a new feed using the URL
|
||||
HandleNewFeed(feedUrl);
|
||||
}
|
||||
// Create a new feed using the URL
|
||||
HandleNewFeed(feedUrl);
|
||||
}
|
||||
}
|
||||
@@ -3,53 +3,52 @@ using System.Linq;
|
||||
using System.Net;
|
||||
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 void HandleDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
private readonly string[] _chromeExtensions = { "chrome-extension://ehojfdcmnajoklleckniaifaijfnkpbi/subscribe.html?", "chrome-extension://nlbjncdgjeocebhnmkbbbdekmmmcbfjd/subscribe.html?" };
|
||||
// Default to not allowed
|
||||
e.Effects = DragDropEffects.None;
|
||||
e.Handled = true;
|
||||
|
||||
private void HandleDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
// Default to not allowed
|
||||
e.Effects = DragDropEffects.None;
|
||||
e.Handled = true;
|
||||
// If there isn't any text in the data then it is not allowed
|
||||
if (!e.Data.GetDataPresent(DataFormats.Text))
|
||||
return;
|
||||
|
||||
// If there isn't any text in the data then it is not allowed
|
||||
if (!e.Data.GetDataPresent(DataFormats.Text))
|
||||
return;
|
||||
// Get the data as a string
|
||||
var data = (string) e.Data.GetData(DataFormats.Text);
|
||||
|
||||
// Get the data as a string
|
||||
var data = (string) e.Data.GetData(DataFormats.Text);
|
||||
// If the data doesn't look like a URI then it is not allowed
|
||||
if (!Uri.IsWellFormedUriString(data, UriKind.Absolute))
|
||||
return;
|
||||
|
||||
// If the data doesn't look like a URI then it is not allowed
|
||||
if (!Uri.IsWellFormedUriString(data, UriKind.Absolute))
|
||||
return;
|
||||
|
||||
// Allowed
|
||||
e.Effects = DragDropEffects.Copy;
|
||||
}
|
||||
|
||||
private void HandleDragDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
// Get the data as a string
|
||||
var data = (string) e.Data.GetData(DataFormats.Text);
|
||||
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return;
|
||||
|
||||
// Check to see if the data starts with any known Chrome extension
|
||||
var chromeExtension = _chromeExtensions.FirstOrDefault(data.StartsWith);
|
||||
|
||||
// Remove the Chrome extension URL and decode the URL
|
||||
if (chromeExtension != null)
|
||||
{
|
||||
data = data[chromeExtension.Length..];
|
||||
data = WebUtility.UrlDecode(data);
|
||||
}
|
||||
|
||||
// Handle the new feed but allow the drag/drop to complete
|
||||
Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data);
|
||||
}
|
||||
// Allowed
|
||||
e.Effects = DragDropEffects.Copy;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDragDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
// Get the data as a string
|
||||
var data = (string) e.Data.GetData(DataFormats.Text);
|
||||
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return;
|
||||
|
||||
// Check to see if the data starts with any known Chrome extension
|
||||
var chromeExtension = _chromeExtensions.FirstOrDefault(data.StartsWith);
|
||||
|
||||
// Remove the Chrome extension URL and decode the URL
|
||||
if (chromeExtension != null)
|
||||
{
|
||||
data = data[chromeExtension.Length..];
|
||||
data = WebUtility.UrlDecode(data);
|
||||
}
|
||||
|
||||
// Handle the new feed but allow the drag/drop to complete
|
||||
Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data);
|
||||
}
|
||||
}
|
||||
@@ -2,101 +2,121 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
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);
|
||||
|
||||
private static string GetAbsoluteUrlString(string baseUrl, string url)
|
||||
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();
|
||||
feed.Source = feedUrl;
|
||||
feed.CategoryId = _database.DefaultCategory.Id;
|
||||
|
||||
// Try to detect the feed type
|
||||
var feedTypeResult = feed.DetectFeedType();
|
||||
|
||||
// If we can't figure it out it could be an HTML page
|
||||
if (feedTypeResult.Item1 == FeedType.Unknown)
|
||||
{
|
||||
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
|
||||
if (!uri.IsAbsoluteUri)
|
||||
uri = new Uri(new Uri(baseUrl), uri);
|
||||
return uri.ToString();
|
||||
// Only check if the feed was able to be read - otherwise fall through and show the dialog
|
||||
if (feedTypeResult.Item2.Length > 0)
|
||||
{
|
||||
// Create and load an HTML document with the text
|
||||
var htmlDocument = new HtmlAgilityPack.HtmlDocument();
|
||||
htmlDocument.LoadHtml(feedTypeResult.Item2);
|
||||
|
||||
// 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>(GetAbsoluteUrlString(feed.Source, n.Attributes["href"].Value), WebUtility.HtmlDecode(n.Attributes["title"]?.Value ?? feedUrl)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
// If there was only one link found then switch to feed to it
|
||||
if (rssLinks.Count == 1)
|
||||
{
|
||||
feed.Source = rssLinks[0].Item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var feedChooserWindow = new FeedChooserWindow();
|
||||
var feedLink = feedChooserWindow.Display(this, rssLinks);
|
||||
|
||||
if (string.IsNullOrEmpty(feedLink))
|
||||
return;
|
||||
|
||||
feed.Source = feedLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleNewFeed(string feedUrl)
|
||||
// Read the feed for the first time
|
||||
var feedReadResult = feed.Read(true);
|
||||
|
||||
// Check to see if this might be rate limited
|
||||
if (feedReadResult == FeedReadResult.TemporarilyUnavailable)
|
||||
{
|
||||
// Create and configure the new feed
|
||||
var feed = Feed.Create();
|
||||
feed.Source = feedUrl;
|
||||
feed.CategoryId = _database.DefaultCategory.Id;
|
||||
// Wait a second
|
||||
Thread.Sleep(1000);
|
||||
|
||||
// Try to detect the feed type
|
||||
var feedTypeResult = feed.DetectFeedType();
|
||||
// Try to read again
|
||||
feedReadResult = feed.Read(true);
|
||||
}
|
||||
|
||||
// If we can't figure it out it could be an HTML page
|
||||
if (feedTypeResult.Item1 == FeedType.Unknown)
|
||||
{
|
||||
// Only check if the feed was able to be read - otherwise fall through and show the dialog
|
||||
if (feedTypeResult.Item2.Length > 0)
|
||||
{
|
||||
// Create and load an HTML document with the text
|
||||
var htmlDocument = new HtmlAgilityPack.HtmlDocument();
|
||||
htmlDocument.LoadHtml(feedTypeResult.Item2);
|
||||
// See if we read the feed okay
|
||||
if (feedReadResult == FeedReadResult.Success)
|
||||
{
|
||||
// Update the feed name to be the title
|
||||
feed.Name = feed.Title;
|
||||
|
||||
// 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>(GetAbsoluteUrlString(feed.Source, n.Attributes["href"].Value), WebUtility.HtmlDecode(n.Attributes["title"]?.Value ?? feedUrl)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
// Add the feed to the feed table
|
||||
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
||||
|
||||
// If there was only one link found then switch to feed to it
|
||||
if (rssLinks.Count == 1)
|
||||
{
|
||||
feed.Source = rssLinks[0].Item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var feedChooserWindow = new FeedChooserWindow();
|
||||
var feedLink = feedChooserWindow.Display(this, rssLinks);
|
||||
// Show a tip
|
||||
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info);
|
||||
|
||||
if (string.IsNullOrEmpty(feedLink))
|
||||
return;
|
||||
_currentFeed = feed;
|
||||
|
||||
feed.Source = feedLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Read the feed for the first time
|
||||
var feedReadResult = feed.Read();
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Feed read failed - create a new feed window
|
||||
var feedForm = new FeedWindow();
|
||||
|
||||
// See if we read the feed okay
|
||||
if (feedReadResult == FeedReadResult.Success)
|
||||
{
|
||||
// Update the feed name to be the title
|
||||
feed.Name = feed.Title;
|
||||
var dialogResult = feedForm.Display(feed, this);
|
||||
|
||||
// Add the feed to the feed table
|
||||
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
||||
// Display the new feed form
|
||||
if (!dialogResult.HasValue || !dialogResult.Value)
|
||||
return;
|
||||
|
||||
// Show a tip
|
||||
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info);
|
||||
// Add the feed to the feed table
|
||||
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Feed read failed - create a new feed window
|
||||
var feedForm = new FeedWindow();
|
||||
_currentFeed = feed;
|
||||
|
||||
var dialogResult = feedForm.Display(feed, this);
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Display the new feed form
|
||||
if (dialogResult.HasValue && dialogResult.Value)
|
||||
{
|
||||
// Add the feed to the feed table
|
||||
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
}
|
||||
}
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,130 +6,129 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
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)
|
||||
switch (e.ChangedButton)
|
||||
{
|
||||
switch (e.ChangedButton)
|
||||
{
|
||||
case MouseButton.XButton1:
|
||||
case MouseButton.XButton1:
|
||||
|
||||
PreviousFeed();
|
||||
break;
|
||||
PreviousFeed();
|
||||
break;
|
||||
|
||||
case MouseButton.XButton2:
|
||||
case MouseButton.XButton2:
|
||||
|
||||
NextFeed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleItemMouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Only handle the middle button
|
||||
if (e.ChangedButton != MouseButton.Middle)
|
||||
return;
|
||||
|
||||
// Get the feed item
|
||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
||||
|
||||
// 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 HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Get the feed item
|
||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
||||
|
||||
// Try to open the item link
|
||||
if (!InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||
return;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Create a new context menu
|
||||
var contextMenu = new ContextMenu();
|
||||
|
||||
// Loop over each feed
|
||||
foreach (var feed in _feedList.OrderBy(feed => feed.Name))
|
||||
{
|
||||
// Build a string to display the feed name and the unread count
|
||||
var display = $"{feed.Name} ({feed.Items.Count(item => !item.BeenRead):d})";
|
||||
|
||||
// Create a menu item
|
||||
var menuItem = new MenuItem
|
||||
{
|
||||
Header = display,
|
||||
Tag = feed,
|
||||
|
||||
// Set the current item to bold
|
||||
FontWeight = feed.Id == _currentFeed.Id ? FontWeights.Bold : FontWeights.Normal
|
||||
};
|
||||
|
||||
// Handle the click
|
||||
menuItem.Click += HandleFeedMenuItemClick;
|
||||
|
||||
// Add the item to the list
|
||||
contextMenu.Items.Add(menuItem);
|
||||
}
|
||||
|
||||
// Set the context menu placement to this button
|
||||
contextMenu.PlacementTarget = this;
|
||||
|
||||
// Open the context menu
|
||||
contextMenu.IsOpen = true;
|
||||
}
|
||||
|
||||
private void HandleFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get the menu item clicked
|
||||
var menuItem = (MenuItem) sender;
|
||||
|
||||
// Get the feed from the menu item tab
|
||||
var feed = (Feed) menuItem.Tag;
|
||||
|
||||
// Loop over all feeds and look for the index of the new one
|
||||
var feedIndex = 0;
|
||||
foreach (var loopFeed in _feedList.OrderBy(loopFeed => loopFeed.Name))
|
||||
{
|
||||
if (loopFeed.Id == feed.Id)
|
||||
{
|
||||
_feedIndex = feedIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
feedIndex++;
|
||||
}
|
||||
|
||||
// Set the current feed
|
||||
_currentFeed = feed;
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
NextFeed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleItemMouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Only handle the middle button
|
||||
if (e.ChangedButton != MouseButton.Middle)
|
||||
return;
|
||||
|
||||
// Get the feed item
|
||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
||||
|
||||
// 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 HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Get the feed item
|
||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
||||
|
||||
// Try to open the item link
|
||||
if (!InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||
return;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Create a new context menu
|
||||
var contextMenu = new ContextMenu();
|
||||
|
||||
// Loop over each feed
|
||||
foreach (var feed in _feedList.OrderBy(feed => feed.Name))
|
||||
{
|
||||
// Build a string to display the feed name and the unread count
|
||||
var display = $"{feed.Name} ({feed.Items.Count(item => !item.BeenRead):d})";
|
||||
|
||||
// Create a menu item
|
||||
var menuItem = new MenuItem
|
||||
{
|
||||
Header = display,
|
||||
Tag = feed,
|
||||
|
||||
// Set the current item to bold
|
||||
FontWeight = feed.Id == _currentFeed.Id ? FontWeights.Bold : FontWeights.Normal
|
||||
};
|
||||
|
||||
// Handle the click
|
||||
menuItem.Click += HandleFeedMenuItemClick;
|
||||
|
||||
// Add the item to the list
|
||||
contextMenu.Items.Add(menuItem);
|
||||
}
|
||||
|
||||
// Set the context menu placement to this button
|
||||
contextMenu.PlacementTarget = this;
|
||||
|
||||
// Open the context menu
|
||||
contextMenu.IsOpen = true;
|
||||
}
|
||||
|
||||
private void HandleFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get the menu item clicked
|
||||
var menuItem = (MenuItem) sender;
|
||||
|
||||
// Get the feed from the menu item tab
|
||||
var feed = (Feed) menuItem.Tag;
|
||||
|
||||
// Loop over all feeds and look for the index of the new one
|
||||
var feedIndex = 0;
|
||||
foreach (var loopFeed in _feedList.OrderBy(loopFeed => loopFeed.Name))
|
||||
{
|
||||
if (loopFeed.Id == feed.Id)
|
||||
{
|
||||
_feedIndex = feedIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
feedIndex++;
|
||||
}
|
||||
|
||||
// Set the current feed
|
||||
_currentFeed = feed;
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
}
|
||||
}
|
||||
@@ -7,191 +7,190 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private BackgroundWorker _feedReadWorker;
|
||||
|
||||
private class FeedReadWorkerInput
|
||||
{
|
||||
private BackgroundWorker _feedReadWorker;
|
||||
public bool ForceRead { get; }
|
||||
public Guid? FeedId { get; }
|
||||
|
||||
private class FeedReadWorkerInput
|
||||
public FeedReadWorkerInput()
|
||||
{
|
||||
public bool ForceRead { get; }
|
||||
public Guid? FeedId { get; }
|
||||
|
||||
public FeedReadWorkerInput()
|
||||
{
|
||||
}
|
||||
|
||||
public FeedReadWorkerInput(bool forceRead)
|
||||
{
|
||||
ForceRead = forceRead;
|
||||
}
|
||||
|
||||
public FeedReadWorkerInput(bool forceRead, Guid? feedId)
|
||||
{
|
||||
ForceRead = forceRead;
|
||||
FeedId = feedId;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetProgressMode(bool value, int feedCount)
|
||||
public FeedReadWorkerInput(bool forceRead)
|
||||
{
|
||||
// Refresh the progress bar if we need it
|
||||
if (value)
|
||||
{
|
||||
FeedReadProgress.Value = 0;
|
||||
FeedReadProgress.Maximum = feedCount + 2;
|
||||
FeedReadProgress.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
FeedReadProgress.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
ForceRead = forceRead;
|
||||
}
|
||||
|
||||
private void ReadCurrentFeed(bool forceRead = false)
|
||||
public FeedReadWorkerInput(bool forceRead, Guid? feedId)
|
||||
{
|
||||
// Don't read if we're already working
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Don't read if there is nothing to read
|
||||
if (!_database.Feeds.Any())
|
||||
return;
|
||||
|
||||
// Switch to progress mode
|
||||
SetProgressMode(true, 1);
|
||||
|
||||
// Create the input class
|
||||
var workerInput = new FeedReadWorkerInput(forceRead, _currentFeed.Id);
|
||||
|
||||
// Start the worker
|
||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
||||
}
|
||||
|
||||
private void ReadFeeds(bool forceRead = false)
|
||||
{
|
||||
// Don't read if we're already working
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Don't read if there is nothing to read
|
||||
if (!_database.Feeds.Any())
|
||||
return;
|
||||
|
||||
// Switch to progress mode
|
||||
SetProgressMode(true, _database.Feeds.Count);
|
||||
|
||||
// Create the input class
|
||||
var workerInput = new FeedReadWorkerInput(forceRead);
|
||||
|
||||
// Start the worker
|
||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
||||
}
|
||||
|
||||
private void HandleFeedReadWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
// Set progress
|
||||
FeedReadProgress.Value = e.ProgressPercentage;
|
||||
}
|
||||
|
||||
private void HandleFeedReadWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Save settings
|
||||
Settings.Default.Save();
|
||||
|
||||
// Set the read timestamp
|
||||
_lastFeedRead = DateTime.Now;
|
||||
|
||||
// Update the current feed
|
||||
DisplayFeed();
|
||||
|
||||
// Switch to normal mode
|
||||
SetProgressMode(false, 0);
|
||||
|
||||
// Check for update
|
||||
if (UpdateCheck.UpdateAvailable)
|
||||
NewVersionLink.Visibility = Visibility.Visible;
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void UpdateErrorLink()
|
||||
{
|
||||
var feedErrorCount = _database.Feeds.Count(f => f.LastReadResult != FeedReadResult.Success);
|
||||
|
||||
// Set the visibility of the error link
|
||||
FeedErrorsLink.Visibility = feedErrorCount == 0 ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
// Set the text to match the number of errors
|
||||
FeedErrorsLink.Text = feedErrorCount == 1
|
||||
? Properties.Resources.FeedErrorLink
|
||||
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
|
||||
}
|
||||
|
||||
private static void HandleFeedReadWorkerStart(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
// Create a new database instance for just this thread
|
||||
var database = new FeedCenterEntities();
|
||||
|
||||
// Get the worker
|
||||
var worker = (BackgroundWorker) sender;
|
||||
|
||||
// Get the input information
|
||||
var workerInput = (FeedReadWorkerInput) e.Argument ?? new FeedReadWorkerInput();
|
||||
|
||||
// Setup for progress
|
||||
var currentProgress = 0;
|
||||
|
||||
// Create the list of feeds to read
|
||||
var feedsToRead = new List<Feed>();
|
||||
|
||||
// If we have a single feed then add it to the list - otherwise add them all
|
||||
if (workerInput.FeedId != null)
|
||||
feedsToRead.Add(database.Feeds.First(feed => feed.Id == workerInput.FeedId));
|
||||
else
|
||||
feedsToRead.AddRange(database.Feeds);
|
||||
|
||||
// Loop over each feed and read it
|
||||
foreach (var feed in feedsToRead)
|
||||
{
|
||||
// Read the feed
|
||||
database.SaveChanges(() => feed.Read(workerInput.ForceRead));
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
}
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
|
||||
// See if we're due for a version check
|
||||
if (DateTime.Now - Settings.Default.LastVersionCheck >= Settings.Default.VersionCheckInterval)
|
||||
{
|
||||
// Get the update information
|
||||
UpdateCheck.CheckForUpdate().Wait();
|
||||
|
||||
// Update the last check time
|
||||
Settings.Default.LastVersionCheck = DateTime.Now;
|
||||
}
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
|
||||
// Sleep for a little bit so the user can see the update
|
||||
Thread.Sleep(Settings.Default.ProgressSleepInterval * 3);
|
||||
ForceRead = forceRead;
|
||||
FeedId = feedId;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetProgressMode(bool value, int feedCount)
|
||||
{
|
||||
// Refresh the progress bar if we need it
|
||||
if (value)
|
||||
{
|
||||
FeedReadProgress.Value = 0;
|
||||
FeedReadProgress.Maximum = feedCount + 2;
|
||||
FeedReadProgress.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
FeedReadProgress.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadCurrentFeed(bool forceRead = false)
|
||||
{
|
||||
// Don't read if we're already working
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Don't read if there is nothing to read
|
||||
if (!_database.Feeds.Any())
|
||||
return;
|
||||
|
||||
// Switch to progress mode
|
||||
SetProgressMode(true, 1);
|
||||
|
||||
// Create the input class
|
||||
var workerInput = new FeedReadWorkerInput(forceRead, _currentFeed.Id);
|
||||
|
||||
// Start the worker
|
||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
||||
}
|
||||
|
||||
private void ReadFeeds(bool forceRead = false)
|
||||
{
|
||||
// Don't read if we're already working
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Don't read if there is nothing to read
|
||||
if (!_database.Feeds.Any())
|
||||
return;
|
||||
|
||||
// Switch to progress mode
|
||||
SetProgressMode(true, _database.Feeds.Count);
|
||||
|
||||
// Create the input class
|
||||
var workerInput = new FeedReadWorkerInput(forceRead);
|
||||
|
||||
// Start the worker
|
||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
||||
}
|
||||
|
||||
private void HandleFeedReadWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
// Set progress
|
||||
FeedReadProgress.Value = e.ProgressPercentage;
|
||||
}
|
||||
|
||||
private void HandleFeedReadWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Save settings
|
||||
Settings.Default.Save();
|
||||
|
||||
// Set the read timestamp
|
||||
_lastFeedRead = DateTime.Now;
|
||||
|
||||
// Update the current feed
|
||||
DisplayFeed();
|
||||
|
||||
// Switch to normal mode
|
||||
SetProgressMode(false, 0);
|
||||
|
||||
// Check for update
|
||||
if (UpdateCheck.UpdateAvailable)
|
||||
NewVersionLink.Visibility = Visibility.Visible;
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void UpdateErrorLink()
|
||||
{
|
||||
var feedErrorCount = _database.Feeds.Count(f => f.LastReadResult != FeedReadResult.Success);
|
||||
|
||||
// Set the visibility of the error link
|
||||
FeedErrorsLink.Visibility = feedErrorCount == 0 ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
// Set the text to match the number of errors
|
||||
FeedErrorsLink.Text = feedErrorCount == 1
|
||||
? Properties.Resources.FeedErrorLink
|
||||
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
|
||||
}
|
||||
|
||||
private static void HandleFeedReadWorkerStart(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
// Create a new database instance for just this thread
|
||||
var database = new FeedCenterEntities();
|
||||
|
||||
// Get the worker
|
||||
var worker = (BackgroundWorker) sender;
|
||||
|
||||
// Get the input information
|
||||
var workerInput = (FeedReadWorkerInput) e.Argument ?? new FeedReadWorkerInput();
|
||||
|
||||
// Setup for progress
|
||||
var currentProgress = 0;
|
||||
|
||||
// Create the list of feeds to read
|
||||
var feedsToRead = new List<Feed>();
|
||||
|
||||
// If we have a single feed then add it to the list - otherwise add them all
|
||||
if (workerInput.FeedId != null)
|
||||
feedsToRead.Add(database.Feeds.First(feed => feed.Id == workerInput.FeedId));
|
||||
else
|
||||
feedsToRead.AddRange(database.Feeds);
|
||||
|
||||
// Loop over each feed and read it
|
||||
foreach (var feed in feedsToRead)
|
||||
{
|
||||
// Read the feed
|
||||
database.SaveChanges(() => feed.Read(workerInput.ForceRead));
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
}
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
|
||||
// See if we're due for a version check
|
||||
if (DateTime.Now - Settings.Default.LastVersionCheck >= Settings.Default.VersionCheckInterval)
|
||||
{
|
||||
// Get the update information
|
||||
UpdateCheck.CheckForUpdate().Wait();
|
||||
|
||||
// Update the last check time
|
||||
Settings.Default.LastVersionCheck = DateTime.Now;
|
||||
}
|
||||
|
||||
// Increment progress
|
||||
currentProgress += 1;
|
||||
|
||||
// Report progress
|
||||
worker.ReportProgress(currentProgress);
|
||||
|
||||
// Sleep for a little bit so the user can see the update
|
||||
Thread.Sleep(Settings.Default.ProgressSleepInterval * 3);
|
||||
}
|
||||
}
|
||||
@@ -3,31 +3,30 @@ using FeedCenter.Properties;
|
||||
using System.Windows;
|
||||
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)
|
||||
{
|
||||
// Ignore if the window is locked
|
||||
if (Settings.Default.WindowLocked)
|
||||
return;
|
||||
// Ignore if the window is locked
|
||||
if (Settings.Default.WindowLocked)
|
||||
return;
|
||||
|
||||
// Start dragging
|
||||
DragMove();
|
||||
}
|
||||
// Start dragging
|
||||
DragMove();
|
||||
}
|
||||
|
||||
private void HandleCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Close the window
|
||||
Close();
|
||||
}
|
||||
private void HandleCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Close the window
|
||||
Close();
|
||||
}
|
||||
|
||||
private void HandleFeedLabelMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Open the link for the current feed on a left double click
|
||||
if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left)
|
||||
InstalledBrowser.OpenLink(Settings.Default.Browser, _currentFeed.Link);
|
||||
}
|
||||
private void HandleFeedLabelMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Open the link for the current feed on a left double click
|
||||
if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left)
|
||||
InstalledBrowser.OpenLink(Settings.Default.Browser, _currentFeed.Link);
|
||||
}
|
||||
}
|
||||
@@ -11,419 +11,418 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow : IDisposable
|
||||
{
|
||||
public partial class MainWindow : IDisposable
|
||||
private Category _currentCategory;
|
||||
private Feed _currentFeed;
|
||||
private FeedCenterEntities _database;
|
||||
private int _feedIndex;
|
||||
private IEnumerable<Feed> _feedList;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
private Category _currentCategory;
|
||||
private Feed _currentFeed;
|
||||
private FeedCenterEntities _database;
|
||||
private int _feedIndex;
|
||||
private IEnumerable<Feed> _feedList;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mainTimer?.Dispose();
|
||||
_feedReadWorker?.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override async void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
|
||||
await SingleInstance.Stop();
|
||||
}
|
||||
|
||||
public async void Initialize()
|
||||
{
|
||||
// Setup the update handler
|
||||
InitializeUpdate();
|
||||
|
||||
// Show the notification icon
|
||||
NotificationIcon.Initialize(this);
|
||||
|
||||
// Load window settings
|
||||
LoadWindowSettings();
|
||||
|
||||
// Set the foreground color to something that can be seen
|
||||
LinkTextList.Foreground = System.Drawing.SystemColors.Desktop.GetBrightness() < 0.5
|
||||
? Brushes.White
|
||||
: Brushes.Black;
|
||||
HeaderLabel.Foreground = LinkTextList.Foreground;
|
||||
|
||||
// Create the background worker that does the actual reading
|
||||
_feedReadWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
|
||||
_feedReadWorker.DoWork += HandleFeedReadWorkerStart;
|
||||
_feedReadWorker.ProgressChanged += HandleFeedReadWorkerProgressChanged;
|
||||
_feedReadWorker.RunWorkerCompleted += HandleFeedReadWorkerCompleted;
|
||||
|
||||
// Setup the database
|
||||
_database = Database.Entities;
|
||||
|
||||
// Initialize the single instance listener
|
||||
SingleInstance.MessageReceived += SingleInstance_MessageReceived;
|
||||
await SingleInstance.StartAsync(App.Name);
|
||||
|
||||
// Handle any command line we were started with
|
||||
HandleCommandLine(Environment.CommandLine);
|
||||
|
||||
// Create a timer to keep track of things we need to do
|
||||
InitializeTimer();
|
||||
|
||||
// Initialize the feed display
|
||||
InitializeDisplay();
|
||||
|
||||
// Check for update
|
||||
if (Settings.Default.CheckVersionAtStartup)
|
||||
await UpdateCheck.CheckForUpdate();
|
||||
|
||||
// Show the link if updates are available
|
||||
if (UpdateCheck.UpdateAvailable)
|
||||
NewVersionLink.Visibility = Visibility.Visible;
|
||||
|
||||
Log.Logger.Information("MainForm creation finished");
|
||||
}
|
||||
|
||||
private void SingleInstance_MessageReceived(object sender, string commandLine)
|
||||
{
|
||||
HandleCommandLine(commandLine);
|
||||
}
|
||||
|
||||
#region Setting events
|
||||
|
||||
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
// Make sure we're on the right thread
|
||||
if (!Dispatcher.CheckAccess())
|
||||
{
|
||||
Dispatcher.Invoke(new EventHandler<PropertyChangedEventArgs>(HandlePropertyChanged), sender, e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
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.Left:
|
||||
case Dock.Right:
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database helpers
|
||||
|
||||
private void ResetDatabase()
|
||||
{
|
||||
// Get the ID of the current feed
|
||||
var currentId = _currentFeed?.IsValid ?? false ? _currentFeed.Id : Guid.Empty;
|
||||
|
||||
// Create a new database object
|
||||
_database.Refresh();
|
||||
|
||||
_feedList = _currentCategory == null
|
||||
? _database.Feeds.ToList()
|
||||
: _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id).ToList();
|
||||
|
||||
UpdateToolbarButtonState();
|
||||
|
||||
// Get a list of feeds ordered by name
|
||||
var feedList = _feedList.OrderBy(f => f.Name).ToList();
|
||||
|
||||
// First try to find the current feed by ID to see if it is still there
|
||||
var newIndex = feedList.FindIndex(f => f.Id == currentId);
|
||||
|
||||
if (newIndex == -1)
|
||||
{
|
||||
// The current feed isn't there anymore so see if we can find a feed at the old index
|
||||
if (feedList.ElementAtOrDefault(_feedIndex) != null)
|
||||
newIndex = _feedIndex;
|
||||
|
||||
// If there is no feed at the old location then give up and go back to the start
|
||||
if (newIndex == -1 && feedList.Count > 0)
|
||||
newIndex = 0;
|
||||
}
|
||||
|
||||
// Set the current index to the new index
|
||||
_feedIndex = newIndex;
|
||||
|
||||
// Re-get the current feed
|
||||
_currentFeed = _feedIndex == -1
|
||||
? null
|
||||
: _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Feed display
|
||||
|
||||
private void UpdateToolbarButtonState()
|
||||
{
|
||||
// Cache the feed count to save (a little) time
|
||||
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;
|
||||
}
|
||||
|
||||
private void InitializeDisplay()
|
||||
{
|
||||
// Get the last category (defaulting to none)
|
||||
_currentCategory =
|
||||
_database.Categories.FirstOrDefault(category =>
|
||||
category.Id.ToString() == Settings.Default.LastCategoryID);
|
||||
DisplayCategory();
|
||||
|
||||
// Get the current feed list to match the category
|
||||
_feedList = _currentCategory == null
|
||||
? _database.Feeds
|
||||
: _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id);
|
||||
|
||||
UpdateToolbarButtonState();
|
||||
|
||||
// Clear the link list
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
// Refresh the feed index
|
||||
_feedIndex = -1;
|
||||
|
||||
// Start the timer
|
||||
StartTimer();
|
||||
|
||||
// Don't go further if we have no feeds
|
||||
if (!_feedList.Any())
|
||||
return;
|
||||
|
||||
// Get the first feed
|
||||
NextFeed();
|
||||
}
|
||||
|
||||
private void NextFeed()
|
||||
{
|
||||
var feedCount = _feedList.Count();
|
||||
|
||||
if (feedCount == 0)
|
||||
return;
|
||||
|
||||
if (Settings.Default.DisplayEmptyFeeds)
|
||||
{
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track if we found something
|
||||
var found = false;
|
||||
|
||||
// Remember our starting position
|
||||
var startIndex = _feedIndex == -1 ? 0 : _feedIndex;
|
||||
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
|
||||
// Loop until we come back to the start index
|
||||
do
|
||||
{
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
|
||||
// If the current feed has unread items then we can display it
|
||||
if (_currentFeed.Items.Any(item => !item.BeenRead))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
} while (_feedIndex != startIndex);
|
||||
|
||||
// If nothing was found then clear the current feed
|
||||
if (!found)
|
||||
{
|
||||
_feedIndex = -1;
|
||||
_currentFeed = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
}
|
||||
|
||||
private void PreviousFeed()
|
||||
{
|
||||
var feedCount = _feedList.Count();
|
||||
|
||||
if (feedCount == 0)
|
||||
return;
|
||||
|
||||
if (Settings.Default.DisplayEmptyFeeds)
|
||||
{
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track if we found something
|
||||
var found = false;
|
||||
|
||||
// Remember our starting position
|
||||
var startIndex = _feedIndex == -1 ? 0 : _feedIndex;
|
||||
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
|
||||
// Loop until we come back to the start index
|
||||
do
|
||||
{
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
|
||||
// If the current feed has unread items then we can display it
|
||||
if (_currentFeed.Items.Any(item => !item.BeenRead))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
} while (_feedIndex != startIndex);
|
||||
|
||||
// If nothing was found then clear the current feed
|
||||
if (!found)
|
||||
{
|
||||
_feedIndex = -1;
|
||||
_currentFeed = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
}
|
||||
|
||||
private void UpdateOpenAllButton()
|
||||
{
|
||||
var multipleOpenAction = _currentFeed.MultipleOpenAction;
|
||||
|
||||
switch (multipleOpenAction)
|
||||
{
|
||||
case MultipleOpenAction.IndividualPages:
|
||||
OpenAllToolbarButton.ToolTip = Properties.Resources.openAllMultipleToolbarButton;
|
||||
break;
|
||||
case MultipleOpenAction.SinglePage:
|
||||
OpenAllToolbarButton.ToolTip = Properties.Resources.openAllSingleToolbarButton;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayFeed()
|
||||
{
|
||||
// Just clear the display if we have no feed
|
||||
if (_currentFeed == null)
|
||||
{
|
||||
FeedLabel.Text = string.Empty;
|
||||
FeedButton.Visibility = Visibility.Hidden;
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the header to the feed title
|
||||
FeedLabel.Text = _currentFeed.Name.Length > 0 ? _currentFeed.Name : _currentFeed.Title;
|
||||
FeedButton.Visibility = _feedList.Count() > 1 ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
// Clear the current list
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
// Sort the items by sequence
|
||||
var sortedItems = _currentFeed.Items.Where(item => !item.BeenRead).OrderBy(item => item.Sequence);
|
||||
|
||||
// Loop over all items in the current feed
|
||||
foreach (var feedItem in sortedItems)
|
||||
{
|
||||
// Add the list item
|
||||
LinkTextList.Items.Add(feedItem);
|
||||
}
|
||||
|
||||
UpdateOpenAllButton();
|
||||
}
|
||||
|
||||
private void MarkAllItemsAsRead()
|
||||
{
|
||||
// Loop over all items and mark them as read
|
||||
_database.SaveChanges(() =>
|
||||
{
|
||||
foreach (FeedItem feedItem in LinkTextList.Items)
|
||||
feedItem.BeenRead = true;
|
||||
});
|
||||
|
||||
// Clear the list
|
||||
LinkTextList.Items.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mainTimer?.Dispose();
|
||||
_feedReadWorker?.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override async void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
|
||||
await SingleInstance.Stop();
|
||||
}
|
||||
|
||||
public async void Initialize()
|
||||
{
|
||||
// Setup the update handler
|
||||
InitializeUpdate();
|
||||
|
||||
// Show the notification icon
|
||||
NotificationIcon.Initialize(this);
|
||||
|
||||
// Load window settings
|
||||
LoadWindowSettings();
|
||||
|
||||
// Set the foreground color to something that can be seen
|
||||
LinkTextList.Foreground = System.Drawing.SystemColors.Desktop.GetBrightness() < 0.5
|
||||
? Brushes.White
|
||||
: Brushes.Black;
|
||||
HeaderLabel.Foreground = LinkTextList.Foreground;
|
||||
|
||||
// Create the background worker that does the actual reading
|
||||
_feedReadWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
|
||||
_feedReadWorker.DoWork += HandleFeedReadWorkerStart;
|
||||
_feedReadWorker.ProgressChanged += HandleFeedReadWorkerProgressChanged;
|
||||
_feedReadWorker.RunWorkerCompleted += HandleFeedReadWorkerCompleted;
|
||||
|
||||
// Setup the database
|
||||
_database = Database.Entities;
|
||||
|
||||
// Initialize the single instance listener
|
||||
SingleInstance.MessageReceived += SingleInstance_MessageReceived;
|
||||
await SingleInstance.StartAsync(App.Name);
|
||||
|
||||
// Handle any command line we were started with
|
||||
HandleCommandLine(Environment.CommandLine);
|
||||
|
||||
// Create a timer to keep track of things we need to do
|
||||
InitializeTimer();
|
||||
|
||||
// Initialize the feed display
|
||||
InitializeDisplay();
|
||||
|
||||
// Check for update
|
||||
if (Settings.Default.CheckVersionAtStartup)
|
||||
await UpdateCheck.CheckForUpdate();
|
||||
|
||||
// Show the link if updates are available
|
||||
if (UpdateCheck.UpdateAvailable)
|
||||
NewVersionLink.Visibility = Visibility.Visible;
|
||||
|
||||
Log.Logger.Information("MainForm creation finished");
|
||||
}
|
||||
|
||||
private void SingleInstance_MessageReceived(object sender, string commandLine)
|
||||
{
|
||||
HandleCommandLine(commandLine);
|
||||
}
|
||||
|
||||
#region Setting events
|
||||
|
||||
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
// Make sure we're on the right thread
|
||||
if (!Dispatcher.CheckAccess())
|
||||
{
|
||||
Dispatcher.Invoke(new EventHandler<PropertyChangedEventArgs>(HandlePropertyChanged), sender, e);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
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.Left:
|
||||
case Dock.Right:
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database helpers
|
||||
|
||||
private void ResetDatabase()
|
||||
{
|
||||
// Get the ID of the current feed
|
||||
var currentId = _currentFeed?.IsValid ?? false ? _currentFeed.Id : Guid.Empty;
|
||||
|
||||
// Create a new database object
|
||||
_database.Refresh();
|
||||
|
||||
_feedList = _currentCategory == null
|
||||
? _database.Feeds.ToList()
|
||||
: _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id).ToList();
|
||||
|
||||
UpdateToolbarButtonState();
|
||||
|
||||
// Get a list of feeds ordered by name
|
||||
var feedList = _feedList.OrderBy(f => f.Name).ToList();
|
||||
|
||||
// First try to find the current feed by ID to see if it is still there
|
||||
var newIndex = feedList.FindIndex(f => f.Id == currentId);
|
||||
|
||||
if (newIndex == -1)
|
||||
{
|
||||
// The current feed isn't there anymore so see if we can find a feed at the old index
|
||||
if (feedList.ElementAtOrDefault(_feedIndex) != null)
|
||||
newIndex = _feedIndex;
|
||||
|
||||
// If there is no feed at the old location then give up and go back to the start
|
||||
if (newIndex == -1 && feedList.Count > 0)
|
||||
newIndex = 0;
|
||||
}
|
||||
|
||||
// Set the current index to the new index
|
||||
_feedIndex = newIndex;
|
||||
|
||||
// Re-get the current feed
|
||||
_currentFeed = _feedIndex == -1
|
||||
? null
|
||||
: _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Feed display
|
||||
|
||||
private void UpdateToolbarButtonState()
|
||||
{
|
||||
// Cache the feed count to save (a little) time
|
||||
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;
|
||||
}
|
||||
|
||||
private void InitializeDisplay()
|
||||
{
|
||||
// Get the last category (defaulting to none)
|
||||
_currentCategory =
|
||||
_database.Categories.FirstOrDefault(category =>
|
||||
category.Id.ToString() == Settings.Default.LastCategoryID);
|
||||
DisplayCategory();
|
||||
|
||||
// Get the current feed list to match the category
|
||||
_feedList = _currentCategory == null
|
||||
? _database.Feeds
|
||||
: _database.Feeds.Where(feed => feed.CategoryId == _currentCategory.Id);
|
||||
|
||||
UpdateToolbarButtonState();
|
||||
|
||||
// Clear the link list
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
// Refresh the feed index
|
||||
_feedIndex = -1;
|
||||
|
||||
// Start the timer
|
||||
StartTimer();
|
||||
|
||||
// Don't go further if we have no feeds
|
||||
if (!_feedList.Any())
|
||||
return;
|
||||
|
||||
// Get the first feed
|
||||
NextFeed();
|
||||
}
|
||||
|
||||
private void NextFeed()
|
||||
{
|
||||
var feedCount = _feedList.Count();
|
||||
|
||||
if (feedCount == 0)
|
||||
return;
|
||||
|
||||
if (Settings.Default.DisplayEmptyFeeds)
|
||||
{
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track if we found something
|
||||
var found = false;
|
||||
|
||||
// Remember our starting position
|
||||
var startIndex = _feedIndex == -1 ? 0 : _feedIndex;
|
||||
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
|
||||
// Loop until we come back to the start index
|
||||
do
|
||||
{
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
|
||||
// If the current feed has unread items then we can display it
|
||||
if (_currentFeed.Items.Any(item => !item.BeenRead))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment the index and adjust if we've gone around the end
|
||||
_feedIndex = (_feedIndex + 1) % feedCount;
|
||||
} while (_feedIndex != startIndex);
|
||||
|
||||
// If nothing was found then clear the current feed
|
||||
if (!found)
|
||||
{
|
||||
_feedIndex = -1;
|
||||
_currentFeed = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
}
|
||||
|
||||
private void PreviousFeed()
|
||||
{
|
||||
var feedCount = _feedList.Count();
|
||||
|
||||
if (feedCount == 0)
|
||||
return;
|
||||
|
||||
if (Settings.Default.DisplayEmptyFeeds)
|
||||
{
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track if we found something
|
||||
var found = false;
|
||||
|
||||
// Remember our starting position
|
||||
var startIndex = _feedIndex == -1 ? 0 : _feedIndex;
|
||||
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
|
||||
// Loop until we come back to the start index
|
||||
do
|
||||
{
|
||||
// Get the feed
|
||||
_currentFeed = _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
|
||||
|
||||
// If the current feed has unread items then we can display it
|
||||
if (_currentFeed.Items.Any(item => !item.BeenRead))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Decrement the feed index
|
||||
_feedIndex--;
|
||||
|
||||
// If we've gone below the start of the list then reset to the end
|
||||
if (_feedIndex < 0)
|
||||
_feedIndex = feedCount - 1;
|
||||
} while (_feedIndex != startIndex);
|
||||
|
||||
// If nothing was found then clear the current feed
|
||||
if (!found)
|
||||
{
|
||||
_feedIndex = -1;
|
||||
_currentFeed = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the feed timestamp
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
|
||||
// Update the display
|
||||
DisplayFeed();
|
||||
}
|
||||
|
||||
private void UpdateOpenAllButton()
|
||||
{
|
||||
var multipleOpenAction = _currentFeed.MultipleOpenAction;
|
||||
|
||||
switch (multipleOpenAction)
|
||||
{
|
||||
case MultipleOpenAction.IndividualPages:
|
||||
OpenAllToolbarButton.ToolTip = Properties.Resources.openAllMultipleToolbarButton;
|
||||
break;
|
||||
case MultipleOpenAction.SinglePage:
|
||||
OpenAllToolbarButton.ToolTip = Properties.Resources.openAllSingleToolbarButton;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayFeed()
|
||||
{
|
||||
// Just clear the display if we have no feed
|
||||
if (_currentFeed == null)
|
||||
{
|
||||
FeedLabel.Text = string.Empty;
|
||||
FeedButton.Visibility = Visibility.Hidden;
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the header to the feed title
|
||||
FeedLabel.Text = _currentFeed.Name.Length > 0 ? _currentFeed.Name : _currentFeed.Title;
|
||||
FeedButton.Visibility = _feedList.Count() > 1 ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
// Clear the current list
|
||||
LinkTextList.Items.Clear();
|
||||
|
||||
// Sort the items by sequence
|
||||
var sortedItems = _currentFeed.Items.Where(item => !item.BeenRead).OrderBy(item => item.Sequence);
|
||||
|
||||
// Loop over all items in the current feed
|
||||
foreach (var feedItem in sortedItems)
|
||||
{
|
||||
// Add the list item
|
||||
LinkTextList.Items.Add(feedItem);
|
||||
}
|
||||
|
||||
UpdateOpenAllButton();
|
||||
}
|
||||
|
||||
private void MarkAllItemsAsRead()
|
||||
{
|
||||
// Loop over all items and mark them as read
|
||||
_database.SaveChanges(() =>
|
||||
{
|
||||
foreach (FeedItem feedItem in LinkTextList.Items)
|
||||
feedItem.BeenRead = true;
|
||||
});
|
||||
|
||||
// Clear the list
|
||||
LinkTextList.Items.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -2,58 +2,57 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private Timer _mainTimer;
|
||||
private DateTime _lastFeedRead;
|
||||
private DateTime _lastFeedDisplay;
|
||||
|
||||
private void InitializeTimer()
|
||||
{
|
||||
private Timer _mainTimer;
|
||||
private DateTime _lastFeedRead;
|
||||
private DateTime _lastFeedDisplay;
|
||||
|
||||
private void InitializeTimer()
|
||||
{
|
||||
_mainTimer = new Timer { Interval = 1000 };
|
||||
_mainTimer.Tick += HandleMainTimerTick;
|
||||
}
|
||||
|
||||
private void TerminateTimer()
|
||||
{
|
||||
StopTimer();
|
||||
|
||||
_mainTimer.Dispose();
|
||||
}
|
||||
|
||||
private void StartTimer()
|
||||
{
|
||||
_mainTimer.Start();
|
||||
}
|
||||
|
||||
private void StopTimer()
|
||||
{
|
||||
_mainTimer.Stop();
|
||||
}
|
||||
|
||||
private void HandleMainTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
// If the background worker is busy then don't do anything
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Stop the timer for now
|
||||
StopTimer();
|
||||
|
||||
// Move to the next feed if the scroll interval has expired and the mouse isn't hovering
|
||||
if (LinkTextList.IsMouseOver)
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
else if (DateTime.Now - _lastFeedDisplay >= Settings.Default.FeedScrollInterval)
|
||||
NextFeed();
|
||||
|
||||
// Check to see if we should try to read the feeds
|
||||
if (DateTime.Now - _lastFeedRead >= Settings.Default.FeedCheckInterval)
|
||||
ReadFeeds();
|
||||
|
||||
// Get the timer going again
|
||||
StartTimer();
|
||||
}
|
||||
_mainTimer = new Timer { Interval = 1000 };
|
||||
_mainTimer.Tick += HandleMainTimerTick;
|
||||
}
|
||||
}
|
||||
|
||||
private void TerminateTimer()
|
||||
{
|
||||
StopTimer();
|
||||
|
||||
_mainTimer.Dispose();
|
||||
}
|
||||
|
||||
private void StartTimer()
|
||||
{
|
||||
_mainTimer.Start();
|
||||
}
|
||||
|
||||
private void StopTimer()
|
||||
{
|
||||
_mainTimer.Stop();
|
||||
}
|
||||
|
||||
private void HandleMainTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
// If the background worker is busy then don't do anything
|
||||
if (_feedReadWorker.IsBusy)
|
||||
return;
|
||||
|
||||
// Stop the timer for now
|
||||
StopTimer();
|
||||
|
||||
// Move to the next feed if the scroll interval has expired and the mouse isn't hovering
|
||||
if (LinkTextList.IsMouseOver)
|
||||
_lastFeedDisplay = DateTime.Now;
|
||||
else if (DateTime.Now - _lastFeedDisplay >= Settings.Default.FeedScrollInterval)
|
||||
NextFeed();
|
||||
|
||||
// Check to see if we should try to read the feeds
|
||||
if (DateTime.Now - _lastFeedRead >= Settings.Default.FeedCheckInterval)
|
||||
ReadFeeds();
|
||||
|
||||
// Get the timer going again
|
||||
StartTimer();
|
||||
}
|
||||
}
|
||||
@@ -8,229 +8,228 @@ using ChrisKaczor.InstalledBrowsers;
|
||||
using FeedCenter.Options;
|
||||
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)
|
||||
PreviousFeed();
|
||||
}
|
||||
|
||||
private void HandleNextToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
NextFeed();
|
||||
}
|
||||
|
||||
private void OpenAllFeedItemsIndividually()
|
||||
{
|
||||
// Create a new list of feed items
|
||||
var feedItems = (from FeedItem feedItem in LinkTextList.Items select feedItem).ToList();
|
||||
|
||||
// Cache the settings object
|
||||
var settings = Settings.Default;
|
||||
|
||||
// Start with a longer sleep interval to give time for the browser to come up
|
||||
var sleepInterval = settings.OpenAllSleepIntervalFirst;
|
||||
|
||||
// Loop over all items
|
||||
foreach (var feedItem in feedItems)
|
||||
{
|
||||
PreviousFeed();
|
||||
}
|
||||
|
||||
private void HandleNextToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
NextFeed();
|
||||
}
|
||||
|
||||
private void OpenAllFeedItemsIndividually()
|
||||
{
|
||||
// Create a new list of feed items
|
||||
var feedItems = (from FeedItem feedItem in LinkTextList.Items select feedItem).ToList();
|
||||
|
||||
// Cache the settings object
|
||||
var settings = Settings.Default;
|
||||
|
||||
// Start with a longer sleep interval to give time for the browser to come up
|
||||
var sleepInterval = settings.OpenAllSleepIntervalFirst;
|
||||
|
||||
// Loop over all items
|
||||
foreach (var feedItem in feedItems)
|
||||
// Try to open the link
|
||||
if (InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||
{
|
||||
// Try to open the link
|
||||
if (InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||
{
|
||||
// Mark the feed as read
|
||||
_database.SaveChanges(() => feedItem.BeenRead = true);
|
||||
// Mark the feed as read
|
||||
_database.SaveChanges(() => feedItem.BeenRead = true);
|
||||
|
||||
// Remove the item
|
||||
LinkTextList.Items.Remove(feedItem);
|
||||
}
|
||||
|
||||
// Wait a little bit
|
||||
Thread.Sleep(sleepInterval);
|
||||
|
||||
// Switch to the normal sleep interval
|
||||
sleepInterval = settings.OpenAllSleepInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleOptionsToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create the options form
|
||||
var optionsWindow = new OptionsWindow { Owner = this };
|
||||
|
||||
// Show the options window
|
||||
optionsWindow.ShowDialog();
|
||||
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void HandleMarkReadToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MarkAllItemsAsRead();
|
||||
}
|
||||
|
||||
private void HandleShowErrorsButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create the feed error window
|
||||
var feedErrorWindow = new FeedErrorWindow();
|
||||
|
||||
// Display the window
|
||||
feedErrorWindow.Display(this);
|
||||
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void HandleRefreshMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (MenuItem) e.Source;
|
||||
|
||||
if (Equals(menuItem, MenuRefresh))
|
||||
ReadCurrentFeed(true);
|
||||
else if (Equals(menuItem, MenuRefreshAll))
|
||||
ReadFeeds(true);
|
||||
}
|
||||
|
||||
private void HandleRefreshToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ReadFeeds(true);
|
||||
}
|
||||
|
||||
private void HandleOpenAllMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (MenuItem) e.Source;
|
||||
|
||||
if (Equals(menuItem, MenuOpenAllSinglePage))
|
||||
OpenAllFeedItemsOnSinglePage();
|
||||
else if (Equals(menuItem, MenuOpenAllMultiplePages))
|
||||
OpenAllFeedItemsIndividually();
|
||||
}
|
||||
|
||||
private void HandleOpenAllToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var multipleOpenAction = _currentFeed.MultipleOpenAction;
|
||||
|
||||
switch (multipleOpenAction)
|
||||
{
|
||||
case MultipleOpenAction.IndividualPages:
|
||||
OpenAllFeedItemsIndividually();
|
||||
break;
|
||||
case MultipleOpenAction.SinglePage:
|
||||
OpenAllFeedItemsOnSinglePage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEditCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create a new feed window
|
||||
var feedWindow = new FeedWindow();
|
||||
|
||||
// Display the feed window and get the result
|
||||
var result = feedWindow.Display(_currentFeed, this);
|
||||
|
||||
// If OK was clicked...
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
// Save
|
||||
_database.SaveChanges(() => { });
|
||||
|
||||
// Update feed
|
||||
DisplayFeed();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeleteCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Confirm this delete since it is for real
|
||||
if (MessageBox.Show(this, Properties.Resources.ConfirmDeleteFeed, string.Empty, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
|
||||
return;
|
||||
|
||||
// Get the current feed
|
||||
var feedToDelete = _currentFeed;
|
||||
|
||||
// Move to the next feed
|
||||
NextFeed();
|
||||
|
||||
// Delete the feed
|
||||
_database.SaveChanges(() => _database.Feeds.Remove(feedToDelete));
|
||||
}
|
||||
|
||||
private void OpenAllFeedItemsOnSinglePage()
|
||||
{
|
||||
var fileName = Path.GetTempFileName() + ".html";
|
||||
TextWriter textWriter = new StreamWriter(fileName);
|
||||
|
||||
using (var htmlTextWriter = new HtmlTextWriter(textWriter))
|
||||
{
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Html);
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Head);
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Title);
|
||||
htmlTextWriter.Write(_currentFeed.Title);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.AddAttribute("http-equiv", "Content-Type");
|
||||
htmlTextWriter.AddAttribute("content", "text/html; charset=utf-8");
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Meta);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Body);
|
||||
|
||||
var sortedItems = from item in _currentFeed.Items where !item.BeenRead orderby item.Sequence ascending select item;
|
||||
|
||||
var firstItem = true;
|
||||
|
||||
foreach (var item in sortedItems)
|
||||
{
|
||||
if (!firstItem)
|
||||
{
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Hr);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
}
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Div);
|
||||
|
||||
htmlTextWriter.AddAttribute(HtmlTextWriterAttribute.Href, item.Link);
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.A);
|
||||
htmlTextWriter.Write(item.Title.Length == 0 ? item.Link : item.Title);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Br);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.Write(item.Description);
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
firstItem = false;
|
||||
}
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
htmlTextWriter.RenderEndTag();
|
||||
// Remove the item
|
||||
LinkTextList.Items.Remove(feedItem);
|
||||
}
|
||||
|
||||
textWriter.Flush();
|
||||
textWriter.Close();
|
||||
// Wait a little bit
|
||||
Thread.Sleep(sleepInterval);
|
||||
|
||||
InstalledBrowser.OpenLink(Settings.Default.Browser, fileName);
|
||||
|
||||
MarkAllItemsAsRead();
|
||||
// Switch to the normal sleep interval
|
||||
sleepInterval = settings.OpenAllSleepInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleOptionsToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create the options form
|
||||
var optionsWindow = new OptionsWindow { Owner = this };
|
||||
|
||||
// Show the options window
|
||||
optionsWindow.ShowDialog();
|
||||
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void HandleMarkReadToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MarkAllItemsAsRead();
|
||||
}
|
||||
|
||||
private void HandleShowErrorsButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create the feed error window
|
||||
var feedErrorWindow = new FeedErrorWindow();
|
||||
|
||||
// Display the window
|
||||
feedErrorWindow.Display(this);
|
||||
|
||||
// Refresh the database to current settings
|
||||
ResetDatabase();
|
||||
|
||||
// Re-initialize the feed display
|
||||
DisplayFeed();
|
||||
|
||||
UpdateErrorLink();
|
||||
}
|
||||
|
||||
private void HandleRefreshMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (MenuItem) e.Source;
|
||||
|
||||
if (Equals(menuItem, MenuRefresh))
|
||||
ReadCurrentFeed(true);
|
||||
else if (Equals(menuItem, MenuRefreshAll))
|
||||
ReadFeeds(true);
|
||||
}
|
||||
|
||||
private void HandleRefreshToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ReadFeeds(true);
|
||||
}
|
||||
|
||||
private void HandleOpenAllMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (MenuItem) e.Source;
|
||||
|
||||
if (Equals(menuItem, MenuOpenAllSinglePage))
|
||||
OpenAllFeedItemsOnSinglePage();
|
||||
else if (Equals(menuItem, MenuOpenAllMultiplePages))
|
||||
OpenAllFeedItemsIndividually();
|
||||
}
|
||||
|
||||
private void HandleOpenAllToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var multipleOpenAction = _currentFeed.MultipleOpenAction;
|
||||
|
||||
switch (multipleOpenAction)
|
||||
{
|
||||
case MultipleOpenAction.IndividualPages:
|
||||
OpenAllFeedItemsIndividually();
|
||||
break;
|
||||
case MultipleOpenAction.SinglePage:
|
||||
OpenAllFeedItemsOnSinglePage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEditCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create a new feed window
|
||||
var feedWindow = new FeedWindow();
|
||||
|
||||
// Display the feed window and get the result
|
||||
var result = feedWindow.Display(_currentFeed, this);
|
||||
|
||||
// If OK was clicked...
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
// Save
|
||||
_database.SaveChanges(() => { });
|
||||
|
||||
// Update feed
|
||||
DisplayFeed();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeleteCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Confirm this delete since it is for real
|
||||
if (MessageBox.Show(this, Properties.Resources.ConfirmDeleteFeed, string.Empty, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
|
||||
return;
|
||||
|
||||
// Get the current feed
|
||||
var feedToDelete = _currentFeed;
|
||||
|
||||
// Move to the next feed
|
||||
NextFeed();
|
||||
|
||||
// Delete the feed
|
||||
_database.SaveChanges(() => _database.Feeds.Remove(feedToDelete));
|
||||
}
|
||||
|
||||
private void OpenAllFeedItemsOnSinglePage()
|
||||
{
|
||||
var fileName = Path.GetTempFileName() + ".html";
|
||||
TextWriter textWriter = new StreamWriter(fileName);
|
||||
|
||||
using (var htmlTextWriter = new HtmlTextWriter(textWriter))
|
||||
{
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Html);
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Head);
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Title);
|
||||
htmlTextWriter.Write(_currentFeed.Title);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.AddAttribute("http-equiv", "Content-Type");
|
||||
htmlTextWriter.AddAttribute("content", "text/html; charset=utf-8");
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Meta);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Body);
|
||||
|
||||
var sortedItems = from item in _currentFeed.Items where !item.BeenRead orderby item.Sequence ascending select item;
|
||||
|
||||
var firstItem = true;
|
||||
|
||||
foreach (var item in sortedItems)
|
||||
{
|
||||
if (!firstItem)
|
||||
{
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Hr);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
}
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Div);
|
||||
|
||||
htmlTextWriter.AddAttribute(HtmlTextWriterAttribute.Href, item.Link);
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.A);
|
||||
htmlTextWriter.Write(item.Title.Length == 0 ? item.Link : item.Title);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Br);
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
htmlTextWriter.Write(item.Description);
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
|
||||
firstItem = false;
|
||||
}
|
||||
|
||||
htmlTextWriter.RenderEndTag();
|
||||
htmlTextWriter.RenderEndTag();
|
||||
}
|
||||
|
||||
textWriter.Flush();
|
||||
textWriter.Close();
|
||||
|
||||
InstalledBrowser.OpenLink(Settings.Default.Browser, fileName);
|
||||
|
||||
MarkAllItemsAsRead();
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,38 @@
|
||||
using FeedCenter.Properties;
|
||||
using System.Windows;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private static void InitializeUpdate()
|
||||
{
|
||||
private static void InitializeUpdate()
|
||||
{
|
||||
UpdateCheck.Initialize(ServerType.GitHub,
|
||||
Settings.Default.VersionLocation,
|
||||
string.Empty,
|
||||
Properties.Resources.ApplicationDisplayName,
|
||||
ApplicationShutdown,
|
||||
ApplicationCurrentMessage,
|
||||
ApplicationUpdateMessage);
|
||||
}
|
||||
UpdateCheck.Initialize(ServerType.GitHub,
|
||||
Settings.Default.VersionLocation,
|
||||
string.Empty,
|
||||
Properties.Resources.ApplicationDisplayName,
|
||||
ApplicationShutdown,
|
||||
ApplicationCurrentMessage,
|
||||
ApplicationUpdateMessage);
|
||||
}
|
||||
|
||||
private static bool ApplicationUpdateMessage(string title, string message)
|
||||
{
|
||||
return MessageBox.Show(message, title, MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes;
|
||||
}
|
||||
private static bool ApplicationUpdateMessage(string title, string message)
|
||||
{
|
||||
return MessageBox.Show(message, title, MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
private static void ApplicationCurrentMessage(string title, string message)
|
||||
{
|
||||
MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
private static void ApplicationCurrentMessage(string title, string message)
|
||||
{
|
||||
MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
private static void ApplicationShutdown()
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
private static void ApplicationShutdown()
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
private void HandleNewVersionLinkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateCheck.DisplayUpdateInformation(true);
|
||||
}
|
||||
private void HandleNewVersionLinkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateCheck.DisplayUpdateInformation(true);
|
||||
}
|
||||
}
|
||||
@@ -7,167 +7,166 @@ using System.Windows.Controls;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace FeedCenter
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
public partial class MainWindow
|
||||
private void LoadWindowSettings()
|
||||
{
|
||||
private void LoadWindowSettings()
|
||||
// Get the last window location
|
||||
var windowLocation = Settings.Default.WindowLocation;
|
||||
|
||||
// Set the window into position
|
||||
Left = windowLocation.X;
|
||||
Top = windowLocation.Y;
|
||||
|
||||
// Get the last window size
|
||||
var windowSize = Settings.Default.WindowSize;
|
||||
|
||||
// Set the window into the previous size if it is valid
|
||||
if (!windowSize.Width.Equals(0) && !windowSize.Height.Equals(0))
|
||||
{
|
||||
// Get the last window location
|
||||
var windowLocation = Settings.Default.WindowLocation;
|
||||
|
||||
// Set the window into position
|
||||
Left = windowLocation.X;
|
||||
Top = windowLocation.Y;
|
||||
|
||||
// Get the last window size
|
||||
var windowSize = Settings.Default.WindowSize;
|
||||
|
||||
// Set the window into the previous size if it is valid
|
||||
if (!windowSize.Width.Equals(0) && !windowSize.Height.Equals(0))
|
||||
{
|
||||
Width = windowSize.Width;
|
||||
Height = windowSize.Height;
|
||||
}
|
||||
|
||||
// Set the location of the navigation tray
|
||||
switch (Settings.Default.ToolbarLocation)
|
||||
{
|
||||
case Dock.Top:
|
||||
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "TopToolbarRow");
|
||||
break;
|
||||
case Dock.Bottom:
|
||||
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "BottomToolbarRow");
|
||||
break;
|
||||
}
|
||||
|
||||
// Load the lock state
|
||||
HandleWindowLockState();
|
||||
Width = windowSize.Width;
|
||||
Height = windowSize.Height;
|
||||
}
|
||||
|
||||
private void SaveWindowSettings()
|
||||
// Set the location of the navigation tray
|
||||
switch (Settings.Default.ToolbarLocation)
|
||||
{
|
||||
// Set the last window location
|
||||
Settings.Default.WindowLocation = new Point(Left, Top);
|
||||
|
||||
// Set the last window size
|
||||
Settings.Default.WindowSize = new Size(Width, Height);
|
||||
|
||||
// Save the dock on the navigation tray
|
||||
Settings.Default.ToolbarLocation = NameBasedGrid.NameBasedGrid.GetRow(NavigationToolbarTray) == "TopToolbarRow" ? Dock.Top : Dock.Bottom;
|
||||
|
||||
// Save settings
|
||||
Settings.Default.Save();
|
||||
case Dock.Top:
|
||||
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "TopToolbarRow");
|
||||
break;
|
||||
case Dock.Bottom:
|
||||
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "BottomToolbarRow");
|
||||
break;
|
||||
}
|
||||
|
||||
private void HandleWindowLockState()
|
||||
// Load the lock state
|
||||
HandleWindowLockState();
|
||||
}
|
||||
|
||||
private void SaveWindowSettings()
|
||||
{
|
||||
// Set the last window location
|
||||
Settings.Default.WindowLocation = new Point(Left, Top);
|
||||
|
||||
// Set the last window size
|
||||
Settings.Default.WindowSize = new Size(Width, Height);
|
||||
|
||||
// Save the dock on the navigation tray
|
||||
Settings.Default.ToolbarLocation = NameBasedGrid.NameBasedGrid.GetRow(NavigationToolbarTray) == "TopToolbarRow" ? Dock.Top : Dock.Bottom;
|
||||
|
||||
// Save settings
|
||||
Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void HandleWindowLockState()
|
||||
{
|
||||
// Set the resize mode for the window
|
||||
ResizeMode = Settings.Default.WindowLocked ? ResizeMode.NoResize : ResizeMode.CanResize;
|
||||
|
||||
// Show or hide the border
|
||||
WindowBorder.BorderBrush = Settings.Default.WindowLocked ? SystemColors.ActiveBorderBrush : Brushes.Transparent;
|
||||
|
||||
// Update the borders
|
||||
UpdateBorder();
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
base.OnClosing(e);
|
||||
|
||||
// Ditch the worker
|
||||
if (_feedReadWorker != null)
|
||||
{
|
||||
// Set the resize mode for the window
|
||||
ResizeMode = Settings.Default.WindowLocked ? ResizeMode.NoResize : ResizeMode.CanResize;
|
||||
|
||||
// Show or hide the border
|
||||
WindowBorder.BorderBrush = Settings.Default.WindowLocked ? SystemColors.ActiveBorderBrush : Brushes.Transparent;
|
||||
|
||||
// Update the borders
|
||||
UpdateBorder();
|
||||
_feedReadWorker.CancelAsync();
|
||||
_feedReadWorker.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
// Get rid of the timer
|
||||
TerminateTimer();
|
||||
|
||||
// Save current window settings
|
||||
SaveWindowSettings();
|
||||
|
||||
// Save settings
|
||||
_database.SaveChanges(Settings.Default.Save);
|
||||
|
||||
// Get rid of the notification icon
|
||||
NotificationIcon.Dispose();
|
||||
}
|
||||
|
||||
private readonly DebounceDispatcher _updateWindowSettingsDispatcher = new(500);
|
||||
|
||||
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
|
||||
}
|
||||
|
||||
private void HandleWindowLocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
|
||||
}
|
||||
|
||||
private void UpdateBorder()
|
||||
{
|
||||
var windowInteropHelper = new WindowInteropHelper(this);
|
||||
|
||||
var screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
|
||||
|
||||
var rectangle = new System.Drawing.Rectangle
|
||||
{
|
||||
base.OnClosing(e);
|
||||
X = (int) Left,
|
||||
Y = (int) Top,
|
||||
Width = (int) Width,
|
||||
Height = (int) Height
|
||||
};
|
||||
|
||||
// Ditch the worker
|
||||
if (_feedReadWorker != null)
|
||||
{
|
||||
_feedReadWorker.CancelAsync();
|
||||
_feedReadWorker.Dispose();
|
||||
}
|
||||
var borderThickness = new Thickness();
|
||||
|
||||
// Get rid of the timer
|
||||
TerminateTimer();
|
||||
if (rectangle.Right != screen.WorkingArea.Right)
|
||||
borderThickness.Right = 1;
|
||||
|
||||
// Save current window settings
|
||||
SaveWindowSettings();
|
||||
if (rectangle.Left != screen.WorkingArea.Left)
|
||||
borderThickness.Left = 1;
|
||||
|
||||
// Save settings
|
||||
_database.SaveChanges(Settings.Default.Save);
|
||||
if (rectangle.Top != screen.WorkingArea.Top)
|
||||
borderThickness.Top = 1;
|
||||
|
||||
// Get rid of the notification icon
|
||||
NotificationIcon.Dispose();
|
||||
}
|
||||
if (rectangle.Bottom != screen.WorkingArea.Bottom)
|
||||
borderThickness.Bottom = 1;
|
||||
|
||||
private readonly DebounceDispatcher _updateWindowSettingsDispatcher = new(500);
|
||||
WindowBorder.BorderThickness = borderThickness;
|
||||
}
|
||||
|
||||
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
|
||||
}
|
||||
private void UpdateWindowSettings()
|
||||
{
|
||||
// Save current window settings
|
||||
SaveWindowSettings();
|
||||
|
||||
private void HandleWindowLocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
_updateWindowSettingsDispatcher.Debounce(() => Dispatcher.Invoke(UpdateWindowSettings));
|
||||
}
|
||||
// Update the border
|
||||
UpdateBorder();
|
||||
}
|
||||
|
||||
private void UpdateBorder()
|
||||
{
|
||||
var windowInteropHelper = new WindowInteropHelper(this);
|
||||
private bool _activated;
|
||||
|
||||
var screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
base.OnActivated(e);
|
||||
|
||||
var rectangle = new System.Drawing.Rectangle
|
||||
{
|
||||
X = (int) Left,
|
||||
Y = (int) Top,
|
||||
Width = (int) Width,
|
||||
Height = (int) Height
|
||||
};
|
||||
if (_activated)
|
||||
return;
|
||||
|
||||
var borderThickness = new Thickness();
|
||||
_activated = true;
|
||||
|
||||
if (rectangle.Right != screen.WorkingArea.Right)
|
||||
borderThickness.Right = 1;
|
||||
// Load the lock state
|
||||
HandleWindowLockState();
|
||||
|
||||
if (rectangle.Left != screen.WorkingArea.Left)
|
||||
borderThickness.Left = 1;
|
||||
// Watch for size and location changes
|
||||
SizeChanged += HandleWindowSizeChanged;
|
||||
LocationChanged += HandleWindowLocationChanged;
|
||||
|
||||
if (rectangle.Top != screen.WorkingArea.Top)
|
||||
borderThickness.Top = 1;
|
||||
|
||||
if (rectangle.Bottom != screen.WorkingArea.Bottom)
|
||||
borderThickness.Bottom = 1;
|
||||
|
||||
WindowBorder.BorderThickness = borderThickness;
|
||||
}
|
||||
|
||||
private void UpdateWindowSettings()
|
||||
{
|
||||
// Save current window settings
|
||||
SaveWindowSettings();
|
||||
|
||||
// Update the border
|
||||
UpdateBorder();
|
||||
}
|
||||
|
||||
private bool _activated;
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
base.OnActivated(e);
|
||||
|
||||
if (_activated)
|
||||
return;
|
||||
|
||||
_activated = true;
|
||||
|
||||
// Load the lock state
|
||||
HandleWindowLockState();
|
||||
|
||||
// Watch for size and location changes
|
||||
SizeChanged += HandleWindowSizeChanged;
|
||||
LocationChanged += HandleWindowLocationChanged;
|
||||
|
||||
// Watch for setting changes
|
||||
Settings.Default.PropertyChanged += HandlePropertyChanged;
|
||||
}
|
||||
// Watch for setting changes
|
||||
Settings.Default.PropertyChanged += HandlePropertyChanged;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user