Working out treeview.

This commit is contained in:
Max 2023-05-15 20:42:42 +02:00
parent 88ce202de4
commit cd9233c162
7 changed files with 27 additions and 242 deletions

View File

@ -1,4 +1,5 @@
using CodeHollow.FeedReader; using System.Threading.Tasks;
using CodeHollow.FeedReader;
namespace SharpRss.Models namespace SharpRss.Models
{ {
@ -9,14 +10,9 @@ namespace SharpRss.Models
_rssUrl = rssUrl; _rssUrl = rssUrl;
_fetchTask = FetchAsync(); _fetchTask = FetchAsync();
} }
private Task _fetchTask; private readonly Task _fetchTask;
private async Task FetchAsync() public async Task FetchAsync() => _feed = await FeedCache.GetFeed(_rssUrl);
{
IsReady = false;
_feed = await FeedCache.GetFeed(_rssUrl);
IsReady = true;
}
private Feed? _feed; private Feed? _feed;
public Feed Base { public Feed Base {
@ -25,16 +21,14 @@ namespace SharpRss.Models
if (_feed == null) if (_feed == null)
{ {
if (_fetchTask.IsFaulted) if (_fetchTask.IsFaulted)
{ IsFaulted = _fetchTask.IsFaulted; return new Feed(); } { return new Feed(); }
if (!(_fetchTask.Status == TaskStatus.Running || _fetchTask.Status == TaskStatus.WaitingForActivation)) if (_fetchTask.Status is not (TaskStatus.Running or TaskStatus.WaitingForActivation))
_fetchTask.Start(); _fetchTask.Start();
_fetchTask.Wait(); _fetchTask.Wait();
} }
return _feed ?? new Feed(); return _feed ?? new Feed();
} }
} }
public bool IsFaulted { get; private set; }
public bool IsReady { get; private set; }
private readonly string _rssUrl; private readonly string _rssUrl;
} }
} }

View File

@ -27,7 +27,6 @@ namespace SharpRss
private static HashSet<FeedModel> feedSet2 = new HashSet<FeedModel>() private static HashSet<FeedModel> feedSet2 = new HashSet<FeedModel>()
{ {
new FeedModel("https://journals.plos.org/plosone/feed/atom"), new FeedModel("https://journals.plos.org/plosone/feed/atom"),
new FeedModel("https://cyberciti.biz/feed"),
new FeedModel("https://itsfoss.com/feed") new FeedModel("https://itsfoss.com/feed")
}; };

View File

@ -1,3 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CodeHollow.FeedReader; using CodeHollow.FeedReader;
using MudBlazor; using MudBlazor;
using SharpRss.Models; using SharpRss.Models;
@ -5,25 +8,23 @@ using ToolQit;
namespace WebSharpRSS.Models namespace WebSharpRSS.Models
{ {
public class GuideItemModel public class TreeItemData
{ {
public GuideItemModel(CategoryModel catModel) public TreeItemData(CategoryModel catModel)
{ {
CategoryModel = catModel; CategoryModel = catModel;
Feeds = CategoryModel.Feeds.Where(x => !x.IsFaulted && x.Base != null).Select(x => new GuideItemModel(x)).ToHashSet(); Feeds = CategoryModel.Feeds.Where(x => x.Base != null).Select(x => new TreeItemData(x)).ToHashSet();
Title = CategoryModel.Name; Title = CategoryModel.Name;
Icon = Icons.Material.Filled.RssFeed; Icon = Icons.Material.Filled.RssFeed;
} }
public GuideItemModel(FeedModel feedModel) public TreeItemData(FeedModel feedModel)
{ {
if (feedModel.IsFaulted)
return;
FeedModel = feedModel; FeedModel = feedModel;
Feed = FeedModel.Base; Feed = FeedModel.Base;
Title = Feed.Title; Title = Feed.Title;
string faviconAdress = Feed.Link.Remove(Feed.Link.IndexOf("http"), Feed.Link.IndexOf("://") + 3); string faviconAddress = Feed.Link.Remove(Feed.Link.IndexOf("http", StringComparison.Ordinal), Feed.Link.IndexOf("://", StringComparison.Ordinal) + 3);
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), faviconAdress); FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), faviconAddress);
} }
public readonly CategoryModel? CategoryModel; public readonly CategoryModel? CategoryModel;
@ -36,7 +37,7 @@ namespace WebSharpRSS.Models
// Category // Category
public bool IsExpanded { get; set; } public bool IsExpanded { get; set; }
public HashSet<GuideItemModel>? Feeds { get; set; } public HashSet<TreeItemData>? Feeds { get; set; }
// Feed // Feed
public Feed? Feed { get; set; } public Feed? Feed { get; set; }
} }

