mirror of
https://github.com/ckaczor/FeedCenter.git
synced 2026-01-13 17:22:48 -05:00
- Add support for filtering by category
- Break up main window into partials instead of using regions
This commit is contained in:
@@ -85,8 +85,9 @@ namespace FeedCenter
|
|||||||
var splashWindow = new SplashWindow();
|
var splashWindow = new SplashWindow();
|
||||||
splashWindow.ShowDialog();
|
splashWindow.ShowDialog();
|
||||||
|
|
||||||
// Set whether we should auto-start
|
// Set whether we should auto-start (if not debugging)
|
||||||
Current.SetStartWithWindows(Settings.Default.StartWithWindows);
|
if (!IsDebugBuild)
|
||||||
|
Current.SetStartWithWindows(Settings.Default.StartWithWindows);
|
||||||
|
|
||||||
// Initialize the window
|
// Initialize the window
|
||||||
mainWindow.Initialize();
|
mainWindow.Initialize();
|
||||||
|
|||||||
@@ -144,9 +144,6 @@
|
|||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Common.Wpf.MarkupExtensions">
|
|
||||||
<HintPath>..\..\Common.Wpf.MarkupExtensions\bin\Release\Common.Wpf.MarkupExtensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
|
<HintPath>..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll</HintPath>
|
||||||
@@ -161,6 +158,10 @@
|
|||||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
<HintPath>..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="NameBasedGrid, Version=0.10.1.0, Culture=neutral, PublicKeyToken=a434c4ad23d0fd33, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\..\Public\namebasedgrid\bin\Debug\NameBasedGrid.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.configuration" />
|
<Reference Include="System.configuration" />
|
||||||
@@ -190,7 +191,18 @@
|
|||||||
<Compile Include="FeedChooserWindow.xaml.cs">
|
<Compile Include="FeedChooserWindow.xaml.cs">
|
||||||
<DependentUpon>FeedChooserWindow.xaml</DependentUpon>
|
<DependentUpon>FeedChooserWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="MainWindow\CategoryList.cs" />
|
||||||
|
<Compile Include="MainWindow\CommandLine.cs" />
|
||||||
|
<Compile Include="MainWindow\DragDrop.cs" />
|
||||||
|
<Compile Include="MainWindow\FeedCreation.cs" />
|
||||||
|
<Compile Include="MainWindow\FeedList.cs" />
|
||||||
|
<Compile Include="MainWindow\FeedReading.cs" />
|
||||||
|
<Compile Include="MainWindow\Header.cs" />
|
||||||
|
<Compile Include="MainWindow\Timer.cs" />
|
||||||
|
<Compile Include="MainWindow\Toolbar.cs" />
|
||||||
|
<Compile Include="MainWindow\WindowHandler.cs" />
|
||||||
<Compile Include="SystemConfiguration.cs" />
|
<Compile Include="SystemConfiguration.cs" />
|
||||||
|
<Compile Include="MainWindow\UpdateHandler.cs" />
|
||||||
<Page Include="App.xaml">
|
<Page Include="App.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -277,7 +289,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="MainWindow.xaml">
|
<Page Include="MainWindow\MainWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -293,7 +305,7 @@
|
|||||||
<Compile Include="Feeds\Feed.cs" />
|
<Compile Include="Feeds\Feed.cs" />
|
||||||
<Compile Include="Feeds\FeedAction.cs" />
|
<Compile Include="Feeds\FeedAction.cs" />
|
||||||
<Compile Include="Feeds\FeedItem.cs" />
|
<Compile Include="Feeds\FeedItem.cs" />
|
||||||
<Compile Include="MainWindow.xaml.cs">
|
<Compile Include="MainWindow\MainWindow.xaml.cs">
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Feeds/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Feeds/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mainwindow/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
File diff suppressed because it is too large
Load Diff
97
Application/MainWindow/CategoryList.cs
Normal file
97
Application/MainWindow/CategoryList.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private void DisplayCategory()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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 = 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)
|
||||||
|
{
|
||||||
|
// 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?.Feeds.ToList() ?? _database.Feeds.ToList();
|
||||||
|
|
||||||
|
// Reset the feed index
|
||||||
|
_feedIndex = -1;
|
||||||
|
|
||||||
|
// Get the first feed
|
||||||
|
NextFeed();
|
||||||
|
|
||||||
|
// Update the feed timestamp
|
||||||
|
_lastFeedDisplay = DateTime.Now;
|
||||||
|
|
||||||
|
// Update the display
|
||||||
|
DisplayCategory();
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Application/MainWindow/CommandLine.cs
Normal file
42
Application/MainWindow/CommandLine.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using Common.IO;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private InterprocessMessageListener _commandLineListener;
|
||||||
|
|
||||||
|
private void HandleCommandLine(object sender, InterprocessMessageListener.InterprocessMessageEventArgs e)
|
||||||
|
{
|
||||||
|
// If the command line is blank then ignore it
|
||||||
|
if (e.Message.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Pad the command line with a trailing space just to be lazy in parsing
|
||||||
|
var commandLine = e.Message + " ";
|
||||||
|
|
||||||
|
// Look for the feed URL in the command line
|
||||||
|
var startPosition = commandLine.IndexOf("feed://", StringComparison.Ordinal);
|
||||||
|
|
||||||
|
// If we found one then we should extract and process it
|
||||||
|
if (startPosition > 0)
|
||||||
|
{
|
||||||
|
// Advance past the protocol
|
||||||
|
startPosition += 7;
|
||||||
|
|
||||||
|
// Starting at the URL position look for the next space
|
||||||
|
var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
// Extract the feed URL
|
||||||
|
var feedUrl = commandLine.Substring(startPosition, endPosition - startPosition);
|
||||||
|
|
||||||
|
// Add the HTTP protocol by default
|
||||||
|
feedUrl = "http://" + feedUrl;
|
||||||
|
|
||||||
|
// Create a new feed using the URL
|
||||||
|
HandleNewFeed(feedUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Application/MainWindow/DragDrop.cs
Normal file
52
Application/MainWindow/DragDrop.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Check to see if the data starts with any known Chrome extension
|
||||||
|
var chromeExtension = _chromeExtensions.FirstOrDefault(c => data.StartsWith(c));
|
||||||
|
|
||||||
|
// Remove the Chrome extension URL and decode the URL
|
||||||
|
if (chromeExtension != null)
|
||||||
|
{
|
||||||
|
data = data.Substring(chromeExtension.Length);
|
||||||
|
data = WebUtility.UrlDecode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the new feed but allow the drag/drop to complete
|
||||||
|
Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
99
Application/MainWindow/FeedCreation.cs
Normal file
99
Application/MainWindow/FeedCreation.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using Common.Internet;
|
||||||
|
using FeedCenter.Options;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private delegate void NewFeedDelegate(string feedUrl);
|
||||||
|
private void HandleNewFeed(string feedUrl)
|
||||||
|
{
|
||||||
|
// Create and configure the new feed
|
||||||
|
var feed = Feed.Create(_database);
|
||||||
|
feed.Source = feedUrl;
|
||||||
|
feed.Category = _database.DefaultCategory;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// 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>(UrlHelper.GetAbsoluteUrlString(feed.Source, n.Attributes["href"].Value), WebUtility.HtmlDecode(n.Attributes["title"]?.Value ?? string.Empty)))
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the feed for the first time
|
||||||
|
var feedReadResult = feed.Read(_database);
|
||||||
|
|
||||||
|
// See if we read the feed okay
|
||||||
|
if (feedReadResult == FeedReadResult.Success)
|
||||||
|
{
|
||||||
|
// Update the feed name to be the title
|
||||||
|
feed.Name = feed.Title;
|
||||||
|
|
||||||
|
// Add the feed to the feed table
|
||||||
|
_database.Feeds.Add(feed);
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
|
||||||
|
// Show a tip
|
||||||
|
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info);
|
||||||
|
|
||||||
|
// Re-initialize the feed display
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Feed read failed - ceate a new feed window
|
||||||
|
var feedForm = new FeedWindow();
|
||||||
|
|
||||||
|
var dialogResult = feedForm.Display(_database, feed, this);
|
||||||
|
|
||||||
|
// Display the new feed form
|
||||||
|
if (dialogResult.HasValue && dialogResult.Value)
|
||||||
|
{
|
||||||
|
// Add the feed to the feed table
|
||||||
|
_database.Feeds.Add(feed);
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
|
||||||
|
// Re-initialize the feed display
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
Application/MainWindow/FeedList.cs
Normal file
135
Application/MainWindow/FeedList.cs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private void HandleLinkTextListMouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.ChangedButton)
|
||||||
|
{
|
||||||
|
case MouseButton.XButton1:
|
||||||
|
|
||||||
|
PreviousFeed();
|
||||||
|
break;
|
||||||
|
|
||||||
|
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
|
||||||
|
feedItem.BeenRead = true;
|
||||||
|
feedItem.New = false;
|
||||||
|
|
||||||
|
// Remove the item from the list
|
||||||
|
LinkTextList.Items.Remove(feedItem);
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// Get the feed item
|
||||||
|
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
||||||
|
|
||||||
|
// Open the item link
|
||||||
|
if (BrowserCommon.OpenLink(feedItem.Link))
|
||||||
|
{
|
||||||
|
// The feed item has been read and is no longer new
|
||||||
|
feedItem.BeenRead = true;
|
||||||
|
feedItem.New = false;
|
||||||
|
|
||||||
|
// Remove the item from the list
|
||||||
|
LinkTextList.Items.Remove(feedItem);
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 == _currentFeed ? 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 == feed)
|
||||||
|
{
|
||||||
|
_feedIndex = feedIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
feedIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current feed
|
||||||
|
_currentFeed = feed;
|
||||||
|
|
||||||
|
// Update the feed timestamp
|
||||||
|
_lastFeedDisplay = DateTime.Now;
|
||||||
|
|
||||||
|
// Update the display
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
Application/MainWindow/FeedReading.cs
Normal file
185
Application/MainWindow/FeedReading.cs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
using Common.Update;
|
||||||
|
using FeedCenter.Properties;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private BackgroundWorker _feedReadWorker;
|
||||||
|
|
||||||
|
private class FeedReadWorkerInput
|
||||||
|
{
|
||||||
|
public bool ForceRead;
|
||||||
|
public Feed Feed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetProgressMode(bool value, int feedCount)
|
||||||
|
{
|
||||||
|
// Reset 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 = forceRead, Feed = _currentFeed };
|
||||||
|
|
||||||
|
// 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 = forceRead, Feed = null };
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// Reset 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;
|
||||||
|
|
||||||
|
// 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.Feed != null)
|
||||||
|
feedsToRead.Add(database.Feeds.First(feed => feed.ID == workerInput.Feed.ID));
|
||||||
|
else
|
||||||
|
feedsToRead.AddRange(database.Feeds);
|
||||||
|
|
||||||
|
// Loop over each feed and read it
|
||||||
|
foreach (var feed in feedsToRead)
|
||||||
|
{
|
||||||
|
// Read the feed
|
||||||
|
feed.Read(database, workerInput.ForceRead);
|
||||||
|
|
||||||
|
// Increment progress
|
||||||
|
currentProgress += 1;
|
||||||
|
|
||||||
|
// Report progress
|
||||||
|
worker.ReportProgress(currentProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
database.SaveChanges();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Application/MainWindow/Header.cs
Normal file
32
Application/MainWindow/Header.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using FeedCenter.Properties;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private void HandleHeaderLabelMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// Ignore if the window is locked
|
||||||
|
if (Settings.Default.WindowLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start dragging
|
||||||
|
DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
BrowserCommon.OpenLink(_currentFeed.Link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,10 @@
|
|||||||
xmlns:windows="clr-namespace:Common.Wpf.Windows;assembly=Common.Wpf"
|
xmlns:windows="clr-namespace:Common.Wpf.Windows;assembly=Common.Wpf"
|
||||||
xmlns:toolbar="clr-namespace:Common.Wpf.Toolbar;assembly=Common.Wpf"
|
xmlns:toolbar="clr-namespace:Common.Wpf.Toolbar;assembly=Common.Wpf"
|
||||||
xmlns:splitButton="clr-namespace:Common.Wpf.Toolbar.SplitButton;assembly=Common.Wpf"
|
xmlns:splitButton="clr-namespace:Common.Wpf.Toolbar.SplitButton;assembly=Common.Wpf"
|
||||||
xmlns:markup="clr-namespace:Common.Wpf.MarkupExtensions;assembly=Common.Wpf.MarkupExtensions"
|
|
||||||
xmlns:linkControl="clr-namespace:Common.Wpf.LinkControl;assembly=Common.Wpf"
|
xmlns:linkControl="clr-namespace:Common.Wpf.LinkControl;assembly=Common.Wpf"
|
||||||
xmlns:htmlTextBlock="clr-namespace:Common.Wpf.HtmlTextBlock;assembly=Common.Wpf"
|
xmlns:htmlTextBlock="clr-namespace:Common.Wpf.HtmlTextBlock;assembly=Common.Wpf"
|
||||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:nameBasedGrid="clr-namespace:NameBasedGrid;assembly=NameBasedGrid"
|
||||||
Title="MainWindow"
|
Title="MainWindow"
|
||||||
Height="360"
|
Height="360"
|
||||||
Width="252"
|
Width="252"
|
||||||
@@ -37,29 +37,31 @@
|
|||||||
Name="WindowBorder"
|
Name="WindowBorder"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
Background="{x:Static SystemColors.DesktopBrush}">
|
Background="{x:Static SystemColors.DesktopBrush}">
|
||||||
<Grid Name="MainGrid">
|
<nameBasedGrid:NameBasedGrid Name="MainGrid">
|
||||||
<Grid.RowDefinitions>
|
<nameBasedGrid:NameBasedGrid.RowDefinitions>
|
||||||
<!-- ReSharper disable UnusedMember.Global -->
|
<!-- ReSharper disable UnusedMember.Global -->
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="HeaderRow" />
|
Name="HeaderRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="NewVersionRow" />
|
Name="NewVersionRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="FeedRow" />
|
Name="CategoryRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="TopToolbarRow" />
|
Name="FeedRow" />
|
||||||
<RowDefinition Height="*"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="FeedListRow" />
|
Name="TopToolbarRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="*"
|
||||||
Name="ProgressRow" />
|
Name="FeedListRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="BottomToolbarRow" />
|
Name="ProgressRow" />
|
||||||
<RowDefinition Height="Auto"
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
Name="FeedErrorsRow" />
|
Name="BottomToolbarRow" />
|
||||||
|
<nameBasedGrid:ColumnOrRow Size="Auto"
|
||||||
|
Name="FeedErrorsRow" />
|
||||||
<!-- ReSharper restore UnusedMember.Global -->
|
<!-- ReSharper restore UnusedMember.Global -->
|
||||||
</Grid.RowDefinitions>
|
</nameBasedGrid:NameBasedGrid.RowDefinitions>
|
||||||
<Grid Height="21"
|
<Grid Height="21"
|
||||||
Grid.Row="{markup:GridRow RowName=HeaderRow}">
|
nameBasedGrid:NameBasedGrid.Row="HeaderRow">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition Width="21" />
|
<ColumnDefinition Width="21" />
|
||||||
@@ -82,7 +84,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
<linkControl:LinkControl Name="NewVersionLink"
|
<linkControl:LinkControl Name="NewVersionLink"
|
||||||
Height="21"
|
Height="21"
|
||||||
Grid.Row="{markup:GridRow NewVersionRow}"
|
nameBasedGrid:NameBasedGrid.Row="NewVersionRow"
|
||||||
Text="{x:Static properties:Resources.NewVersionLink}"
|
Text="{x:Static properties:Resources.NewVersionLink}"
|
||||||
Background="AntiqueWhite"
|
Background="AntiqueWhite"
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
@@ -90,8 +92,34 @@
|
|||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Click="HandleNewVersionLinkClick">
|
Click="HandleNewVersionLinkClick">
|
||||||
</linkControl:LinkControl>
|
</linkControl:LinkControl>
|
||||||
|
<Grid Name="CategoryGrid"
|
||||||
|
Height="21"
|
||||||
|
nameBasedGrid:NameBasedGrid.Row="CategoryRow"
|
||||||
|
Visibility="Visible">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="21" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="*Category Name"
|
||||||
|
Name="CategoryLabel"
|
||||||
|
Padding="3,0"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="White"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Width="Auto"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Grid.Column="0" />
|
||||||
|
<Button Width="13"
|
||||||
|
Height="13"
|
||||||
|
Click="HandleCategoryButtonClick"
|
||||||
|
FontFamily="Marlett"
|
||||||
|
Content="u"
|
||||||
|
FontSize="8"
|
||||||
|
Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
<Grid Height="21"
|
<Grid Height="21"
|
||||||
Grid.Row="{markup:GridRow RowName=FeedRow}">
|
nameBasedGrid:NameBasedGrid.Row="FeedRow">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition Width="21" />
|
<ColumnDefinition Width="21" />
|
||||||
@@ -122,7 +150,7 @@
|
|||||||
Background="{x:Static SystemColors.DesktopBrush}"
|
Background="{x:Static SystemColors.DesktopBrush}"
|
||||||
MouseUp="HandleLinkTextListMouseUp"
|
MouseUp="HandleLinkTextListMouseUp"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
Grid.Row="{markup:GridRow RowName=FeedListRow}"
|
nameBasedGrid:NameBasedGrid.Row="FeedListRow"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||||
<ListBoxItem Content="Test item" />
|
<ListBoxItem Content="Test item" />
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@@ -185,11 +213,11 @@
|
|||||||
<ProgressBar Name="FeedReadProgress"
|
<ProgressBar Name="FeedReadProgress"
|
||||||
Height="15"
|
Height="15"
|
||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Grid.Row="{markup:GridRow RowName=ProgressRow}" />
|
nameBasedGrid:NameBasedGrid.Row="ProgressRow" />
|
||||||
<ToolBarTray Name="NavigationToolbarTray"
|
<ToolBarTray Name="NavigationToolbarTray"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Grid.Row="{markup:GridRow RowName=BottomToolbarRow}">
|
nameBasedGrid:NameBasedGrid.Row="TopToolbarRow">
|
||||||
<ToolBar ToolBarTray.IsLocked="True"
|
<ToolBar ToolBarTray.IsLocked="True"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ToolBar.OverflowMode="Never">
|
ToolBar.OverflowMode="Never">
|
||||||
@@ -198,15 +226,15 @@
|
|||||||
Name="PreviousToolbarButton"
|
Name="PreviousToolbarButton"
|
||||||
Click="HandlePreviousToolbarButtonClick"
|
Click="HandlePreviousToolbarButtonClick"
|
||||||
ToolTip="{x:Static properties:Resources.previousToolbarButton}"
|
ToolTip="{x:Static properties:Resources.previousToolbarButton}"
|
||||||
ImageSource="Resources/Left.ico" />
|
ImageSource="../Resources/Left.ico" />
|
||||||
<toolbar:ImageButton Height="20"
|
<toolbar:ImageButton Height="20"
|
||||||
Width="20"
|
Width="20"
|
||||||
Name="NextToolbarButton"
|
Name="NextToolbarButton"
|
||||||
Click="HandleNextToolbarButtonClick"
|
Click="HandleNextToolbarButtonClick"
|
||||||
ToolTip="{x:Static properties:Resources.nextToolbarButton}"
|
ToolTip="{x:Static properties:Resources.nextToolbarButton}"
|
||||||
ImageSource="Resources/Right.ico" />
|
ImageSource="../Resources/Right.ico" />
|
||||||
<splitButton:SplitButton Name="RefreshToolbarButton"
|
<splitButton:SplitButton Name="RefreshToolbarButton"
|
||||||
Image="Resources/Rss-Download.ico"
|
Image="../Resources/Rss-Download.ico"
|
||||||
ToolTip="{x:Static properties:Resources.refreshAllToolbarButton}"
|
ToolTip="{x:Static properties:Resources.refreshAllToolbarButton}"
|
||||||
Height="20"
|
Height="20"
|
||||||
MinWidth="35"
|
MinWidth="35"
|
||||||
@@ -222,7 +250,7 @@
|
|||||||
</splitButton:SplitButton.DropDownContextMenu>
|
</splitButton:SplitButton.DropDownContextMenu>
|
||||||
</splitButton:SplitButton>
|
</splitButton:SplitButton>
|
||||||
<splitButton:SplitButton Name="OpenAllToolbarButton"
|
<splitButton:SplitButton Name="OpenAllToolbarButton"
|
||||||
Image="Resources/News.ico"
|
Image="../Resources/News.ico"
|
||||||
ToolTip="{x:Static properties:Resources.openAllMultipleToolbarButton}"
|
ToolTip="{x:Static properties:Resources.openAllMultipleToolbarButton}"
|
||||||
Height="20"
|
Height="20"
|
||||||
MinWidth="35"
|
MinWidth="35"
|
||||||
@@ -243,13 +271,13 @@
|
|||||||
Name="MarkReadToolbarButton"
|
Name="MarkReadToolbarButton"
|
||||||
Click="HandleMarkReadToolbarButtonClick"
|
Click="HandleMarkReadToolbarButtonClick"
|
||||||
ToolTip="{x:Static properties:Resources.markReadToolbarButton}"
|
ToolTip="{x:Static properties:Resources.markReadToolbarButton}"
|
||||||
ImageSource="Resources/Comments-edit.ico" />
|
ImageSource="../Resources/Comments-edit.ico" />
|
||||||
<splitButton:SplitButton Height="20"
|
<splitButton:SplitButton Height="20"
|
||||||
MinWidth="35"
|
MinWidth="35"
|
||||||
Margin="5,0,0,0"
|
Margin="5,0,0,0"
|
||||||
Click="HandleOptionsToolbarButtonClick"
|
Click="HandleOptionsToolbarButtonClick"
|
||||||
ToolTip="{x:Static properties:Resources.optionsToolbarButton}"
|
ToolTip="{x:Static properties:Resources.optionsToolbarButton}"
|
||||||
Image="Resources/Compile.ico">
|
Image="../Resources/Compile.ico">
|
||||||
<splitButton:SplitButton.DropDownContextMenu>
|
<splitButton:SplitButton.DropDownContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<MenuItem Header="{x:Static properties:Resources.lockWindowCheckBox}"
|
<MenuItem Header="{x:Static properties:Resources.lockWindowCheckBox}"
|
||||||
@@ -269,7 +297,7 @@
|
|||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
<linkControl:LinkControl Name="FeedErrorsLink"
|
<linkControl:LinkControl Name="FeedErrorsLink"
|
||||||
Height="21"
|
Height="21"
|
||||||
Grid.Row="{markup:GridRow FeedErrorsRow}"
|
nameBasedGrid:NameBasedGrid.Row="FeedErrorsRow"
|
||||||
Text="{x:Static properties:Resources.FeedErrorsLink}"
|
Text="{x:Static properties:Resources.FeedErrorsLink}"
|
||||||
ToolTip="{x:Static properties:Resources.showErrorsToolbarButton}"
|
ToolTip="{x:Static properties:Resources.showErrorsToolbarButton}"
|
||||||
Background="AntiqueWhite"
|
Background="AntiqueWhite"
|
||||||
@@ -278,6 +306,6 @@
|
|||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Click="HandleShowErrorsButtonClick">
|
Click="HandleShowErrorsButtonClick">
|
||||||
</linkControl:LinkControl>
|
</linkControl:LinkControl>
|
||||||
</Grid>
|
</nameBasedGrid:NameBasedGrid>
|
||||||
</Border>
|
</Border>
|
||||||
</windows:SnappingWindow>
|
</windows:SnappingWindow>
|
||||||
395
Application/MainWindow/MainWindow.xaml.cs
Normal file
395
Application/MainWindow/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
using Common.Debug;
|
||||||
|
using Common.Helpers;
|
||||||
|
using Common.IO;
|
||||||
|
using Common.Update;
|
||||||
|
using FeedCenter.Properties;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private FeedCenterEntities _database;
|
||||||
|
private int _feedIndex;
|
||||||
|
|
||||||
|
private Category _currentCategory;
|
||||||
|
private ICollection<Feed> _feedList;
|
||||||
|
private Feed _currentFeed;
|
||||||
|
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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 = new FeedCenterEntities();
|
||||||
|
|
||||||
|
// Initialize the command line listener
|
||||||
|
_commandLineListener = new InterprocessMessageListener(Properties.Resources.ApplicationName);
|
||||||
|
_commandLineListener.MessageReceived += HandleCommandLine;
|
||||||
|
|
||||||
|
// Handle any command line we were started with
|
||||||
|
HandleCommandLine(null, new InterprocessMessageListener.InterprocessMessageEventArgs(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)
|
||||||
|
UpdateCheck.CheckForUpdate();
|
||||||
|
|
||||||
|
// Show the link if updates are available
|
||||||
|
if (UpdateCheck.UpdateAvailable)
|
||||||
|
NewVersionLink.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
Tracer.WriteLine("MainForm creation finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.MultipleLineDisplay))
|
||||||
|
{
|
||||||
|
// Update the current feed
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.WindowLocked))
|
||||||
|
{
|
||||||
|
// Update the window for the new window lock value
|
||||||
|
HandleWindowLockState();
|
||||||
|
}
|
||||||
|
else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.ToolbarLocation))
|
||||||
|
{
|
||||||
|
// Update the window for the toolbar location
|
||||||
|
switch (Settings.Default.ToolbarLocation)
|
||||||
|
{
|
||||||
|
case Dock.Top:
|
||||||
|
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "TopToolbarRow");
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Dock.Bottom:
|
||||||
|
NameBasedGrid.NameBasedGrid.SetRow(NavigationToolbarTray, "BottomToolbarRow");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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()
|
||||||
|
{
|
||||||
|
UpdateToolbarButtonState();
|
||||||
|
|
||||||
|
// 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?.Feeds.ToList() ?? _database.Feeds.ToList();
|
||||||
|
|
||||||
|
// Clear the link list
|
||||||
|
LinkTextList.Items.Clear();
|
||||||
|
|
||||||
|
// Reset the feed index
|
||||||
|
_feedIndex = -1;
|
||||||
|
|
||||||
|
// Start the timer
|
||||||
|
StartTimer();
|
||||||
|
|
||||||
|
// Don't go further if we have no feeds
|
||||||
|
if (_feedList.Count == 0)
|
||||||
|
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.Count(item => !item.BeenRead) > 0)
|
||||||
|
{
|
||||||
|
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.Count(item => !item.BeenRead) > 0)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
foreach (FeedItem feedItem in LinkTextList.Items)
|
||||||
|
feedItem.BeenRead = true;
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
|
||||||
|
// Clear the list
|
||||||
|
LinkTextList.Items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Database helpers
|
||||||
|
|
||||||
|
private void ResetDatabase()
|
||||||
|
{
|
||||||
|
// Get the ID of the current feed
|
||||||
|
var currentId = _currentFeed?.ID ?? Guid.Empty;
|
||||||
|
|
||||||
|
// Create a new database object
|
||||||
|
_database = new FeedCenterEntities();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
59
Application/MainWindow/Timer.cs
Normal file
59
Application/MainWindow/Timer.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using FeedCenter.Properties;
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
254
Application/MainWindow/Toolbar.cs
Normal file
254
Application/MainWindow/Toolbar.cs
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
using FeedCenter.Options;
|
||||||
|
using FeedCenter.Properties;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Web.UI;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Get the browser
|
||||||
|
var browser = BrowserCommon.FindBrowser(Settings.Default.Browser);
|
||||||
|
|
||||||
|
// 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 (BrowserCommon.OpenLink(browser, feedItem.Link))
|
||||||
|
{
|
||||||
|
// Mark the feed as read
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the changes
|
||||||
|
_database.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleOptionsToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Create the options form
|
||||||
|
var optionsWindow = new OptionsWindow { Owner = this };
|
||||||
|
|
||||||
|
// Show the options form and get the result
|
||||||
|
var result = optionsWindow.ShowDialog();
|
||||||
|
|
||||||
|
// If okay was selected
|
||||||
|
if (result.HasValue && result.Value)
|
||||||
|
{
|
||||||
|
// Reset the database to current settings
|
||||||
|
ResetDatabase();
|
||||||
|
|
||||||
|
// Re-initialize the feed display
|
||||||
|
DisplayFeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
var result = feedErrorWindow.Display(this);
|
||||||
|
|
||||||
|
// If okay was selected
|
||||||
|
if (result.GetValueOrDefault())
|
||||||
|
{
|
||||||
|
// Reset 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(_database, _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.ConfirmDelete, 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 all items
|
||||||
|
foreach (var item in feedToDelete.Items.ToList())
|
||||||
|
_database.FeedItems.Remove(item);
|
||||||
|
|
||||||
|
// Delete the feed
|
||||||
|
_database.Feeds.Remove(feedToDelete);
|
||||||
|
|
||||||
|
// Save
|
||||||
|
_database.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
BrowserCommon.OpenLink(fileName);
|
||||||
|
|
||||||
|
MarkAllItemsAsRead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Application/MainWindow/UpdateHandler.cs
Normal file
40
Application/MainWindow/UpdateHandler.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using Common.Update;
|
||||||
|
using FeedCenter.Properties;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
private static void InitializeUpdate()
|
||||||
|
{
|
||||||
|
UpdateCheck.ApplicationName = Properties.Resources.ApplicationDisplayName;
|
||||||
|
UpdateCheck.UpdateServer = Settings.Default.VersionLocation;
|
||||||
|
UpdateCheck.UpdateFile = Settings.Default.VersionFile;
|
||||||
|
UpdateCheck.ApplicationShutdown = ApplicationShutdown;
|
||||||
|
UpdateCheck.ApplicationCurrentMessage = ApplicationCurrentMessage;
|
||||||
|
UpdateCheck.ApplicationUpdateMessage = ApplicationUpdateMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ApplicationShutdown()
|
||||||
|
{
|
||||||
|
Application.Current.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleNewVersionLinkClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Display update information
|
||||||
|
UpdateCheck.DisplayUpdateInformation(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
180
Application/MainWindow/WindowHandler.cs
Normal file
180
Application/MainWindow/WindowHandler.cs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
using FeedCenter.Properties;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using Common.Helpers;
|
||||||
|
|
||||||
|
namespace FeedCenter
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
_feedReadWorker.CancelAsync();
|
||||||
|
_feedReadWorker.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get rid of the timer
|
||||||
|
TerminateTimer();
|
||||||
|
|
||||||
|
// Save current window settings
|
||||||
|
SaveWindowSettings();
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
Settings.Default.Save();
|
||||||
|
|
||||||
|
// Save options
|
||||||
|
_database.SaveChanges();
|
||||||
|
|
||||||
|
// Get rid of the notification icon
|
||||||
|
NotificationIcon.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelayedMethod _windowStateDelay;
|
||||||
|
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_windowStateDelay == null)
|
||||||
|
_windowStateDelay = new DelayedMethod(500, UpdateWindowSettings);
|
||||||
|
|
||||||
|
_windowStateDelay.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleWindowLocationChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (_windowStateDelay == null)
|
||||||
|
_windowStateDelay = new DelayedMethod(500, UpdateWindowSettings);
|
||||||
|
|
||||||
|
_windowStateDelay.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBorder()
|
||||||
|
{
|
||||||
|
var windowInteropHelper = new WindowInteropHelper(this);
|
||||||
|
|
||||||
|
var screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
|
||||||
|
|
||||||
|
var rectangle = new System.Drawing.Rectangle
|
||||||
|
{
|
||||||
|
X = (int) Left,
|
||||||
|
Y = (int) Top,
|
||||||
|
Width = (int) Width,
|
||||||
|
Height = (int) Height
|
||||||
|
};
|
||||||
|
|
||||||
|
var borderThickness = new Thickness();
|
||||||
|
|
||||||
|
if (rectangle.Right != screen.WorkingArea.Right)
|
||||||
|
borderThickness.Right = 1;
|
||||||
|
|
||||||
|
if (rectangle.Left != screen.WorkingArea.Left)
|
||||||
|
borderThickness.Left = 1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -394,7 +394,9 @@ namespace FeedCenter.Options
|
|||||||
|
|
||||||
_collectionViewSource.View.Refresh();
|
_collectionViewSource.View.Refresh();
|
||||||
|
|
||||||
//textBlock.TextDecorations = null;
|
var dataGridRow = (DataGridRow) sender;
|
||||||
|
|
||||||
|
dataGridRow.FontWeight = FontWeights.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleListBoxItemPreviewMouseMove(object sender, MouseEventArgs e)
|
private void HandleListBoxItemPreviewMouseMove(object sender, MouseEventArgs e)
|
||||||
|
|||||||
18
Application/Properties/Resources.Designer.cs
generated
18
Application/Properties/Resources.Designer.cs
generated
@@ -96,6 +96,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to < all >.
|
||||||
|
/// </summary>
|
||||||
|
public static string AllCategory {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AllCategory", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -196,6 +205,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Category: {0}.
|
||||||
|
/// </summary>
|
||||||
|
public static string CategoryFilterHeader {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("CategoryFilterHeader", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Category.
|
/// Looks up a localized string similar to Category.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -517,4 +517,10 @@
|
|||||||
<data name="FeedChooserWindow" xml:space="preserve">
|
<data name="FeedChooserWindow" xml:space="preserve">
|
||||||
<value>Choose Feed to Add</value>
|
<value>Choose Feed to Add</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AllCategory" xml:space="preserve">
|
||||||
|
<value>< all ></value>
|
||||||
|
</data>
|
||||||
|
<data name="CategoryFilterHeader" xml:space="preserve">
|
||||||
|
<value>Category: {0}</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
12
Application/Properties/Settings.Designer.cs
generated
12
Application/Properties/Settings.Designer.cs
generated
@@ -277,5 +277,17 @@ namespace FeedCenter.Properties {
|
|||||||
return ((string)(this["VersionLocation"]));
|
return ((string)(this["VersionLocation"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string LastCategoryID {
|
||||||
|
get {
|
||||||
|
return ((string)(this["LastCategoryID"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["LastCategoryID"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,5 +68,8 @@
|
|||||||
<Setting Name="VersionLocation" Type="System.String" Scope="Application">
|
<Setting Name="VersionLocation" Type="System.String" Scope="Application">
|
||||||
<Value Profile="(Default)">http://server/FeedCenter/</Value>
|
<Value Profile="(Default)">http://server/FeedCenter/</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="LastCategoryID" Type="System.String" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@@ -57,6 +57,9 @@
|
|||||||
<setting name="MultipleLineDisplay" serializeAs="String">
|
<setting name="MultipleLineDisplay" serializeAs="String">
|
||||||
<value>Normal</value>
|
<value>Normal</value>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="LastCategoryID" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
</FeedCenter.Properties.Settings>
|
</FeedCenter.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
<applicationSettings>
|
<applicationSettings>
|
||||||
|
|||||||
Reference in New Issue
Block a user