mirror of
https://github.com/ckaczor/FeedCenter.git
synced 2026-01-17 09:35:39 -05:00
Compare commits
20 Commits
main
...
prerelease
| Author | SHA1 | Date | |
|---|---|---|---|
| 9717e2d6af | |||
| 7ace91684c | |||
| c186de0394 | |||
| 41d0b055dd | |||
| 2d32d740a4 | |||
| 5e7fa4a2e0 | |||
| 66ea567eaa | |||
| 6bae35a255 | |||
| cdd22c6632 | |||
| b68f794e7d | |||
| 4291d301cc | |||
| af88692aab | |||
| 3b1303c7d4 | |||
| ce1fed6636 | |||
| 40f7dd0fa4 | |||
| 00c2cb7227 | |||
| 4d7d7c041a | |||
| 636c7f9b2a | |||
| 41029671dc | |||
| 4e721efa55 |
188
Application/Accounts/Account.cs
Normal file
188
Application/Accounts/Account.cs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
using FeedCenter.Feeds;
|
||||||
|
using Realms;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public class Account : RealmObject, INotifyDataErrorInfo
|
||||||
|
{
|
||||||
|
public const string DefaultName = "< Local >";
|
||||||
|
|
||||||
|
private readonly DataErrorDictionary _dataErrorDictionary;
|
||||||
|
|
||||||
|
public Account() : this(AccountType.Local)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account(AccountType type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
|
||||||
|
_dataErrorDictionary = new DataErrorDictionary();
|
||||||
|
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IAccountReader _accountReader;
|
||||||
|
|
||||||
|
private IAccountReader GetAccountReader()
|
||||||
|
{
|
||||||
|
_accountReader ??= AccountReaderFactory.CreateAccountReader(this);
|
||||||
|
|
||||||
|
return _accountReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public AccountType Type
|
||||||
|
{
|
||||||
|
get => Enum.TryParse(TypeRaw, out AccountType result) ? result : AccountType.Local;
|
||||||
|
set => TypeRaw = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsFeedEdit => GetAccountReader().SupportsFeedEdit;
|
||||||
|
|
||||||
|
public bool SupportsFeedDelete => GetAccountReader().SupportsFeedDelete;
|
||||||
|
|
||||||
|
private string TypeRaw { get; set; }
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => RawName;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RawName = value;
|
||||||
|
|
||||||
|
ValidateString(nameof(Name), RawName);
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapTo("Name")]
|
||||||
|
private string RawName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string Url
|
||||||
|
{
|
||||||
|
get => RawUrl;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RawUrl = value;
|
||||||
|
|
||||||
|
ValidateString(nameof(Url), RawUrl);
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapTo("Url")]
|
||||||
|
public string RawUrl { get; set; }
|
||||||
|
|
||||||
|
public string Username
|
||||||
|
{
|
||||||
|
get => RawUsername;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RawUsername = value;
|
||||||
|
|
||||||
|
if (!Authenticate)
|
||||||
|
{
|
||||||
|
_dataErrorDictionary.ClearErrors(nameof(Username));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateString(nameof(Username), RawUsername);
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapTo("Username")]
|
||||||
|
public string RawUsername { get; set; }
|
||||||
|
|
||||||
|
public string Password
|
||||||
|
{
|
||||||
|
get => RawPassword;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
RawPassword = value;
|
||||||
|
|
||||||
|
if (!Authenticate)
|
||||||
|
{
|
||||||
|
_dataErrorDictionary.ClearErrors(nameof(Password));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateString(nameof(Password), RawPassword);
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MapTo("Password")]
|
||||||
|
public string RawPassword { get; set; }
|
||||||
|
|
||||||
|
public bool Authenticate { get; set; }
|
||||||
|
|
||||||
|
public bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
|
public int CheckInterval { get; set; } = 60;
|
||||||
|
|
||||||
|
public DateTimeOffset LastChecked { get; set; }
|
||||||
|
|
||||||
|
public bool HasErrors => _dataErrorDictionary.Any();
|
||||||
|
|
||||||
|
public IEnumerable GetErrors(string propertyName)
|
||||||
|
{
|
||||||
|
return _dataErrorDictionary.GetErrors(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
|
||||||
|
|
||||||
|
private void DataErrorDictionaryErrorsChanged(object sender, DataErrorsChangedEventArgs e)
|
||||||
|
{
|
||||||
|
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(e.PropertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateString(string propertyName, string value)
|
||||||
|
{
|
||||||
|
_dataErrorDictionary.ClearErrors(propertyName);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
_dataErrorDictionary.AddError(propertyName, $"{propertyName} cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Account CreateDefault()
|
||||||
|
{
|
||||||
|
return new Account { Name = DefaultName, Type = AccountType.Local };
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetProgressSteps(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var progressSteps = await GetAccountReader().GetProgressSteps(accountReadInput);
|
||||||
|
|
||||||
|
return progressSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AccountReadResult> Read(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
// If not enabled then do nothing
|
||||||
|
if (!Enabled)
|
||||||
|
return AccountReadResult.NotEnabled;
|
||||||
|
|
||||||
|
// Check if we're forcing a read
|
||||||
|
if (!accountReadInput.ForceRead)
|
||||||
|
{
|
||||||
|
// Figure out how long since we last checked
|
||||||
|
var timeSpan = DateTimeOffset.Now - LastChecked;
|
||||||
|
|
||||||
|
// Check if we are due to read the feed
|
||||||
|
if (timeSpan.TotalMinutes < CheckInterval)
|
||||||
|
return AccountReadResult.NotDue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountReadResult = await GetAccountReader().Read(accountReadInput);
|
||||||
|
|
||||||
|
return accountReadResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Application/Accounts/AccountReadInput.cs
Normal file
11
Application/Accounts/AccountReadInput.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public class AccountReadInput(FeedCenterEntities entities, Guid? feedId, bool forceRead, Action incrementProgress)
|
||||||
|
{
|
||||||
|
public FeedCenterEntities Entities { get; set; } = entities;
|
||||||
|
public Guid? FeedId { get; set; } = feedId;
|
||||||
|
public bool ForceRead { get; set; } = forceRead;
|
||||||
|
public Action IncrementProgress { get; private set; } = incrementProgress ?? throw new ArgumentNullException(nameof(incrementProgress));
|
||||||
|
}
|
||||||
8
Application/Accounts/AccountReadResult.cs
Normal file
8
Application/Accounts/AccountReadResult.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public enum AccountReadResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
NotDue,
|
||||||
|
NotEnabled
|
||||||
|
}
|
||||||
16
Application/Accounts/AccountReaderFactory.cs
Normal file
16
Application/Accounts/AccountReaderFactory.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
internal static class AccountReaderFactory
|
||||||
|
{
|
||||||
|
internal static IAccountReader CreateAccountReader(Account account) =>
|
||||||
|
account.Type switch
|
||||||
|
{
|
||||||
|
AccountType.Miniflux => new MinifluxReader(account),
|
||||||
|
AccountType.Local => new LocalReader(account),
|
||||||
|
AccountType.Fever => new FeverReader(account),
|
||||||
|
AccountType.GoogleReader => new GoogleReaderReader(account),
|
||||||
|
_ => throw new NotSupportedException($"Account type '{account.Type}' is not supported."),
|
||||||
|
};
|
||||||
|
}
|
||||||
9
Application/Accounts/AccountType.cs
Normal file
9
Application/Accounts/AccountType.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public enum AccountType
|
||||||
|
{
|
||||||
|
Local,
|
||||||
|
Fever,
|
||||||
|
GoogleReader,
|
||||||
|
Miniflux
|
||||||
|
}
|
||||||
175
Application/Accounts/FeverReader.cs
Normal file
175
Application/Accounts/FeverReader.cs
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
using ChrisKaczor.FeverClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
using FeverFeedItem = ChrisKaczor.FeverClient.Models.FeedItem;
|
||||||
|
|
||||||
|
internal class FeverReader(Account account) : IAccountReader
|
||||||
|
{
|
||||||
|
public async Task<int> GetProgressSteps(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||||
|
|
||||||
|
var feverClient = new FeverClient(account.Url, apiKey);
|
||||||
|
|
||||||
|
var feeds = await feverClient.GetFeeds();
|
||||||
|
|
||||||
|
return feeds.Count() * 2 + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AccountReadResult> Read(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var checkTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||||
|
|
||||||
|
var feverClient = new FeverClient(account.Url, apiKey);
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feverFeeds = (await feverClient.GetFeeds()).ToList();
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var allFeverFeedItems = await GetAllFeverFeedItems(feverClient);
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var existingFeedsByRemoteId = accountReadInput.Entities.Feeds.Where(f => f.Account.Id == account.Id) .ToDictionary(f => f.RemoteId);
|
||||||
|
|
||||||
|
var transaction = accountReadInput.Entities.BeginTransaction();
|
||||||
|
|
||||||
|
foreach (var feverFeed in feverFeeds)
|
||||||
|
{
|
||||||
|
var feed = existingFeedsByRemoteId.GetValueOrDefault(feverFeed.Id.ToString(), null);
|
||||||
|
|
||||||
|
if (feed == null)
|
||||||
|
{
|
||||||
|
feed = new Feed
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
RemoteId = feverFeed.Id.ToString(),
|
||||||
|
Title = feverFeed.Title,
|
||||||
|
Source = feverFeed.Url,
|
||||||
|
Link = feverFeed.SiteUrl,
|
||||||
|
Account = account,
|
||||||
|
Name = feverFeed.Title,
|
||||||
|
CategoryId = accountReadInput.Entities.DefaultCategory.Id,
|
||||||
|
Enabled = true,
|
||||||
|
CheckInterval = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
accountReadInput.Entities.Feeds.Add(feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
feed.Name = feverFeed.Title;
|
||||||
|
feed.Title = feverFeed.Title;
|
||||||
|
feed.Link = feverFeed.SiteUrl;
|
||||||
|
feed.Source = feverFeed.Url;
|
||||||
|
feed.LastReadResult = FeedReadResult.Success;
|
||||||
|
feed.LastChecked = checkTime;
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feverFeedItems = allFeverFeedItems.GetValueOrDefault(feverFeed.Id, []);
|
||||||
|
|
||||||
|
var existingFeedItemsByRemoteId = feed.Items.ToDictionary(fi => fi.RemoteId);
|
||||||
|
|
||||||
|
var sequence = 1;
|
||||||
|
|
||||||
|
foreach (var feverFeedItem in feverFeedItems)
|
||||||
|
{
|
||||||
|
var feedItem = existingFeedItemsByRemoteId.GetValueOrDefault(feverFeedItem.Id.ToString(), null);
|
||||||
|
|
||||||
|
if (feedItem == null)
|
||||||
|
{
|
||||||
|
feedItem = new FeedItem
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
RemoteId = feverFeedItem.Id.ToString(),
|
||||||
|
Title = feverFeedItem.Title,
|
||||||
|
Link = feverFeedItem.Url,
|
||||||
|
Description = feverFeedItem.Html,
|
||||||
|
BeenRead = feverFeedItem.IsRead,
|
||||||
|
FeedId = feed.Id,
|
||||||
|
Guid = Guid.NewGuid().ToString(),
|
||||||
|
Sequence = sequence++,
|
||||||
|
};
|
||||||
|
|
||||||
|
feed.Items.Add(feedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
feedItem.LastFound = checkTime;
|
||||||
|
feedItem.BeenRead = feverFeedItem.IsRead;
|
||||||
|
feedItem.Sequence = sequence++;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feedItemsNotSeen = feed.Items.Where(fi => fi.LastFound != checkTime).ToList();
|
||||||
|
|
||||||
|
foreach (var feedItemNotSeen in feedItemsNotSeen)
|
||||||
|
{
|
||||||
|
feed.Items.Remove(feedItemNotSeen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feedsNotSeen = accountReadInput.Entities.Feeds.Where(f => f.Account.Id == account.Id && f.LastChecked != checkTime).ToList();
|
||||||
|
|
||||||
|
foreach (var feedNotSeen in feedsNotSeen)
|
||||||
|
{
|
||||||
|
accountReadInput.Entities.Feeds.Remove(feedNotSeen);
|
||||||
|
}
|
||||||
|
|
||||||
|
account.LastChecked = checkTime;
|
||||||
|
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
return AccountReadResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<Dictionary<int, List<FeverFeedItem>>> GetAllFeverFeedItems(FeverClient feverClient)
|
||||||
|
{
|
||||||
|
var allFeverFeedItems = new List<FeverFeedItem>();
|
||||||
|
|
||||||
|
await foreach (var page in feverClient.GetAllFeedItems())
|
||||||
|
{
|
||||||
|
allFeverFeedItems.AddRange(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
var grouped = allFeverFeedItems.OrderByDescending(fi => fi.CreatedOnTime).GroupBy(fi => fi.FeedId);
|
||||||
|
|
||||||
|
return grouped.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MarkFeedItemRead(string feedItemId)
|
||||||
|
{
|
||||||
|
var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||||
|
|
||||||
|
var feverClient = new FeverClient(account.Url, apiKey);
|
||||||
|
|
||||||
|
await feverClient.MarkFeedItemAsRead(int.Parse(feedItemId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsFeedDelete => false;
|
||||||
|
|
||||||
|
public bool SupportsFeedEdit => false;
|
||||||
|
|
||||||
|
private static string GetApiKey(Account account)
|
||||||
|
{
|
||||||
|
var input = $"{account.Username}:{account.Password}";
|
||||||
|
var hash = MD5.HashData(Encoding.UTF8.GetBytes(input));
|
||||||
|
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
147
Application/Accounts/GoogleReaderReader.cs
Normal file
147
Application/Accounts/GoogleReaderReader.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
internal class GoogleReaderReader(Account account) : IAccountReader
|
||||||
|
{
|
||||||
|
public Task<int> GetProgressSteps(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
return Task.FromResult(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AccountReadResult> Read(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var checkTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
//var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||||
|
|
||||||
|
//var feverClient = new FeverClient.FeverClient(account.Url, apiKey);
|
||||||
|
|
||||||
|
//accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
//var feverFeeds = feverClient.GetFeeds().Result.ToList();
|
||||||
|
|
||||||
|
//accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
//var allFeverFeedItems = feverClient.GetAllFeedItems().Result.ToList();
|
||||||
|
|
||||||
|
//accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var transaction = accountReadInput.Entities.BeginTransaction();
|
||||||
|
|
||||||
|
//foreach (var feverFeed in feverFeeds)
|
||||||
|
//{
|
||||||
|
// var feed = accountReadInput.Entities.Feeds.FirstOrDefault(f => f.RemoteId == feverFeed.Id.ToString() && f.Account.Id == account.Id);
|
||||||
|
|
||||||
|
// if (feed == null)
|
||||||
|
// {
|
||||||
|
// feed = new Feed
|
||||||
|
// {
|
||||||
|
// Id = Guid.NewGuid(),
|
||||||
|
// RemoteId = feverFeed.Id.ToString(),
|
||||||
|
// Title = feverFeed.Title,
|
||||||
|
// Source = feverFeed.Url,
|
||||||
|
// Link = feverFeed.SiteUrl,
|
||||||
|
// Account = account,
|
||||||
|
// Name = feverFeed.Title,
|
||||||
|
// CategoryId = accountReadInput.Entities.DefaultCategory.Id,
|
||||||
|
// Enabled = true,
|
||||||
|
// CheckInterval = 0,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// accountReadInput.Entities.Feeds.Add(feed);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// feed.Name = feverFeed.Title;
|
||||||
|
// feed.Title = feverFeed.Title;
|
||||||
|
// feed.Link = feverFeed.SiteUrl;
|
||||||
|
// feed.Source = feverFeed.Url;
|
||||||
|
// feed.LastReadResult = FeedReadResult.Success;
|
||||||
|
// feed.LastChecked = checkTime;
|
||||||
|
|
||||||
|
// accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
// var feverFeedItems = allFeverFeedItems
|
||||||
|
// .Where(f => f.FeedId == feverFeed.Id)
|
||||||
|
// .OrderByDescending(fi => fi.CreatedOnTime).ToList();
|
||||||
|
|
||||||
|
// var sequence = 1;
|
||||||
|
|
||||||
|
// foreach (var feverFeedItem in feverFeedItems)
|
||||||
|
// {
|
||||||
|
// var feedItem = feed.Items.FirstOrDefault(f => f.RemoteId == feverFeedItem.Id.ToString());
|
||||||
|
|
||||||
|
// if (feedItem == null)
|
||||||
|
// {
|
||||||
|
// feedItem = new FeedItem
|
||||||
|
// {
|
||||||
|
// Id = Guid.NewGuid(),
|
||||||
|
// RemoteId = feverFeedItem.Id.ToString(),
|
||||||
|
// Title = feverFeedItem.Title,
|
||||||
|
// Link = feverFeedItem.Url,
|
||||||
|
// Description = feverFeedItem.Html,
|
||||||
|
// BeenRead = feverFeedItem.IsRead,
|
||||||
|
// FeedId = feed.Id,
|
||||||
|
// Guid = Guid.NewGuid().ToString(),
|
||||||
|
// Sequence = sequence++,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// feed.Items.Add(feedItem);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// feedItem.LastFound = checkTime;
|
||||||
|
// feedItem.BeenRead = feverFeedItem.IsRead;
|
||||||
|
// feedItem.Sequence = sequence++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
// var feedItemsNotSeen = feed.Items.Where(fi => fi.LastFound != checkTime).ToList();
|
||||||
|
|
||||||
|
// foreach (var feedItemNotSeen in feedItemsNotSeen)
|
||||||
|
// {
|
||||||
|
// feed.Items.Remove(feedItemNotSeen);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
//var feedsNotSeen = accountReadInput.Entities.Feeds.Where(f => f.Account.Id == account.Id && f.LastChecked != checkTime).ToList();
|
||||||
|
|
||||||
|
//foreach (var feedNotSeen in feedsNotSeen)
|
||||||
|
//{
|
||||||
|
// accountReadInput.Entities.Feeds.Remove(feedNotSeen);
|
||||||
|
//}
|
||||||
|
|
||||||
|
account.LastChecked = checkTime;
|
||||||
|
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
return AccountReadResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task MarkFeedItemRead(string feedItemId)
|
||||||
|
{
|
||||||
|
//var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||||
|
|
||||||
|
//var feverClient = new FeverClient.FeverClient(account.Url, apiKey);
|
||||||
|
|
||||||
|
//await feverClient.MarkFeedItemAsRead(int.Parse(feedItemId));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsFeedDelete => false;
|
||||||
|
|
||||||
|
public bool SupportsFeedEdit => false;
|
||||||
|
|
||||||
|
//private static string GetApiKey(Account account)
|
||||||
|
//{
|
||||||
|
// var input = $"{account.Username}:{account.Password}";
|
||||||
|
// var hash = MD5.HashData(Encoding.UTF8.GetBytes(input));
|
||||||
|
// return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||||
|
//}
|
||||||
|
}
|
||||||
12
Application/Accounts/IAccountReader.cs
Normal file
12
Application/Accounts/IAccountReader.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public interface IAccountReader
|
||||||
|
{
|
||||||
|
public Task<int> GetProgressSteps(AccountReadInput accountReadInput);
|
||||||
|
public Task<AccountReadResult> Read(AccountReadInput accountReadInput);
|
||||||
|
public Task MarkFeedItemRead(string feedItemId);
|
||||||
|
public bool SupportsFeedDelete { get; }
|
||||||
|
public bool SupportsFeedEdit { get; }
|
||||||
|
}
|
||||||
53
Application/Accounts/LocalReader.cs
Normal file
53
Application/Accounts/LocalReader.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
public class LocalReader(Account account) : IAccountReader
|
||||||
|
{
|
||||||
|
public Task<int> GetProgressSteps(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var enabledFeedCount = accountReadInput.Entities.Feeds.Count(f => f.Account.Type == AccountType.Local && f.Enabled);
|
||||||
|
|
||||||
|
return Task.FromResult(enabledFeedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AccountReadResult> Read(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var checkTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
// 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 (accountReadInput.FeedId != null)
|
||||||
|
feedsToRead.Add(accountReadInput.Entities.Feeds.First(feed => feed.Id == accountReadInput.FeedId));
|
||||||
|
else
|
||||||
|
feedsToRead.AddRange(accountReadInput.Entities.Feeds.Where(f => f.Account.Type == AccountType.Local));
|
||||||
|
|
||||||
|
// Loop over each feed and read it
|
||||||
|
foreach (var feed in feedsToRead)
|
||||||
|
{
|
||||||
|
// Read the feed
|
||||||
|
accountReadInput.Entities.SaveChanges(() => feed.Read(accountReadInput.ForceRead));
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.Entities.SaveChanges(() => account.LastChecked = checkTime);
|
||||||
|
|
||||||
|
return Task.FromResult(AccountReadResult.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task MarkFeedItemRead(string feedItemId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsFeedDelete => true;
|
||||||
|
|
||||||
|
public bool SupportsFeedEdit => true;
|
||||||
|
}
|
||||||
151
Application/Accounts/MinifluxReader.cs
Normal file
151
Application/Accounts/MinifluxReader.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ChrisKaczor.MinifluxClient;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
|
namespace FeedCenter.Accounts;
|
||||||
|
|
||||||
|
internal class MinifluxReader(Account account) : IAccountReader
|
||||||
|
{
|
||||||
|
public async Task<int> GetProgressSteps(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var minifluxClient = new MinifluxClient(account.Url, account.Password);
|
||||||
|
|
||||||
|
int feedCount;
|
||||||
|
if (accountReadInput.FeedId.HasValue)
|
||||||
|
{
|
||||||
|
feedCount = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var feeds = await minifluxClient.GetFeeds();
|
||||||
|
feedCount = feeds.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
return feedCount * 2 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AccountReadResult> Read(AccountReadInput accountReadInput)
|
||||||
|
{
|
||||||
|
var checkTime = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
var minifluxClient = new MinifluxClient(account.Url, account.Password);
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var localFeeds = accountReadInput.Entities.Feeds.ToList();
|
||||||
|
var remoteFeeds = (await minifluxClient.GetFeeds()).ToList();
|
||||||
|
|
||||||
|
if (accountReadInput.FeedId.HasValue)
|
||||||
|
{
|
||||||
|
localFeeds = localFeeds.Where(f => f.Id == accountReadInput.FeedId.Value).ToList();
|
||||||
|
remoteFeeds = remoteFeeds.Where(rf => rf.Id.ToString() == localFeeds.First().RemoteId).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var transaction = accountReadInput.Entities.BeginTransaction();
|
||||||
|
|
||||||
|
foreach (var remoteFeed in remoteFeeds)
|
||||||
|
{
|
||||||
|
var feed = accountReadInput.Entities.Feeds.FirstOrDefault(f => f.RemoteId == remoteFeed.Id.ToString() && f.Account.Id == account.Id);
|
||||||
|
|
||||||
|
if (feed == null)
|
||||||
|
{
|
||||||
|
feed = new Feed
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
RemoteId = remoteFeed.Id.ToString(),
|
||||||
|
Title = remoteFeed.Title,
|
||||||
|
Source = remoteFeed.FeedUrl,
|
||||||
|
Link = remoteFeed.SiteUrl,
|
||||||
|
Account = account,
|
||||||
|
Name = remoteFeed.Title,
|
||||||
|
CategoryId = accountReadInput.Entities.DefaultCategory.Id,
|
||||||
|
Enabled = true,
|
||||||
|
CheckInterval = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
accountReadInput.Entities.Feeds.Add(feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
feed.Name = remoteFeed.Title;
|
||||||
|
feed.Title = remoteFeed.Title;
|
||||||
|
feed.Link = remoteFeed.SiteUrl;
|
||||||
|
feed.Source = remoteFeed.FeedUrl;
|
||||||
|
feed.LastReadResult = FeedReadResult.Success;
|
||||||
|
feed.LastChecked = checkTime;
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var sequence = 1;
|
||||||
|
|
||||||
|
var remoteFeedItems = (await minifluxClient.GetFeedEntries(remoteFeed.Id, SortField.PublishedAt, SortDirection.Descending)).ToList();
|
||||||
|
|
||||||
|
foreach (var remoteFeedItem in remoteFeedItems)
|
||||||
|
{
|
||||||
|
var feedItem = feed.Items.FirstOrDefault(f => f.RemoteId == remoteFeedItem.Id.ToString());
|
||||||
|
|
||||||
|
if (feedItem == null)
|
||||||
|
{
|
||||||
|
feedItem = new FeedItem
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
RemoteId = remoteFeedItem.Id.ToString(),
|
||||||
|
Title = remoteFeedItem.Title,
|
||||||
|
Link = remoteFeedItem.Url,
|
||||||
|
Description = remoteFeedItem.Content,
|
||||||
|
BeenRead = remoteFeedItem.Status == "read",
|
||||||
|
FeedId = feed.Id,
|
||||||
|
Guid = Guid.NewGuid().ToString(),
|
||||||
|
Sequence = sequence++,
|
||||||
|
};
|
||||||
|
|
||||||
|
feed.Items.Add(feedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
feedItem.LastFound = checkTime;
|
||||||
|
feedItem.BeenRead = remoteFeedItem.Status == "read";
|
||||||
|
feedItem.Sequence = sequence++;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feedItemsNotSeen = feed.Items.Where(fi => fi.LastFound != checkTime).ToList();
|
||||||
|
|
||||||
|
foreach (var feedItemNotSeen in feedItemsNotSeen)
|
||||||
|
{
|
||||||
|
feed.Items.Remove(feedItemNotSeen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
var feedsNotSeen = localFeeds.Where(f => f.Account.Id == account.Id && f.LastChecked != checkTime).ToList();
|
||||||
|
|
||||||
|
foreach (var feedNotSeen in feedsNotSeen)
|
||||||
|
{
|
||||||
|
accountReadInput.Entities.Feeds.Remove(feedNotSeen);
|
||||||
|
}
|
||||||
|
|
||||||
|
account.LastChecked = checkTime;
|
||||||
|
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
accountReadInput.IncrementProgress();
|
||||||
|
|
||||||
|
return AccountReadResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MarkFeedItemRead(string feedItemId)
|
||||||
|
{
|
||||||
|
var minifluxClient = new MinifluxClient(account.Url, account.Password);
|
||||||
|
|
||||||
|
await minifluxClient.MarkFeedEntries([long.Parse(feedItemId)], FeedEntryStatus.Read);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SupportsFeedDelete => true;
|
||||||
|
|
||||||
|
public bool SupportsFeedEdit => true;
|
||||||
|
}
|
||||||
@@ -35,8 +35,8 @@ public partial class App
|
|||||||
var app = new App();
|
var app = new App();
|
||||||
app.InitializeComponent();
|
app.InitializeComponent();
|
||||||
|
|
||||||
// Create an single instance handle to see if we are already running
|
// Create a single instance handle to see if we are already running
|
||||||
var isolationHandle = SingleInstance.GetSingleInstanceHandleAsync(Name).Result;
|
var isolationHandle = SingleInstance.GetSingleInstanceHandleAsync(Name).GetAwaiter().GetResult();
|
||||||
|
|
||||||
// If there is another copy then pass it the command line and exit
|
// If there is another copy then pass it the command line and exit
|
||||||
if (isolationHandle == null)
|
if (isolationHandle == null)
|
||||||
|
|||||||
@@ -7,18 +7,5 @@ public static class Database
|
|||||||
public static string DatabaseFile { get; set; }
|
public static string DatabaseFile { get; set; }
|
||||||
public static string DatabasePath { get; set; }
|
public static string DatabasePath { get; set; }
|
||||||
|
|
||||||
public static FeedCenterEntities Entities { get; set; }
|
|
||||||
|
|
||||||
public static bool Exists => File.Exists(DatabaseFile);
|
public static bool Exists => File.Exists(DatabaseFile);
|
||||||
|
|
||||||
public static bool Loaded { get; set; }
|
|
||||||
|
|
||||||
public static void Load()
|
|
||||||
{
|
|
||||||
if (Loaded) return;
|
|
||||||
|
|
||||||
Entities = new FeedCenterEntities();
|
|
||||||
|
|
||||||
Loaded = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ using System.Collections.Generic;
|
|||||||
using System.Data.SqlServerCe;
|
using System.Data.SqlServerCe;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.Data;
|
namespace FeedCenter.Data;
|
||||||
|
|
||||||
|
|||||||
@@ -4,24 +4,17 @@ using System.Collections.Specialized;
|
|||||||
|
|
||||||
namespace FeedCenter.Data;
|
namespace FeedCenter.Data;
|
||||||
|
|
||||||
public class RealmObservableCollection<T> : ObservableCollection<T> where T : IRealmObject
|
public class RealmObservableCollection<T>(Realm realm) : ObservableCollection<T>(realm.All<T>()) where T : IRealmObject
|
||||||
{
|
{
|
||||||
private readonly Realm _realm;
|
|
||||||
|
|
||||||
public RealmObservableCollection(Realm realm) : base(realm.All<T>())
|
|
||||||
{
|
|
||||||
_realm = realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.OldItems != null)
|
if (e.OldItems != null)
|
||||||
foreach (T item in e.OldItems)
|
foreach (T item in e.OldItems)
|
||||||
_realm.Remove(item);
|
realm.Remove(item);
|
||||||
|
|
||||||
if (e.NewItems != null)
|
if (e.NewItems != null)
|
||||||
foreach (T item in e.NewItems)
|
foreach (T item in e.NewItems)
|
||||||
_realm.Add(item);
|
realm.Add(item);
|
||||||
|
|
||||||
base.OnCollectionChanged(e);
|
base.OnCollectionChanged(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using FeedCenter.Data;
|
||||||
using System.Linq;
|
|
||||||
using FeedCenter.Data;
|
|
||||||
using FeedCenter.Options;
|
using FeedCenter.Options;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
@@ -12,16 +14,59 @@ public class FeedCenterEntities
|
|||||||
{
|
{
|
||||||
var realmConfiguration = new RealmConfiguration($"{Database.DatabaseFile}")
|
var realmConfiguration = new RealmConfiguration($"{Database.DatabaseFile}")
|
||||||
{
|
{
|
||||||
SchemaVersion = 1,
|
SchemaVersion = 2,
|
||||||
MigrationCallback = (migration, oldSchemaVersion) =>
|
MigrationCallback = (migration, oldSchemaVersion) =>
|
||||||
{
|
{
|
||||||
|
Account localAccount;
|
||||||
|
|
||||||
|
if (oldSchemaVersion == 1)
|
||||||
|
{
|
||||||
|
localAccount = Account.CreateDefault();
|
||||||
|
migration.NewRealm.Add(localAccount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
localAccount = migration.NewRealm.All<Account>().First(a => a.Type == AccountType.Local);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newVersionCategories = migration.NewRealm.All<Category>();
|
||||||
|
|
||||||
|
foreach (var newVersionCategory in newVersionCategories)
|
||||||
|
{
|
||||||
|
switch (oldSchemaVersion)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
newVersionCategory.Account = localAccount;
|
||||||
|
newVersionCategory.RemoteId = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var newVersionFeeds = migration.NewRealm.All<Feed>();
|
var newVersionFeeds = migration.NewRealm.All<Feed>();
|
||||||
|
|
||||||
foreach (var newVersionFeed in newVersionFeeds)
|
foreach (var newVersionFeed in newVersionFeeds)
|
||||||
{
|
{
|
||||||
if (oldSchemaVersion == 0)
|
switch (oldSchemaVersion)
|
||||||
{
|
{
|
||||||
newVersionFeed.UserAgent = null;
|
case 0:
|
||||||
|
newVersionFeed.UserAgent = null;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
newVersionFeed.Account = localAccount;
|
||||||
|
newVersionFeed.RemoteId = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newVersionFeedItems = migration.NewRealm.All<FeedItem>();
|
||||||
|
|
||||||
|
foreach (var newVersionFeedItem in newVersionFeedItems)
|
||||||
|
{
|
||||||
|
switch (oldSchemaVersion)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
newVersionFeedItem.RemoteId = null;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,13 +74,20 @@ public class FeedCenterEntities
|
|||||||
|
|
||||||
RealmInstance = Realm.GetInstance(realmConfiguration);
|
RealmInstance = Realm.GetInstance(realmConfiguration);
|
||||||
|
|
||||||
|
Accounts = new RealmObservableCollection<Account>(RealmInstance);
|
||||||
Settings = new RealmObservableCollection<Setting>(RealmInstance);
|
Settings = new RealmObservableCollection<Setting>(RealmInstance);
|
||||||
Feeds = new RealmObservableCollection<Feed>(RealmInstance);
|
Feeds = new RealmObservableCollection<Feed>(RealmInstance);
|
||||||
Categories = new RealmObservableCollection<Category>(RealmInstance);
|
Categories = new RealmObservableCollection<Category>(RealmInstance);
|
||||||
|
|
||||||
|
if (!Accounts.Any())
|
||||||
|
{
|
||||||
|
RealmInstance.Write(() => Accounts.Add(Account.CreateDefault()));
|
||||||
|
}
|
||||||
|
|
||||||
if (!Categories.Any())
|
if (!Categories.Any())
|
||||||
{
|
{
|
||||||
RealmInstance.Write(() => Categories.Add(Category.CreateDefault()));
|
var localAccount = Accounts.First(a => a.Type == AccountType.Local);
|
||||||
|
RealmInstance.Write(() => Categories.Add(Category.CreateDefault(localAccount)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,15 +98,16 @@ public class FeedCenterEntities
|
|||||||
get { return Categories.First(c => c.IsDefault); }
|
get { return Categories.First(c => c.IsDefault); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public RealmObservableCollection<Feed> Feeds { get; private set; }
|
public Account LocalAccount
|
||||||
private Realm RealmInstance { get; }
|
|
||||||
public RealmObservableCollection<Setting> Settings { get; private set; }
|
|
||||||
|
|
||||||
public void Refresh()
|
|
||||||
{
|
{
|
||||||
RealmInstance.Refresh();
|
get { return Accounts.First(a => a.Type == AccountType.Local); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RealmObservableCollection<Feed> Feeds { get; }
|
||||||
|
public RealmObservableCollection<Account> Accounts { get; }
|
||||||
|
private Realm RealmInstance { get; }
|
||||||
|
public RealmObservableCollection<Setting> Settings { get; }
|
||||||
|
|
||||||
public void SaveChanges(Action action)
|
public void SaveChanges(Action action)
|
||||||
{
|
{
|
||||||
RealmInstance.Write(action);
|
RealmInstance.Write(action);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net70-windows</TargetFramework>
|
<TargetFramework>net10.0-windows8.0</TargetFramework>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<UseWindowsForms>false</UseWindowsForms>
|
<UseWindowsForms>false</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||||
|
<RestoreEnablePackagePruning>false</RestoreEnablePackagePruning>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition>
|
<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition>
|
||||||
@@ -25,35 +26,38 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ChrisKaczor.ApplicationUpdate" Version="1.0.7" />
|
<PackageReference Include="ChrisKaczor.ApplicationUpdate" Version="1.0.7" />
|
||||||
|
<PackageReference Include="ChrisKaczor.FeverClient" Version="1.0.3" />
|
||||||
<PackageReference Include="ChrisKaczor.GenericSettingsProvider" Version="1.0.4" />
|
<PackageReference Include="ChrisKaczor.GenericSettingsProvider" Version="1.0.4" />
|
||||||
<PackageReference Include="ChrisKaczor.InstalledBrowsers" Version="1.0.4" />
|
<PackageReference Include="ChrisKaczor.InstalledBrowsers" Version="1.0.4" />
|
||||||
|
<PackageReference Include="ChrisKaczor.MinifluxClient" Version="1.0.3" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Application.SingleInstance" Version="1.0.5" />
|
<PackageReference Include="ChrisKaczor.Wpf.Application.SingleInstance" Version="1.0.5" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" />
|
<PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Controls.HtmlTextBlock" Version="1.0.3" />
|
<PackageReference Include="ChrisKaczor.Wpf.Controls.HtmlTextBlock" Version="1.0.6" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Controls.Link" Version="1.0.4" />
|
<PackageReference Include="ChrisKaczor.Wpf.Controls.Link" Version="1.0.4" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Controls.Toolbar" Version="1.0.3" />
|
<PackageReference Include="ChrisKaczor.Wpf.Controls.Toolbar" Version="1.0.3" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Validation" Version="1.0.4" />
|
<PackageReference Include="ChrisKaczor.Wpf.Validation" Version="1.0.4" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Windows.ControlBox" Version="1.0.3" />
|
<PackageReference Include="ChrisKaczor.Wpf.Windows.ControlBox" Version="1.0.3" />
|
||||||
<PackageReference Include="ChrisKaczor.Wpf.Windows.SnappingWindow" Version="1.0.4" />
|
<PackageReference Include="ChrisKaczor.Wpf.Windows.SnappingWindow" Version="1.0.4" />
|
||||||
<PackageReference Include="Dapper" Version="2.0.123" />
|
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||||
<PackageReference Include="DebounceThrottle" Version="2.0.0" />
|
<PackageReference Include="DebounceThrottle" Version="3.0.1" />
|
||||||
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.0.108" />
|
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.3.2" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
|
||||||
<PackageReference Include="HtmlTextWriter" Version="2.1.1" />
|
<PackageReference Include="HtmlTextWriter" Version="3.0.2" />
|
||||||
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
|
<PackageReference Include="MahApps.Metro" Version="2.4.11" />
|
||||||
<PackageReference Include="Microsoft.SqlServer.Compact" Version="4.0.8876.1" GeneratePathProperty="true">
|
<PackageReference Include="Microsoft.SqlServer.Compact" Version="4.0.8876.1" GeneratePathProperty="true">
|
||||||
<NoWarn>NU1701</NoWarn>
|
<NoWarn>NU1701</NoWarn>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.6" />
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="10.0.0" />
|
||||||
<PackageReference Include="NameBasedGrid" Version="0.10.1">
|
<PackageReference Include="NameBasedGrid" Version="1.0.0">
|
||||||
<NoWarn>NU1701</NoWarn>
|
<NoWarn>NU1701</NoWarn>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.21.1" />
|
<PackageReference Include="Realm" Version="20.1.0" />
|
||||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
<PackageReference Include="Serilog" Version="4.3.0" />
|
||||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="10.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Resources\Application.ico" />
|
<Resource Include="Resources\Application.ico" />
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
<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>
|
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=feeds/@EntryIndexedValue">False</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mainwindow/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=mainwindow/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
49
Application/FeedCenter.sln
Normal file
49
Application/FeedCenter.sln
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 18
|
||||||
|
VisualStudioVersion = 18.0.11018.127
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FeedCenter", "FeedCenter.csproj", "{BD3D12F2-DE23-4466-83B1-1EB617A877A4}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{1462AAAD-B01B-4FF6-9B9F-595D239C9D1E}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
..\.gitignore = ..\.gitignore
|
||||||
|
..\appveyor.yml = ..\appveyor.yml
|
||||||
|
..\LICENSE.md = ..\LICENSE.md
|
||||||
|
..\README.md = ..\README.md
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|Mixed Platforms = Release|Mixed Platforms
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x64.ActiveCfg = Release|x86
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B1D182A0-263B-4AB8-8413-56303DBD4CCC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -3,4 +3,6 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kaczor/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Miniflux/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:linkControl="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
xmlns:linkControl="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
||||||
xmlns:controlBox="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:controlBox="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:feedCenter="clr-namespace:FeedCenter"
|
xmlns:feedCenter="clr-namespace:FeedCenter"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
x:Class="FeedCenter.FeedErrorWindow"
|
x:Class="FeedCenter.FeedErrorWindow"
|
||||||
Title="{x:Static my:Resources.FeedErrorWindow}"
|
Title="{x:Static my:Resources.FeedErrorWindow}"
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
HeadersVisibility="Column"
|
HeadersVisibility="Column"
|
||||||
Background="{x:Null}"
|
Background="{x:Null}"
|
||||||
CanUserSortColumns="True"
|
CanUserSortColumns="True"
|
||||||
d:DataContext="{d:DesignInstance Type=feedCenter:Feed}" SelectionChanged="FeedDataGrid_SelectionChanged">
|
d:DataContext="{d:DesignInstance Type=feeds:Feed}" SelectionChanged="FeedDataGrid_SelectionChanged">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}"
|
<DataGridTextColumn Header="{x:Static my:Resources.FeedNameColumnHeader}"
|
||||||
Binding="{Binding Name}"
|
Binding="{Binding Name}"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Windows;
|
|||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using ChrisKaczor.InstalledBrowsers;
|
using ChrisKaczor.InstalledBrowsers;
|
||||||
using FeedCenter.Data;
|
using FeedCenter.Feeds;
|
||||||
using FeedCenter.Options;
|
using FeedCenter.Options;
|
||||||
using FeedCenter.Properties;
|
using FeedCenter.Properties;
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ namespace FeedCenter;
|
|||||||
public partial class FeedErrorWindow
|
public partial class FeedErrorWindow
|
||||||
{
|
{
|
||||||
private CollectionViewSource _collectionViewSource;
|
private CollectionViewSource _collectionViewSource;
|
||||||
|
private readonly FeedCenterEntities _entities = new();
|
||||||
|
|
||||||
public FeedErrorWindow()
|
public FeedErrorWindow()
|
||||||
{
|
{
|
||||||
@@ -23,7 +24,7 @@ public partial class FeedErrorWindow
|
|||||||
public void Display(Window owner)
|
public void Display(Window owner)
|
||||||
{
|
{
|
||||||
// Create a view and sort it by name
|
// Create a view and sort it by name
|
||||||
_collectionViewSource = new CollectionViewSource { Source = Database.Entities.Feeds };
|
_collectionViewSource = new CollectionViewSource { Source = _entities.Feeds };
|
||||||
_collectionViewSource.Filter += HandleCollectionViewSourceFilter;
|
_collectionViewSource.Filter += HandleCollectionViewSourceFilter;
|
||||||
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ public partial class FeedErrorWindow
|
|||||||
|
|
||||||
var feed = (Feed) FeedDataGrid.SelectedItem;
|
var feed = (Feed) FeedDataGrid.SelectedItem;
|
||||||
|
|
||||||
var feedWindow = new FeedWindow();
|
var feedWindow = new FeedWindow(_entities);
|
||||||
|
|
||||||
feedWindow.Display(feed, GetWindow(this));
|
feedWindow.Display(feed, GetWindow(this));
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ public partial class FeedErrorWindow
|
|||||||
|
|
||||||
var feed = (Feed) FeedDataGrid.SelectedItem;
|
var feed = (Feed) FeedDataGrid.SelectedItem;
|
||||||
|
|
||||||
Database.Entities.SaveChanges(() => Database.Entities.Feeds.Remove(feed));
|
_entities.SaveChanges(() => _entities.Feeds.Remove(feed));
|
||||||
|
|
||||||
SetFeedButtonStates();
|
SetFeedButtonStates();
|
||||||
}
|
}
|
||||||
@@ -118,8 +119,6 @@ public partial class FeedErrorWindow
|
|||||||
entities.SaveChanges(() => feed.Read(true));
|
entities.SaveChanges(() => feed.Read(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
Database.Entities.Refresh();
|
|
||||||
|
|
||||||
var selectedIndex = FeedDataGrid.SelectedIndex;
|
var selectedIndex = FeedDataGrid.SelectedIndex;
|
||||||
|
|
||||||
_collectionViewSource.View.Refresh();
|
_collectionViewSource.View.Refresh();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.FeedParsers;
|
namespace FeedCenter.FeedParsers;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.FeedParsers;
|
namespace FeedCenter.FeedParsers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using FeedCenter.Xml;
|
using FeedCenter.Xml;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.FeedParsers;
|
namespace FeedCenter.FeedParsers;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.FeedParsers;
|
namespace FeedCenter.FeedParsers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using JetBrains.Annotations;
|
using System;
|
||||||
using Realms;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Realms;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public class Category : RealmObject, INotifyDataErrorInfo
|
public class Category : RealmObject, INotifyDataErrorInfo
|
||||||
{
|
{
|
||||||
@@ -22,6 +23,10 @@ public class Category : RealmObject, INotifyDataErrorInfo
|
|||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public string RemoteId { get; set; }
|
||||||
|
|
||||||
|
public Account Account { get; set; }
|
||||||
|
|
||||||
public bool IsDefault { get; internal set; }
|
public bool IsDefault { get; internal set; }
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
@@ -56,9 +61,9 @@ public class Category : RealmObject, INotifyDataErrorInfo
|
|||||||
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(e.PropertyName));
|
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(e.PropertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Category CreateDefault()
|
public static Category CreateDefault(Account account)
|
||||||
{
|
{
|
||||||
return new Category { Name = DefaultName, IsDefault = true };
|
return new Category { Name = DefaultName, IsDefault = true, Account = account };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateName()
|
private void ValidateName()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
internal class DataErrorDictionary : Dictionary<string, List<string>>
|
internal class DataErrorDictionary : Dictionary<string, List<string>>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using System.Text;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ChrisKaczor.ApplicationUpdate;
|
using ChrisKaczor.ApplicationUpdate;
|
||||||
using FeedCenter.Data;
|
using FeedCenter.Accounts;
|
||||||
using FeedCenter.FeedParsers;
|
using FeedCenter.FeedParsers;
|
||||||
using FeedCenter.Properties;
|
using FeedCenter.Properties;
|
||||||
using FeedCenter.Xml;
|
using FeedCenter.Xml;
|
||||||
@@ -20,7 +20,7 @@ using JetBrains.Annotations;
|
|||||||
using Realms;
|
using Realms;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public partial class Feed : RealmObject, INotifyDataErrorInfo
|
public partial class Feed : RealmObject, INotifyDataErrorInfo
|
||||||
{
|
{
|
||||||
@@ -34,14 +34,16 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
|||||||
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
|
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string RemoteId { get; set; }
|
||||||
public bool Authenticate { get; set; }
|
public bool Authenticate { get; set; }
|
||||||
public Guid CategoryId { get; set; }
|
public Guid CategoryId { get; set; }
|
||||||
public int CheckInterval { get; set; } = 60;
|
public int CheckInterval { get; set; } = 60;
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
|
public Account Account { get; set; }
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public IList<FeedItem> Items { get; }
|
public IList<FeedItem> Items { get; }
|
||||||
@@ -171,9 +173,9 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
|||||||
|
|
||||||
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
|
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
|
||||||
|
|
||||||
public static Feed Create()
|
public static Feed Create(FeedCenterEntities entities)
|
||||||
{
|
{
|
||||||
return new Feed { Id = Guid.NewGuid(), CategoryId = Database.Entities.DefaultCategory.Id };
|
return new Feed { Id = Guid.NewGuid(), CategoryId = entities.DefaultCategory.Id, Account = entities.LocalAccount };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DataErrorDictionaryErrorsChanged(object sender, DataErrorsChangedEventArgs e)
|
private void DataErrorDictionaryErrorsChanged(object sender, DataErrorsChangedEventArgs e)
|
||||||
@@ -215,7 +217,7 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the feed was successfully read and we have no last update timestamp - set the last update timestamp to now
|
// If the feed was successfully read, and we have no last update timestamp - set the last update timestamp to now
|
||||||
if (result == FeedReadResult.Success && LastUpdated == default)
|
if (result == FeedReadResult.Success && LastUpdated == default)
|
||||||
LastUpdated = DateTimeOffset.Now;
|
LastUpdated = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,28 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
using FeedCenter.Options;
|
using FeedCenter.Options;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public partial class FeedItem : RealmObject
|
public partial class FeedItem : RealmObject
|
||||||
{
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
public bool BeenRead { get; set; }
|
public bool BeenRead { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public Guid FeedId { get; set; }
|
public Guid FeedId { get; set; }
|
||||||
public string Guid { get; set; }
|
public string Guid { get; set; }
|
||||||
|
|
||||||
[PrimaryKey]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public DateTimeOffset LastFound { get; set; }
|
public DateTimeOffset LastFound { get; set; }
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
public bool New { get; set; }
|
public bool New { get; set; }
|
||||||
public int Sequence { get; set; }
|
public int Sequence { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
public string RemoteId { get; set; }
|
||||||
|
|
||||||
public static FeedItem Create()
|
public static FeedItem Create()
|
||||||
{
|
{
|
||||||
@@ -42,7 +45,7 @@ public partial class FeedItem : RealmObject
|
|||||||
case MultipleLineDisplay.FirstLine:
|
case MultipleLineDisplay.FirstLine:
|
||||||
|
|
||||||
// Find the first newline
|
// Find the first newline
|
||||||
var newlineIndex = title.IndexOf("\n", StringComparison.Ordinal);
|
var newlineIndex = title.IndexOf('\n', StringComparison.Ordinal);
|
||||||
|
|
||||||
// If a newline was found return everything before it
|
// If a newline was found return everything before it
|
||||||
if (newlineIndex > -1)
|
if (newlineIndex > -1)
|
||||||
@@ -70,6 +73,22 @@ public partial class FeedItem : RealmObject
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task MarkAsRead(FeedCenterEntities entities)
|
||||||
|
{
|
||||||
|
var feed = entities.Feeds.FirstOrDefault(f => f.Id == FeedId);
|
||||||
|
|
||||||
|
entities.SaveChanges(() =>
|
||||||
|
{
|
||||||
|
BeenRead = true;
|
||||||
|
New = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (feed == null || feed.Account.Type == AccountType.Local)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await AccountReaderFactory.CreateAccountReader(feed.Account).MarkFeedItemRead(RemoteId);
|
||||||
|
}
|
||||||
|
|
||||||
[GeneratedRegex("\\n")]
|
[GeneratedRegex("\\n")]
|
||||||
private static partial Regex NewlineRegex();
|
private static partial Regex NewlineRegex();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public enum FeedReadResult
|
public enum FeedReadResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public enum FeedType
|
public enum FeedType
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace FeedCenter;
|
namespace FeedCenter.Feeds;
|
||||||
|
|
||||||
public enum MultipleOpenAction
|
public enum MultipleOpenAction
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,13 +5,7 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="Realm" minOccurs="0" maxOccurs="1">
|
<xs:element name="Realm" minOccurs="0" maxOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType></xs:complexType>
|
||||||
<xs:attribute name="DisableAnalytics" type="xs:boolean">
|
|
||||||
<xs:annotation>
|
|
||||||
<xs:documentation>Disables anonymized usage information from being sent on build. Read more about what data is being collected and why here: https://github.com/realm/realm-dotnet/blob/main/Realm/Realm.Weaver/Analytics.cs</xs:documentation>
|
|
||||||
</xs:annotation>
|
|
||||||
</xs:attribute>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
@@ -21,9 +22,8 @@ public partial class MainWindow
|
|||||||
private void HandleNewFeed(string feedUrl)
|
private void HandleNewFeed(string feedUrl)
|
||||||
{
|
{
|
||||||
// Create and configure the new feed
|
// Create and configure the new feed
|
||||||
var feed = Feed.Create();
|
var feed = Feed.Create(_database);
|
||||||
feed.Source = feedUrl;
|
feed.Source = feedUrl;
|
||||||
feed.CategoryId = _database.DefaultCategory.Id;
|
|
||||||
|
|
||||||
// Try to detect the feed type
|
// Try to detect the feed type
|
||||||
var feedTypeResult = feed.DetectFeedType();
|
var feedTypeResult = feed.DetectFeedType();
|
||||||
@@ -31,7 +31,7 @@ public partial class MainWindow
|
|||||||
// If we can't figure it out it could be an HTML page
|
// If we can't figure it out it could be an HTML page
|
||||||
if (feedTypeResult.Item1 == FeedType.Unknown)
|
if (feedTypeResult.Item1 == FeedType.Unknown)
|
||||||
{
|
{
|
||||||
// Only check if the feed was able to be read - otherwise fall through and show the dialog
|
// Only check if the feed was read - otherwise fall through and show the dialog
|
||||||
if (feedTypeResult.Item2.Length > 0)
|
if (feedTypeResult.Item2.Length > 0)
|
||||||
{
|
{
|
||||||
// Create and load an HTML document with the text
|
// Create and load an HTML document with the text
|
||||||
@@ -87,19 +87,11 @@ public partial class MainWindow
|
|||||||
|
|
||||||
// Show a tip
|
// Show a tip
|
||||||
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), H.NotifyIcon.Core.NotificationIcon.Info);
|
NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), H.NotifyIcon.Core.NotificationIcon.Info);
|
||||||
|
|
||||||
_currentFeed = feed;
|
|
||||||
|
|
||||||
// Refresh the database to current settings
|
|
||||||
ResetDatabase();
|
|
||||||
|
|
||||||
// Re-initialize the feed display
|
|
||||||
DisplayFeed();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Feed read failed - create a new feed window
|
// Feed read failed - create a new feed window
|
||||||
var feedForm = new FeedWindow();
|
var feedForm = new FeedWindow(_database);
|
||||||
|
|
||||||
var dialogResult = feedForm.Display(feed, this);
|
var dialogResult = feedForm.Display(feed, this);
|
||||||
|
|
||||||
@@ -109,14 +101,14 @@ public partial class MainWindow
|
|||||||
|
|
||||||
// Add the feed to the feed table
|
// Add the feed to the feed table
|
||||||
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
_database.SaveChanges(() => _database.Feeds.Add(feed));
|
||||||
|
|
||||||
_currentFeed = feed;
|
|
||||||
|
|
||||||
// Refresh the database to current settings
|
|
||||||
ResetDatabase();
|
|
||||||
|
|
||||||
// Re-initialize the feed display
|
|
||||||
DisplayFeed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_currentFeed = feed;
|
||||||
|
|
||||||
|
// Refresh the database to current settings
|
||||||
|
ResetDatabase();
|
||||||
|
|
||||||
|
// Re-initialize the feed display
|
||||||
|
DisplayFeed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,44 +30,36 @@ public partial class MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleItemMouseUp(object sender, MouseButtonEventArgs e)
|
private async void HandleItemMouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
// Only handle the middle button
|
// Only handle the middle button
|
||||||
if (e.ChangedButton != MouseButton.Middle)
|
if (e.ChangedButton != MouseButton.Middle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get the feed item
|
// Get the feed item
|
||||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
var feedItem = (Feeds.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
|
// Remove the item from the list
|
||||||
LinkTextList.Items.Remove(feedItem);
|
LinkTextList.Items.Remove(feedItem);
|
||||||
|
|
||||||
|
// The feed item has been read and is no longer new
|
||||||
|
await feedItem.MarkAsRead(_database);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
private async void HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
// Get the feed item
|
// Get the feed item
|
||||||
var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext;
|
var feedItem = (Feeds.FeedItem) ((ListBoxItem) sender).DataContext;
|
||||||
|
|
||||||
// Try to open the item link
|
// Try to open the item link
|
||||||
if (!InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
if (!InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||||
return;
|
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
|
// Remove the item from the list
|
||||||
LinkTextList.Items.Remove(feedItem);
|
LinkTextList.Items.Remove(feedItem);
|
||||||
|
|
||||||
|
// The feed item has been read and is no longer new
|
||||||
|
await feedItem.MarkAsRead(_database);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleFeedButtonClick(object sender, RoutedEventArgs e)
|
private void HandleFeedButtonClick(object sender, RoutedEventArgs e)
|
||||||
@@ -111,7 +103,7 @@ public partial class MainWindow
|
|||||||
var menuItem = (MenuItem) sender;
|
var menuItem = (MenuItem) sender;
|
||||||
|
|
||||||
// Get the feed from the menu item tab
|
// Get the feed from the menu item tab
|
||||||
var feed = (Feed) menuItem.Tag;
|
var feed = (Feeds.Feed) menuItem.Tag;
|
||||||
|
|
||||||
// Loop over all feeds and look for the index of the new one
|
// Loop over all feeds and look for the index of the new one
|
||||||
var feedIndex = 0;
|
var feedIndex = 0;
|
||||||
|
|||||||
@@ -1,46 +1,28 @@
|
|||||||
using ChrisKaczor.ApplicationUpdate;
|
using ChrisKaczor.ApplicationUpdate;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
using FeedCenter.Properties;
|
using FeedCenter.Properties;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
public partial class MainWindow
|
public partial class MainWindow
|
||||||
{
|
{
|
||||||
private BackgroundWorker _feedReadWorker;
|
private bool _reading;
|
||||||
|
|
||||||
private class FeedReadWorkerInput
|
private void SetProgressMode(bool showProgress, int maximum)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// Refresh the progress bar if we need it
|
// Refresh the progress bar if we need it
|
||||||
if (value)
|
if (showProgress)
|
||||||
{
|
{
|
||||||
FeedReadProgress.Value = 0;
|
FeedReadProgress.Value = 0;
|
||||||
FeedReadProgress.Maximum = feedCount + 2;
|
FeedReadProgress.Maximum = maximum + 2;
|
||||||
FeedReadProgress.Visibility = Visibility.Visible;
|
FeedReadProgress.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -49,53 +31,72 @@ public partial class MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadCurrentFeed(bool forceRead = false)
|
private async void ReadCurrentFeed(bool forceRead = false)
|
||||||
{
|
{
|
||||||
// Don't read if we're already working
|
try
|
||||||
if (_feedReadWorker.IsBusy)
|
{
|
||||||
return;
|
// Don't read if we're already working
|
||||||
|
if (_reading)
|
||||||
|
return;
|
||||||
|
|
||||||
// Don't read if there is nothing to read
|
_reading = true;
|
||||||
if (!_database.Feeds.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Switch to progress mode
|
// Don't read if there is nothing to read
|
||||||
SetProgressMode(true, 1);
|
if (!_database.Feeds.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
// Create the input class
|
var accountReadInput = new AccountReadInput(_database, _currentFeed.Id, forceRead, () => { });
|
||||||
var workerInput = new FeedReadWorkerInput(forceRead, _currentFeed.Id);
|
|
||||||
|
|
||||||
// Start the worker
|
// Switch to progress mode
|
||||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
SetProgressMode(true, await _currentFeed.Account.GetProgressSteps(accountReadInput));
|
||||||
|
|
||||||
|
// Start reading
|
||||||
|
await HandleFeedReadWorkerStart(forceRead, _currentFeed.Id);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadFeeds(bool forceRead = false)
|
private async Task ReadFeeds(bool forceRead = false)
|
||||||
{
|
{
|
||||||
// Don't read if we're already working
|
// Don't read if we're already working
|
||||||
if (_feedReadWorker.IsBusy)
|
if (_reading)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_reading = true;
|
||||||
|
|
||||||
// Don't read if there is nothing to read
|
// Don't read if there is nothing to read
|
||||||
if (!_database.Feeds.Any())
|
if (!_database.Accounts.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var accountReadInput = new AccountReadInput(_database, null, forceRead, () => { });
|
||||||
|
|
||||||
|
// Calculate total progress steps
|
||||||
|
var progressSteps = 0;
|
||||||
|
|
||||||
|
foreach (var account in _database.Accounts)
|
||||||
|
{
|
||||||
|
progressSteps += await account.GetProgressSteps(accountReadInput);
|
||||||
|
}
|
||||||
|
|
||||||
// Switch to progress mode
|
// Switch to progress mode
|
||||||
SetProgressMode(true, _database.Feeds.Count);
|
SetProgressMode(true, progressSteps);
|
||||||
|
|
||||||
// Create the input class
|
// Start reading
|
||||||
var workerInput = new FeedReadWorkerInput(forceRead);
|
await HandleFeedReadWorkerStart(forceRead, null);
|
||||||
|
|
||||||
// Start the worker
|
|
||||||
_feedReadWorker.RunWorkerAsync(workerInput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleFeedReadWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
|
private void IncrementProgress()
|
||||||
{
|
{
|
||||||
|
Debug.Assert(FeedReadProgress.Value + 1 <= FeedReadProgress.Maximum);
|
||||||
|
|
||||||
// Set progress
|
// Set progress
|
||||||
FeedReadProgress.Value = e.ProgressPercentage;
|
FeedReadProgress.Value++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleFeedReadWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
private void CompleteRead()
|
||||||
{
|
{
|
||||||
// Refresh the database to current settings
|
// Refresh the database to current settings
|
||||||
ResetDatabase();
|
ResetDatabase();
|
||||||
@@ -117,6 +118,8 @@ public partial class MainWindow
|
|||||||
NewVersionLink.Visibility = Visibility.Visible;
|
NewVersionLink.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
UpdateErrorLink();
|
UpdateErrorLink();
|
||||||
|
|
||||||
|
_reading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateErrorLink()
|
private void UpdateErrorLink()
|
||||||
@@ -132,65 +135,61 @@ public partial class MainWindow
|
|||||||
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
|
: string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleFeedReadWorkerStart(object sender, DoWorkEventArgs e)
|
private async Task HandleFeedReadWorkerStart(bool forceRead, Guid? feedId)
|
||||||
{
|
{
|
||||||
// Create a new database instance for just this thread
|
try
|
||||||
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
|
// Create a new database instance for just this thread
|
||||||
database.SaveChanges(() => feed.Read(workerInput.ForceRead));
|
var database = new FeedCenterEntities();
|
||||||
|
|
||||||
// Increment progress
|
var accountsToRead = new List<Account>();
|
||||||
currentProgress += 1;
|
|
||||||
|
// If we have a single feed then get the account for that feed
|
||||||
|
if (feedId != null)
|
||||||
|
{
|
||||||
|
var feed = database.Feeds.FirstOrDefault(f => f.Id == feedId);
|
||||||
|
|
||||||
|
if (feed != null)
|
||||||
|
accountsToRead.Add(feed.Account);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise get all accounts
|
||||||
|
accountsToRead.AddRange(database.Accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over each account and read it
|
||||||
|
foreach (var account in accountsToRead)
|
||||||
|
{
|
||||||
|
var accountReadInput = new AccountReadInput(database, feedId, forceRead, IncrementProgress);
|
||||||
|
|
||||||
|
await account.Read(accountReadInput);
|
||||||
|
}
|
||||||
|
|
||||||
// Report progress
|
// Report progress
|
||||||
worker.ReportProgress(currentProgress);
|
IncrementProgress();
|
||||||
|
|
||||||
|
// See if we're due for a version check
|
||||||
|
if (UpdateCheck.LocalVersion.Major > 0 && DateTime.Now - Settings.Default.LastVersionCheck >= Settings.Default.VersionCheckInterval)
|
||||||
|
{
|
||||||
|
// Get the update information
|
||||||
|
await UpdateCheck.CheckForUpdate(Settings.Default.IncludePrerelease);
|
||||||
|
|
||||||
|
// Update the last check time
|
||||||
|
Settings.Default.LastVersionCheck = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report progress
|
||||||
|
IncrementProgress();
|
||||||
|
|
||||||
|
// Sleep for a little bit so the user can see the update
|
||||||
|
Thread.Sleep(Settings.Default.ProgressSleepInterval * 3);
|
||||||
|
|
||||||
|
CompleteRead();
|
||||||
}
|
}
|
||||||
|
catch (Exception exception)
|
||||||
// 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
|
HandleException(exception);
|
||||||
UpdateCheck.CheckForUpdate(Settings.Default.IncludePrerelease).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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,11 +285,13 @@
|
|||||||
<MenuItem Header="{x:Static properties:Resources.lockWindowCheckBox}"
|
<MenuItem Header="{x:Static properties:Resources.lockWindowCheckBox}"
|
||||||
IsCheckable="True"
|
IsCheckable="True"
|
||||||
IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=WindowLocked}" />
|
IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=WindowLocked}" />
|
||||||
<Separator />
|
<Separator Name="SettingsMenuSeparator" />
|
||||||
<MenuItem Header="{x:Static properties:Resources.CurrentFeed}">
|
<MenuItem Name="CurrentFeedMenu" Header="{x:Static properties:Resources.CurrentFeed}">
|
||||||
<MenuItem Header="{x:Static properties:Resources.EditMenu}"
|
<MenuItem Name="EditCurrentFeedMenuItem"
|
||||||
|
Header="{x:Static properties:Resources.EditMenu}"
|
||||||
Click="HandleEditCurrentFeedMenuItemClick" />
|
Click="HandleEditCurrentFeedMenuItemClick" />
|
||||||
<MenuItem Header="{x:Static properties:Resources.DeleteMenu}"
|
<MenuItem Name="DeleteCurrentFeedMenuItem"
|
||||||
|
Header="{x:Static properties:Resources.DeleteMenu}"
|
||||||
Click="HandleDeleteCurrentFeedMenuItemClick" />
|
Click="HandleDeleteCurrentFeedMenuItemClick" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using ChrisKaczor.ApplicationUpdate;
|
using ChrisKaczor.ApplicationUpdate;
|
||||||
using ChrisKaczor.Wpf.Application;
|
using ChrisKaczor.Wpf.Application;
|
||||||
using FeedCenter.Data;
|
using FeedCenter.Feeds;
|
||||||
using FeedCenter.Properties;
|
using FeedCenter.Properties;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -29,7 +30,6 @@ public partial class MainWindow : IDisposable
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_mainTimer?.Dispose();
|
_mainTimer?.Dispose();
|
||||||
_feedReadWorker?.Dispose();
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
@@ -39,24 +39,21 @@ public partial class MainWindow : IDisposable
|
|||||||
base.OnSourceInitialized(e);
|
base.OnSourceInitialized(e);
|
||||||
|
|
||||||
// Initialize the window
|
// Initialize the window
|
||||||
Initialize();
|
Initialize().ContinueWith(_ => { }, TaskScheduler.FromCurrentSynchronizationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
|
|
||||||
await SingleInstance.Stop();
|
SingleInstance.Stop().ContinueWith(_ => { }, TaskScheduler.FromCurrentSynchronizationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Initialize()
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
// Setup the update handler
|
// Set up the update handler
|
||||||
InitializeUpdate();
|
InitializeUpdate();
|
||||||
|
|
||||||
// Show the notification icon
|
|
||||||
NotificationIcon.Initialize(this);
|
|
||||||
|
|
||||||
// Load window settings
|
// Load window settings
|
||||||
LoadWindowSettings();
|
LoadWindowSettings();
|
||||||
|
|
||||||
@@ -66,14 +63,8 @@ public partial class MainWindow : IDisposable
|
|||||||
: Brushes.Black;
|
: Brushes.Black;
|
||||||
HeaderLabel.Foreground = LinkTextList.Foreground;
|
HeaderLabel.Foreground = LinkTextList.Foreground;
|
||||||
|
|
||||||
// Create the background worker that does the actual reading
|
// Set up the database
|
||||||
_feedReadWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
|
_database = new FeedCenterEntities();
|
||||||
_feedReadWorker.DoWork += HandleFeedReadWorkerStart;
|
|
||||||
_feedReadWorker.ProgressChanged += HandleFeedReadWorkerProgressChanged;
|
|
||||||
_feedReadWorker.RunWorkerCompleted += HandleFeedReadWorkerCompleted;
|
|
||||||
|
|
||||||
// Setup the database
|
|
||||||
_database = Database.Entities;
|
|
||||||
|
|
||||||
// Initialize the single instance listener
|
// Initialize the single instance listener
|
||||||
SingleInstance.MessageReceived += SingleInstance_MessageReceived;
|
SingleInstance.MessageReceived += SingleInstance_MessageReceived;
|
||||||
@@ -88,13 +79,26 @@ public partial class MainWindow : IDisposable
|
|||||||
// Initialize the feed display
|
// Initialize the feed display
|
||||||
InitializeDisplay();
|
InitializeDisplay();
|
||||||
|
|
||||||
// Check for update
|
if (UpdateCheck.LocalVersion.Major > 0)
|
||||||
if (Settings.Default.CheckVersionAtStartup)
|
{
|
||||||
await UpdateCheck.CheckForUpdate(Settings.Default.IncludePrerelease);
|
// Check for update
|
||||||
|
if (Settings.Default.CheckVersionAtStartup)
|
||||||
|
await UpdateCheck.CheckForUpdate(Settings.Default.IncludePrerelease);
|
||||||
|
|
||||||
// Show the link if updates are available
|
// Show the link if updates are available
|
||||||
if (UpdateCheck.UpdateAvailable)
|
if (UpdateCheck.UpdateAvailable)
|
||||||
NewVersionLink.Visibility = Visibility.Visible;
|
NewVersionLink.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Show the notification icon
|
||||||
|
NotificationIcon.Initialize(this);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Logger.Error(e, "");
|
||||||
|
}
|
||||||
|
|
||||||
Log.Logger.Information("MainForm creation finished");
|
Log.Logger.Information("MainForm creation finished");
|
||||||
}
|
}
|
||||||
@@ -151,7 +155,7 @@ public partial class MainWindow : IDisposable
|
|||||||
var currentId = _currentFeed?.IsValid ?? false ? _currentFeed.Id : Guid.Empty;
|
var currentId = _currentFeed?.IsValid ?? false ? _currentFeed.Id : Guid.Empty;
|
||||||
|
|
||||||
// Create a new database object
|
// Create a new database object
|
||||||
_database.Refresh();
|
_database = new FeedCenterEntities();
|
||||||
|
|
||||||
_feedList = _currentCategory == null
|
_feedList = _currentCategory == null
|
||||||
? _database.Feeds.ToList()
|
? _database.Feeds.ToList()
|
||||||
@@ -188,7 +192,9 @@ public partial class MainWindow : IDisposable
|
|||||||
private void UpdateToolbarButtonState()
|
private void UpdateToolbarButtonState()
|
||||||
{
|
{
|
||||||
// Cache the feed count to save (a little) time
|
// Cache the feed count to save (a little) time
|
||||||
var feedCount = Settings.Default.DisplayEmptyFeeds ? _feedList.Count() : _feedList.Count(x => x.Items.Any(y => !y.BeenRead));
|
var feedCount = Settings.Default.DisplayEmptyFeeds
|
||||||
|
? _feedList.Count()
|
||||||
|
: _feedList.Count(x => x.Items.Any(y => !y.BeenRead));
|
||||||
|
|
||||||
// Set button states
|
// Set button states
|
||||||
PreviousToolbarButton.IsEnabled = feedCount > 1;
|
PreviousToolbarButton.IsEnabled = feedCount > 1;
|
||||||
@@ -200,6 +206,11 @@ public partial class MainWindow : IDisposable
|
|||||||
FeedLabel.Visibility = feedCount == 0 ? Visibility.Hidden : Visibility.Visible;
|
FeedLabel.Visibility = feedCount == 0 ? Visibility.Hidden : Visibility.Visible;
|
||||||
FeedButton.Visibility = feedCount == 0 ? Visibility.Hidden : Visibility.Visible;
|
FeedButton.Visibility = feedCount == 0 ? Visibility.Hidden : Visibility.Visible;
|
||||||
CategoryGrid.Visibility = _database.Categories.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
|
CategoryGrid.Visibility = _database.Categories.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
|
EditCurrentFeedMenuItem.Visibility = _currentFeed?.Account.SupportsFeedEdit ?? false ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
DeleteCurrentFeedMenuItem.Visibility = _currentFeed?.Account.SupportsFeedDelete ?? false ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
CurrentFeedMenu.Visibility = EditCurrentFeedMenuItem.IsVisible || DeleteCurrentFeedMenuItem.IsVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
SettingsMenuSeparator.Visibility = CurrentFeedMenu.Visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeDisplay()
|
private void InitializeDisplay()
|
||||||
@@ -405,16 +416,14 @@ public partial class MainWindow : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateOpenAllButton();
|
UpdateOpenAllButton();
|
||||||
|
UpdateToolbarButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MarkAllItemsAsRead()
|
private async Task MarkAllItemsAsRead()
|
||||||
{
|
{
|
||||||
// Loop over all items and mark them as read
|
// Loop over all items and mark them as read
|
||||||
_database.SaveChanges(() =>
|
foreach (FeedItem feedItem in LinkTextList.Items)
|
||||||
{
|
await feedItem.MarkAsRead(_database);
|
||||||
foreach (FeedItem feedItem in LinkTextList.Items)
|
|
||||||
feedItem.BeenRead = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear the list
|
// Clear the list
|
||||||
LinkTextList.Items.Clear();
|
LinkTextList.Items.Clear();
|
||||||
|
|||||||
@@ -38,29 +38,36 @@ public partial class MainWindow
|
|||||||
_mainTimer?.Stop();
|
_mainTimer?.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleMainTimerElapsed(object sender, EventArgs e)
|
private async void HandleMainTimerElapsed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_dispatcher.Invoke(() =>
|
try
|
||||||
{
|
{
|
||||||
// If the background worker is busy then don't do anything
|
await _dispatcher.Invoke(async () =>
|
||||||
if (_feedReadWorker.IsBusy)
|
{
|
||||||
return;
|
// If the background worker is busy then don't do anything
|
||||||
|
if (_reading)
|
||||||
|
return;
|
||||||
|
|
||||||
// Stop the timer for now
|
// Stop the timer for now
|
||||||
StopTimer();
|
StopTimer();
|
||||||
|
|
||||||
// Move to the next feed if the scroll interval has expired and the mouse isn't hovering
|
// Move to the next feed if the scroll interval has expired and the mouse isn't hovering
|
||||||
if (LinkTextList.IsMouseOver)
|
if (LinkTextList.IsMouseOver)
|
||||||
_lastFeedDisplay = DateTime.Now;
|
_lastFeedDisplay = DateTime.Now;
|
||||||
else if (DateTime.Now - _lastFeedDisplay >= Settings.Default.FeedScrollInterval)
|
else if (DateTime.Now - _lastFeedDisplay >= Settings.Default.FeedScrollInterval)
|
||||||
NextFeed();
|
NextFeed();
|
||||||
|
|
||||||
// Check to see if we should try to read the feeds
|
// Check to see if we should try to read the feeds
|
||||||
if (DateTime.Now - _lastFeedRead >= Settings.Default.FeedCheckInterval)
|
if (DateTime.Now - _lastFeedRead >= Settings.Default.FeedCheckInterval)
|
||||||
ReadFeeds();
|
await ReadFeeds();
|
||||||
|
|
||||||
// Get the timer going again
|
// Get the timer going again
|
||||||
StartTimer();
|
StartTimer();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
using System.IO;
|
using ChrisKaczor.InstalledBrowsers;
|
||||||
|
using FeedCenter.Options;
|
||||||
|
using FeedCenter.Properties;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Web.UI;
|
using System.Web.UI;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using ChrisKaczor.InstalledBrowsers;
|
using FeedCenter.Feeds;
|
||||||
using FeedCenter.Options;
|
using Serilog;
|
||||||
using FeedCenter.Properties;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
@@ -22,7 +27,7 @@ public partial class MainWindow
|
|||||||
NextFeed();
|
NextFeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenAllFeedItemsIndividually()
|
private async Task OpenAllFeedItemsIndividually()
|
||||||
{
|
{
|
||||||
// Create a new list of feed items
|
// Create a new list of feed items
|
||||||
var feedItems = (from FeedItem feedItem in LinkTextList.Items select feedItem).ToList();
|
var feedItems = (from FeedItem feedItem in LinkTextList.Items select feedItem).ToList();
|
||||||
@@ -40,7 +45,7 @@ public partial class MainWindow
|
|||||||
if (InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
if (InstalledBrowser.OpenLink(Settings.Default.Browser, feedItem.Link))
|
||||||
{
|
{
|
||||||
// Mark the feed as read
|
// Mark the feed as read
|
||||||
_database.SaveChanges(() => feedItem.BeenRead = true);
|
await feedItem.MarkAsRead(_database);
|
||||||
|
|
||||||
// Remove the item
|
// Remove the item
|
||||||
LinkTextList.Items.Remove(feedItem);
|
LinkTextList.Items.Remove(feedItem);
|
||||||
@@ -71,9 +76,21 @@ public partial class MainWindow
|
|||||||
UpdateErrorLink();
|
UpdateErrorLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleMarkReadToolbarButtonClick(object sender, RoutedEventArgs e)
|
internal static void HandleException(Exception exception)
|
||||||
{
|
{
|
||||||
MarkAllItemsAsRead();
|
Log.Logger.Write(LogEventLevel.Debug, exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleMarkReadToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await MarkAllItemsAsRead();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleShowErrorsButtonClick(object sender, RoutedEventArgs e)
|
private void HandleShowErrorsButtonClick(object sender, RoutedEventArgs e)
|
||||||
@@ -93,50 +110,78 @@ public partial class MainWindow
|
|||||||
UpdateErrorLink();
|
UpdateErrorLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleRefreshMenuItemClick(object sender, RoutedEventArgs e)
|
private async void HandleRefreshMenuItemClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var menuItem = (MenuItem) e.Source;
|
try
|
||||||
|
|
||||||
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:
|
var menuItem = (MenuItem) e.Source;
|
||||||
OpenAllFeedItemsIndividually();
|
|
||||||
break;
|
if (Equals(menuItem, MenuRefresh))
|
||||||
case MultipleOpenAction.SinglePage:
|
ReadCurrentFeed(true);
|
||||||
OpenAllFeedItemsOnSinglePage();
|
else if (Equals(menuItem, MenuRefreshAll))
|
||||||
break;
|
await ReadFeeds(true);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleRefreshToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ReadFeeds(true);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleOpenAllMenuItemClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var menuItem = (MenuItem) e.Source;
|
||||||
|
|
||||||
|
if (Equals(menuItem, MenuOpenAllSinglePage))
|
||||||
|
await OpenAllFeedItemsOnSinglePage();
|
||||||
|
else if (Equals(menuItem, MenuOpenAllMultiplePages))
|
||||||
|
await OpenAllFeedItemsIndividually();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleOpenAllToolbarButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var multipleOpenAction = _currentFeed.MultipleOpenAction;
|
||||||
|
|
||||||
|
switch (multipleOpenAction)
|
||||||
|
{
|
||||||
|
case MultipleOpenAction.IndividualPages:
|
||||||
|
await OpenAllFeedItemsIndividually();
|
||||||
|
break;
|
||||||
|
case MultipleOpenAction.SinglePage:
|
||||||
|
await OpenAllFeedItemsOnSinglePage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
HandleException(exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleEditCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
private void HandleEditCurrentFeedMenuItemClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
// Create a new feed window
|
// Create a new feed window
|
||||||
var feedWindow = new FeedWindow();
|
var feedWindow = new FeedWindow(_database);
|
||||||
|
|
||||||
// Display the feed window and get the result
|
// Display the feed window and get the result
|
||||||
var result = feedWindow.Display(_currentFeed, this);
|
var result = feedWindow.Display(_currentFeed, this);
|
||||||
@@ -174,19 +219,19 @@ public partial class MainWindow
|
|||||||
DisplayFeed();
|
DisplayFeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenAllFeedItemsOnSinglePage()
|
private async Task OpenAllFeedItemsOnSinglePage()
|
||||||
{
|
{
|
||||||
var fileName = Path.GetTempFileName() + ".html";
|
var fileName = Path.GetTempFileName() + ".html";
|
||||||
TextWriter textWriter = new StreamWriter(fileName);
|
TextWriter textWriter = new StreamWriter(fileName);
|
||||||
|
|
||||||
using (var htmlTextWriter = new HtmlTextWriter(textWriter))
|
await using (var htmlTextWriter = new HtmlTextWriter(textWriter))
|
||||||
{
|
{
|
||||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Html);
|
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Html);
|
||||||
|
|
||||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Head);
|
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Head);
|
||||||
|
|
||||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Title);
|
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Title);
|
||||||
htmlTextWriter.Write(_currentFeed.Title);
|
await htmlTextWriter.WriteAsync(_currentFeed.Title);
|
||||||
htmlTextWriter.RenderEndTag();
|
htmlTextWriter.RenderEndTag();
|
||||||
|
|
||||||
htmlTextWriter.AddAttribute("http-equiv", "Content-Type");
|
htmlTextWriter.AddAttribute("http-equiv", "Content-Type");
|
||||||
@@ -214,13 +259,13 @@ public partial class MainWindow
|
|||||||
|
|
||||||
htmlTextWriter.AddAttribute(HtmlTextWriterAttribute.Href, item.Link);
|
htmlTextWriter.AddAttribute(HtmlTextWriterAttribute.Href, item.Link);
|
||||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.A);
|
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.A);
|
||||||
htmlTextWriter.Write(item.Title.Length == 0 ? item.Link : item.Title);
|
await htmlTextWriter.WriteAsync(item.Title.Length == 0 ? item.Link : item.Title);
|
||||||
htmlTextWriter.RenderEndTag();
|
htmlTextWriter.RenderEndTag();
|
||||||
|
|
||||||
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Br);
|
htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Br);
|
||||||
htmlTextWriter.RenderEndTag();
|
htmlTextWriter.RenderEndTag();
|
||||||
|
|
||||||
htmlTextWriter.Write(item.Description);
|
await htmlTextWriter.WriteAsync(item.Description);
|
||||||
|
|
||||||
htmlTextWriter.RenderEndTag();
|
htmlTextWriter.RenderEndTag();
|
||||||
|
|
||||||
@@ -231,11 +276,11 @@ public partial class MainWindow
|
|||||||
htmlTextWriter.RenderEndTag();
|
htmlTextWriter.RenderEndTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
textWriter.Flush();
|
await textWriter.FlushAsync();
|
||||||
textWriter.Close();
|
textWriter.Close();
|
||||||
|
|
||||||
InstalledBrowser.OpenLink(Settings.Default.Browser, fileName);
|
InstalledBrowser.OpenLink(Settings.Default.Browser, fileName);
|
||||||
|
|
||||||
MarkAllItemsAsRead();
|
await MarkAllItemsAsRead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,13 +76,6 @@ public partial class MainWindow
|
|||||||
{
|
{
|
||||||
base.OnClosing(e);
|
base.OnClosing(e);
|
||||||
|
|
||||||
// Ditch the worker
|
|
||||||
if (_feedReadWorker != null)
|
|
||||||
{
|
|
||||||
_feedReadWorker.CancelAsync();
|
|
||||||
_feedReadWorker.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get rid of the timer
|
// Get rid of the timer
|
||||||
TerminateTimer();
|
TerminateTimer();
|
||||||
|
|
||||||
@@ -96,7 +89,7 @@ public partial class MainWindow
|
|||||||
NotificationIcon.Dispose();
|
NotificationIcon.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly DebounceDispatcher _updateWindowSettingsDispatcher = new(500);
|
private readonly DebounceDispatcher _updateWindowSettingsDispatcher = new(TimeSpan.FromMilliseconds(500));
|
||||||
|
|
||||||
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal static class NotificationIcon
|
|||||||
_notificationIcon = new TaskbarIcon { Icon = Resources.Application };
|
_notificationIcon = new TaskbarIcon { Icon = Resources.Application };
|
||||||
_notificationIcon.TrayMouseDoubleClick += HandleNotificationIconDoubleClick;
|
_notificationIcon.TrayMouseDoubleClick += HandleNotificationIconDoubleClick;
|
||||||
|
|
||||||
// Setup the menu
|
// Set up the menu
|
||||||
var contextMenu = new ContextMenu();
|
var contextMenu = new ContextMenu();
|
||||||
contextMenu.Opened += HandleContextMenuOpened;
|
contextMenu.Opened += HandleContextMenuOpened;
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ internal static class NotificationIcon
|
|||||||
public static void Dispose()
|
public static void Dispose()
|
||||||
{
|
{
|
||||||
// Get rid of the icon
|
// Get rid of the icon
|
||||||
_notificationIcon.Dispose();
|
_notificationIcon?.Dispose();
|
||||||
_notificationIcon = null;
|
_notificationIcon = null;
|
||||||
|
|
||||||
_mainWindow = null;
|
_mainWindow = null;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace FeedCenter.Options;
|
|||||||
|
|
||||||
public partial class AboutOptionsPanel
|
public partial class AboutOptionsPanel
|
||||||
{
|
{
|
||||||
public AboutOptionsPanel(Window parentWindow) : base(parentWindow)
|
public AboutOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
29
Application/Options/AccountTypeItem.cs
Normal file
29
Application/Options/AccountTypeItem.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
|
||||||
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
|
public class AccountTypeItem
|
||||||
|
{
|
||||||
|
public AccountType AccountType { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public static List<AccountTypeItem> AccountTypes =>
|
||||||
|
[
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = Properties.Resources.AccountTypeFever,
|
||||||
|
AccountType = AccountType.Fever
|
||||||
|
},
|
||||||
|
//new()
|
||||||
|
//{
|
||||||
|
// Name = Properties.Resources.AccountTypeGoogleReader,
|
||||||
|
// AccountType = AccountType.GoogleReader
|
||||||
|
//}
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = Properties.Resources.AccountTypeMiniflux,
|
||||||
|
AccountType = AccountType.Miniflux
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
23
Application/Options/AccountTypeToNameConverter.cs
Normal file
23
Application/Options/AccountTypeToNameConverter.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
|
||||||
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
|
public class AccountTypeToNameConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is AccountType accountType)
|
||||||
|
return AccountTypeItem.AccountTypes.First(at => at.AccountType == accountType).Name;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
141
Application/Options/AccountWindow.xaml
Normal file
141
Application/Options/AccountWindow.xaml
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<Window x:Class="FeedCenter.Options.AccountWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
||||||
|
xmlns:feedCenter="clr-namespace:FeedCenter"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
d:DataContext="{d:DesignInstance Type=accounts:Account}"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||||
|
xmlns:options="clr-namespace:FeedCenter.Options"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
|
xmlns:accounts="clr-namespace:FeedCenter.Accounts"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="AccountWindow"
|
||||||
|
Height="350"
|
||||||
|
Width="450"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
Icon="/FeedCenter;component/Resources/Application.ico"
|
||||||
|
FocusManager.FocusedElement="{Binding ElementName=NameTextBox}">
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid Margin="6">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TabControl Name="OptionsTabControl"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
mah:HeaderedControlHelper.HeaderFontSize="16"
|
||||||
|
mah:TabControlHelper.Underlined="SelectedTabItem">
|
||||||
|
<TabItem Header="{x:Static properties:Resources.generalTab}">
|
||||||
|
<StackPanel Margin="0,4"
|
||||||
|
options:Spacing.Vertical="8">
|
||||||
|
<ComboBox Name="AccountTypeComboBox"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.accountTypeLabel}"
|
||||||
|
DisplayMemberPath="Name"
|
||||||
|
ItemsSource="{Binding Source={x:Static options:AccountTypeItem.AccountTypes}}"
|
||||||
|
SelectedValuePath="AccountType"
|
||||||
|
SelectedValue="{Binding Path=Type, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}" />
|
||||||
|
<TextBox Name="NameTextBox"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.accountNameLabel}"
|
||||||
|
mah:TextBoxHelper.SelectAllOnFocus="True"
|
||||||
|
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
<TextBox Name="UrlTextBox"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.accountUrlLabel}"
|
||||||
|
mah:TextBoxHelper.SelectAllOnFocus="True"
|
||||||
|
Text="{Binding Path=Url, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
<CheckBox Name="ReadIntervalCheckBox"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
IsChecked="{Binding Path=Enabled, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="{x:Static properties:Resources.accountReadIntervalPrefix}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Padding="0" />
|
||||||
|
<mah:NumericUpDown Width="100"
|
||||||
|
Maximum="10080"
|
||||||
|
Minimum="1"
|
||||||
|
IsEnabled="{Binding ElementName=ReadIntervalCheckBox, Path=IsChecked}"
|
||||||
|
Value="{Binding CheckInterval, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
<Label Content="{x:Static properties:Resources.accountReadIntervalSuffix}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="5,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Padding="0" />
|
||||||
|
</StackPanel>
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Header="{x:Static properties:Resources.authenticationTab}">
|
||||||
|
<StackPanel Margin="0,4">
|
||||||
|
<CheckBox Content="{x:Static properties:Resources.accountRequiresAuthenticationCheckBox}"
|
||||||
|
Margin="0,0,0,4"
|
||||||
|
Name="RequiresAuthenticationCheckBox"
|
||||||
|
IsChecked="{Binding Path=Authenticate, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
<TextBox Name="AuthenticationUserNameTextBox"
|
||||||
|
Margin="25,0,0,4"
|
||||||
|
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.authenticationUserNameLabel}"
|
||||||
|
Text="{Binding Path=Username, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
<PasswordBox Name="AuthenticationPasswordTextBox"
|
||||||
|
Margin="25,0,0,8"
|
||||||
|
Style="{StaticResource MahApps.Styles.PasswordBox.Button.Revealed}"
|
||||||
|
mah:PasswordBoxBindingBehavior.Password="{Binding Password, UpdateSourceTrigger=Explicit, ValidatesOnDataErrors=True}"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.authenticationPasswordLabel}"
|
||||||
|
IsEnabled="{Binding ElementName=RequiresAuthenticationCheckBox, Path=IsChecked}" />
|
||||||
|
</StackPanel>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
<Grid Name="AccountReadProgress"
|
||||||
|
Grid.Row="1"
|
||||||
|
Height="20"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<ProgressBar Name="AccountReadProgressBar" />
|
||||||
|
<TextBlock Text="Loading account..."
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
<StackPanel
|
||||||
|
Name="ButtonPanel"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Visibility="Visible"
|
||||||
|
Margin="0,5,0,0"
|
||||||
|
HorizontalAlignment="Right">
|
||||||
|
<Button Content="{x:Static properties:Resources.OkayButton}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Width="75"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
IsDefault="True"
|
||||||
|
Click="HandleOkayButtonClick" />
|
||||||
|
<Button Content="{x:Static properties:Resources.CancelButton}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Width="75"
|
||||||
|
IsCancel="True" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
78
Application/Options/AccountWindow.xaml.cs
Normal file
78
Application/Options/AccountWindow.xaml.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using ChrisKaczor.Wpf.Validation;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
|
||||||
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
|
public partial class AccountWindow
|
||||||
|
{
|
||||||
|
private Account _account;
|
||||||
|
private bool _isNew;
|
||||||
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
|
public AccountWindow(FeedCenterEntities entities)
|
||||||
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool? Display(Account account, Window owner, bool isNew)
|
||||||
|
{
|
||||||
|
_account = account;
|
||||||
|
_isNew = isNew;
|
||||||
|
|
||||||
|
DataContext = account;
|
||||||
|
|
||||||
|
Title = isNew ? Properties.Resources.AccountWindowAdd : Properties.Resources.AccountWindowEdit;
|
||||||
|
|
||||||
|
Owner = owner;
|
||||||
|
|
||||||
|
return ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var transaction = _entities.BeginTransaction();
|
||||||
|
|
||||||
|
if (!this.IsValid(OptionsTabControl))
|
||||||
|
{
|
||||||
|
transaction.Rollback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isNew)
|
||||||
|
{
|
||||||
|
_entities.Accounts.Add(_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
var accountId = _account.Id;
|
||||||
|
|
||||||
|
var accountReadInput = new AccountReadInput(_entities, null, true, () => AccountReadProgressBar.Value++);
|
||||||
|
|
||||||
|
AccountReadProgressBar.Value = 0;
|
||||||
|
AccountReadProgressBar.Maximum = await _account.GetProgressSteps(accountReadInput);
|
||||||
|
|
||||||
|
AccountReadProgress.Visibility = Visibility.Visible;
|
||||||
|
ButtonPanel.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
//var entities = new FeedCenterEntities();
|
||||||
|
var account = _entities.Accounts.First(a => a.Id == accountId);
|
||||||
|
await account.Read(accountReadInput);
|
||||||
|
|
||||||
|
DialogResult = true;
|
||||||
|
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
MainWindow.HandleException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
Application/Options/AccountsOptionsPanel.xaml
Normal file
100
Application/Options/AccountsOptionsPanel.xaml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<options:OptionsPanelBase x:Class="FeedCenter.Options.AccountsOptionsPanel"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:options="clr-namespace:FeedCenter.Options"
|
||||||
|
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
||||||
|
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
||||||
|
xmlns:feedCenter="clr-namespace:FeedCenter"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
|
xmlns:accounts="clr-namespace:FeedCenter.Accounts"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="311"
|
||||||
|
d:DesignWidth="425">
|
||||||
|
<options:OptionsPanelBase.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<options:AccountTypeToNameConverter x:Key="AccountTypeToNameConverter" />
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</options:OptionsPanelBase.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<DataGrid Name="AccountDataGrid"
|
||||||
|
SelectionChanged="HandleAccountDataGridSelectionChanged"
|
||||||
|
Grid.Row="0"
|
||||||
|
SelectionMode="Single"
|
||||||
|
SelectionUnit="FullRow"
|
||||||
|
Grid.Column="0"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
GridLinesVisibility="None"
|
||||||
|
CanUserResizeRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
BorderThickness="1,1,1,1"
|
||||||
|
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
|
||||||
|
AllowDrop="True"
|
||||||
|
Background="{x:Null}"
|
||||||
|
d:DataContext="{d:DesignInstance accounts:Account }">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Binding="{Binding Name}"
|
||||||
|
Header="{x:Static properties:Resources.AccountNameColumnHeader}"
|
||||||
|
SortDirection="Ascending"
|
||||||
|
Width="*" />
|
||||||
|
<DataGridTextColumn Binding="{Binding Type, Converter={StaticResource AccountTypeToNameConverter}}"
|
||||||
|
Header="{x:Static properties:Resources.AccountTypeColumnHeader}"
|
||||||
|
Width="*" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow"
|
||||||
|
BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
|
||||||
|
<EventSetter Event="MouseDoubleClick"
|
||||||
|
Handler="HandleAccountDataGridRowMouseDoubleClick" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
</DataGrid>
|
||||||
|
<Border Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
BorderThickness="1,0,1,1"
|
||||||
|
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" />
|
||||||
|
<Border Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
BorderThickness="1,0,1,1"
|
||||||
|
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
|
||||||
|
<controls:Link Name="AddAccountButton"
|
||||||
|
Margin="2"
|
||||||
|
Click="HandleAddAccountButtonClick"
|
||||||
|
Text="{x:Static properties:Resources.AddLink}"
|
||||||
|
ToolTip="{x:Static properties:Resources.AddAccountButton}">
|
||||||
|
</controls:Link>
|
||||||
|
<controls:Link Name="EditAccountButton"
|
||||||
|
Margin="2"
|
||||||
|
Click="HandleEditAccountButtonClick"
|
||||||
|
Text="{x:Static properties:Resources.EditLink}"
|
||||||
|
ToolTip="{x:Static properties:Resources.EditAccountButton}">
|
||||||
|
</controls:Link>
|
||||||
|
<controls:Link Name="DeleteAccountButton"
|
||||||
|
Margin="2"
|
||||||
|
Click="HandleDeleteAccountButtonClick"
|
||||||
|
Text="{x:Static properties:Resources.DeleteLink}"
|
||||||
|
ToolTip="{x:Static properties:Resources.DeleteAccountButton}">
|
||||||
|
</controls:Link>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</options:OptionsPanelBase>
|
||||||
129
Application/Options/AccountsOptionsPanel.xaml.cs
Normal file
129
Application/Options/AccountsOptionsPanel.xaml.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
|
||||||
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
|
public partial class AccountsOptionsPanel
|
||||||
|
{
|
||||||
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
|
public AccountsOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CategoryName => Properties.Resources.optionCategoryAccounts;
|
||||||
|
|
||||||
|
public override void LoadPanel()
|
||||||
|
{
|
||||||
|
base.LoadPanel();
|
||||||
|
|
||||||
|
var collectionViewSource = new CollectionViewSource { Source = _entities.Accounts };
|
||||||
|
collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
||||||
|
collectionViewSource.IsLiveSortingRequested = true;
|
||||||
|
collectionViewSource.View.Filter = item =>
|
||||||
|
{
|
||||||
|
if (item is not Account account)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Filter out local accounts
|
||||||
|
return account.Type != AccountType.Local;
|
||||||
|
};
|
||||||
|
|
||||||
|
AccountDataGrid.ItemsSource = collectionViewSource.View;
|
||||||
|
AccountDataGrid.SelectedIndex = 0;
|
||||||
|
|
||||||
|
SetAccountButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAccountButtonStates()
|
||||||
|
{
|
||||||
|
AddAccountButton.IsEnabled = true;
|
||||||
|
|
||||||
|
EditAccountButton.IsEnabled = AccountDataGrid.SelectedItem != null;
|
||||||
|
DeleteAccountButton.IsEnabled = AccountDataGrid.SelectedItem != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAccount()
|
||||||
|
{
|
||||||
|
var account = new Account(AccountType.Miniflux);
|
||||||
|
|
||||||
|
var accountWindow = new AccountWindow(_entities);
|
||||||
|
|
||||||
|
var result = accountWindow.Display(account, Window.GetWindow(this), true);
|
||||||
|
|
||||||
|
if (!result.HasValue || !result.Value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AccountDataGrid.SelectedItem = account;
|
||||||
|
|
||||||
|
SetAccountButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditSelectedAccount()
|
||||||
|
{
|
||||||
|
if (AccountDataGrid.SelectedItem == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var account = (Account) AccountDataGrid.SelectedItem;
|
||||||
|
|
||||||
|
var accountWindow = new AccountWindow(_entities);
|
||||||
|
|
||||||
|
accountWindow.Display(account, Window.GetWindow(this), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteSelectedAccount()
|
||||||
|
{
|
||||||
|
var account = (Account) AccountDataGrid.SelectedItem;
|
||||||
|
|
||||||
|
if (MessageBox.Show(ParentWindow, string.Format(Properties.Resources.ConfirmDeleteAccount, account.Name),
|
||||||
|
Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question,
|
||||||
|
MessageBoxResult.No) == MessageBoxResult.No)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var index = AccountDataGrid.SelectedIndex;
|
||||||
|
|
||||||
|
if (index == AccountDataGrid.Items.Count - 1)
|
||||||
|
AccountDataGrid.SelectedIndex = index - 1;
|
||||||
|
else
|
||||||
|
AccountDataGrid.SelectedIndex = index + 1;
|
||||||
|
|
||||||
|
_entities.SaveChanges(() => _entities.Accounts.Remove(account));
|
||||||
|
|
||||||
|
SetAccountButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAddAccountButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AddAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleEditAccountButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
EditSelectedAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDeleteAccountButtonClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
DeleteSelectedAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAccountDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SetAccountButtonStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAccountDataGridRowMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (!EditAccountButton.IsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EditSelectedAccount();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
||||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||||
xmlns:options="clr-namespace:FeedCenter.Options"
|
xmlns:options="clr-namespace:FeedCenter.Options"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
Icon="/FeedCenter;component/Resources/Application.ico"
|
Icon="/FeedCenter;component/Resources/Application.ico"
|
||||||
FocusManager.FocusedElement="{Binding ElementName=FeedLinkFilterText}">
|
FocusManager.FocusedElement="{Binding ElementName=FeedLinkFilterText}">
|
||||||
@@ -99,9 +100,9 @@
|
|||||||
mah:TextBoxHelper.Watermark="{x:Static my:Resources.openLabel}"
|
mah:TextBoxHelper.Watermark="{x:Static my:Resources.openLabel}"
|
||||||
IsEnabled="{Binding ElementName=OpenCheckBox, Path=IsChecked}">
|
IsEnabled="{Binding ElementName=OpenCheckBox, Path=IsChecked}">
|
||||||
<ComboBoxItem Content="{x:Static my:Resources.openAllMultipleToolbarButton}"
|
<ComboBoxItem Content="{x:Static my:Resources.openAllMultipleToolbarButton}"
|
||||||
Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" />
|
Tag="{x:Static feeds:MultipleOpenAction.IndividualPages}" />
|
||||||
<ComboBoxItem Content="{x:Static my:Resources.openAllSingleToolbarButton}"
|
<ComboBoxItem Content="{x:Static my:Resources.openAllSingleToolbarButton}"
|
||||||
Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" />
|
Tag="{x:Static feeds:MultipleOpenAction.SinglePage}" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
<StackPanel Grid.Column="0"
|
<StackPanel Grid.Column="0"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using FeedCenter.Data;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.Options;
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
@@ -12,9 +12,12 @@ public partial class BulkFeedWindow
|
|||||||
{
|
{
|
||||||
private List<CheckedListItem<Feed>> _checkedListBoxItems;
|
private List<CheckedListItem<Feed>> _checkedListBoxItems;
|
||||||
private CollectionViewSource _collectionViewSource;
|
private CollectionViewSource _collectionViewSource;
|
||||||
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
public BulkFeedWindow()
|
public BulkFeedWindow(FeedCenterEntities entities)
|
||||||
{
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +25,7 @@ public partial class BulkFeedWindow
|
|||||||
{
|
{
|
||||||
_checkedListBoxItems = new List<CheckedListItem<Feed>>();
|
_checkedListBoxItems = new List<CheckedListItem<Feed>>();
|
||||||
|
|
||||||
foreach (var feed in Database.Entities.Feeds)
|
foreach (var feed in _entities.Feeds)
|
||||||
_checkedListBoxItems.Add(new CheckedListItem<Feed> { Item = feed });
|
_checkedListBoxItems.Add(new CheckedListItem<Feed> { Item = feed });
|
||||||
|
|
||||||
_collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems };
|
_collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems };
|
||||||
@@ -52,7 +55,7 @@ public partial class BulkFeedWindow
|
|||||||
|
|
||||||
private void HandleOkButtonClick(object sender, RoutedEventArgs e)
|
private void HandleOkButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Database.Entities.SaveChanges(() =>
|
_entities.SaveChanges(() =>
|
||||||
{
|
{
|
||||||
foreach (var item in _checkedListBoxItems.Where(i => i.IsChecked))
|
foreach (var item in _checkedListBoxItems.Where(i => i.IsChecked))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox"
|
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.ControlBox"
|
||||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||||
xmlns:options="clr-namespace:FeedCenter.Options"
|
xmlns:options="clr-namespace:FeedCenter.Options"
|
||||||
d:DataContext="{d:DesignInstance Type=feedCenter:Category}"
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
|
d:DataContext="{d:DesignInstance Type=feeds:Category}"
|
||||||
Title="CategoryWindow"
|
Title="CategoryWindow"
|
||||||
Width="300"
|
Width="300"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
@@ -24,14 +25,17 @@
|
|||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
|
<ResourceDictionary
|
||||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
|
||||||
|
<ResourceDictionary
|
||||||
|
Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
<StackPanel Margin="6"
|
<StackPanel Margin="6"
|
||||||
options:Spacing.Vertical="5">
|
options:Spacing.Vertical="5">
|
||||||
<TextBox mah:TextBoxHelper.UseFloatingWatermark="True"
|
<TextBox Name="NameTextBox"
|
||||||
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.categoryNameLabel}"
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.categoryNameLabel}"
|
||||||
mah:TextBoxHelper.SelectAllOnFocus="True"
|
mah:TextBoxHelper.SelectAllOnFocus="True"
|
||||||
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=True}" />
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
using System.Windows;
|
using ChrisKaczor.Wpf.Validation;
|
||||||
using ChrisKaczor.Wpf.Validation;
|
using System.Windows;
|
||||||
using FeedCenter.Data;
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.Options;
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
public partial class CategoryWindow
|
public partial class CategoryWindow
|
||||||
{
|
{
|
||||||
public CategoryWindow()
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
|
public CategoryWindow(FeedCenterEntities entities)
|
||||||
{
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +34,7 @@ public partial class CategoryWindow
|
|||||||
|
|
||||||
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var transaction = Database.Entities.BeginTransaction();
|
var transaction = _entities.BeginTransaction();
|
||||||
|
|
||||||
if (!this.IsValid())
|
if (!this.IsValid())
|
||||||
{
|
{
|
||||||
@@ -39,7 +43,6 @@ public partial class CategoryWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
Database.Entities.Refresh();
|
|
||||||
|
|
||||||
// Dialog is good
|
// Dialog is good
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
namespace FeedCenter.Options
|
namespace FeedCenter.Options;
|
||||||
{
|
|
||||||
public class CheckedFeedListItem : CheckedListItem<Feed>
|
public class CheckedFeedListItem : CheckedListItem<Feeds.Feed>;
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ namespace FeedCenter.Options;
|
|||||||
|
|
||||||
public partial class DisplayOptionsPanel
|
public partial class DisplayOptionsPanel
|
||||||
{
|
{
|
||||||
public DisplayOptionsPanel(Window parentWindow) : base(parentWindow)
|
public DisplayOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
||||||
xmlns:feedCenter="clr-namespace:FeedCenter"
|
xmlns:feedCenter="clr-namespace:FeedCenter"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
d:DataContext="{d:DesignInstance Type=feedCenter:Feed}"
|
d:DataContext="{d:DesignInstance Type=feeds:Feed}"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||||
xmlns:options="clr-namespace:FeedCenter.Options"
|
xmlns:options="clr-namespace:FeedCenter.Options"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="FeedWindow"
|
Title="FeedWindow"
|
||||||
Height="350"
|
Height="350"
|
||||||
@@ -90,9 +91,9 @@
|
|||||||
mah:TextBoxHelper.UseFloatingWatermark="True"
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.openLabel}">
|
mah:TextBoxHelper.Watermark="{x:Static properties:Resources.openLabel}">
|
||||||
<ComboBoxItem Content="{x:Static properties:Resources.openAllSingleToolbarButton}"
|
<ComboBoxItem Content="{x:Static properties:Resources.openAllSingleToolbarButton}"
|
||||||
Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" />
|
Tag="{x:Static feeds:MultipleOpenAction.SinglePage}" />
|
||||||
<ComboBoxItem Content="{x:Static properties:Resources.openAllMultipleToolbarButton}"
|
<ComboBoxItem Content="{x:Static properties:Resources.openAllMultipleToolbarButton}"
|
||||||
Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" />
|
Tag="{x:Static feeds:MultipleOpenAction.IndividualPages}" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
<ComboBox Name="UserAgentComboBox"
|
<ComboBox Name="UserAgentComboBox"
|
||||||
mah:TextBoxHelper.UseFloatingWatermark="True"
|
mah:TextBoxHelper.UseFloatingWatermark="True"
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
using ChrisKaczor.Wpf.Validation;
|
using ChrisKaczor.Wpf.Validation;
|
||||||
using FeedCenter.Data;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace FeedCenter.Options;
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
public partial class FeedWindow
|
public partial class FeedWindow
|
||||||
{
|
{
|
||||||
public FeedWindow()
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
|
public FeedWindow(FeedCenterEntities entities)
|
||||||
{
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? Display(Feed feed, Window owner)
|
public bool? Display(Feeds.Feed feed, Window owner)
|
||||||
{
|
{
|
||||||
CategoryComboBox.ItemsSource = Database.Entities.Categories;
|
CategoryComboBox.ItemsSource = _entities.Categories;
|
||||||
|
|
||||||
DataContext = feed;
|
DataContext = feed;
|
||||||
|
|
||||||
@@ -26,7 +29,7 @@ public partial class FeedWindow
|
|||||||
|
|
||||||
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var transaction = Database.Entities.BeginTransaction();
|
var transaction = _entities.BeginTransaction();
|
||||||
|
|
||||||
if (!this.IsValid(OptionsTabControl))
|
if (!this.IsValid(OptionsTabControl))
|
||||||
{
|
{
|
||||||
@@ -35,7 +38,6 @@ public partial class FeedWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
Database.Entities.Refresh();
|
|
||||||
|
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
xmlns:properties="clr-namespace:FeedCenter.Properties"
|
||||||
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
|
||||||
xmlns:feedCenter="clr-namespace:FeedCenter"
|
xmlns:feedCenter="clr-namespace:FeedCenter"
|
||||||
|
xmlns:feeds="clr-namespace:FeedCenter.Feeds"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="311"
|
d:DesignHeight="311"
|
||||||
d:DesignWidth="425">
|
d:DesignWidth="425">
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
|
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
Background="{x:Null}"
|
Background="{x:Null}"
|
||||||
d:DataContext="{d:DesignInstance feedCenter:Category }">
|
d:DataContext="{d:DesignInstance feeds:Category }">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Binding="{Binding Name}"
|
<DataGridTextColumn Binding="{Binding Name}"
|
||||||
Header="{x:Static properties:Resources.CategoryNameColumnHeader}"
|
Header="{x:Static properties:Resources.CategoryNameColumnHeader}"
|
||||||
@@ -80,7 +81,7 @@
|
|||||||
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
|
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
|
||||||
Background="{x:Null}"
|
Background="{x:Null}"
|
||||||
SelectionChanged="HandleFeedDataGridSelectionChanged"
|
SelectionChanged="HandleFeedDataGridSelectionChanged"
|
||||||
d:DataContext="{d:DesignInstance feedCenter:Feed }">
|
d:DataContext="{d:DesignInstance feeds:Feed }">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Binding="{Binding Name}"
|
<DataGridTextColumn Binding="{Binding Name}"
|
||||||
Header="{x:Static properties:Resources.FeedNameColumnHeader}"
|
Header="{x:Static properties:Resources.FeedNameColumnHeader}"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using FeedCenter.Data;
|
using Microsoft.Win32;
|
||||||
using Microsoft.Win32;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -8,15 +7,20 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using FeedCenter.Accounts;
|
||||||
|
using FeedCenter.Feeds;
|
||||||
|
|
||||||
namespace FeedCenter.Options;
|
namespace FeedCenter.Options;
|
||||||
|
|
||||||
public partial class FeedsOptionsPanel
|
public partial class FeedsOptionsPanel
|
||||||
{
|
{
|
||||||
private CollectionViewSource _collectionViewSource;
|
private CollectionViewSource _collectionViewSource;
|
||||||
|
private readonly FeedCenterEntities _entities;
|
||||||
|
|
||||||
public FeedsOptionsPanel(Window parentWindow) : base(parentWindow)
|
public FeedsOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
{
|
{
|
||||||
|
_entities = entities;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +30,7 @@ public partial class FeedsOptionsPanel
|
|||||||
{
|
{
|
||||||
base.LoadPanel();
|
base.LoadPanel();
|
||||||
|
|
||||||
var collectionViewSource = new CollectionViewSource { Source = Database.Entities.Categories };
|
var collectionViewSource = new CollectionViewSource { Source = _entities.Categories };
|
||||||
collectionViewSource.SortDescriptions.Add(new SortDescription("SortKey", ListSortDirection.Ascending));
|
collectionViewSource.SortDescriptions.Add(new SortDescription("SortKey", ListSortDirection.Ascending));
|
||||||
collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
||||||
collectionViewSource.IsLiveSortingRequested = true;
|
collectionViewSource.IsLiveSortingRequested = true;
|
||||||
@@ -44,20 +48,20 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
private void AddFeed()
|
private void AddFeed()
|
||||||
{
|
{
|
||||||
var feed = Feed.Create();
|
var feed = Feed.Create(_entities);
|
||||||
|
|
||||||
var category = (Category) CategoryDataGrid.SelectedItem;
|
var category = (Category) CategoryDataGrid.SelectedItem;
|
||||||
|
|
||||||
feed.CategoryId = category.Id;
|
feed.CategoryId = category.Id;
|
||||||
|
|
||||||
var feedWindow = new FeedWindow();
|
var feedWindow = new FeedWindow(_entities);
|
||||||
|
|
||||||
var result = feedWindow.Display(feed, Window.GetWindow(this));
|
var result = feedWindow.Display(feed, Window.GetWindow(this));
|
||||||
|
|
||||||
if (!result.HasValue || !result.Value)
|
if (!result.HasValue || !result.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Database.Entities.SaveChanges(() => Database.Entities.Feeds.Add(feed));
|
_entities.SaveChanges(() => _entities.Feeds.Add(feed));
|
||||||
|
|
||||||
FeedDataGrid.SelectedItem = feed;
|
FeedDataGrid.SelectedItem = feed;
|
||||||
|
|
||||||
@@ -71,7 +75,7 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
var feed = (Feed) FeedDataGrid.SelectedItem;
|
var feed = (Feed) FeedDataGrid.SelectedItem;
|
||||||
|
|
||||||
var feedWindow = new FeedWindow();
|
var feedWindow = new FeedWindow(_entities);
|
||||||
|
|
||||||
feedWindow.Display(feed, Window.GetWindow(this));
|
feedWindow.Display(feed, Window.GetWindow(this));
|
||||||
}
|
}
|
||||||
@@ -86,7 +90,7 @@ public partial class FeedsOptionsPanel
|
|||||||
FeedDataGrid.SelectedItems.CopyTo(selectedItems, 0);
|
FeedDataGrid.SelectedItems.CopyTo(selectedItems, 0);
|
||||||
|
|
||||||
foreach (var feed in selectedItems)
|
foreach (var feed in selectedItems)
|
||||||
Database.Entities.SaveChanges(() => Database.Entities.Feeds.Remove(feed));
|
_entities.SaveChanges(() => _entities.Feeds.Remove(feed));
|
||||||
|
|
||||||
SetFeedButtonStates();
|
SetFeedButtonStates();
|
||||||
}
|
}
|
||||||
@@ -116,7 +120,7 @@ public partial class FeedsOptionsPanel
|
|||||||
ExportFeeds();
|
ExportFeeds();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ExportFeeds()
|
private void ExportFeeds()
|
||||||
{
|
{
|
||||||
var saveFileDialog = new SaveFileDialog
|
var saveFileDialog = new SaveFileDialog
|
||||||
{
|
{
|
||||||
@@ -143,7 +147,7 @@ public partial class FeedsOptionsPanel
|
|||||||
xmlWriter.WriteStartElement("opml");
|
xmlWriter.WriteStartElement("opml");
|
||||||
xmlWriter.WriteStartElement("body");
|
xmlWriter.WriteStartElement("body");
|
||||||
|
|
||||||
foreach (var feed in Database.Entities.Feeds.OrderBy(feed => feed.Name))
|
foreach (var feed in _entities.Feeds.OrderBy(feed => feed.Name))
|
||||||
{
|
{
|
||||||
xmlWriter.WriteStartElement("outline");
|
xmlWriter.WriteStartElement("outline");
|
||||||
|
|
||||||
@@ -162,7 +166,7 @@ public partial class FeedsOptionsPanel
|
|||||||
xmlWriter.Close();
|
xmlWriter.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ImportFeeds()
|
private void ImportFeeds()
|
||||||
{
|
{
|
||||||
var openFileDialog = new OpenFileDialog
|
var openFileDialog = new OpenFileDialog
|
||||||
{
|
{
|
||||||
@@ -188,8 +192,7 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
while (xmlReader.NodeType != XmlNodeType.EndElement)
|
while (xmlReader.NodeType != XmlNodeType.EndElement)
|
||||||
{
|
{
|
||||||
var feed = Feed.Create();
|
var feed = Feed.Create(_entities);
|
||||||
feed.CategoryId = Database.Entities.Categories.First(c => c.IsDefault).Id;
|
|
||||||
|
|
||||||
while (xmlReader.MoveToNextAttribute())
|
while (xmlReader.MoveToNextAttribute())
|
||||||
{
|
{
|
||||||
@@ -218,7 +221,7 @@ public partial class FeedsOptionsPanel
|
|||||||
if (string.IsNullOrEmpty(feed.Name))
|
if (string.IsNullOrEmpty(feed.Name))
|
||||||
feed.Name = feed.Title;
|
feed.Name = feed.Title;
|
||||||
|
|
||||||
Database.Entities.Feeds.Add(feed);
|
_entities.SaveChanges(() => _entities.Feeds.Add(feed));
|
||||||
|
|
||||||
xmlReader.MoveToElement();
|
xmlReader.MoveToElement();
|
||||||
|
|
||||||
@@ -242,23 +245,23 @@ public partial class FeedsOptionsPanel
|
|||||||
var selectedId = ((Category) CategoryDataGrid.SelectedItem).Id;
|
var selectedId = ((Category) CategoryDataGrid.SelectedItem).Id;
|
||||||
|
|
||||||
EditCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
|
EditCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
|
||||||
selectedId != Database.Entities.DefaultCategory.Id;
|
selectedId != _entities.DefaultCategory.Id;
|
||||||
DeleteCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
|
DeleteCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
|
||||||
selectedId != Database.Entities.DefaultCategory.Id;
|
selectedId != _entities.DefaultCategory.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddCategory()
|
private void AddCategory()
|
||||||
{
|
{
|
||||||
var category = new Category();
|
var category = new Category();
|
||||||
|
|
||||||
var categoryWindow = new CategoryWindow();
|
var categoryWindow = new CategoryWindow(_entities);
|
||||||
|
|
||||||
var result = categoryWindow.Display(category, Window.GetWindow(this));
|
var result = categoryWindow.Display(category, Window.GetWindow(this));
|
||||||
|
|
||||||
if (!result.HasValue || !result.Value)
|
if (!result.HasValue || !result.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Database.Entities.SaveChanges(() => Database.Entities.Categories.Add(category));
|
_entities.SaveChanges(() => _entities.Categories.Add(category));
|
||||||
|
|
||||||
CategoryDataGrid.SelectedItem = category;
|
CategoryDataGrid.SelectedItem = category;
|
||||||
|
|
||||||
@@ -272,7 +275,7 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
var category = (Category) CategoryDataGrid.SelectedItem;
|
var category = (Category) CategoryDataGrid.SelectedItem;
|
||||||
|
|
||||||
var categoryWindow = new CategoryWindow();
|
var categoryWindow = new CategoryWindow(_entities);
|
||||||
|
|
||||||
categoryWindow.Display(category, Window.GetWindow(this));
|
categoryWindow.Display(category, Window.GetWindow(this));
|
||||||
}
|
}
|
||||||
@@ -284,10 +287,10 @@ public partial class FeedsOptionsPanel
|
|||||||
if (MessageBox.Show(ParentWindow, string.Format(Properties.Resources.ConfirmDeleteCategory, category.Name), Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
|
if (MessageBox.Show(ParentWindow, string.Format(Properties.Resources.ConfirmDeleteCategory, category.Name), Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCategory = Database.Entities.DefaultCategory;
|
var defaultCategory = _entities.DefaultCategory;
|
||||||
|
|
||||||
foreach (var feed in Database.Entities.Feeds.Where(f => f.CategoryId == category.Id))
|
foreach (var feed in _entities.Feeds.Where(f => f.CategoryId == category.Id))
|
||||||
Database.Entities.SaveChanges(() => feed.CategoryId = defaultCategory.Id);
|
_entities.SaveChanges(() => feed.CategoryId = defaultCategory.Id);
|
||||||
|
|
||||||
var index = CategoryDataGrid.SelectedIndex;
|
var index = CategoryDataGrid.SelectedIndex;
|
||||||
|
|
||||||
@@ -296,7 +299,7 @@ public partial class FeedsOptionsPanel
|
|||||||
else
|
else
|
||||||
CategoryDataGrid.SelectedIndex = index + 1;
|
CategoryDataGrid.SelectedIndex = index + 1;
|
||||||
|
|
||||||
Database.Entities.SaveChanges(() => Database.Entities.Categories.Remove(category));
|
_entities.SaveChanges(() => _entities.Categories.Remove(category));
|
||||||
|
|
||||||
SetCategoryButtonStates();
|
SetCategoryButtonStates();
|
||||||
}
|
}
|
||||||
@@ -320,7 +323,7 @@ public partial class FeedsOptionsPanel
|
|||||||
{
|
{
|
||||||
if (_collectionViewSource == null)
|
if (_collectionViewSource == null)
|
||||||
{
|
{
|
||||||
_collectionViewSource = new CollectionViewSource { Source = Database.Entities.Feeds };
|
_collectionViewSource = new CollectionViewSource { Source = _entities.Feeds };
|
||||||
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
|
||||||
_collectionViewSource.Filter += HandleCollectionViewSourceFilter;
|
_collectionViewSource.Filter += HandleCollectionViewSourceFilter;
|
||||||
|
|
||||||
@@ -342,7 +345,7 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
var feed = (Feed) e.Item;
|
var feed = (Feed) e.Item;
|
||||||
|
|
||||||
e.Accepted = feed.CategoryId == selectedCategory.Id;
|
e.Accepted = feed.CategoryId == selectedCategory.Id && feed.Account.Type == AccountType.Local;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCategoryDataGridRowDrop(object sender, DragEventArgs e)
|
private void HandleCategoryDataGridRowDrop(object sender, DragEventArgs e)
|
||||||
@@ -352,7 +355,7 @@ public partial class FeedsOptionsPanel
|
|||||||
var category = (Category) ((DataGridRow) sender).Item;
|
var category = (Category) ((DataGridRow) sender).Item;
|
||||||
|
|
||||||
foreach (var feed in feedList!)
|
foreach (var feed in feedList!)
|
||||||
Database.Entities.SaveChanges(() => feed.CategoryId = category.Id);
|
_entities.SaveChanges(() => feed.CategoryId = category.Id);
|
||||||
|
|
||||||
_collectionViewSource.View.Refresh();
|
_collectionViewSource.View.Refresh();
|
||||||
|
|
||||||
@@ -382,7 +385,7 @@ public partial class FeedsOptionsPanel
|
|||||||
|
|
||||||
private void HandleMultipleEditClick(object sender, RoutedEventArgs e)
|
private void HandleMultipleEditClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var bulkFeedWindow = new BulkFeedWindow();
|
var bulkFeedWindow = new BulkFeedWindow(_entities);
|
||||||
bulkFeedWindow.Display(Window.GetWindow(this));
|
bulkFeedWindow.Display(Window.GetWindow(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace FeedCenter.Options;
|
|||||||
|
|
||||||
public partial class GeneralOptionsPanel
|
public partial class GeneralOptionsPanel
|
||||||
{
|
{
|
||||||
public GeneralOptionsPanel(Window parentWindow) : base(parentWindow)
|
public GeneralOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ namespace FeedCenter.Options;
|
|||||||
public class OptionsPanelBase : UserControl
|
public class OptionsPanelBase : UserControl
|
||||||
{
|
{
|
||||||
protected readonly Window ParentWindow;
|
protected readonly Window ParentWindow;
|
||||||
|
protected readonly FeedCenterEntities Entities;
|
||||||
|
|
||||||
protected OptionsPanelBase(Window parentWindow)
|
protected OptionsPanelBase(Window parentWindow, FeedCenterEntities entities)
|
||||||
{
|
{
|
||||||
ParentWindow = parentWindow;
|
ParentWindow = parentWindow;
|
||||||
|
Entities = entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string CategoryName => null;
|
public virtual string CategoryName => null;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace FeedCenter.Options;
|
|||||||
public partial class OptionsWindow
|
public partial class OptionsWindow
|
||||||
{
|
{
|
||||||
private readonly List<OptionsPanelBase> _optionPanels = new();
|
private readonly List<OptionsPanelBase> _optionPanels = new();
|
||||||
|
private readonly FeedCenterEntities _entities = new();
|
||||||
|
|
||||||
public OptionsWindow()
|
public OptionsWindow()
|
||||||
{
|
{
|
||||||
@@ -20,11 +21,12 @@ public partial class OptionsWindow
|
|||||||
|
|
||||||
private void AddCategories()
|
private void AddCategories()
|
||||||
{
|
{
|
||||||
_optionPanels.Add(new GeneralOptionsPanel(this));
|
_optionPanels.Add(new GeneralOptionsPanel(this, _entities));
|
||||||
_optionPanels.Add(new DisplayOptionsPanel(this));
|
_optionPanels.Add(new DisplayOptionsPanel(this, _entities));
|
||||||
_optionPanels.Add(new FeedsOptionsPanel(this));
|
_optionPanels.Add(new FeedsOptionsPanel(this, _entities));
|
||||||
_optionPanels.Add(new UpdateOptionsPanel(this));
|
_optionPanels.Add(new AccountsOptionsPanel(this, _entities));
|
||||||
_optionPanels.Add(new AboutOptionsPanel(this));
|
_optionPanels.Add(new UpdateOptionsPanel(this, _entities));
|
||||||
|
_optionPanels.Add(new AboutOptionsPanel(this, _entities));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadCategories()
|
private void LoadCategories()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace FeedCenter.Options;
|
|||||||
|
|
||||||
public partial class UpdateOptionsPanel
|
public partial class UpdateOptionsPanel
|
||||||
{
|
{
|
||||||
public UpdateOptionsPanel(Window parentWindow) : base(parentWindow)
|
public UpdateOptionsPanel(Window parentWindow, FeedCenterEntities entities) : base(parentWindow, entities)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class UserAgentItem
|
|||||||
{
|
{
|
||||||
new UserAgentItem
|
new UserAgentItem
|
||||||
{
|
{
|
||||||
Caption = Properties.Resources.ApplicationUserAgentCaption,
|
Caption = Resources.ApplicationUserAgentCaption,
|
||||||
UserAgent = string.Empty
|
UserAgent = string.Empty
|
||||||
},
|
},
|
||||||
new UserAgentItem
|
new UserAgentItem
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ using System.Windows;
|
|||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyCompany("Chris Kaczor")]
|
[assembly: AssemblyCompany("Chris Kaczor")]
|
||||||
[assembly: AssemblyProduct("Feed Center")]
|
[assembly: AssemblyProduct("Feed Center")]
|
||||||
[assembly: AssemblyCopyright("Copyright © Chris Kaczor 2023")]
|
[assembly: AssemblyCopyright("Copyright © Chris Kaczor 2025")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
[assembly: SupportedOSPlatform("windows")]
|
[assembly: TargetPlatform("Windows10.0")]
|
||||||
|
[assembly: SupportedOSPlatform("Windows10.0")]
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
[assembly: AssemblyConfiguration("Debug build")]
|
[assembly: AssemblyConfiguration("Debug build")]
|
||||||
@@ -24,5 +25,5 @@ using System.Windows;
|
|||||||
[assembly: NeutralResourcesLanguage("en-US")]
|
[assembly: NeutralResourcesLanguage("en-US")]
|
||||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.1.0.0")]
|
[assembly: AssemblyVersion("0.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
[assembly: AssemblyFileVersion("0.0.0.0")]
|
||||||
17
Application/Properties/PublishProfiles/x64.pubxml
Normal file
17
Application/Properties/PublishProfiles/x64.pubxml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Any CPU</Platform>
|
||||||
|
<PublishDir>bin\Release\publish\</PublishDir>
|
||||||
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
|
<_TargetId>Folder</_TargetId>
|
||||||
|
<TargetFramework>net10.0-windows8.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
166
Application/Properties/Resources.Designer.cs
generated
166
Application/Properties/Resources.Designer.cs
generated
@@ -19,7 +19,7 @@ namespace FeedCenter.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
public class Resources {
|
public class Resources {
|
||||||
@@ -60,6 +60,123 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Name.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountNameColumnHeader {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountNameColumnHeader", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Name.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountNameLabel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountNameLabel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Refresh account every.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountReadIntervalPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountReadIntervalPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to minutes.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountReadIntervalSuffix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountReadIntervalSuffix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to _Account requires authentication.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountRequiresAuthenticationCheckBox {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountRequiresAuthenticationCheckBox", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Type.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountTypeColumnHeader {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountTypeColumnHeader", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Fever.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountTypeFever {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountTypeFever", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Google Reader.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountTypeGoogleReader {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountTypeGoogleReader", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Type.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountTypeLabel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountTypeLabel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Miniflux.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountTypeMiniflux {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountTypeMiniflux", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to URL.
|
||||||
|
/// </summary>
|
||||||
|
public static string accountUrlLabel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("accountUrlLabel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Add Account.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountWindowAdd {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountWindowAdd", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Edit Account.
|
||||||
|
/// </summary>
|
||||||
|
public static string AccountWindowEdit {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountWindowEdit", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to A_ctions.
|
/// Looks up a localized string similar to A_ctions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -69,6 +186,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Add Account.
|
||||||
|
/// </summary>
|
||||||
|
public static string AddAccountButton {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AddAccountButton", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Add Category.
|
/// Looks up a localized string similar to Add Category.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -277,6 +403,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Are you sure you want to delete this account?.
|
||||||
|
/// </summary>
|
||||||
|
public static string ConfirmDeleteAccount {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ConfirmDeleteAccount", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Are you sure you want to delete this category?
|
/// Looks up a localized string similar to Are you sure you want to delete this category?
|
||||||
///
|
///
|
||||||
@@ -543,6 +678,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Delete Account.
|
||||||
|
/// </summary>
|
||||||
|
public static string DeleteAccountButton {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("DeleteAccountButton", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Delete Category.
|
/// Looks up a localized string similar to Delete Category.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -597,6 +741,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Edit Account.
|
||||||
|
/// </summary>
|
||||||
|
public static string EditAccountButton {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("EditAccountButton", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Edit Category.
|
/// Looks up a localized string similar to Edit Category.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1164,6 +1317,15 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Accounts.
|
||||||
|
/// </summary>
|
||||||
|
public static string optionCategoryAccounts {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("optionCategoryAccounts", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Categories.
|
/// Looks up a localized string similar to Categories.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1183,7 +1345,7 @@ namespace FeedCenter.Properties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Feeds.
|
/// Looks up a localized string similar to Local Feeds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string optionCategoryFeeds {
|
public static string optionCategoryFeeds {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -230,7 +230,7 @@
|
|||||||
<value>About</value>
|
<value>About</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="optionCategoryFeeds" xml:space="preserve">
|
<data name="optionCategoryFeeds" xml:space="preserve">
|
||||||
<value>Feeds</value>
|
<value>Local Feeds</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="optionCategoryUpdate" xml:space="preserve">
|
<data name="optionCategoryUpdate" xml:space="preserve">
|
||||||
<value>Update</value>
|
<value>Update</value>
|
||||||
@@ -561,7 +561,61 @@ All feeds currently in category "{0}" will be moved to the default category.</va
|
|||||||
<data name="FeedReadResult_TooManyRequests" xml:space="preserve">
|
<data name="FeedReadResult_TooManyRequests" xml:space="preserve">
|
||||||
<value>Too many requests</value>
|
<value>Too many requests</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="optionCategoryAccounts" xml:space="preserve">
|
||||||
|
<value>Accounts</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountNameColumnHeader" xml:space="preserve">
|
||||||
|
<value>Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="AddAccountButton" xml:space="preserve">
|
||||||
|
<value>Add Account</value>
|
||||||
|
</data>
|
||||||
|
<data name="EditAccountButton" xml:space="preserve">
|
||||||
|
<value>Edit Account</value>
|
||||||
|
</data>
|
||||||
|
<data name="DeleteAccountButton" xml:space="preserve">
|
||||||
|
<value>Delete Account</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountWindowAdd" xml:space="preserve">
|
||||||
|
<value>Add Account</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountWindowEdit" xml:space="preserve">
|
||||||
|
<value>Edit Account</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConfirmDeleteAccount" xml:space="preserve">
|
||||||
|
<value>Are you sure you want to delete this account?</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountNameLabel" xml:space="preserve">
|
||||||
|
<value>Name</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountUrlLabel" xml:space="preserve">
|
||||||
|
<value>URL</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountReadIntervalPrefix" xml:space="preserve">
|
||||||
|
<value>_Refresh account every</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountReadIntervalSuffix" xml:space="preserve">
|
||||||
|
<value>minutes</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountRequiresAuthenticationCheckBox" xml:space="preserve">
|
||||||
|
<value>_Account requires authentication</value>
|
||||||
|
</data>
|
||||||
|
<data name="accountTypeLabel" xml:space="preserve">
|
||||||
|
<value>Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountTypeFever" xml:space="preserve">
|
||||||
|
<value>Fever</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountTypeColumnHeader" xml:space="preserve">
|
||||||
|
<value>Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountTypeGoogleReader" xml:space="preserve">
|
||||||
|
<value>Google Reader</value>
|
||||||
|
</data>
|
||||||
<data name="includePrereleaseCheckBox" xml:space="preserve">
|
<data name="includePrereleaseCheckBox" xml:space="preserve">
|
||||||
<value>Include _prerelease</value>
|
<value>Include _prerelease</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AccountTypeMiniflux" xml:space="preserve">
|
||||||
|
<value>Miniflux</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -9,12 +9,7 @@ public static class SettingsStore
|
|||||||
{
|
{
|
||||||
public static object OpenDataStore()
|
public static object OpenDataStore()
|
||||||
{
|
{
|
||||||
if (!Database.Exists)
|
return !Database.Exists ? null : new FeedCenterEntities();
|
||||||
return null;
|
|
||||||
|
|
||||||
Database.Load();
|
|
||||||
|
|
||||||
return Database.Entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetSettingValue(object dataStore, string name, Version _)
|
public static string GetSettingValue(object dataStore, string name, Version _)
|
||||||
|
|||||||
@@ -11,20 +11,13 @@ namespace FeedCenter;
|
|||||||
|
|
||||||
public partial class SplashWindow : IDisposable
|
public partial class SplashWindow : IDisposable
|
||||||
{
|
{
|
||||||
private class ProgressStep
|
private class ProgressStep(string key, string caption, ProgressStep.ProgressCallback callback)
|
||||||
{
|
{
|
||||||
public delegate bool ProgressCallback();
|
public delegate bool ProgressCallback();
|
||||||
|
|
||||||
public readonly string Key;
|
public readonly string Key = key;
|
||||||
public readonly string Caption;
|
public readonly string Caption = caption;
|
||||||
public readonly ProgressCallback Callback;
|
public readonly ProgressCallback Callback = callback;
|
||||||
|
|
||||||
public ProgressStep(string key, string caption, ProgressCallback callback)
|
|
||||||
{
|
|
||||||
Key = key;
|
|
||||||
Caption = caption;
|
|
||||||
Callback = callback;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<ProgressStep> _progressSteps = new();
|
private readonly List<ProgressStep> _progressSteps = new();
|
||||||
@@ -180,12 +173,7 @@ public partial class SplashWindow : IDisposable
|
|||||||
|
|
||||||
private bool LoadDatabase()
|
private bool LoadDatabase()
|
||||||
{
|
{
|
||||||
_dispatcher.Invoke(() =>
|
_dispatcher.Invoke(() => Settings.Default.Reload());
|
||||||
{
|
|
||||||
Database.Load();
|
|
||||||
|
|
||||||
Settings.Default.Reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using FeedCenter.Properties;
|
using FeedCenter.Properties;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace FeedCenter;
|
namespace FeedCenter;
|
||||||
|
|
||||||
@@ -9,7 +8,7 @@ public static class SystemConfiguration
|
|||||||
{
|
{
|
||||||
private static bool UseDebugPath => Environment.CommandLine.IndexOf("/debugPath", StringComparison.InvariantCultureIgnoreCase) != -1;
|
private static bool UseDebugPath => Environment.CommandLine.IndexOf("/debugPath", StringComparison.InvariantCultureIgnoreCase) != -1;
|
||||||
|
|
||||||
public static string DataDirectory => UseDebugPath ? Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) : UserSettingsPath;
|
public static string DataDirectory => UseDebugPath ? Path.GetDirectoryName(AppContext.BaseDirectory) : UserSettingsPath;
|
||||||
|
|
||||||
public static string UserSettingsPath
|
public static string UserSettingsPath
|
||||||
{
|
{
|
||||||
@@ -17,7 +16,7 @@ public static class SystemConfiguration
|
|||||||
{
|
{
|
||||||
// If we're running in debug mode then use a local path for the database and logs
|
// If we're running in debug mode then use a local path for the database and logs
|
||||||
if (UseDebugPath)
|
if (UseDebugPath)
|
||||||
return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
return Path.GetDirectoryName(AppContext.BaseDirectory);
|
||||||
|
|
||||||
// Get the path to the local application data directory
|
// Get the path to the local application data directory
|
||||||
var path = Path.Combine(
|
var path = Path.Combine(
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
|
||||||
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
|
|
||||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
|
||||||
|
|
||||||
<?define ProductName="$(fileVersion.ProductName($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
<?define CompanyName="$(fileVersion.CompanyName($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
<?define ProductVersion="$(fileVersion.ProductVersion($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
|
|
||||||
<Bundle Name="$(var.ProductName)"
|
|
||||||
Version="$(var.ProductVersion)"
|
|
||||||
Manufacturer="$(var.CompanyName)"
|
|
||||||
UpgradeCode="5e5c13a5-635e-4310-a653-0f9760f46935"
|
|
||||||
Compressed="no">
|
|
||||||
|
|
||||||
<util:DirectorySearch Id="DotnetDesktopRuntimeSearch_x86"
|
|
||||||
Path="[ProgramFilesFolder]dotnet\shared\Microsoft.WindowsDesktop.App\7.0.5"
|
|
||||||
Result="exists"
|
|
||||||
Variable="DotnetDesktopRuntimeExists_x86"
|
|
||||||
Condition="NOT VersionNT64" />
|
|
||||||
|
|
||||||
<util:DirectorySearch Id="DotnetDesktopRuntimeSearch_x64"
|
|
||||||
Path="[ProgramFiles64Folder]dotnet\shared\Microsoft.WindowsDesktop.App\7.0.5"
|
|
||||||
Result="exists"
|
|
||||||
Variable="DotnetDesktopRuntimeExists_x64"
|
|
||||||
Condition="VersionNT64" />
|
|
||||||
|
|
||||||
<BootstrapperApplicationRef Id="WixExtendedBootstrapperApplication.HyperlinkLicense">
|
|
||||||
<bal:WixExtendedBootstrapperApplication LicenseUrl=""
|
|
||||||
SuppressOptionsUI="yes"
|
|
||||||
ShowVersion="yes"
|
|
||||||
LocalizationFile="Bundle.wxl"
|
|
||||||
LaunchPassive="yes"
|
|
||||||
LaunchQuiet="yes"
|
|
||||||
LaunchTarget="[LocalAppDataFolder]$(var.ProductName)\FeedCenter.exe" />
|
|
||||||
</BootstrapperApplicationRef>
|
|
||||||
|
|
||||||
<Chain>
|
|
||||||
<ExePackage Id="runtime_desktop_x64"
|
|
||||||
DisplayName=".NET 7.0 Desktop Runtime (x64)"
|
|
||||||
InstallCommand="/install /quiet"
|
|
||||||
Permanent="yes"
|
|
||||||
Compressed="no"
|
|
||||||
DownloadUrl="https://download.visualstudio.microsoft.com/download/pr/dffb1939-cef1-4db3-a579-5475a3061cdd/578b208733c914c7b7357f6baa4ecfd6/windowsdesktop-runtime-7.0.5-win-x64.exe"
|
|
||||||
Name="windowsdesktop-runtime-7.0.5-win-x64.exe"
|
|
||||||
DetectCondition="DotnetDesktopRuntimeExists_x64 = 1"
|
|
||||||
InstallCondition='VersionNT64'>
|
|
||||||
<RemotePayload ProductName="Microsoft Windows Desktop Runtime - 7.0.5 (x64)"
|
|
||||||
Description="Microsoft Windows Desktop Runtime - 7.0.5 (x64)"
|
|
||||||
Version="7.0.5.32327"
|
|
||||||
Hash="5B4232EED009E6B66C64A6096B1277995DE63F57"
|
|
||||||
Size="57609944" />
|
|
||||||
</ExePackage>
|
|
||||||
<ExePackage Id="runtime_desktop_x32"
|
|
||||||
DisplayName=".NET 7.0 Desktop Runtime (x86)"
|
|
||||||
InstallCommand="/install /quiet"
|
|
||||||
Permanent="yes"
|
|
||||||
Compressed="no"
|
|
||||||
DownloadUrl="https://download.visualstudio.microsoft.com/download/pr/eb64dcd1-d277-4798-ada1-600805c9e2dc/fc73c843d66f3996e7ef22468f4902e6/windowsdesktop-runtime-7.0.5-win-x86.exe"
|
|
||||||
Name="windowsdesktop-runtime-7.0.5-win-x86.exe"
|
|
||||||
DetectCondition="DotnetDesktopRuntimeExists_x86 = 1"
|
|
||||||
InstallCondition='NOT VersionNT64'>
|
|
||||||
<RemotePayload ProductName="Microsoft Windows Desktop Runtime - 7.0.5 (x86)"
|
|
||||||
Description="Microsoft Windows Desktop Runtime - 7.0.5 (x86)"
|
|
||||||
Version="7.0.5.32327"
|
|
||||||
Hash="3987657473EA907DEC2FA48F492A5FC2B83B5060"
|
|
||||||
Size="52816632" />
|
|
||||||
</ExePackage>
|
|
||||||
<MsiPackage Id="FeedCenter"
|
|
||||||
SourceFile="$(var.Setup.TargetPath)"
|
|
||||||
Compressed="yes" />
|
|
||||||
</Chain>
|
|
||||||
</Bundle>
|
|
||||||
</Wix>
|
|
||||||
128
FeedCenter.sln
128
FeedCenter.sln
@@ -1,128 +0,0 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.5.33414.496
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FeedCenter", "Application\FeedCenter.csproj", "{BD3D12F2-DE23-4466-83B1-1EB617A877A4}"
|
|
||||||
EndProject
|
|
||||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "Setup\Setup.wixproj", "{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}"
|
|
||||||
EndProject
|
|
||||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Bootstrapper", "Bootstrapper\Bootstrapper.wixproj", "{5E5C13A5-635E-4310-A653-0F9760F46935}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{1462AAAD-B01B-4FF6-9B9F-595D239C9D1E}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.gitignore = .gitignore
|
|
||||||
appveyor.yml = appveyor.yml
|
|
||||||
LICENSE.md = LICENSE.md
|
|
||||||
README.md = README.md
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug (No Installer)|Any CPU = Debug (No Installer)|Any CPU
|
|
||||||
Debug (No Installer)|Mixed Platforms = Debug (No Installer)|Mixed Platforms
|
|
||||||
Debug (No Installer)|x64 = Debug (No Installer)|x64
|
|
||||||
Debug (No Installer)|x86 = Debug (No Installer)|x86
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release (No Installer)|Any CPU = Release (No Installer)|Any CPU
|
|
||||||
Release (No Installer)|Mixed Platforms = Release (No Installer)|Mixed Platforms
|
|
||||||
Release (No Installer)|x64 = Release (No Installer)|x64
|
|
||||||
Release (No Installer)|x86 = Release (No Installer)|x86
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
Release|Mixed Platforms = Release|Mixed Platforms
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|Mixed Platforms.Build.0 = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|x64.ActiveCfg = Debug|x64
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|x64.Build.0 = Debug|x64
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|x86.ActiveCfg = Debug|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug (No Installer)|x86.Build.0 = Debug|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|x64.ActiveCfg = Release|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|x86.ActiveCfg = Release|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release (No Installer)|x86.Build.0 = Release|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x64.ActiveCfg = Release|x86
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{BD3D12F2-DE23-4466-83B1-1EB617A877A4}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|Any CPU.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|Mixed Platforms.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|x64.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|x64.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|x86.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug (No Installer)|x86.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|Any CPU.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|Any CPU.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x64.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x64.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release (No Installer)|Any CPU.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release (No Installer)|Mixed Platforms.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release (No Installer)|x64.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release (No Installer)|x86.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release (No Installer)|x86.Build.0 = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|Any CPU.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|Any CPU.Build.0 = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|Mixed Platforms.Build.0 = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x64.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x86.Build.0 = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|Any CPU.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|Mixed Platforms.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|x64.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|x64.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|x86.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug (No Installer)|x86.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|Any CPU.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|Any CPU.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|Mixed Platforms.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x64.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x64.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x86.ActiveCfg = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x86.Build.0 = Debug|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release (No Installer)|Any CPU.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release (No Installer)|Mixed Platforms.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release (No Installer)|x64.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release (No Installer)|x86.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release (No Installer)|x86.Build.0 = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|Any CPU.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|Any CPU.Build.0 = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|Mixed Platforms.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|Mixed Platforms.Build.0 = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x64.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x86.Build.0 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {B1D182A0-263B-4AB8-8413-56303DBD4CCC}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -43,14 +43,6 @@
|
|||||||
</WixExtension>
|
</WixExtension>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Application\FeedCenter.csproj">
|
|
||||||
<Name>FeedCenter</Name>
|
|
||||||
<Project>{bd3d12f2-de23-4466-83b1-1eb617a877a4}</Project>
|
|
||||||
<Private>True</Private>
|
|
||||||
<DoNotHarvest>True</DoNotHarvest>
|
|
||||||
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
|
|
||||||
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\Setup\Setup.wixproj">
|
<ProjectReference Include="..\Setup\Setup.wixproj">
|
||||||
<Name>Setup</Name>
|
<Name>Setup</Name>
|
||||||
<Project>{dfb3fe30-18ea-4216-8d92-11df9c8d50f1}</Project>
|
<Project>{dfb3fe30-18ea-4216-8d92-11df9c8d50f1}</Project>
|
||||||
38
Installer/Bootstrapper/Bundle.wxs
Normal file
38
Installer/Bootstrapper/Bundle.wxs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||||
|
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
|
||||||
|
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||||
|
|
||||||
|
<?define ExecutableName="FeedCenter.exe" ?>
|
||||||
|
|
||||||
|
<?define BuildPath="..\..\Application\bin\Release\publish" ?>
|
||||||
|
<?define BuildExecutable="$(var.BuildPath)\$(var.ExecutableName)" ?>
|
||||||
|
|
||||||
|
<?define ProductName="$(fileVersion.ProductName($(var.BuildExecutable)))" ?>
|
||||||
|
<?define CompanyName="$(fileVersion.CompanyName($(var.BuildExecutable)))" ?>
|
||||||
|
<?define ProductVersion="$(fileVersion.ProductVersion($(var.BuildExecutable)))" ?>
|
||||||
|
|
||||||
|
<Bundle Name="$(var.ProductName)"
|
||||||
|
Version="$(var.ProductVersion)"
|
||||||
|
Manufacturer="$(var.CompanyName)"
|
||||||
|
UpgradeCode="5e5c13a5-635e-4310-a653-0f9760f46935"
|
||||||
|
Compressed="no">
|
||||||
|
|
||||||
|
<BootstrapperApplicationRef Id="WixExtendedBootstrapperApplication.HyperlinkLicense">
|
||||||
|
<bal:WixExtendedBootstrapperApplication LicenseUrl=""
|
||||||
|
SuppressOptionsUI="yes"
|
||||||
|
ShowVersion="yes"
|
||||||
|
LocalizationFile="Bundle.wxl"
|
||||||
|
LaunchPassive="yes"
|
||||||
|
LaunchQuiet="yes"
|
||||||
|
LaunchTarget="[LocalAppDataFolder]$(var.ProductName)\FeedCenter.exe" />
|
||||||
|
</BootstrapperApplicationRef>
|
||||||
|
|
||||||
|
<Chain>
|
||||||
|
<MsiPackage Id="FeedCenter"
|
||||||
|
SourceFile="$(var.Setup.TargetPath)"
|
||||||
|
Compressed="yes" />
|
||||||
|
</Chain>
|
||||||
|
</Bundle>
|
||||||
|
</Wix>
|
||||||
51
Installer/Installer.sln
Normal file
51
Installer/Installer.sln
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 18
|
||||||
|
VisualStudioVersion = 18.0.11018.127
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "Setup\Setup.wixproj", "{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}"
|
||||||
|
EndProject
|
||||||
|
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Bootstrapper", "Bootstrapper\Bootstrapper.wixproj", "{5E5C13A5-635E-4310-A653-0F9760F46935}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|ARM64 = Debug|ARM64
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|ARM64 = Release|ARM64
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|ARM64.ActiveCfg = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|ARM64.Build.0 = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x64.ActiveCfg = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x64.Build.0 = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|ARM64.ActiveCfg = Release|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|ARM64.Build.0 = Release|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x64.ActiveCfg = Release|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x64.Build.0 = Release|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{DFB3FE30-18EA-4216-8D92-11DF9C8D50F1}.Release|x86.Build.0 = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|ARM64.ActiveCfg = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|ARM64.Build.0 = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x64.ActiveCfg = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x64.Build.0 = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|ARM64.ActiveCfg = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|ARM64.Build.0 = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x64.ActiveCfg = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x64.Build.0 = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{5E5C13A5-635E-4310-A653-0F9760F46935}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {A3D28F74-5EC6-4995-A173-9D03FE88AB51}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
196
Installer/Setup/Product.wxs
Normal file
196
Installer/Setup/Product.wxs
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||||
|
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"
|
||||||
|
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||||
|
|
||||||
|
<?define ExecutableName="FeedCenter.exe" ?>
|
||||||
|
|
||||||
|
<?define BuildPath="..\..\Application\bin\Release\publish" ?>
|
||||||
|
<?define BuildExecutable="$(var.BuildPath)\$(var.ExecutableName)" ?>
|
||||||
|
|
||||||
|
<?define ProductName="$(fileVersion.ProductName($(var.BuildExecutable)))" ?>
|
||||||
|
<?define CompanyName="$(fileVersion.CompanyName($(var.BuildExecutable)))" ?>
|
||||||
|
<?define ProductVersion="$(fileVersion.ProductVersion($(var.BuildExecutable)))" ?>
|
||||||
|
<?define FileDescription="$(fileVersion.FileDescription($(var.BuildExecutable)))" ?>
|
||||||
|
|
||||||
|
<Product Id="*"
|
||||||
|
Name="$(var.ProductName)"
|
||||||
|
Language="1033"
|
||||||
|
Version="$(var.ProductVersion)"
|
||||||
|
Manufacturer="$(var.CompanyName)"
|
||||||
|
UpgradeCode="47f30e4a-a861-47ac-b82d-35e4b886992a">
|
||||||
|
<Package InstallerVersion="405"
|
||||||
|
Compressed="yes"
|
||||||
|
InstallScope="perUser" />
|
||||||
|
|
||||||
|
<util:CloseApplication Id="CloseApplication"
|
||||||
|
Target="$(var.ExecutableName)"
|
||||||
|
CloseMessage="yes"
|
||||||
|
Timeout="5" />
|
||||||
|
|
||||||
|
<MajorUpgrade Schedule="afterInstallValidate"
|
||||||
|
AllowDowngrades="no"
|
||||||
|
AllowSameVersionUpgrades="no"
|
||||||
|
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||||
|
|
||||||
|
<MediaTemplate />
|
||||||
|
|
||||||
|
<Feature Id="ProductFeature"
|
||||||
|
Title="$(var.ProductName)"
|
||||||
|
Level="1">
|
||||||
|
<ComponentGroupRef Id="ProductComponents" />
|
||||||
|
</Feature>
|
||||||
|
</Product>
|
||||||
|
|
||||||
|
<Fragment>
|
||||||
|
<Directory Id="TARGETDIR"
|
||||||
|
Name="SourceDir">
|
||||||
|
<Directory Id="LocalAppDataFolder">
|
||||||
|
<Directory Id="INSTALLFOLDER"
|
||||||
|
Name="$(var.ProductName)">
|
||||||
|
<Directory Id="SqlServerCe_32"
|
||||||
|
Name="x86" />
|
||||||
|
<Directory Id="SqlServerCe_64"
|
||||||
|
Name="amd64" />
|
||||||
|
<Directory Id="Runtimes"
|
||||||
|
Name="runtimes">
|
||||||
|
<Directory Id="Runtimes_Win_x32"
|
||||||
|
Name="win-x32">
|
||||||
|
<Directory Id="Runtimes_Win_x32_Native"
|
||||||
|
Name="native" />
|
||||||
|
</Directory>
|
||||||
|
<Directory Id="Runtimes_Win_x64"
|
||||||
|
Name="win-x64">
|
||||||
|
<Directory Id="Runtimes_Win_x64_Native"
|
||||||
|
Name="native" />
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
<Directory Id="ProgramMenuFolder">
|
||||||
|
<Directory Id="ApplicationProgramsFolder"
|
||||||
|
Name="$(var.ProductName)" />
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
|
<Fragment>
|
||||||
|
<ComponentGroup Id="ProductComponents">
|
||||||
|
<Component Id="SqlServerCe_64"
|
||||||
|
Guid="{67DB1CF4-23F2-4252-896C-714438959C9A}"
|
||||||
|
Directory="SqlServerCe_64">
|
||||||
|
|
||||||
|
<RegistryValue Root='HKCU'
|
||||||
|
Key='Software\Feed Center\Setup'
|
||||||
|
Type='integer'
|
||||||
|
Name='SqlServerCe_64'
|
||||||
|
Value='1'
|
||||||
|
KeyPath='yes' />
|
||||||
|
|
||||||
|
<File Id="sqlceca40_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlceca40.dll" />
|
||||||
|
<File Id="sqlcecompact40_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlcecompact40.dll" />
|
||||||
|
<File Id="sqlceer40EN_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlceer40EN.dll" />
|
||||||
|
<File Id="sqlceme40_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlceme40.dll" />
|
||||||
|
<File Id="sqlceqp40_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlceqp40.dll" />
|
||||||
|
<File Id="sqlcese40_64"
|
||||||
|
Source="$(var.BuildPath)\amd64\sqlcese40.dll" />
|
||||||
|
|
||||||
|
<RemoveFolder Id='SqlServerCe_64'
|
||||||
|
On='uninstall' />
|
||||||
|
</Component>
|
||||||
|
<Component Id="FeedCenter"
|
||||||
|
Guid="{9B2B9C65-8E68-4F82-9AC5-16EBCAC34B9E}"
|
||||||
|
Directory="INSTALLFOLDER">
|
||||||
|
|
||||||
|
<RegistryValue Root='HKCU'
|
||||||
|
Key='Software\Feed Center\Setup'
|
||||||
|
Type='integer'
|
||||||
|
Name='FeedCenter'
|
||||||
|
Value='1'
|
||||||
|
KeyPath='yes' />
|
||||||
|
|
||||||
|
<!-- Capabilities keys for Vista/7 "Set Program Access and Defaults" -->
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="SOFTWARE\Feed Center\Capabilities"
|
||||||
|
Name="ApplicationDescription"
|
||||||
|
Value="$(var.FileDescription)"
|
||||||
|
Type="string" />
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="SOFTWARE\Feed Center\Capabilities"
|
||||||
|
Name="ApplicationName"
|
||||||
|
Value="$(var.ProductName)"
|
||||||
|
Type="string" />
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="SOFTWARE\Feed Center\Capabilities\URLAssociations"
|
||||||
|
Name="feed"
|
||||||
|
Value="FeedCenter.URL.feed"
|
||||||
|
Type="string" />
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="SOFTWARE\Feed Center\Capabilities\URLAssociations"
|
||||||
|
Name="feeds"
|
||||||
|
Value="FeedCenter.URL.feed"
|
||||||
|
Type="string" />
|
||||||
|
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="SOFTWARE\RegisteredApplications"
|
||||||
|
Name="Feed Center"
|
||||||
|
Value="SOFTWARE\Feed Center\Capabilities"
|
||||||
|
Type="string" />
|
||||||
|
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="Software\Classes\FeedCenter.URL.feed"
|
||||||
|
Value="URL:Feed Center Add RSS Feed"
|
||||||
|
Type="string" />
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="Software\Classes\FeedCenter.URL.feed\DefaultIcon"
|
||||||
|
Value="[INSTALLFOLDER]$(var.ExecutableName)"
|
||||||
|
Type="string" />
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="Software\Classes\FeedCenter.URL.feed\shell\open\command"
|
||||||
|
Value=""[INSTALLFOLDER]$(var.ExecutableName)" %1"
|
||||||
|
Type="string" />
|
||||||
|
|
||||||
|
<File Id="D3DCompiler_47_cor3.dll" Source="$(var.BuildPath)\D3DCompiler_47_cor3.dll" />
|
||||||
|
<File Id="FeedCenter.dll.config" Source="$(var.BuildPath)\FeedCenter.dll.config" />
|
||||||
|
<File Id="FeedCenter.exe" Source="$(var.BuildPath)\FeedCenter.exe" />
|
||||||
|
<File Id="FeedCenter.pdb" Source="$(var.BuildPath)\FeedCenter.pdb" />
|
||||||
|
<File Id="PenImc_cor3.dll" Source="$(var.BuildPath)\PenImc_cor3.dll" />
|
||||||
|
<File Id="PresentationNative_cor3.dll" Source="$(var.BuildPath)\PresentationNative_cor3.dll" />
|
||||||
|
<File Id="realm_wrappers.dll" Source="$(var.BuildPath)\realm-wrappers.dll" />
|
||||||
|
<File Id="sni.dll" Source="$(var.BuildPath)\sni.dll" />
|
||||||
|
<File Id="vcruntime140_cor3.dll" Source="$(var.BuildPath)\vcruntime140_cor3.dll" />
|
||||||
|
<File Id="wpfgfx_cor3.dll" Source="$(var.BuildPath)\wpfgfx_cor3.dll" />
|
||||||
|
|
||||||
|
<RemoveFolder Id='INSTALLFOLDER'
|
||||||
|
On='uninstall' />
|
||||||
|
</Component>
|
||||||
|
<Component Id="ApplicationShortcut"
|
||||||
|
Guid="{63CF0995-E117-4BB9-9077-76F570FDFAA9}"
|
||||||
|
Directory="ApplicationProgramsFolder">
|
||||||
|
|
||||||
|
<Shortcut Id="StartMenuShortcut"
|
||||||
|
Directory="ApplicationProgramsFolder"
|
||||||
|
Advertise="no"
|
||||||
|
Name="$(var.ProductName)"
|
||||||
|
Target="[INSTALLFOLDER]\$(var.ExecutableName)"
|
||||||
|
WorkingDirectory="INSTALLFOLDER" />
|
||||||
|
|
||||||
|
<RemoveFolder Id="ApplicationProgramsFolder"
|
||||||
|
On="uninstall" />
|
||||||
|
|
||||||
|
<RegistryValue Root="HKCU"
|
||||||
|
Key="Software\Feed Center\Setup"
|
||||||
|
Name="Shortcut"
|
||||||
|
Type="integer"
|
||||||
|
Value="1"
|
||||||
|
KeyPath="yes" />
|
||||||
|
</Component>
|
||||||
|
</ComponentGroup>
|
||||||
|
</Fragment>
|
||||||
|
</Wix>
|
||||||
@@ -42,16 +42,6 @@
|
|||||||
<Name>WixNetFxExtension</Name>
|
<Name>WixNetFxExtension</Name>
|
||||||
</WixExtension>
|
</WixExtension>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Application\FeedCenter.csproj">
|
|
||||||
<Name>FeedCenter</Name>
|
|
||||||
<Project>{bd3d12f2-de23-4466-83b1-1eb617a877a4}</Project>
|
|
||||||
<Private>True</Private>
|
|
||||||
<DoNotHarvest>True</DoNotHarvest>
|
|
||||||
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
|
|
||||||
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="packages.config" />
|
<Content Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -1,377 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
|
||||||
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"
|
|
||||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
|
||||||
<?define ProductName="$(fileVersion.ProductName($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
<?define CompanyName="$(fileVersion.CompanyName($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
<?define ProductVersion="$(fileVersion.ProductVersion($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
<?define FileDescription="$(fileVersion.FileDescription($(var.FeedCenter.TargetPath)))" ?>
|
|
||||||
|
|
||||||
<Product Id="*"
|
|
||||||
Name="$(var.ProductName)"
|
|
||||||
Language="1033"
|
|
||||||
Version="$(var.ProductVersion)"
|
|
||||||
Manufacturer="$(var.CompanyName)"
|
|
||||||
UpgradeCode="47f30e4a-a861-47ac-b82d-35e4b886992a">
|
|
||||||
<Package InstallerVersion="405"
|
|
||||||
Compressed="yes"
|
|
||||||
InstallScope="perUser" />
|
|
||||||
|
|
||||||
<util:CloseApplication Id="CloseApplication"
|
|
||||||
Target="FeedCenter.exe"
|
|
||||||
CloseMessage="yes"
|
|
||||||
Timeout="5" />
|
|
||||||
|
|
||||||
<MajorUpgrade Schedule="afterInstallValidate"
|
|
||||||
AllowDowngrades="no"
|
|
||||||
AllowSameVersionUpgrades="no"
|
|
||||||
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
|
||||||
|
|
||||||
<MediaTemplate />
|
|
||||||
|
|
||||||
<Feature Id="ProductFeature"
|
|
||||||
Title="$(var.ProductName)"
|
|
||||||
Level="1">
|
|
||||||
<ComponentGroupRef Id="ProductComponents" />
|
|
||||||
</Feature>
|
|
||||||
</Product>
|
|
||||||
|
|
||||||
<Fragment>
|
|
||||||
<Directory Id="TARGETDIR"
|
|
||||||
Name="SourceDir">
|
|
||||||
<Directory Id="LocalAppDataFolder">
|
|
||||||
<Directory Id="INSTALLFOLDER"
|
|
||||||
Name="$(var.ProductName)">
|
|
||||||
<Directory Id="SqlServerCe_32"
|
|
||||||
Name="x86" />
|
|
||||||
<Directory Id="SqlServerCe_64"
|
|
||||||
Name="amd64" />
|
|
||||||
<Directory Id="Runtimes"
|
|
||||||
Name="runtimes">
|
|
||||||
<Directory Id="Runtimes_Win_x32"
|
|
||||||
Name="win-x32">
|
|
||||||
<Directory Id="Runtimes_Win_x32_Native"
|
|
||||||
Name="native" />
|
|
||||||
</Directory>
|
|
||||||
<Directory Id="Runtimes_Win_x64"
|
|
||||||
Name="win-x64">
|
|
||||||
<Directory Id="Runtimes_Win_x64_Native"
|
|
||||||
Name="native" />
|
|
||||||
</Directory>
|
|
||||||
</Directory>
|
|
||||||
</Directory>
|
|
||||||
</Directory>
|
|
||||||
<Directory Id="ProgramMenuFolder">
|
|
||||||
<Directory Id="ApplicationProgramsFolder"
|
|
||||||
Name="$(var.ProductName)" />
|
|
||||||
</Directory>
|
|
||||||
</Directory>
|
|
||||||
</Fragment>
|
|
||||||
|
|
||||||
<Fragment>
|
|
||||||
<ComponentGroup Id="ProductComponents">
|
|
||||||
<Component Id="SqlServerCe_32"
|
|
||||||
Guid="{800607E9-65ED-489F-83A2-C73AA36A9D1D}"
|
|
||||||
Directory="SqlServerCe_32">
|
|
||||||
|
|
||||||
<RegistryValue Root='HKCU'
|
|
||||||
Key='Software\Feed Center\Setup'
|
|
||||||
Type='integer'
|
|
||||||
Name='SqlServerCe_32'
|
|
||||||
Value='1'
|
|
||||||
KeyPath='yes' />
|
|
||||||
|
|
||||||
<File Id="sqlceca40_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlceca40.dll" />
|
|
||||||
<File Id="sqlcecompact40_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlcecompact40.dll" />
|
|
||||||
<File Id="sqlceer40EN_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlceer40EN.dll" />
|
|
||||||
<File Id="sqlceme40_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlceme40.dll" />
|
|
||||||
<File Id="sqlceqp40_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlceqp40.dll" />
|
|
||||||
<File Id="sqlcese40_32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\x86\sqlcese40.dll" />
|
|
||||||
|
|
||||||
<RemoveFolder Id='SqlServerCe_32'
|
|
||||||
On='uninstall' />
|
|
||||||
</Component>
|
|
||||||
<Component Id="SqlServerCe_64"
|
|
||||||
Guid="{67DB1CF4-23F2-4252-896C-714438959C9A}"
|
|
||||||
Directory="SqlServerCe_64">
|
|
||||||
|
|
||||||
<RegistryValue Root='HKCU'
|
|
||||||
Key='Software\Feed Center\Setup'
|
|
||||||
Type='integer'
|
|
||||||
Name='SqlServerCe_64'
|
|
||||||
Value='1'
|
|
||||||
KeyPath='yes' />
|
|
||||||
|
|
||||||
<File Id="sqlceca40_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlceca40.dll" />
|
|
||||||
<File Id="sqlcecompact40_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlcecompact40.dll" />
|
|
||||||
<File Id="sqlceer40EN_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlceer40EN.dll" />
|
|
||||||
<File Id="sqlceme40_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlceme40.dll" />
|
|
||||||
<File Id="sqlceqp40_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlceqp40.dll" />
|
|
||||||
<File Id="sqlcese40_64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\amd64\sqlcese40.dll" />
|
|
||||||
|
|
||||||
<RemoveFolder Id='SqlServerCe_64'
|
|
||||||
On='uninstall' />
|
|
||||||
</Component>
|
|
||||||
<Component Id="Runtimes_Win_x32_Native"
|
|
||||||
Guid="{E07B7F53-9FA0-426D-8ADF-A9FFF4E1ED02}"
|
|
||||||
Directory="Runtimes_Win_x32_Native">
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Feed Center\Setup"
|
|
||||||
Type="integer"
|
|
||||||
Name="Runtimes_Win_x32"
|
|
||||||
Value="1"
|
|
||||||
KeyPath="yes" />
|
|
||||||
|
|
||||||
<File Id="realm_wrappers.dll_x32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\runtimes\win-x86\native\realm-wrappers.dll" />
|
|
||||||
<File Id="sni.dll_x32"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\runtimes\win-x86\native\sni.dll" />
|
|
||||||
</Component>
|
|
||||||
<Component Id="Runtimes_Win_x64_Native"
|
|
||||||
Guid="{566D640B-F34D-4400-9B86-10EFD669A8B7}"
|
|
||||||
Directory="Runtimes_Win_x64_Native">
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Feed Center\Setup"
|
|
||||||
Type="integer"
|
|
||||||
Name="Runtimes_Win_x64"
|
|
||||||
Value="1"
|
|
||||||
KeyPath="yes" />
|
|
||||||
|
|
||||||
<File Id="realm_wrappers.dll_x64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\runtimes\win-x64\native\realm-wrappers.dll" />
|
|
||||||
<File Id="sni.dll_x64"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\runtimes\win-x64\native\sni.dll" />
|
|
||||||
</Component>
|
|
||||||
<Component Id="FeedCenter"
|
|
||||||
Guid="{9B2B9C65-8E68-4F82-9AC5-16EBCAC34B9E}"
|
|
||||||
Directory="INSTALLFOLDER">
|
|
||||||
|
|
||||||
<RegistryValue Root='HKCU'
|
|
||||||
Key='Software\Feed Center\Setup'
|
|
||||||
Type='integer'
|
|
||||||
Name='FeedCenter'
|
|
||||||
Value='1'
|
|
||||||
KeyPath='yes' />
|
|
||||||
|
|
||||||
<!-- Capabilities keys for Vista/7 "Set Program Access and Defaults" -->
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="SOFTWARE\Feed Center\Capabilities"
|
|
||||||
Name="ApplicationDescription"
|
|
||||||
Value="$(var.FileDescription)"
|
|
||||||
Type="string" />
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="SOFTWARE\Feed Center\Capabilities"
|
|
||||||
Name="ApplicationName"
|
|
||||||
Value="$(var.ProductName)"
|
|
||||||
Type="string" />
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="SOFTWARE\Feed Center\Capabilities\URLAssociations"
|
|
||||||
Name="feed"
|
|
||||||
Value="FeedCenter.URL.feed"
|
|
||||||
Type="string" />
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="SOFTWARE\Feed Center\Capabilities\URLAssociations"
|
|
||||||
Name="feeds"
|
|
||||||
Value="FeedCenter.URL.feed"
|
|
||||||
Type="string" />
|
|
||||||
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="SOFTWARE\RegisteredApplications"
|
|
||||||
Name="Feed Center"
|
|
||||||
Value="SOFTWARE\Feed Center\Capabilities"
|
|
||||||
Type="string" />
|
|
||||||
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Classes\FeedCenter.URL.feed"
|
|
||||||
Value="URL:Feed Center Add RSS Feed"
|
|
||||||
Type="string" />
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Classes\FeedCenter.URL.feed\DefaultIcon"
|
|
||||||
Value="[INSTALLFOLDER]FeedCenter.exe"
|
|
||||||
Type="string" />
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Classes\FeedCenter.URL.feed\shell\open\command"
|
|
||||||
Value=""[INSTALLFOLDER]FeedCenter.exe" %1"
|
|
||||||
Type="string" />
|
|
||||||
|
|
||||||
<File Id="ChrisKaczor.ApplicationUpdate.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.ApplicationUpdate.dll" />
|
|
||||||
<File Id="ChrisKaczor.GenericSettingsProvider.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.GenericSettingsProvider.dll" />
|
|
||||||
<File Id="ChrisKaczor.InstalledBrowsers.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.InstalledBrowsers.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Application.SingleInstance.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Application.SingleInstance.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Application.StartWithWindows.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Application.StartWithWindows.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Controls.HtmlTextBlock.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Controls.HtmlTextBlock.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Controls.Link.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Controls.Link.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Controls.Toolbar.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Controls.Toolbar.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Validation.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Validation.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Windows.ControlBox.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Windows.ControlBox.dll" />
|
|
||||||
<File Id="ChrisKaczor.Wpf.Windows.SnappingWindow.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ChrisKaczor.Wpf.Windows.SnappingWindow.dll" />
|
|
||||||
<File Id="ControlzEx.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\ControlzEx.dll" />
|
|
||||||
<File Id="Dapper.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Dapper.dll" />
|
|
||||||
<File Id="DebounceThrottle.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\DebounceThrottle.dll" />
|
|
||||||
<File Id="FeedCenter.deps.json"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\FeedCenter.deps.json" />
|
|
||||||
<File Id="FeedCenter.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\FeedCenter.dll" />
|
|
||||||
<File Id="FeedCenter.dll.config"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\FeedCenter.dll.config" />
|
|
||||||
<File Id="FeedCenter.exe"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\FeedCenter.exe" />
|
|
||||||
<File Id="FeedCenter.runtimeconfig.json"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\FeedCenter.runtimeconfig.json" />
|
|
||||||
<File Id="H.Formatters.BinaryFormatter.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.Formatters.BinaryFormatter.dll" />
|
|
||||||
<File Id="H.Formatters.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.Formatters.dll" />
|
|
||||||
<File Id="H.GeneratedIcons.System.Drawing.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.GeneratedIcons.System.Drawing.dll" />
|
|
||||||
<File Id="H.NotifyIcon.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.NotifyIcon.dll" />
|
|
||||||
<File Id="H.NotifyIcon.Wpf.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.NotifyIcon.Wpf.dll" />
|
|
||||||
<File Id="H.Pipes.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\H.Pipes.dll" />
|
|
||||||
<File Id="HtmlAgilityPack.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\HtmlAgilityPack.dll" />
|
|
||||||
<File Id="HtmlTextWriter.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\HtmlTextWriter.dll" />
|
|
||||||
<File Id="JetBrains.Annotations.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\JetBrains.Annotations.dll" />
|
|
||||||
<File Id="MahApps.Metro.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\MahApps.Metro.dll" />
|
|
||||||
<File Id="Microsoft.Bcl.AsyncInterfaces.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Microsoft.Bcl.AsyncInterfaces.dll" />
|
|
||||||
<File Id="Microsoft.Extensions.ObjectPool.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Microsoft.Extensions.ObjectPool.dll" />
|
|
||||||
<File Id="Microsoft.Xaml.Behaviors.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Microsoft.Xaml.Behaviors.dll" />
|
|
||||||
<File Id="MongoDB.Bson.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\MongoDB.Bson.dll" />
|
|
||||||
<File Id="NameBasedGrid.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\NameBasedGrid.dll" />
|
|
||||||
<File Id="Newtonsoft.Json.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Newtonsoft.Json.dll" />
|
|
||||||
<File Id="Realm.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Realm.dll" />
|
|
||||||
<File Id="Remotion.Linq.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Remotion.Linq.dll" />
|
|
||||||
<File Id="Serilog.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Serilog.dll" />
|
|
||||||
<File Id="Serilog.Enrichers.Thread.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Serilog.Enrichers.Thread.dll" />
|
|
||||||
<File Id="Serilog.Sinks.Console.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Serilog.Sinks.Console.dll" />
|
|
||||||
<File Id="Serilog.Sinks.File.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\Serilog.Sinks.File.dll" />
|
|
||||||
<File Id="System.ComponentModel.Composition.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ComponentModel.Composition.dll" />
|
|
||||||
<File Id="System.ComponentModel.Composition.Registration.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ComponentModel.Composition.Registration.dll" />
|
|
||||||
<File Id="System.Data.Odbc.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Data.Odbc.dll" />
|
|
||||||
<File Id="System.Data.OleDb.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Data.OleDb.dll" />
|
|
||||||
<File Id="System.Data.SqlClient.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Data.SqlClient.dll" />
|
|
||||||
<File Id="System.Data.SqlServerCe.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Data.SqlServerCe.dll" />
|
|
||||||
<File Id="System.DirectoryServices.AccountManagement.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.DirectoryServices.AccountManagement.dll" />
|
|
||||||
<File Id="System.DirectoryServices.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.DirectoryServices.dll" />
|
|
||||||
<File Id="System.DirectoryServices.Protocols.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.DirectoryServices.Protocols.dll" />
|
|
||||||
<File Id="System.IO.Ports.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.IO.Ports.dll" />
|
|
||||||
<File Id="System.Management.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Management.dll" />
|
|
||||||
<File Id="System.Private.ServiceModel.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Private.ServiceModel.dll" />
|
|
||||||
<File Id="System.Reflection.Context.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Reflection.Context.dll" />
|
|
||||||
<File Id="System.Runtime.Caching.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Runtime.Caching.dll" />
|
|
||||||
<File Id="System.Security.Cryptography.Pkcs.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Security.Cryptography.Pkcs.dll" />
|
|
||||||
<File Id="System.Security.Cryptography.ProtectedData.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Security.Cryptography.ProtectedData.dll" />
|
|
||||||
<File Id="System.Security.Cryptography.Xml.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Security.Cryptography.Xml.dll" />
|
|
||||||
<File Id="System.ServiceModel.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.dll" />
|
|
||||||
<File Id="System.ServiceModel.Duplex.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.Duplex.dll" />
|
|
||||||
<File Id="System.ServiceModel.Http.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.Http.dll" />
|
|
||||||
<File Id="System.ServiceModel.NetTcp.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.NetTcp.dll" />
|
|
||||||
<File Id="System.ServiceModel.Primitives.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.Primitives.dll" />
|
|
||||||
<File Id="System.ServiceModel.Security.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.Security.dll" />
|
|
||||||
<File Id="System.ServiceModel.Syndication.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceModel.Syndication.dll" />
|
|
||||||
<File Id="System.ServiceProcess.ServiceController.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.ServiceProcess.ServiceController.dll" />
|
|
||||||
<File Id="System.Speech.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Speech.dll" />
|
|
||||||
<File Id="System.Threading.AccessControl.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Threading.AccessControl.dll" />
|
|
||||||
<File Id="System.Web.Services.Description.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\System.Web.Services.Description.dll" />
|
|
||||||
<File Id="WpfScreenHelper.dll"
|
|
||||||
Source="$(var.FeedCenter.TargetDir)\WpfScreenHelper.dll" />
|
|
||||||
|
|
||||||
<RemoveFolder Id='INSTALLFOLDER'
|
|
||||||
On='uninstall' />
|
|
||||||
</Component>
|
|
||||||
<Component Id="ApplicationShortcut"
|
|
||||||
Guid="{63CF0995-E117-4BB9-9077-76F570FDFAA9}"
|
|
||||||
Directory="ApplicationProgramsFolder">
|
|
||||||
|
|
||||||
<Shortcut Id="StartMenuShortcut"
|
|
||||||
Directory="ApplicationProgramsFolder"
|
|
||||||
Advertise="no"
|
|
||||||
Name="$(var.ProductName)"
|
|
||||||
Target="[INSTALLFOLDER]\$(var.FeedCenter.TargetName)"
|
|
||||||
WorkingDirectory="INSTALLFOLDER" />
|
|
||||||
|
|
||||||
<RemoveFolder Id="ApplicationProgramsFolder"
|
|
||||||
On="uninstall" />
|
|
||||||
|
|
||||||
<RegistryValue Root="HKCU"
|
|
||||||
Key="Software\Feed Center\Setup"
|
|
||||||
Name="Shortcut"
|
|
||||||
Type="integer"
|
|
||||||
Value="1"
|
|
||||||
KeyPath="yes" />
|
|
||||||
</Component>
|
|
||||||
</ComponentGroup>
|
|
||||||
</Fragment>
|
|
||||||
</Wix>
|
|
||||||
46
appveyor.yml
46
appveyor.yml
@@ -1,26 +1,44 @@
|
|||||||
version: 1.1.0.{build}
|
version: 1.1.0.{build}
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- main
|
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
skip_tags: true
|
skip_tags: true
|
||||||
image: Visual Studio 2022
|
image: Visual Studio 2022
|
||||||
configuration: Release
|
configuration: Release
|
||||||
platform: x86
|
platform: x86
|
||||||
assembly_info:
|
assembly_info:
|
||||||
patch: true
|
patch: true
|
||||||
file: 'Properties\AssemblyInfo.cs'
|
file: 'Properties\AssemblyInfo.cs'
|
||||||
assembly_version: '{version}'
|
assembly_version: "{version}"
|
||||||
assembly_file_version: '{version}'
|
assembly_file_version: "{version}"
|
||||||
|
environment:
|
||||||
|
DOTNET_NOLOGO: true
|
||||||
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
|
install:
|
||||||
|
- ps: |
|
||||||
|
Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -UseBasicParsing -OutFile "$env:temp\dotnet-install.ps1"
|
||||||
|
& $env:temp\dotnet-install.ps1 -Architecture x64 -Version '10.0.100' -InstallDir "$env:ProgramFiles\dotnet"
|
||||||
|
before_build:
|
||||||
|
- ps: dotnet --version
|
||||||
|
- ps: nuget restore .\Installer\
|
||||||
|
- ps: dotnet publish .\Application\ /p:PublishProfile=Properties\PublishProfiles\x64.pubxml
|
||||||
build:
|
build:
|
||||||
project: FeedCenter.sln
|
project: Installer\Installer.sln
|
||||||
verbosity: minimal
|
verbosity: minimal
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: Bootstrapper\bin\Release\FeedCenterSetup.exe
|
- path: Installer\Bootstrapper\bin\Release\FeedCenterSetup.exe
|
||||||
name: Release
|
name: Release
|
||||||
deploy:
|
for:
|
||||||
- provider: Environment
|
- branches:
|
||||||
name: GitHub
|
only:
|
||||||
before_build:
|
- main
|
||||||
- cmd: nuget restore
|
deploy:
|
||||||
|
- provider: Environment
|
||||||
|
name: GitHub
|
||||||
|
|
||||||
|
- branches:
|
||||||
|
only:
|
||||||
|
- prerelease
|
||||||
|
version: 1.2.0.{build}
|
||||||
|
deploy:
|
||||||
|
- provider: Environment
|
||||||
|
name: GitHub-Prerelease
|
||||||
|
|||||||
Reference in New Issue
Block a user