From 39137877852b96f3116b9579349c49cd6ecb99ff Mon Sep 17 00:00:00 2001 From: oliver254 Date: Sat, 11 Jun 2022 20:41:30 +0200 Subject: [PATCH 1/4] #8 : Change article view --- .../ViewModels/MainWindowViewModel.cs | 3 +- .../Views/ArticleView.axaml | 39 +++++++++++-------- .../Views/MainWindow.axaml | 20 +++++++--- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs index 524d9b7..0801a9f 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs @@ -76,7 +76,8 @@ private async void AddFeed(Feed? feed) private async void LoadArticles(Feed feed) { _cancellationTokenSource?.Cancel(); - _cancellationTokenSource = new CancellationTokenSource(); + _cancellationTokenSource = new CancellationTokenSource(); + Articles.Clear(); foreach(var article in await ArticleService.LoadAsync(feed, _cancellationTokenSource.Token)) { Articles.Add(new ArticleViewModel(article)); diff --git a/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml index 1f2b716..88ab9f0 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml @@ -4,20 +4,27 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Monbsoft.Feeader.Avalonia.Views.ArticleView"> - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml index 1eaf8e1..4d07e69 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml @@ -16,14 +16,22 @@ - + - - - + + + + + + + + + + \ No newline at end of file From af80af5837c153d6c2e05994197cdc8f98b8fea0 Mon Sep 17 00:00:00 2001 From: oliver254 Date: Mon, 13 Jun 2022 00:49:29 +0200 Subject: [PATCH 2/4] #8 : Add settings window --- .../Models/FeedContext.cs | 18 +++ .../Monbsoft.Feeader.Avalonia.csproj | 5 + .../ViewModels/AddFeedViewModel.cs | 61 ---------- .../ViewModels/ArticleViewModel.cs | 5 +- .../ViewModels/ChangeFeedViewModel.cs | 110 ++++++++++++++++++ .../ViewModels/MainWindowViewModel.cs | 16 ++- .../ViewModels/SettingsWindowViewModel.cs | 22 ++++ .../Views/AddFeedWindow.axaml | 27 ----- .../Views/ArticleView.axaml | 37 +++--- .../Views/ChangeFeedView.axaml | 39 +++++++ ...uView.axaml.cs => ChangeFeedView.axaml.cs} | 4 +- .../{NavMenuView.axaml => FeedListView.axaml} | 8 +- .../Views/FeedListView.axaml.cs | 19 +++ .../Views/MainWindow.axaml | 4 +- .../Views/MainWindow.axaml.cs | 17 ++- .../Views/SettingsWindow.axaml | 12 ++ ...indow.axaml.cs => SettingsWindow.axaml.cs} | 9 +- 17 files changed, 268 insertions(+), 145 deletions(-) create mode 100644 src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs delete mode 100644 src/Monbsoft.Feeader.Avalonia/ViewModels/AddFeedViewModel.cs create mode 100644 src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs create mode 100644 src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs delete mode 100644 src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml create mode 100644 src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml rename src/Monbsoft.Feeader.Avalonia/Views/{NavMenuView.axaml.cs => ChangeFeedView.axaml.cs} (78%) rename src/Monbsoft.Feeader.Avalonia/Views/{NavMenuView.axaml => FeedListView.axaml} (84%) create mode 100644 src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml.cs create mode 100644 src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml rename src/Monbsoft.Feeader.Avalonia/Views/{AddFeedWindow.axaml.cs => SettingsWindow.axaml.cs} (54%) diff --git a/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs b/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs new file mode 100644 index 0000000..701068e --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Monbsoft.Feeader.Avalonia.Models +{ + public class FeedContext + { + public FeedContext(IEnumerable feeds) + { + Feeds = feeds.ToList(); + } + + public List Feeds { get; } + } +} diff --git a/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj b/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj index 6c25e31..2c71bc2 100644 --- a/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj +++ b/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj @@ -29,4 +29,9 @@ + + + ChangeFeedView.axaml + + diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/AddFeedViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/AddFeedViewModel.cs deleted file mode 100644 index 679b7bd..0000000 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/AddFeedViewModel.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Monbsoft.Feeader.Avalonia.Models; -using Monbsoft.Feeader.Avalonia.Services; -using NLog.Fluent; -using ReactiveUI; -using System; -using System.Linq; -using System.Reactive; -using System.Reactive.Linq; - -namespace Monbsoft.Feeader.Avalonia.ViewModels -{ - public class AddFeedViewModel : ViewModelBase - { - private string? _name; - private string? _url; - - public AddFeedViewModel() - { - this.WhenAnyValue(x => x.Url) - .Where(x => !string.IsNullOrWhiteSpace(x)) - .Throttle(TimeSpan.FromMilliseconds(400)) - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(DoSearch); - - AddCommand = ReactiveCommand.Create(() => - { - - return new Feed(Name, Url); - }); - - } - - - public ReactiveCommand AddCommand { get; } - - public string? Name - { - get => _name; - set => this.RaiseAndSetIfChanged(ref _name, value); - } - - public string? Url - { - get => _url; - set => this.RaiseAndSetIfChanged(ref _url, value); - } - - private async void DoSearch(string url) - { - try - { - var feed = await FeedService.GetFeedDataAsync(url); - Name = feed.Name; - } - catch(Exception ex) - { - Log.Error(ex.Message); - } - } - } -} \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs index b5864f0..3a053df 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs @@ -11,8 +11,9 @@ namespace Monbsoft.Feeader.Avalonia.ViewModels { public class ArticleViewModel : ViewModelBase { - private Uri? _pictureUri; private Bitmap? _picture; + private Uri? _pictureUri; + private Feed? _selectedFeed; public ArticleViewModel(Article article) { @@ -54,7 +55,7 @@ public async Task LoadPictureAsync(CancellationToken cancellationToken) if (_pictureUri != null) { Picture = await PictureService.LoadPictureBitmapAsync(_pictureUri, cancellationToken); - } + } } } } diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs new file mode 100644 index 0000000..fd282da --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs @@ -0,0 +1,110 @@ +using Monbsoft.Feeader.Avalonia.Models; +using Monbsoft.Feeader.Avalonia.Services; +using NLog.Fluent; +using ReactiveUI; +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; + +namespace Monbsoft.Feeader.Avalonia.ViewModels +{ + public class ChangeFeedViewModel : ViewModelBase + { + private FeedContext _context; + private string _name; + private string _url; + private Feed? _selectedFeed; + private FeedState _state; + + public ChangeFeedViewModel(FeedContext context) + { + this.WhenAnyValue(x => x.Url) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Throttle(TimeSpan.FromMilliseconds(400)) + .ObserveOn(RxApp.MainThreadScheduler) + .Subscribe(DoSearch); + + this.WhenAnyValue(x => x.SelectedFeed) + .ObserveOn(RxApp.MainThreadScheduler) + .Subscribe(f => + { + Name = f?.Name; + Url = f?.Link; + _state = f != null ? FeedState.Change : FeedState.Add; + }); + + Feeds = new ObservableCollection(context.Feeds); + _state = FeedState.Add; + _context = context; + + AddCommand = ReactiveCommand.Create(() => + { + if(_state == FeedState.Change && _selectedFeed != null) + { + _context.Feeds.Remove(_selectedFeed); + } + _context.Feeds.Add(new Feed(Name!, Url!)); + return _context; + }); + + } + + /// + /// A + /// + public ReactiveCommand AddCommand { get; } + /// + /// Gets the feeds + /// + public ObservableCollection Feeds { get; } + /// + /// Gets the name of the feed + /// + public string? Name + { + get => _name; + set => this.RaiseAndSetIfChanged(ref _name, value); + } + /// + /// Gets or sets the selected feed + /// + public Feed? SelectedFeed + { + get => _selectedFeed; + set => this.RaiseAndSetIfChanged(ref _selectedFeed, value); + } + /// + /// Gets the url of the feed + /// + public string? Url + { + get => _url; + set => this.RaiseAndSetIfChanged(ref _url, value); + } + + private async void DoSearch(string? url) + { + try + { + if (!string.IsNullOrEmpty(url)) + { + var feed = await FeedService.GetFeedDataAsync(url); + Name = feed.Name; + } + } + catch(Exception ex) + { + Log.Error(ex.Message); + } + } + + enum FeedState + { + Add = 0, + Change = 1 + } + + } +} \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs index 0801a9f..29bdfa6 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs @@ -2,14 +2,12 @@ using Monbsoft.Feeader.Avalonia.Services; using ReactiveUI; using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reactive.Concurrency; using System.Reactive.Linq; using System.Threading; -using System.Threading.Tasks; using System.Windows.Input; namespace Monbsoft.Feeader.Avalonia.ViewModels; @@ -23,13 +21,12 @@ public class MainWindowViewModel : ViewModelBase public MainWindowViewModel() { - ShowDialog = new Interaction(); + ShowDialog = new Interaction(); - AddFeedCommand = ReactiveCommand.CreateFromTask(async () => + ShowSettingsCommand = ReactiveCommand.CreateFromTask(async () => { - var store = new AddFeedViewModel(); + var store = new SettingsWindowViewModel(new FeedContext(Feeds)); var feed = await ShowDialog.Handle(store); - AddFeed(feed); }); this.WhenAnyValue(x => x.SelectedFeed) @@ -39,7 +36,7 @@ public MainWindowViewModel() RxApp.MainThreadScheduler.Schedule(LoadFeedsAsync); } - public ICommand AddFeedCommand { get; } + public ICommand ShowSettingsCommand { get; } public ObservableCollection Articles { get; } = new (); public ObservableCollection Feeds { get; } = new(); public Feed? SelectedFeed @@ -52,8 +49,8 @@ public ArticleViewModel? SelectedArticle get => _selectedArticle; set => this.RaiseAndSetIfChanged(ref _selectedArticle, value); } - public Interaction ShowDialog { get; } - + public Interaction ShowDialog { get; } + public async void LoadFeedsAsync() { FeedService.InitializeCache(); @@ -72,6 +69,7 @@ private async void AddFeed(Feed? feed) return; Feeds.Add(feed); await FeedService.SaveAsync(Feeds.ToList()); + Debug.WriteLine($"Feed {feed?.Name} added"); } private async void LoadArticles(Feed feed) { diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs new file mode 100644 index 0000000..6ab4fd8 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs @@ -0,0 +1,22 @@ +using Monbsoft.Feeader.Avalonia.Models; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Monbsoft.Feeader.Avalonia.ViewModels +{ + public class SettingsWindowViewModel : ViewModelBase + { + private readonly FeedContext _feedContext; + + public SettingsWindowViewModel(FeedContext context) + { + ChangeFeedViewModel = new ChangeFeedViewModel(context); + } + + public ChangeFeedViewModel ChangeFeedViewModel { get; } + } +} diff --git a/src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml b/src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml deleted file mode 100644 index 2f27393..0000000 --- a/src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml index 88ab9f0..3f624fa 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/ArticleView.axaml @@ -4,27 +4,20 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Monbsoft.Feeader.Avalonia.Views.ArticleView"> - - - - - + - - - - - + HorizontalAlignment="Stretch" + MaxHeight="300"/> + + + \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml new file mode 100644 index 0000000..8f9e7d6 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs similarity index 78% rename from src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml.cs rename to src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs index 0233294..d871e1e 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs @@ -4,9 +4,9 @@ namespace Monbsoft.Feeader.Avalonia.Views { - public partial class NavMenuView : UserControl + public partial class AddFeedView : UserControl { - public NavMenuView() + public AddFeedView() { InitializeComponent(); } diff --git a/src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml similarity index 84% rename from src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml rename to src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml index 18cdc04..a1e2afc 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/NavMenuView.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml @@ -3,7 +3,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Monbsoft.Feeader.Avalonia.Views.NavMenuView"> + x:Class="Monbsoft.Feeader.Avalonia.Views.FeedListView"> @@ -19,11 +19,11 @@ - + >Settings - \ No newline at end of file + diff --git a/src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml.cs new file mode 100644 index 0000000..1542095 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Views/FeedListView.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Monbsoft.Feeader.Avalonia.Views +{ + public partial class FeedListView : UserControl + { + public FeedListView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml index 4d07e69..d2e1a9b 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml @@ -17,9 +17,9 @@ - + - + diff --git a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs index c7162b6..3d467ab 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs @@ -12,23 +12,22 @@ public partial class MainWindow : ReactiveWindow { public MainWindow() { - InitializeComponent(); - this.WhenActivated(d => d(ViewModel!.ShowDialog.RegisterHandler(DoShowDialogAsync))); + InitializeComponent(); + this.WhenActivated(d => d(ViewModel!.ShowDialog.RegisterHandler(DoSettingsAsync))); } - private async Task DoShowDialogAsync(InteractionContext interaction) + private async Task DoSettingsAsync(InteractionContext interaction) { - var dialog = new AddFeedWindow(); + var dialog = new SettingsWindow(); dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; dialog.DataContext = interaction.Input; - dialog.Height = 200; - dialog.Width = 355; + dialog.Height = 450; + dialog.Width = 850; - var result = await dialog.ShowDialog(this); + var result = await dialog.ShowDialog(this); interaction.SetOutput(result); - - } + } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); diff --git a/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml new file mode 100644 index 0000000..74d8172 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml @@ -0,0 +1,12 @@ + + + + + diff --git a/src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs similarity index 54% rename from src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml.cs rename to src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs index 9cda3ba..7d4e687 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/AddFeedWindow.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs @@ -1,22 +1,17 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; -using Monbsoft.Feeader.Avalonia.ViewModels; -using ReactiveUI; -using System; namespace Monbsoft.Feeader.Avalonia.Views { - public partial class AddFeedWindow : ReactiveWindow + public partial class SettingsWindow : Window { - public AddFeedWindow() + public SettingsWindow() { InitializeComponent(); #if DEBUG this.AttachDevTools(); #endif - this.WhenActivated(d => d(ViewModel!.AddCommand.Subscribe(Close))); } private void InitializeComponent() From c13fe1668b02991b44607e01ccaa2fb9585ad9b8 Mon Sep 17 00:00:00 2001 From: oliver254 Date: Fri, 17 Jun 2022 00:41:37 +0200 Subject: [PATCH 3/4] #5 : Add settings for feeds --- src/Monbsoft.Feeader.Avalonia/Models/Feed.cs | 20 ++++++++ .../Models/FeedContext.cs | 18 ------- .../Models/SettingsContext.cs | 23 +++++++++ .../Monbsoft.Feeader.Avalonia.csproj | 5 -- .../ViewModels/ArticleViewModel.cs | 1 - ...eFeedViewModel.cs => EditFeedViewModel.cs} | 50 +++---------------- .../ViewModels/MainWindowViewModel.cs | 6 +-- .../ViewModels/SettingsWindowViewModel.cs | 12 +++-- .../Views/ChangeFeedView.axaml | 39 --------------- .../Views/EditFeedView.axaml | 32 ++++++++++++ ...eedView.axaml.cs => EditFeedView.axaml.cs} | 4 +- .../Views/MainWindow.axaml.cs | 10 ++-- .../Views/SettingsWindow.axaml | 3 +- .../Views/SettingsWindow.axaml.cs | 5 +- 14 files changed, 106 insertions(+), 122 deletions(-) delete mode 100644 src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs create mode 100644 src/Monbsoft.Feeader.Avalonia/Models/SettingsContext.cs rename src/Monbsoft.Feeader.Avalonia/ViewModels/{ChangeFeedViewModel.cs => EditFeedViewModel.cs} (55%) delete mode 100644 src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml create mode 100644 src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml rename src/Monbsoft.Feeader.Avalonia/Views/{ChangeFeedView.axaml.cs => EditFeedView.axaml.cs} (77%) diff --git a/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs b/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs index 4a269ee..7bf72ae 100644 --- a/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs +++ b/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs @@ -22,5 +22,25 @@ public Feed(string name, string link, DateTime creationDate) public string Link { get; set; } public string Name { get; } + public override bool Equals(object? obj) + { + Feed? other = obj as Feed; + + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + return string.Equals(Name, other.Name) && string.Equals(Link, other.Link); + + } + public override int GetHashCode() + { + return Name.GetHashCode() ^ Link.GetHashCode(); + } + override public string ToString() + { + return Name; + } + } } diff --git a/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs b/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs deleted file mode 100644 index 701068e..0000000 --- a/src/Monbsoft.Feeader.Avalonia/Models/FeedContext.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Monbsoft.Feeader.Avalonia.Models -{ - public class FeedContext - { - public FeedContext(IEnumerable feeds) - { - Feeds = feeds.ToList(); - } - - public List Feeds { get; } - } -} diff --git a/src/Monbsoft.Feeader.Avalonia/Models/SettingsContext.cs b/src/Monbsoft.Feeader.Avalonia/Models/SettingsContext.cs new file mode 100644 index 0000000..73c6e04 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Models/SettingsContext.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Monbsoft.Feeader.Avalonia.Models +{ + public class SettingsContext + { + public SettingsContext() + { + Feeds = new ObservableCollection(); + } + public SettingsContext(IEnumerable feeds) + { + Feeds = new ObservableCollection(feeds); + } + + public ObservableCollection Feeds { get; } + } +} diff --git a/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj b/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj index 2c71bc2..6c25e31 100644 --- a/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj +++ b/src/Monbsoft.Feeader.Avalonia/Monbsoft.Feeader.Avalonia.csproj @@ -29,9 +29,4 @@ - - - ChangeFeedView.axaml - - diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs index 3a053df..388147e 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/ArticleViewModel.cs @@ -13,7 +13,6 @@ public class ArticleViewModel : ViewModelBase { private Bitmap? _picture; private Uri? _pictureUri; - private Feed? _selectedFeed; public ArticleViewModel(Article article) { diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs similarity index 55% rename from src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs rename to src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs index fd282da..4110023 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/ChangeFeedViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs @@ -10,15 +10,11 @@ namespace Monbsoft.Feeader.Avalonia.ViewModels { - public class ChangeFeedViewModel : ViewModelBase + public class EditFeedViewModel : ViewModelBase { - private FeedContext _context; private string _name; private string _url; - private Feed? _selectedFeed; - private FeedState _state; - - public ChangeFeedViewModel(FeedContext context) + public EditFeedViewModel(SettingsContext context) { this.WhenAnyValue(x => x.Url) .Where(x => !string.IsNullOrWhiteSpace(x)) @@ -26,27 +22,11 @@ public ChangeFeedViewModel(FeedContext context) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(DoSearch); - this.WhenAnyValue(x => x.SelectedFeed) - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(f => - { - Name = f?.Name; - Url = f?.Link; - _state = f != null ? FeedState.Change : FeedState.Add; - }); - Feeds = new ObservableCollection(context.Feeds); - _state = FeedState.Add; - _context = context; - + AddCommand = ReactiveCommand.Create(() => { - if(_state == FeedState.Change && _selectedFeed != null) - { - _context.Feeds.Remove(_selectedFeed); - } - _context.Feeds.Add(new Feed(Name!, Url!)); - return _context; + Feeds.Add(new Feed("name", "https://feed.com")); }); } @@ -54,10 +34,7 @@ public ChangeFeedViewModel(FeedContext context) /// /// A /// - public ReactiveCommand AddCommand { get; } - /// - /// Gets the feeds - /// + public ReactiveCommand AddCommand { get; } public ObservableCollection Feeds { get; } /// /// Gets the name of the feed @@ -68,14 +45,6 @@ public string? Name set => this.RaiseAndSetIfChanged(ref _name, value); } /// - /// Gets or sets the selected feed - /// - public Feed? SelectedFeed - { - get => _selectedFeed; - set => this.RaiseAndSetIfChanged(ref _selectedFeed, value); - } - /// /// Gets the url of the feed /// public string? Url @@ -98,13 +67,6 @@ private async void DoSearch(string? url) { Log.Error(ex.Message); } - } - - enum FeedState - { - Add = 0, - Change = 1 - } - + } } } \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs index 29bdfa6..c4b5796 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs @@ -21,11 +21,11 @@ public class MainWindowViewModel : ViewModelBase public MainWindowViewModel() { - ShowDialog = new Interaction(); + ShowDialog = new Interaction(); ShowSettingsCommand = ReactiveCommand.CreateFromTask(async () => { - var store = new SettingsWindowViewModel(new FeedContext(Feeds)); + var store = new SettingsWindowViewModel(new SettingsContext(Feeds)); var feed = await ShowDialog.Handle(store); }); @@ -49,7 +49,7 @@ public ArticleViewModel? SelectedArticle get => _selectedArticle; set => this.RaiseAndSetIfChanged(ref _selectedArticle, value); } - public Interaction ShowDialog { get; } + public Interaction ShowDialog { get; } public async void LoadFeedsAsync() { diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs index 6ab4fd8..9dc0ded 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/SettingsWindowViewModel.cs @@ -10,13 +10,17 @@ namespace Monbsoft.Feeader.Avalonia.ViewModels { public class SettingsWindowViewModel : ViewModelBase { - private readonly FeedContext _feedContext; - public SettingsWindowViewModel(FeedContext context) + public SettingsWindowViewModel(SettingsContext context) { - ChangeFeedViewModel = new ChangeFeedViewModel(context); + EditFeedViewModel = new EditFeedViewModel(context); } - public ChangeFeedViewModel ChangeFeedViewModel { get; } + public EditFeedViewModel EditFeedViewModel { get; } + + public SettingsContext CreateContext() + { + return new SettingsContext(EditFeedViewModel.Feeds); + } } } diff --git a/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml deleted file mode 100644 index 8f9e7d6..0000000 --- a/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml new file mode 100644 index 0000000..2cc23f4 --- /dev/null +++ b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml.cs similarity index 77% rename from src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs rename to src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml.cs index d871e1e..d28e091 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/ChangeFeedView.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml.cs @@ -4,9 +4,9 @@ namespace Monbsoft.Feeader.Avalonia.Views { - public partial class AddFeedView : UserControl + public partial class EditFeedView : UserControl { - public AddFeedView() + public EditFeedView() { InitializeComponent(); } diff --git a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs index 3d467ab..2d29e0c 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/MainWindow.axaml.cs @@ -4,6 +4,7 @@ using Monbsoft.Feeader.Avalonia.Models; using Monbsoft.Feeader.Avalonia.ViewModels; using ReactiveUI; +using System.Reactive; using System.Threading.Tasks; namespace Monbsoft.Feeader.Avalonia.Views @@ -16,16 +17,17 @@ public MainWindow() this.WhenActivated(d => d(ViewModel!.ShowDialog.RegisterHandler(DoSettingsAsync))); } - private async Task DoSettingsAsync(InteractionContext interaction) + private async Task DoSettingsAsync(InteractionContext interaction) { var dialog = new SettingsWindow(); dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; dialog.DataContext = interaction.Input; dialog.Height = 450; dialog.Width = 850; - - var result = await dialog.ShowDialog(this); - interaction.SetOutput(result); + + await dialog.ShowDialog(this); + + interaction.SetOutput(dialog.ViewModel?.CreateContext() ?? new SettingsContext()); } private void InitializeComponent() diff --git a/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml index 74d8172..614409b 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml @@ -7,6 +7,7 @@ x:Class="Monbsoft.Feeader.Avalonia.Views.SettingsWindow" Title="Settings"> - + + diff --git a/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs index 7d4e687..cea61c8 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs +++ b/src/Monbsoft.Feeader.Avalonia/Views/SettingsWindow.axaml.cs @@ -1,10 +1,12 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using Monbsoft.Feeader.Avalonia.ViewModels; namespace Monbsoft.Feeader.Avalonia.Views { - public partial class SettingsWindow : Window + public partial class SettingsWindow : ReactiveWindow { public SettingsWindow() { @@ -12,6 +14,7 @@ public SettingsWindow() #if DEBUG this.AttachDevTools(); #endif + } private void InitializeComponent() From c62a5ad1e451be6e38642aceec106f44b5d3703f Mon Sep 17 00:00:00 2001 From: oliver254 Date: Fri, 17 Jun 2022 01:17:54 +0200 Subject: [PATCH 4/4] #5 : Change edit feed --- src/Monbsoft.Feeader.Avalonia/Models/Feed.cs | 2 +- .../ViewModels/EditFeedViewModel.cs | 22 ++++++- .../ViewModels/MainWindowViewModel.cs | 62 ++++++++++--------- .../Views/EditFeedView.axaml | 31 ++++++++-- 4 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs b/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs index 7bf72ae..a4e5bed 100644 --- a/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs +++ b/src/Monbsoft.Feeader.Avalonia/Models/Feed.cs @@ -20,7 +20,7 @@ public Feed(string name, string link, DateTime creationDate) public DateTime CreationDate { get; } public string Link { get; set; } - public string Name { get; } + public string Name { get; set; } public override bool Equals(object? obj) { diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs index 4110023..f2d3342 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/EditFeedViewModel.cs @@ -4,6 +4,7 @@ using ReactiveUI; using System; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Reactive; using System.Reactive.Linq; @@ -13,6 +14,7 @@ namespace Monbsoft.Feeader.Avalonia.ViewModels public class EditFeedViewModel : ViewModelBase { private string _name; + private Feed? _selected; private string _url; public EditFeedViewModel(SettingsContext context) { @@ -27,12 +29,21 @@ public EditFeedViewModel(SettingsContext context) AddCommand = ReactiveCommand.Create(() => { Feeds.Add(new Feed("name", "https://feed.com")); + Debug.WriteLine($"Feed added"); + }); + RemoveCommand = ReactiveCommand.Create(() => + { + if(_selected != null) + { + Feeds.Remove(_selected); + Debug.WriteLine($"Feed {_selected?.Name} removed"); + } }); } /// - /// A + /// Gets the add command /// public ReactiveCommand AddCommand { get; } public ObservableCollection Feeds { get; } @@ -44,6 +55,15 @@ public string? Name get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } + public ReactiveCommand RemoveCommand { get; } + /// + /// Gets or sets the selected feed + /// + public Feed SelectedFeed + { + get => _selected; + set => this.RaiseAndSetIfChanged(ref _selected, value); + } /// /// Gets the url of the feed /// diff --git a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs index c4b5796..a7dd5e4 100644 --- a/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/src/Monbsoft.Feeader.Avalonia/ViewModels/MainWindowViewModel.cs @@ -20,72 +20,78 @@ public class MainWindowViewModel : ViewModelBase public MainWindowViewModel() { - ShowDialog = new Interaction(); ShowSettingsCommand = ReactiveCommand.CreateFromTask(async () => { var store = new SettingsWindowViewModel(new SettingsContext(Feeds)); - var feed = await ShowDialog.Handle(store); + var context = await ShowDialog.Handle(store); + await FeedService.SaveAsync(context.Feeds.ToList()); + LoadFeedsAsync(); }); this.WhenAnyValue(x => x.SelectedFeed) - .WhereNotNull() .Subscribe(LoadArticles); + FeedService.InitializeCache(); + PictureService.InitializePictureCache(); + RxApp.MainThreadScheduler.Schedule(LoadFeedsAsync); } public ICommand ShowSettingsCommand { get; } - public ObservableCollection Articles { get; } = new (); + public ObservableCollection Articles { get; } = new(); public ObservableCollection Feeds { get; } = new(); + public Feed? SelectedFeed { get => _selectedFeed; set => this.RaiseAndSetIfChanged(ref _selectedFeed, value); } + public ArticleViewModel? SelectedArticle { get => _selectedArticle; set => this.RaiseAndSetIfChanged(ref _selectedArticle, value); } - public Interaction ShowDialog { get; } - + + public Interaction ShowDialog { get; } + public async void LoadFeedsAsync() { - FeedService.InitializeCache(); - PictureService.InitializePictureCache(); - var feeds = await FeedService.LoadAsync(); + var feeds = await FeedService.LoadAsync(); + + SelectedFeed = null; + Feeds.Clear(); - foreach(var feed in feeds) + foreach (var feed in feeds) { Feeds.Add(feed); } Trace.TraceInformation("{0} feeds loaded", Feeds.Count); } - private async void AddFeed(Feed? feed) - { - if (feed == null) - return; - Feeds.Add(feed); - await FeedService.SaveAsync(Feeds.ToList()); - Debug.WriteLine($"Feed {feed?.Name} added"); - } - private async void LoadArticles(Feed feed) + + private async void LoadArticles(Feed? feed) { + Articles.Clear(); + _cancellationTokenSource?.Cancel(); _cancellationTokenSource = new CancellationTokenSource(); - Articles.Clear(); - foreach(var article in await ArticleService.LoadAsync(feed, _cancellationTokenSource.Token)) - { - Articles.Add(new ArticleViewModel(article)); - } - if (!_cancellationTokenSource.IsCancellationRequested) + + if (feed != null) { - LoadPictures(_cancellationTokenSource.Token); + foreach (var article in await ArticleService.LoadAsync(feed, _cancellationTokenSource.Token)) + { + Articles.Add(new ArticleViewModel(article)); + } + if (!_cancellationTokenSource.IsCancellationRequested) + { + LoadPictures(_cancellationTokenSource.Token); + } } Trace.TraceInformation("{0} articles loaded", Articles.Count); } + private async void LoadPictures(CancellationToken cancellationToken) { foreach (var article in Articles) @@ -95,8 +101,8 @@ private async void LoadPictures(CancellationToken cancellationToken) if (cancellationToken.IsCancellationRequested) { return; - } + } } Trace.TraceInformation("Pictures loaded"); } -} +} \ No newline at end of file diff --git a/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml index 2cc23f4..2a54a63 100644 --- a/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml +++ b/src/Monbsoft.Feeader.Avalonia/Views/EditFeedView.axaml @@ -7,7 +7,7 @@ - + @@ -19,14 +19,37 @@ - - + - + + + + + + + + + + + + + + + \ No newline at end of file