View File

@ -1,6 +1,6 @@
{ {
"Paths": { "Paths": {
"FaviconResolveUrl": "https://icons.duckduckgo.com/ip3/{0}.ico", "FaviconResolveUrl": "http://www.google.com/s2/favicons?domain={0}",
"LogPath": "/home/max/GitHub/SharpRSS/WebSharpRSS/logs/log_.json" "LogPath": "/home/max/GitHub/SharpRSS/WebSharpRSS/logs/log_.json"
}, },
"SQL": { "SQL": {

View File

@ -1,149 +0,0 @@
@using CodeHollow.FeedReader
@using SharpRss.Models
@using ToolQit
@using ToolQit.Containers
@using ToolQit.Extensions
@using WebSharpRSS.Models;
<style>
.cat-item {
background: var(--background-color);
width: 100%;
display: flex;
position: relative;
box-sizing: border-box;
text-align: start;
align-items: center;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 12px;
justify-content: flex-start;
text-decoration: none;
}
.cat-item:hover {
background: var(--hover-bg-color);
}
.cat-item-text {
flex: 1 1 auto;
min-width: 0;
}
.cat-item-icon {
display: inline-flex;
min-width: 56px;
flex-shrink: 0;
}
.feed-item {
background: var(--background-color);
width: 100%;
display: flex;
position: relative;
box-sizing: border-box;
text-align: start;
align-items: center;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 30px;
justify-content: flex-start;
text-decoration: none;
}
.feed-item:hover {
background: var(--hover-bg-color);
}
.feed-item-text {
flex: 1 1 auto;
min-width: 0;
}
.feed-item-icon {
display: inline-flex;
min-width: 56px;
flex-shrink: 0;
}
</style>
<div>
<MudText>@HeaderText</MudText>
@foreach (GuideItemModel guideModel in GuideItems)
{
<GuideItem Model="@guideModel" ItemClicked="ItemClicked"/>
#if false
<div>
<div @onclick="@(() => guideItem.ItemClick())" class="cat-item mud-ripple" style="--hover-bg-color: @Colors.Blue.Accent1; --background-color: @(guideItem.IsSelected ? Colors.Blue.Accent2 : "transparent")">
<div class="cat-item-icon">
@if (guideItem.FaviconUrl != null)
{
<MudImage ObjectFit="ObjectFit.ScaleDown" Src="@guideItem.FaviconUrl" />
}
else
{
<MudIcon Class="pointer-events-none" Icon="@guideItem.Icon" Size="Size.Medium" />
}
</div>
<div class="cat-item-text">
<MudText Class="pointer-events-none" Typo="Typo.subtitle1">@guideItem.Title</MudText>
</div>
</div>
@* Feeds *@
@if (guideItem.IsExpanded && guideItem.Feeds != null)
{
foreach (FeedModel feed in guideItem.Feeds)
{
if (feed == null || feed.Base == null) continue;
<div @onclick="() => ItemClicked(feed)" class="feed-item mud-ripple" style="--hover-bg-color: @Colors.Blue.Accent1; --background-color: @(feed.IsSelected ? Colors.Blue.Accent2 : "transparent")">
<div class="feed-item-icon">
@*@if (!guideFeed.FaviconUrl.IsNullEmptyWhiteSpace())
{
<MudImage ObjectFit="ObjectFit.ScaleDown" Src="@guideFeed.FaviconUrl"/>
}
else
{
<MudIcon Icon="@Icons.Material.Filled.RssFeed" Size="Size.Medium"/>
}*@
<MudIcon Icon="@Icons.Material.Filled.RssFeed" Size="Size.Medium"/>
</div>
<div class="feed-item-text">
<MudText Class="pointer-events-none">@feed.Base.Title</MudText>
</div>
</div>
}
}
</div>
#endif
}
</div>
@code {
[Parameter]
public string HeaderText { get; set; } = string.Empty;
[Parameter]
public HashSet<GuideItemModel> GuideItems { get; set; } = new HashSet<GuideItemModel>();
[Parameter]
public Action<CategoryModel>? CatItemClicked { get; set; }
[Parameter]
public Action<FeedModel>? FeedItemClicked { get; set; }
GuideItemModel? _selectedItem;
void ItemClicked(GuideItemModel model)
{
model.IsExpanded = !model.IsExpanded;
if (_selectedItem != model)
{
if (_selectedItem != null)
_selectedItem.IsSelected = false;
_selectedItem = model;
_selectedItem.IsSelected = true;
}
if (model.Feeds != null && model.Feeds.Count >= 1)
{
if (model.CategoryModel != null)
CatItemClicked?.Invoke(model.CategoryModel);
}
else
{
if (model.FeedModel != null)
FeedItemClicked?.Invoke(model.FeedModel);
}
}
}

View File

@ -1,45 +0,0 @@
@using WebSharpRSS.Models;
<div>
<div @onclick="@(() => ItemClickedVoid())" class="cat-item mud-ripple" style="--hover-bg-color: @Colors.Blue.Accent1; --background-color: @(Model.IsSelected ? Colors.Blue.Accent2 : "transparent")">
<div class="cat-item-icon">
@if (Model.FaviconUrl != null)
{
<MudImage ObjectFit="ObjectFit.ScaleDown" Src="@Model.FaviconUrl" />
}
else
{
<MudIcon Class="pointer-events-none" Icon="@Model.Icon" Size="Size.Medium" />
}
</div>
<div class="cat-item-text">
<MudText Class="pointer-events-none" Typo="Typo.subtitle1">@Model.Title</MudText>
</div>
</div>
@if (IsExpanded && Model.Feeds != null && !(Model.Feeds.Count <= 0))
{
foreach (GuideItemModel item in Model.Feeds)
{
<div style="margin-left: 20px">
<GuideItem Model="@item" />
</div>
}
}
</div>
@code {
[Parameter]
public GuideItemModel Model { get; set; }
[Parameter]
public EventCallback<GuideItemModel> ItemClicked { get; set; }
public bool IsExpanded { get; set; }
private void ItemClickedVoid()
{
IsExpanded = !IsExpanded;
ItemClicked.InvokeAsync(Model);
}
}

View File

@ -10,36 +10,21 @@
<MudNavMenu> <MudNavMenu>
<MudNavLink Href="/" Icon="@Icons.Material.Filled.Home">Home</MudNavLink> <MudNavLink Href="/" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
</MudNavMenu> </MudNavMenu>
<CategoryGuide GuideItems="Categories" CatItemClicked="CategoryClicked" FeedItemClicked="FeedClicked"/> <MudTreeView Items="Categories" @bind-SelectedValue="SelectedItem" @bind-ActivatedItem="ActivatedItem" Hover="true">
<ItemTemplate>
<MudTreeViewItem Items="@context.Feeds" Icon="@context.Icon" Text="@context.Title"/>
</ItemTemplate>
</MudTreeView>
</MudStack> </MudStack>
@code { @code {
public HashSet<GuideItemModel> Categories = new HashSet<GuideItemModel>(); public HashSet<TreeItemData> Categories = new HashSet<TreeItemData>();
private TreeItemData ActivatedItem { get; set; }
private TreeItemData SelectedItem { get; set; }
protected override async void OnInitialized() protected override async void OnInitialized()
{ {
Log.Verbose("Setting up test data"); Log.Verbose("Loading guide data...");
//Categories = _rssService.GetCategories().Result;
HashSet<CategoryModel> cats = await _rssService.GetCategories(); HashSet<CategoryModel> cats = await _rssService.GetCategories();
await Task.Run(() => Categories = cats.Select(x => new GuideItemModel(x)).ToHashSet()); await Task.Run(() => Categories = cats.Select(x => new TreeItemData(x)).ToHashSet());
}
private void Callback(MudListItem obj)
{
switch (obj.Value)
{
case CategoryModel catModel:
break;
case FeedModel feedModel:
break;
} }
} }
private void CategoryClicked(CategoryModel cat)
{
}
private void FeedClicked(FeedModel guideFeedItem)
{
}
}